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