1 /* rotate.c - image rotation
3 * Raster graphics library
5 * Copyright (c) 2000-2003 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
38 static RImage
*rotate_image_90(RImage
*source
);
39 static RImage
*rotate_image_270(RImage
*source
);
40 static RImage
*rotate_image_any(RImage
*source
, float angle
);
43 RImage
*RRotateImage(RImage
*image
, float angle
)
46 * Angle steps below this value would represent a rotation
47 * of less than 1 pixel for a 4k wide image, so not worth
48 * bothering the difference. That makes it a perfect
49 * candidate for an Epsilon when trying to compare angle
52 static const float min_usable_angle
= 0.00699F
;
54 angle
= fmod(angle
, 360.0);
58 if (angle
< min_usable_angle
) {
59 /* Rotate by 0 degree */
60 return RCloneImage(image
);
62 } else if ((angle
> 90.0F
- min_usable_angle
) &&
63 (angle
< 90.0F
+ min_usable_angle
)) {
64 return rotate_image_90(image
);
66 } else if ((angle
> 180.0F
- min_usable_angle
) &&
67 (angle
< 180.0F
+ min_usable_angle
)) {
68 return wraster_rotate_image_180(image
);
70 } else if ((angle
> 270.0F
- min_usable_angle
) &&
71 (angle
< 270.0F
+ min_usable_angle
)) {
72 return rotate_image_270(image
);
75 return rotate_image_any(image
, angle
);
79 static RImage
*rotate_image_90(RImage
*source
)
85 nwidth
= source
->height
;
86 nheight
= source
->width
;
88 target
= RCreateImage(nwidth
, nheight
, (source
->format
!= RRGBFormat
));
92 if (source
->format
== RRGBFormat
) {
93 unsigned char *optr
, *nptr
;
96 for (x
= nwidth
; x
; x
--) {
97 nptr
= target
->data
+ 3 * (x
- 1);
98 for (y
= nheight
; y
; y
--) {
108 unsigned char *optr
, *nptr
;
111 for (x
= nwidth
; x
; x
--) {
112 nptr
= target
->data
+ 4 * (x
- 1);
113 for (y
= nheight
; y
; y
--) {
127 RImage
*wraster_rotate_image_180(RImage
*source
)
133 nwidth
= source
->width
;
134 nheight
= source
->height
;
136 target
= RCreateImage(nwidth
, nheight
, (source
->format
!= RRGBFormat
));
140 if (source
->format
== RRGBFormat
) {
141 unsigned char *optr
, *nptr
;
144 nptr
= target
->data
+ nwidth
* nheight
* 3 - 3;
146 for (y
= 0; y
< nheight
; y
++) {
147 for (x
= 0; x
< nwidth
; x
++) {
158 unsigned char *optr
, *nptr
;
161 nptr
= target
->data
+ nwidth
* nheight
* 4 - 4;
163 for (y
= nheight
* nwidth
- 1; y
>= 0; y
--) {
177 static RImage
*rotate_image_270(RImage
*source
)
183 nwidth
= source
->height
;
184 nheight
= source
->width
;
186 target
= RCreateImage(nwidth
, nheight
, (source
->format
!= RRGBFormat
));
190 if (source
->format
== RRGBFormat
) {
191 unsigned char *optr
, *nptr
;
194 for (x
= nwidth
; x
; x
--) {
195 nptr
= target
->data
+ 3 * nwidth
* nheight
- x
* 3;
196 for (y
= nheight
; y
; y
--) {
206 unsigned char *optr
, *nptr
;
209 for (x
= nwidth
; x
; x
--) {
210 nptr
= target
->data
+ 4 * nwidth
* nheight
- x
* 4;
211 for (y
= nheight
; y
; y
--) {
226 * Image rotation through Bresenham's line algorithm:
228 * If a square must be rotate by angle a, like in:
234 * |A1 6 / | A_______B
235 * | \5 / a| <--- |1 2 3 4|
236 * |__C/_)_| |5 6 7 8|
239 * for each point P1 in the line from C to A
240 * for each point P2 in the perpendicular line starting at P1
241 * get pixel from the source and plot at P2
242 * increment pixel location from source
248 copyLine(int x1
, int y1
, int x2
, int y2
, int nwidth
, int format
, unsigned char *dst
, unsigned char **src
)
250 unsigned char *s
= *src
;
271 dpru
= dpr
- (dx
<< 1);
275 /* fetch and draw the pixel */
276 offset
= (x1
+ y1
* nwidth
) << 2;
277 dst
[offset
++] = *s
++;
278 dst
[offset
++] = *s
++;
279 dst
[offset
++] = *s
++;
280 if (format
== RRGBAFormat
)
281 dst
[offset
++] = *s
++;
298 dpru
= dpr
- (dy
<< 1);
302 /* fetch and draw the pixel */
303 offset
= (x1
+ y1
* nwidth
) << 2;
304 dst
[offset
++] = *s
++;
305 dst
[offset
++] = *s
++;
306 dst
[offset
++] = *s
++;
307 if (format
== RRGBAFormat
)
308 dst
[offset
++] = *s
++;
328 static RImage
*rotate_image_any(RImage
*source
, float angle
)
331 puts("NOT FULLY IMPLEMENTED");
332 return RCloneImage(source
);
341 unsigned char *src
, *dst
;
344 /* only 180o for now */
348 angle
= (angle
* WM_PI
) / 180.0;
350 nwidth
= ceil(abs(cos(angle
) * image
->width
))
351 + ceil(abs(cos(WM_PI
/ 2 - angle
) * image
->width
));
353 nheight
= ceil(abs(sin(angle
) * image
->height
))
354 + ceil(abs(cos(WM_PI
/ 2 - angle
) * image
->height
));
356 img
= RCreateImage(nwidth
, nheight
, True
);
363 x1
= floor(abs(cos(WM_PI
/ 2 - angle
) * image
->width
));
367 y2
= floor(abs(sin(WM_PI
/ 2 - angle
) * image
->width
));
369 xx
= floor(abs(cos(angle
) * image
->height
)) - 1;
372 printf("%ix%i, %i %i %i %i %i\n", nwidth
, nheight
, x1
, y1
, x2
, y2
, (int)((angle
* 180.0) / WM_PI
));
388 dpru
= dpr
- (dx
<< 1);
393 copyLine(x1
, y1
, xx
, yy
, nwidth
, image
->format
, dst
, &src
);
411 dpru
= dpr
- (dy
<< 1);
415 xx
= abs(x1
* sin(angle
* WM_PI
/ 180.0));
416 yy
= abs(y1
* cos(angle
* WM_PI
/ 180.0));
418 copyLine(x1
, y1
, xx
, yy
, nwidth
, image
->format
, dst
, &src
);