WINGs: fix possible NULL pointer dereference (Coverity #50197)
[wmaker-crm.git] / wrlib / rotate.c
blobfead8ae7667cb734939dcac117a5b43a3da37a74
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,
20 * MA 02110-1301, USA.
23 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <X11/Xlib.h>
29 #include "wraster.h"
31 #include <math.h>
33 #ifndef PI
34 #define PI 3.14159265358979323846
35 #endif
37 static RImage *rotateImage(RImage * image, float angle);
39 RImage *RRotateImage(RImage * image, float angle)
41 RImage *img;
42 int nwidth, nheight;
43 int x, y;
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
51 * to known values
53 static const float min_usable_angle = 0.00699;
55 angle = fmod(angle, 360.0);
56 if (angle < 0.0)
57 angle += 360.0;
59 if (angle < min_usable_angle) {
60 /* Rotate by 0 degree */
61 return RCloneImage(image);
63 } else if ((angle > 90.0 - min_usable_angle) &&
64 (angle < 90.0 + min_usable_angle)) {
65 nwidth = image->height;
66 nheight = image->width;
68 img = RCreateImage(nwidth, nheight, True);
69 if (!img) {
70 return NULL;
73 if (bpp == 3) {
74 unsigned char *optr, *nptr;
75 unsigned offs;
77 offs = nwidth * 4;
79 optr = image->data;
81 for (x = 0; x < nwidth; x++) {
82 nptr = img->data + x * 4;
83 for (y = nheight; y; y--) {
84 nptr[0] = *optr++;
85 nptr[1] = *optr++;
86 nptr[2] = *optr++;
87 nptr[3] = 255;
89 nptr += offs;
92 } else {
93 unsigned *optr, *nptr;
94 unsigned *p;
96 optr = (unsigned *)image->data;
97 p = (unsigned *)img->data;
98 for (x = 0; x < nwidth; x++) {
99 nptr = p++;
100 for (y = nheight; y; y--) {
101 *nptr = *optr++;
102 nptr += nwidth;
106 } else if ((angle > 180.0 - min_usable_angle) &&
107 (angle < 180.0 + min_usable_angle)) {
109 nwidth = image->width;
110 nheight = image->height;
111 img = RCreateImage(nwidth, nheight, True);
112 if (!img) {
113 return NULL;
116 if (bpp == 3) {
117 unsigned char *optr, *nptr;
119 optr = image->data;
120 nptr = img->data + nwidth * nheight * 4 - 4;
122 for (y = 0; y < nheight; y++) {
123 for (x = 0; x < nwidth; x++) {
124 nptr[0] = optr[0];
125 nptr[1] = optr[1];
126 nptr[2] = optr[2];
127 nptr[3] = 255;
129 optr += 3;
130 nptr -= 4;
133 } else {
134 unsigned *optr, *nptr;
136 optr = (unsigned *)image->data;
137 nptr = (unsigned *)img->data + nwidth * nheight - 1;
139 for (y = nheight * nwidth - 1; y >= 0; y--) {
140 *nptr = *optr;
141 optr++;
142 nptr--;
145 } else if ((angle > 270.0 - min_usable_angle) &&
146 (angle < 270.0 + min_usable_angle)) {
147 nwidth = image->height;
148 nheight = image->width;
150 img = RCreateImage(nwidth, nheight, True);
151 if (!img) {
152 return NULL;
155 if (bpp == 3) {
156 unsigned char *optr, *nptr;
157 unsigned offs;
159 offs = nwidth * 4;
161 optr = image->data;
163 for (x = 0; x < nwidth; x++) {
164 nptr = img->data + x * 4;
165 for (y = nheight; y; y--) {
166 nptr[0] = *optr++;
167 nptr[1] = *optr++;
168 nptr[2] = *optr++;
169 nptr[3] = 255;
171 nptr += offs;
174 } else {
175 unsigned *optr, *nptr;
176 unsigned *p;
178 optr = (unsigned *)image->data;
179 p = (unsigned *)img->data + nwidth * nheight;
180 for (x = 0; x < nwidth; x++) {
181 nptr = p--;
182 for (y = nheight; y; y--) {
183 *nptr = *optr++;
184 nptr -= nwidth;
188 } else {
189 img = rotateImage(image, angle);
192 return img;
196 * Image rotation through Bresenham's line algorithm:
198 * If a square must be rotate by angle a, like in:
199 * _______
200 * | B |
201 * | /4\ |
202 * | /3 8\|
203 * | /2 7 /|
204 * |A1 6 / | A_______B
205 * | \5 / a| <--- |1 2 3 4|
206 * |__C/_)_| |5 6 7 8|
207 * C-------
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
216 static void
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;
220 int dx, dy;
221 int xi, yi;
222 int offset;
223 int dpr, dpru, p;
225 dx = abs(x2 - x1);
226 dy = abs(y2 - y1);
228 if (x1 > x2)
229 xi = -1;
230 else
231 xi = 1;
232 if (y1 > y2)
233 yi = -1;
234 else
235 yi = 1;
237 if (dx >= dy) {
239 dpr = dy << 1;
240 dpru = dpr - (dx << 1);
241 p = dpr - dx;
243 while (dx-- >= 0) {
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++;
251 else
252 dst[offset++] = 255;
254 /* calc next step */
255 if (p > 0) {
256 x1 += xi;
257 y1 += yi;
258 p += dpru;
259 } else {
260 x1 += xi;
261 p += dpr;
264 } else {
266 dpr = dx << 1;
267 dpru = dpr - (dy << 1);
268 p = dpr - dy;
270 while (dy-- >= 0) {
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++;
278 else
279 dst[offset++] = 255;
281 /* calc next step */
282 if (p > 0) {
283 x1 += xi;
284 y1 += yi;
285 p += dpru;
286 } else {
287 y1 += yi;
288 p += dpr;
293 *src = s;
296 static RImage *rotateImage(RImage * image, float angle)
298 RImage *img;
299 int nwidth, nheight;
300 int x1, y1;
301 int x2, y2;
302 int dx, dy;
303 int xi, yi;
304 int xx, yy;
305 unsigned char *src, *dst;
306 int dpr, dpru, p;
308 /* only 180o for now */
309 if (angle > 180.0)
310 angle -= 180.0;
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);
321 if (!img)
322 return NULL;
324 src = image->data;
325 dst = img->data;
327 x1 = floor(abs(cos(PI / 2 - angle) * image->width));
328 y1 = 0;
330 x2 = 0;
331 y2 = floor(abs(sin(PI / 2 - angle) * image->width));
333 xx = floor(abs(cos(angle) * image->height)) - 1;
334 yy = nheight - 1;
336 printf("%ix%i, %i %i %i %i %i\n", nwidth, nheight, x1, y1, x2, y2, (int)((angle * 180.0) / PI));
338 dx = abs(x2 - x1);
339 dy = abs(y2 - y1);
341 if (x1 > x2)
342 xi = -1;
343 else
344 xi = 1;
345 if (y1 > y2)
346 yi = -1;
347 else
348 yi = 1;
350 if (dx >= dy) {
351 dpr = dy << 1;
352 dpru = dpr - (dx << 1);
353 p = dpr - dx;
355 while (dx-- >= 0) {
357 copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src);
359 /* calc next step */
361 if (p > 0) {
362 x1 += xi;
363 y1 += yi;
364 xx += xi;
365 yy += yi;
366 p += dpru;
367 } else {
368 x1 += xi;
369 xx += xi;
370 p += dpr;
373 } else {
374 puts("NOT IMPLEMTENED");
375 return img;
376 dpr = dx << 1;
377 dpru = dpr - (dy << 1);
378 p = dpr - dy;
380 while (dy-- >= 0) {
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);
386 /* calc next step */
387 if (p > 0) {
388 x1 += xi;
389 y1 += yi;
390 p += dpru;
391 } else {
392 y1 += yi;
393 p += dpr;
398 return img;