1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /*
20 * This file is part of the XForms library package.
21 * Copyright (c) 1993, 1998-2002 By T.C. Zhao
22 * All rights reserved.
23 *
24 * Image rotation
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "include/forms.h"
32 #include "flimage.h"
33 #include "flimage_int.h"
34 #include <stdlib.h>
35 #include <math.h>
36
37 #ifndef M_PI
38 #define M_PI 3.1415926
39 #endif
40
41
42 static void *rotate_matrix( void *,
43 int,
44 int,
45 int,
46 size_t );
47
48
49 /***************************************
50 * rotation angle is one-tenth of a degree
51 ***************************************/
52
53 int
flimage_rotate(FL_IMAGE * im,int deg,int subp)54 flimage_rotate( FL_IMAGE * im,
55 int deg,
56 int subp )
57 {
58 int nw,
59 nh;
60 float mat[ 2 ][ 2 ];
61 void *r,
62 *g = 0,
63 *b = 0;
64
65 /* normalize the angle to within (0,360) */
66
67 while ( deg < 0 )
68 deg += 3600;
69 while ( deg >= 3600 )
70 deg -= 3600;
71
72 if ( deg == 0 || deg == 3600 )
73 return 0;
74
75 /* handle special cases TODO */
76
77 if ( deg % 900 == 0 )
78 {
79 deg /= 10;
80 if ( im->type == FL_IMAGE_RGB )
81 {
82 r = rotate_matrix( im->red, im->h, im->w, deg,
83 sizeof **im->red );
84 g = rotate_matrix( im->green, im->h, im->w, deg,
85 sizeof **im->green );
86 b = rotate_matrix( im->blue, im->h, im->w, deg,
87 sizeof **im->blue );
88 }
89 else if ( im->type == FL_IMAGE_GRAY )
90 r = rotate_matrix( im->gray, im->h, im->w, deg, sizeof **im->gray );
91 else if ( im->type == FL_IMAGE_CI )
92 r = rotate_matrix( im->ci, im->h, im->w, deg, sizeof **im->ci );
93 else
94 {
95 M_err( "flimage_rotate", "InternalError: unsupported image "
96 "type\n" );
97 return -1;
98 }
99
100 if ( deg % 180 == 0 )
101 {
102 nw = im->w;
103 nh = im->h;
104 }
105 else
106 {
107 nw = im->h;
108 nh = im->w;
109 }
110
111 if ( ! r )
112 return -1;
113
114 flimage_replace_image( im, nw, nh, r, g, b );
115
116 return 0;
117 }
118
119 /* three shear is slightly faster , but with general transform,
120 * we save a lot of code */
121
122 mat[ 0 ][ 0 ] = mat[ 1 ][ 1 ] = cos( deg * M_PI / 1800.0 );
123 mat[ 0 ][ 1 ] = sin( deg * M_PI / 1800.0 );
124 mat[ 1 ][ 0 ] = -mat[ 0 ][ 1 ];
125
126 nw = nh = 0;
127
128 if ( flimage_warp(im, mat, nw, nh, subp) >= 0 )
129 {
130 im->completed = im->h;
131 im->visual_cue( im, "Rotation Done" );
132 return 0;
133 }
134 else
135 return -1;
136 }
137
138
139 static int flip_matrix( void *,
140 int,
141 int,
142 int,
143 int );
144
145
146 /***************************************
147 ***************************************/
148
149 int
flimage_flip(FL_IMAGE * im,int axis)150 flimage_flip( FL_IMAGE * im,
151 int axis )
152 {
153 int err = 0;
154
155 if ( im->type == FL_IMAGE_RGB )
156 err = flip_matrix( im->red, im->h, im->w, 1, axis ) < 0
157 || flip_matrix( im->green, im->h, im->w, 1, axis ) < 0
158 || flip_matrix( im->blue, im->h, im->w, 1, axis ) < 0;
159 else if (FL_IsGray(im->type))
160 err = flip_matrix( im->gray, im->h, im->w, 2, axis ) < 0;
161 else
162 err = flip_matrix( im->ci, im->h, im->w, 2, axis ) < 0;
163
164 if ( ! err )
165 im->modified = 1;
166
167 return err ? -1 : 0;
168 }
169
170
171 /* low level matrix stuff */
172
173 #define flip_col( type, matrix, rows, cols ) \
174 do { \
175 type **mm = matrix, \
176 *t, \
177 *h, \
178 tmp; \
179 int j; \
180 for ( j = 0; j < rows; j++ ) \
181 for( t = ( h = mm[ j ] ) + cols - 1; t > h; t--, h++ ) \
182 { \
183 tmp = *h; \
184 *h = *t; \
185 *t = tmp; \
186 } \
187 } while ( 0 )
188
189
190
191 /***************************************
192 * flip a matrix. Mirror about the x or y
193 ***************************************/
194
195 static int
flip_matrix(void * matrix,int rows,int cols,int esize,int what)196 flip_matrix( void * matrix,
197 int rows,
198 int cols,
199 int esize,
200 int what )
201 {
202 if ( what == 'c' || what == 'x' ) /* flip columns */
203 {
204 if ( esize == 2 )
205 flip_col( unsigned short, matrix, rows, cols );
206 else
207 flip_col( unsigned char, matrix, rows, cols );
208 }
209 else
210 {
211 int i,
212 is = rows / 2;
213 size_t size = esize * cols;
214 unsigned char *tmp,
215 **mm = matrix;
216
217 if ( ! ( tmp = fl_malloc( size ) ) )
218 return -1;
219
220 /* if we only flip the pointers, this will be faster, but then, the
221 1-d property is violated */
222
223 for ( i = 0; i < is; i++ )
224 {
225 memcpy( tmp, mm[ i ], size );
226 memcpy( mm[ i ], mm[ rows - 1 - i ], size );
227 memcpy( mm[ rows - 1 - i ], tmp, size );
228 }
229
230 fl_free( tmp );
231 }
232
233 return 0;
234 }
235
236
237 /* special angles: +-90, +-180 */
238 /***************************************************************
239 * rotate a matrix by 90, or -90 or multiples of it
240 * Rotate 180 can be implented as two 90 rotations, but current
241 * code is faster.
242 *
243 * NOTE: input dimension is the diemsnion of the matrix to be
244 * rotated. caller must take care of the rotated dimensions
245 **************************************************************/
246
247 /* Rotate 90 degrees */
248
249 #define DO_M90( type, out, in ) \
250 do { \
251 type *p= ( ( type ** ) out )[ 0 ], \
252 **o= in; \
253 int i, \
254 j; \
255 for ( j = 0; j < col; j++ ) \
256 { \
257 for ( i = row - 1; i >= 0; i-- ) \
258 *p++ = o[ i ][ j ]; \
259 } \
260 } while ( 0 )
261
262 /* Rotate -90 degrees */
263
264 #define DO_90( type, out, in ) \
265 do { \
266 type *p= ( ( type ** ) out )[ 0 ], \
267 **o= in; \
268 int i, \
269 j; \
270 for ( j = col - 1; j >= 0; j-- ) \
271 { \
272 for ( i = 0; i < row; i++ ) \
273 *p++ = o[ i ][ j ]; \
274 } \
275 } while ( 0 )
276
277 #define DO_180( ty, out, in ) \
278 do { \
279 ty *p= ( ( ty ** ) out )[ 0 ], \
280 *o= ( ( ty ** ) in )[ 0 ]; \
281 ty *os; \
282 for ( os= o + col * row-1 ; os > o; *p++ = *os-- ) \
283 /* empty */ ; \
284 } while( 0 )
285
286
287
288 /***************************************
289 ***************************************/
290
291 static void *
rotate_matrix(void * m,int row,int col,int deg,size_t e)292 rotate_matrix( void * m,
293 int row,
294 int col,
295 int deg,
296 size_t e )
297 {
298 int nrow = row,
299 ncol = col;
300 void *mm;
301
302 /* Coerce angle to be +/- 360 */
303
304 deg %= 360;
305
306 /* Now coerce it into +/- 180. */
307
308 if ( abs( deg ) > 180 )
309 {
310 if ( deg < 0 )
311 deg += 360;
312 else
313 deg -= 360;
314 }
315
316 if ( deg == 90 || deg == -90 )
317 {
318 nrow = col;
319 ncol = row;
320 }
321
322 if ( ! ( mm = fl_get_matrix( nrow, ncol, e ) ) )
323 return 0;
324
325 if ( deg == 90 )
326 {
327 if ( e == 2 )
328 DO_90( unsigned short, mm, m );
329 else
330 DO_90( unsigned char, mm, m );
331 }
332 else if ( deg == -90 )
333 {
334 if ( e == 2 )
335 DO_M90( unsigned short, mm, m );
336 else
337 DO_M90( unsigned char, mm, m );
338 }
339 else if ( deg == 180 || deg == -180 )
340 {
341 if ( e == 2 )
342 DO_180( unsigned short, mm, m );
343 else
344 DO_180( unsigned char, mm, m );
345 }
346 else
347 {
348 M_err( "RotateMatrix", "InternalError: bad special angle\n" );
349 return 0;
350 }
351
352 return mm;
353 }
354
355
356 /*
357 * Local variables:
358 * tab-width: 4
359 * indent-tabs-mode: nil
360 * End:
361 */
362