1 #if HAVE_GD_BUNDLED
2 # include "gd.h"
3 #else
4 # include <gd.h>
5 #endif
6
7 #include "gd_intern.h"
8 #include <math.h>
9
10 /*
11 * Rotate function Added on 2003/12
12 * by Pierre-Alain Joye (pierre@php.net)
13 **/
14 /* Begin rotate function */
15 #ifdef ROTATE_PI
16 #undef ROTATE_PI
17 #endif /* ROTATE_PI */
18
19 #define ROTATE_DEG2RAD 3.1415926535897932384626433832795/180
gdImageSkewX(gdImagePtr dst,gdImagePtr src,int uRow,int iOffset,double dWeight,int clrBack,int ignoretransparent)20 void gdImageSkewX (gdImagePtr dst, gdImagePtr src, int uRow, int iOffset, double dWeight, int clrBack, int ignoretransparent)
21 {
22 typedef int (*FuncPtr)(gdImagePtr, int, int);
23 int i, r, g, b, a, clrBackR, clrBackG, clrBackB, clrBackA;
24 FuncPtr f;
25
26 int pxlOldLeft, pxlLeft=0, pxlSrc;
27
28 /* Keep clrBack as color index if required */
29 if (src->trueColor) {
30 pxlOldLeft = clrBack;
31 f = gdImageGetTrueColorPixel;
32 } else {
33 pxlOldLeft = clrBack;
34 clrBackR = gdImageRed(src, clrBack);
35 clrBackG = gdImageGreen(src, clrBack);
36 clrBackB = gdImageBlue(src, clrBack);
37 clrBackA = gdImageAlpha(src, clrBack);
38 clrBack = gdTrueColorAlpha(clrBackR, clrBackG, clrBackB, clrBackA);
39 f = gdImageGetPixel;
40 }
41
42 for (i = 0; i < iOffset; i++) {
43 gdImageSetPixel (dst, i, uRow, clrBack);
44 }
45
46 if (i < dst->sx) {
47 gdImageSetPixel (dst, i, uRow, clrBack);
48 }
49
50 for (i = 0; i < src->sx; i++) {
51 pxlSrc = f (src,i,uRow);
52
53 r = (int)(gdImageRed(src,pxlSrc) * dWeight);
54 g = (int)(gdImageGreen(src,pxlSrc) * dWeight);
55 b = (int)(gdImageBlue(src,pxlSrc) * dWeight);
56 a = (int)(gdImageAlpha(src,pxlSrc) * dWeight);
57
58 pxlLeft = gdImageColorAllocateAlpha(src, r, g, b, a);
59
60 if (pxlLeft == -1) {
61 pxlLeft = gdImageColorClosestAlpha(src, r, g, b, a);
62 }
63
64 r = gdImageRed(src,pxlSrc) - (gdImageRed(src,pxlLeft) - gdImageRed(src,pxlOldLeft));
65 g = gdImageGreen(src,pxlSrc) - (gdImageGreen(src,pxlLeft) - gdImageGreen(src,pxlOldLeft));
66 b = gdImageBlue(src,pxlSrc) - (gdImageBlue(src,pxlLeft) - gdImageBlue(src,pxlOldLeft));
67 a = gdImageAlpha(src,pxlSrc) - (gdImageAlpha(src,pxlLeft) - gdImageAlpha(src,pxlOldLeft));
68
69 if (r>255) {
70 r = 255;
71 }
72
73 if (g>255) {
74 g = 255;
75 }
76
77 if (b>255) {
78 b = 255;
79 }
80
81 if (a>127) {
82 a = 127;
83 }
84
85 if (ignoretransparent && pxlSrc == dst->transparent) {
86 pxlSrc = dst->transparent;
87 } else {
88 pxlSrc = gdImageColorAllocateAlpha(dst, r, g, b, a);
89
90 if (pxlSrc == -1) {
91 pxlSrc = gdImageColorClosestAlpha(dst, r, g, b, a);
92 }
93 }
94
95 if ((i + iOffset >= 0) && (i + iOffset < dst->sx)) {
96 gdImageSetPixel (dst, i+iOffset, uRow, pxlSrc);
97 }
98
99 pxlOldLeft = pxlLeft;
100 }
101
102 i += iOffset;
103
104 if (i < dst->sx) {
105 gdImageSetPixel (dst, i, uRow, pxlLeft);
106 }
107
108 gdImageSetPixel (dst, iOffset, uRow, clrBack);
109
110 i--;
111
112 while (++i < dst->sx) {
113 gdImageSetPixel (dst, i, uRow, clrBack);
114 }
115 }
116
gdImageSkewY(gdImagePtr dst,gdImagePtr src,int uCol,int iOffset,double dWeight,int clrBack,int ignoretransparent)117 void gdImageSkewY (gdImagePtr dst, gdImagePtr src, int uCol, int iOffset, double dWeight, int clrBack, int ignoretransparent)
118 {
119 typedef int (*FuncPtr)(gdImagePtr, int, int);
120 int i, iYPos=0, r, g, b, a;
121 FuncPtr f;
122 int pxlOldLeft, pxlLeft=0, pxlSrc;
123
124 if (src->trueColor) {
125 f = gdImageGetTrueColorPixel;
126 } else {
127 f = gdImageGetPixel;
128 }
129
130 for (i = 0; i<=iOffset; i++) {
131 gdImageSetPixel (dst, uCol, i, clrBack);
132 }
133 r = (int)((double)gdImageRed(src,clrBack) * dWeight);
134 g = (int)((double)gdImageGreen(src,clrBack) * dWeight);
135 b = (int)((double)gdImageBlue(src,clrBack) * dWeight);
136 a = (int)((double)gdImageAlpha(src,clrBack) * dWeight);
137
138 pxlOldLeft = gdImageColorAllocateAlpha(dst, r, g, b, a);
139
140 for (i = 0; i < src->sy; i++) {
141 pxlSrc = f (src, uCol, i);
142 iYPos = i + iOffset;
143
144 r = (int)((double)gdImageRed(src,pxlSrc) * dWeight);
145 g = (int)((double)gdImageGreen(src,pxlSrc) * dWeight);
146 b = (int)((double)gdImageBlue(src,pxlSrc) * dWeight);
147 a = (int)((double)gdImageAlpha(src,pxlSrc) * dWeight);
148
149 pxlLeft = gdImageColorAllocateAlpha(src, r, g, b, a);
150
151 if (pxlLeft == -1) {
152 pxlLeft = gdImageColorClosestAlpha(src, r, g, b, a);
153 }
154
155 r = gdImageRed(src,pxlSrc) - (gdImageRed(src,pxlLeft) - gdImageRed(src,pxlOldLeft));
156 g = gdImageGreen(src,pxlSrc) - (gdImageGreen(src,pxlLeft) - gdImageGreen(src,pxlOldLeft));
157 b = gdImageBlue(src,pxlSrc) - (gdImageBlue(src,pxlLeft) - gdImageBlue(src,pxlOldLeft));
158 a = gdImageAlpha(src,pxlSrc) - (gdImageAlpha(src,pxlLeft) - gdImageAlpha(src,pxlOldLeft));
159
160 if (r>255) {
161 r = 255;
162 }
163
164 if (g>255) {
165 g = 255;
166 }
167
168 if (b>255) {
169 b = 255;
170 }
171
172 if (a>127) {
173 a = 127;
174 }
175
176 if (ignoretransparent && pxlSrc == dst->transparent) {
177 pxlSrc = dst->transparent;
178 } else {
179 pxlSrc = gdImageColorAllocateAlpha(dst, r, g, b, a);
180
181 if (pxlSrc == -1) {
182 pxlSrc = gdImageColorClosestAlpha(dst, r, g, b, a);
183 }
184 }
185
186 if ((iYPos >= 0) && (iYPos < dst->sy)) {
187 gdImageSetPixel (dst, uCol, iYPos, pxlSrc);
188 }
189
190 pxlOldLeft = pxlLeft;
191 }
192
193 i = iYPos;
194 if (i < dst->sy) {
195 gdImageSetPixel (dst, uCol, i, pxlLeft);
196 }
197
198 i--;
199 while (++i < dst->sy) {
200 gdImageSetPixel (dst, uCol, i, clrBack);
201 }
202 }
203
204 /* Rotates an image by 90 degrees (counter clockwise) */
gdImageRotate90(gdImagePtr src,int ignoretransparent)205 gdImagePtr gdImageRotate90 (gdImagePtr src, int ignoretransparent)
206 {
207 int uY, uX;
208 int c,r,g,b,a;
209 gdImagePtr dst;
210 typedef int (*FuncPtr)(gdImagePtr, int, int);
211 FuncPtr f;
212
213 if (src->trueColor) {
214 f = gdImageGetTrueColorPixel;
215 } else {
216 f = gdImageGetPixel;
217 }
218 dst = gdImageCreateTrueColor(src->sy, src->sx);
219
220 if (dst != NULL) {
221 int old_blendmode = dst->alphaBlendingFlag;
222 dst->alphaBlendingFlag = 0;
223
224 dst->transparent = src->transparent;
225
226 gdImagePaletteCopy (dst, src);
227
228 for (uY = 0; uY<src->sy; uY++) {
229 for (uX = 0; uX<src->sx; uX++) {
230 c = f (src, uX, uY);
231 if (!src->trueColor) {
232 r = gdImageRed(src,c);
233 g = gdImageGreen(src,c);
234 b = gdImageBlue(src,c);
235 a = gdImageAlpha(src,c);
236 c = gdTrueColorAlpha(r, g, b, a);
237 }
238 if (ignoretransparent && c == dst->transparent) {
239 gdImageSetPixel(dst, uY, (dst->sy - uX - 1), dst->transparent);
240 } else {
241 gdImageSetPixel(dst, uY, (dst->sy - uX - 1), c);
242 }
243 }
244 }
245 dst->alphaBlendingFlag = old_blendmode;
246 }
247
248 return dst;
249 }
250
251 /* Rotates an image by 180 degrees (counter clockwise) */
gdImageRotate180(gdImagePtr src,int ignoretransparent)252 gdImagePtr gdImageRotate180 (gdImagePtr src, int ignoretransparent)
253 {
254 int uY, uX;
255 int c,r,g,b,a;
256 gdImagePtr dst;
257 typedef int (*FuncPtr)(gdImagePtr, int, int);
258 FuncPtr f;
259
260 if (src->trueColor) {
261 f = gdImageGetTrueColorPixel;
262 } else {
263 f = gdImageGetPixel;
264 }
265 dst = gdImageCreateTrueColor(src->sx, src->sy);
266
267 if (dst != NULL) {
268 int old_blendmode = dst->alphaBlendingFlag;
269 dst->alphaBlendingFlag = 0;
270
271 dst->transparent = src->transparent;
272
273 gdImagePaletteCopy (dst, src);
274
275 for (uY = 0; uY<src->sy; uY++) {
276 for (uX = 0; uX<src->sx; uX++) {
277 c = f (src, uX, uY);
278 if (!src->trueColor) {
279 r = gdImageRed(src,c);
280 g = gdImageGreen(src,c);
281 b = gdImageBlue(src,c);
282 a = gdImageAlpha(src,c);
283 c = gdTrueColorAlpha(r, g, b, a);
284 }
285
286 if (ignoretransparent && c == dst->transparent) {
287 gdImageSetPixel(dst, (dst->sx - uX - 1), (dst->sy - uY - 1), dst->transparent);
288 } else {
289 gdImageSetPixel(dst, (dst->sx - uX - 1), (dst->sy - uY - 1), c);
290 }
291 }
292 }
293 dst->alphaBlendingFlag = old_blendmode;
294 }
295
296 return dst;
297 }
298
299 /* Rotates an image by 270 degrees (counter clockwise) */
gdImageRotate270(gdImagePtr src,int ignoretransparent)300 gdImagePtr gdImageRotate270 (gdImagePtr src, int ignoretransparent)
301 {
302 int uY, uX;
303 int c,r,g,b,a;
304 gdImagePtr dst;
305 typedef int (*FuncPtr)(gdImagePtr, int, int);
306 FuncPtr f;
307
308 if (src->trueColor) {
309 f = gdImageGetTrueColorPixel;
310 } else {
311 f = gdImageGetPixel;
312 }
313 dst = gdImageCreateTrueColor (src->sy, src->sx);
314
315 if (dst != NULL) {
316 int old_blendmode = dst->alphaBlendingFlag;
317 dst->alphaBlendingFlag = 0;
318
319 dst->transparent = src->transparent;
320
321 gdImagePaletteCopy (dst, src);
322
323 for (uY = 0; uY<src->sy; uY++) {
324 for (uX = 0; uX<src->sx; uX++) {
325 c = f (src, uX, uY);
326 if (!src->trueColor) {
327 r = gdImageRed(src,c);
328 g = gdImageGreen(src,c);
329 b = gdImageBlue(src,c);
330 a = gdImageAlpha(src,c);
331 c = gdTrueColorAlpha(r, g, b, a);
332 }
333
334 if (ignoretransparent && c == dst->transparent) {
335 gdImageSetPixel(dst, (dst->sx - uY - 1), uX, dst->transparent);
336 } else {
337 gdImageSetPixel(dst, (dst->sx - uY - 1), uX, c);
338 }
339 }
340 }
341 dst->alphaBlendingFlag = old_blendmode;
342 }
343
344 return dst;
345 }
346
gdImageRotate45(gdImagePtr src,double dAngle,int clrBack,int ignoretransparent)347 gdImagePtr gdImageRotate45 (gdImagePtr src, double dAngle, int clrBack, int ignoretransparent)
348 {
349 typedef int (*FuncPtr)(gdImagePtr, int, int);
350 gdImagePtr dst1,dst2,dst3;
351 FuncPtr f;
352 double dRadAngle, dSinE, dTan, dShear;
353 double dOffset; /* Variable skew offset */
354 int u, iShear, newx, newy;
355 int clrBackR, clrBackG, clrBackB, clrBackA;
356
357 /* See GEMS I for the algorithm details */
358 dRadAngle = dAngle * ROTATE_DEG2RAD; /* Angle in radians */
359 dSinE = sin (dRadAngle);
360 dTan = tan (dRadAngle / 2.0);
361
362 newx = (int)(src->sx + src->sy * fabs(dTan));
363 newy = src->sy;
364
365 /* 1st shear */
366 if (src->trueColor) {
367 f = gdImageGetTrueColorPixel;
368 } else {
369 f = gdImageGetPixel;
370 }
371
372 dst1 = gdImageCreateTrueColor(newx, newy);
373 /******* Perform 1st shear (horizontal) ******/
374 if (dst1 == NULL) {
375 return NULL;
376 }
377 #ifdef HAVE_GD_BUNDLED
378 dst1->alphaBlendingFlag = gdEffectReplace;
379 #else
380 gdImageAlphaBlending(dst1, 0);
381 #endif
382 if (dAngle == 0.0) {
383 /* Returns copy of src */
384 gdImageCopy (dst1, src,0,0,0,0,src->sx,src->sy);
385 return dst1;
386 }
387
388 gdImagePaletteCopy (dst1, src);
389
390 if (ignoretransparent) {
391 if (gdImageTrueColor(src)) {
392 dst1->transparent = src->transparent;
393 } else {
394
395 dst1->transparent = gdTrueColorAlpha(gdImageRed(src, src->transparent), gdImageBlue(src, src->transparent), gdImageGreen(src, src->transparent), 127);
396 }
397 }
398
399 dRadAngle = dAngle * ROTATE_DEG2RAD; /* Angle in radians */
400 dSinE = sin (dRadAngle);
401 dTan = tan (dRadAngle / 2.0);
402
403 for (u = 0; u < dst1->sy; u++) {
404 if (dTan >= 0.0) {
405 dShear = ((double)(u + 0.5)) * dTan;
406 } else {
407 dShear = ((double)(u - dst1->sy) + 0.5) * dTan;
408 }
409
410 iShear = (int)floor(dShear);
411 gdImageSkewX(dst1, src, u, iShear, (dShear - iShear), clrBack, ignoretransparent);
412 }
413
414 /*
415 The 1st shear may use the original clrBack as color index
416 Convert it once here
417 */
418 if(!src->trueColor) {
419 clrBackR = gdImageRed(src, clrBack);
420 clrBackG = gdImageGreen(src, clrBack);
421 clrBackB = gdImageBlue(src, clrBack);
422 clrBackA = gdImageAlpha(src, clrBack);
423 clrBack = gdTrueColorAlpha(clrBackR, clrBackG, clrBackB, clrBackA);
424 }
425 /* 2nd shear */
426 newx = dst1->sx;
427
428 if (dSinE > 0.0) {
429 dOffset = (src->sx-1) * dSinE;
430 } else {
431 dOffset = -dSinE * (src->sx - newx);
432 }
433
434 newy = (int) ((double) src->sx * fabs( dSinE ) + (double) src->sy * cos (dRadAngle))+1;
435
436 if (src->trueColor) {
437 f = gdImageGetTrueColorPixel;
438 } else {
439 f = gdImageGetPixel;
440 }
441 dst2 = gdImageCreateTrueColor(newx, newy);
442 if (dst2 == NULL) {
443 gdImageDestroy(dst1);
444 return NULL;
445 }
446
447 #ifdef HAVE_GD_BUNDLED
448 dst2->alphaBlendingFlag = gdEffectReplace;
449 #else
450 gdImageAlphaBlending(dst2, 0);
451 #endif
452
453 if (ignoretransparent) {
454 dst2->transparent = dst1->transparent;
455 }
456
457 for (u = 0; u < dst2->sx; u++, dOffset -= dSinE) {
458 iShear = (int)floor (dOffset);
459 gdImageSkewY(dst2, dst1, u, iShear, (dOffset - (double)iShear), clrBack, ignoretransparent);
460 }
461
462 /* 3rd shear */
463 gdImageDestroy(dst1);
464
465 newx = (int) ((double)src->sy * fabs (dSinE) + (double)src->sx * cos (dRadAngle)) + 1;
466 newy = dst2->sy;
467
468 if (src->trueColor) {
469 f = gdImageGetTrueColorPixel;
470 } else {
471 f = gdImageGetPixel;
472 }
473 dst3 = gdImageCreateTrueColor(newx, newy);
474 if (dst3 == NULL) {
475 gdImageDestroy(dst2);
476 return NULL;
477 }
478
479 #ifdef HAVE_GD_BUNDLED
480 dst3->alphaBlendingFlag = gdEffectReplace;
481 #else
482 gdImageAlphaBlending(dst3, 0);
483 #endif
484
485 if (ignoretransparent) {
486 dst3->transparent = dst2->transparent;
487 }
488
489 if (dSinE >= 0.0) {
490 dOffset = (double)(src->sx - 1) * dSinE * -dTan;
491 } else {
492 dOffset = dTan * ((double)(src->sx - 1) * -dSinE + (double)(1 - newy));
493 }
494
495 for (u = 0; u < dst3->sy; u++, dOffset += dTan) {
496 int iShear = (int)floor(dOffset);
497 gdImageSkewX(dst3, dst2, u, iShear, (dOffset - iShear), clrBack, ignoretransparent);
498 }
499
500 gdImageDestroy(dst2);
501
502 return dst3;
503 }
504
gdImageRotate(gdImagePtr src,double dAngle,int clrBack,int ignoretransparent)505 gdImagePtr gdImageRotate (gdImagePtr src, double dAngle, int clrBack, int ignoretransparent)
506 {
507 gdImagePtr pMidImg;
508 gdImagePtr rotatedImg;
509
510 if (src == NULL) {
511 return NULL;
512 }
513
514 if (!gdImageTrueColor(src) && (clrBack < 0 || clrBack>=gdImageColorsTotal(src))) {
515 return NULL;
516 }
517
518 while (dAngle >= 360.0) {
519 dAngle -= 360.0;
520 }
521
522 while (dAngle < 0) {
523 dAngle += 360.0;
524 }
525
526 if (dAngle == 90.00) {
527 return gdImageRotate90(src, ignoretransparent);
528 }
529 if (dAngle == 180.00) {
530 return gdImageRotate180(src, ignoretransparent);
531 }
532 if(dAngle == 270.00) {
533 return gdImageRotate270 (src, ignoretransparent);
534 }
535
536 if ((dAngle > 45.0) && (dAngle <= 135.0)) {
537 pMidImg = gdImageRotate90 (src, ignoretransparent);
538 dAngle -= 90.0;
539 } else if ((dAngle > 135.0) && (dAngle <= 225.0)) {
540 pMidImg = gdImageRotate180 (src, ignoretransparent);
541 dAngle -= 180.0;
542 } else if ((dAngle > 225.0) && (dAngle <= 315.0)) {
543 pMidImg = gdImageRotate270 (src, ignoretransparent);
544 dAngle -= 270.0;
545 } else {
546 return gdImageRotate45 (src, dAngle, clrBack, ignoretransparent);
547 }
548
549 if (pMidImg == NULL) {
550 return NULL;
551 }
552
553 rotatedImg = gdImageRotate45 (pMidImg, dAngle, clrBack, ignoretransparent);
554 gdImageDestroy(pMidImg);
555
556 return rotatedImg;
557 }
558 /* End Rotate function */
559
560
561