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,
34 #define PI 3.14159265358979323846
37 static RImage
*rotateImage(RImage
* image
, float angle
);
39 RImage
*RRotateImage(RImage
* image
, float angle
)
44 int bpp
= image
->format
== RRGBAFormat
? 4 : 3;
47 * Angle steps below this value would represent a rotation
48 * of less than 1 pixel for a 4k wide image, so not worth
49 * bothering the difference. That makes it a perfect
50 * candidate for an Epsilon when trying to compare angle
53 static const float min_usable_angle
= 0.00699;
55 angle
= ((int)angle
% 360) + (angle
- (int)angle
);
57 if (angle
< min_usable_angle
) {
58 /* Rotate by 0 degree */
59 return RCloneImage(image
);
61 } else if ((angle
> 90.0 - min_usable_angle
) &&
62 (angle
< 90.0 + min_usable_angle
)) {
63 nwidth
= image
->height
;
64 nheight
= image
->width
;
66 img
= RCreateImage(nwidth
, nheight
, True
);
72 unsigned char *optr
, *nptr
;
80 for (x
= 0; x
< nwidth
; x
++) {
81 nptr
= img
->data
+ x
* 4;
82 for (y
= nheight
; y
; y
--) {
92 unsigned *optr
, *nptr
;
95 optr
= (unsigned *)image
->data
;
96 p
= (unsigned *)img
->data
;
97 for (x
= 0; x
< nwidth
; x
++) {
99 for (y
= nheight
; y
; y
--) {
105 } else if ((angle
> 180.0 - min_usable_angle
) &&
106 (angle
< 180.0 + min_usable_angle
)) {
108 nwidth
= image
->width
;
109 nheight
= image
->height
;
110 img
= RCreateImage(nwidth
, nheight
, True
);
116 unsigned char *optr
, *nptr
;
119 nptr
= img
->data
+ nwidth
* nheight
* 4 - 4;
121 for (y
= 0; y
< nheight
; y
++) {
122 for (x
= 0; x
< nwidth
; x
++) {
133 unsigned *optr
, *nptr
;
135 optr
= (unsigned *)image
->data
;
136 nptr
= (unsigned *)img
->data
+ nwidth
* nheight
- 1;
138 for (y
= nheight
* nwidth
- 1; y
>= 0; y
--) {
144 } else if ((angle
> 270.0 - min_usable_angle
) &&
145 (angle
< 270.0 + min_usable_angle
)) {
146 nwidth
= image
->height
;
147 nheight
= image
->width
;
149 img
= RCreateImage(nwidth
, nheight
, True
);
155 unsigned char *optr
, *nptr
;
163 for (x
= 0; x
< nwidth
; x
++) {
164 nptr
= img
->data
+ x
* 4;
165 for (y
= nheight
; y
; y
--) {
175 unsigned *optr
, *nptr
;
178 optr
= (unsigned *)image
->data
;
179 p
= (unsigned *)img
->data
+ nwidth
* nheight
;
180 for (x
= 0; x
< nwidth
; x
++) {
182 for (y
= nheight
; y
; y
--) {
189 img
= rotateImage(image
, angle
);
196 * Image rotation through Bresenham's line algorithm:
198 * If a square must be rotate by angle a, like in:
204 * |A1 6 / | A_______B
205 * | \5 / a| <--- |1 2 3 4|
206 * |__C/_)_| |5 6 7 8|
209 * for each point P1 in the line from C to A
210 * for each point P2 in the perpendicular line starting at P1
211 * get pixel from the source and plot at P2
212 * increment pixel location from source
217 copyLine(int x1
, int y1
, int x2
, int y2
, int nwidth
, int format
, unsigned char *dst
, unsigned char **src
)
219 unsigned char *s
= *src
;
240 dpru
= dpr
- (dx
<< 1);
244 /* fetch and draw the pixel */
245 offset
= (x1
+ y1
* nwidth
) << 2;
246 dst
[offset
++] = *s
++;
247 dst
[offset
++] = *s
++;
248 dst
[offset
++] = *s
++;
249 if (format
== RRGBAFormat
)
250 dst
[offset
++] = *s
++;
267 dpru
= dpr
- (dy
<< 1);
271 /* fetch and draw the pixel */
272 offset
= (x1
+ y1
* nwidth
) << 2;
273 dst
[offset
++] = *s
++;
274 dst
[offset
++] = *s
++;
275 dst
[offset
++] = *s
++;
276 if (format
== RRGBAFormat
)
277 dst
[offset
++] = *s
++;
296 static RImage
*rotateImage(RImage
* image
, float angle
)
305 unsigned char *src
, *dst
;
308 /* only 180o for now */
312 angle
= (angle
* PI
) / 180.0;
314 nwidth
= ceil(abs(cos(angle
) * image
->width
))
315 + ceil(abs(cos(PI
/ 2 - angle
) * image
->width
));
317 nheight
= ceil(abs(sin(angle
) * image
->height
))
318 + ceil(abs(cos(PI
/ 2 - angle
) * image
->height
));
320 img
= RCreateImage(nwidth
, nheight
, True
);
327 x1
= floor(abs(cos(PI
/ 2 - angle
) * image
->width
));
331 y2
= floor(abs(sin(PI
/ 2 - angle
) * image
->width
));
333 xx
= floor(abs(cos(angle
) * image
->height
)) - 1;
336 printf("%ix%i, %i %i %i %i %i\n", nwidth
, nheight
, x1
, y1
, x2
, y2
, (int)((angle
* 180.0) / PI
));
352 dpru
= dpr
- (dx
<< 1);
357 copyLine(x1
, y1
, xx
, yy
, nwidth
, image
->format
, dst
, &src
);
374 puts("NOT IMPLEMTENED");
377 dpru
= dpr
- (dy
<< 1);
381 xx
= abs(x1
* sin(angle
* PI
/ 180.0));
382 yy
= abs(y1
* cos(angle
* PI
/ 180.0));
384 copyLine(x1
, y1
, xx
, yy
, nwidth
, image
->format
, dst
, &src
);