1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "gd_intern.h"
12
13 /* 2.03: don't include zlib here or we can't build without PNG */
14 #include "gd.h"
15 #include "gdhelpers.h"
16 #include "gd_color.h"
17 #include "gd_errors.h"
18
19 /* 2.0.12: this now checks the clipping rectangle */
20 #define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2))))
21
22 #ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */
23 #define CHARSET_EBCDIC
24 #define __attribute__(any) /*nothing */
25 #endif
26 /*_OSD_POSIX*/
27
28 #ifndef CHARSET_EBCDIC
29 #define ASC(ch) ch
30 #else /*CHARSET_EBCDIC */
31 #define ASC(ch) gd_toascii[(unsigned char)ch]
32 static const unsigned char gd_toascii[256] = {
33 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
34 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */
35 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
36 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */
37 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
38 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */
39 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
40 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */
41 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
42 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
43 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
44 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */
45 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
46 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
47 /*-/........^,%_>?*/
48 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
49 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */
50 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
51 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */
52 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
53 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */
54 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
55 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */
56 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
57 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */
58 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
59 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */
60 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
61 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */
62 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
63 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */
64 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
65 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
66 };
67 #endif /*CHARSET_EBCDIC */
68
69 /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
70 #define floor_cast(exp) ((long) exp)
71
72 extern const int gdCosT[];
73 extern const int gdSinT[];
74
75 /**
76 * Group: Error Handling
77 */
78
gd_stderr_error(int priority,const char * format,va_list args)79 void gd_stderr_error(int priority, const char *format, va_list args)
80 {
81 switch (priority) {
82 case GD_ERROR:
83 fputs("GD Error: ", stderr);
84 break;
85 case GD_WARNING:
86 fputs("GD Warning: ", stderr);
87 break;
88 case GD_NOTICE:
89 fputs("GD Notice: ", stderr);
90 break;
91 case GD_INFO:
92 fputs("GD Info: ", stderr);
93 break;
94 case GD_DEBUG:
95 fputs("GD Debug: ", stderr);
96 break;
97 }
98 vfprintf(stderr, format, args);
99 fflush(stderr);
100 }
101
102 static gdErrorMethod gd_error_method = gd_stderr_error;
103
_gd_error_ex(int priority,const char * format,va_list args)104 static void _gd_error_ex(int priority, const char *format, va_list args)
105 {
106 if (gd_error_method) {
107 gd_error_method(priority, format, args);
108 }
109 }
110
gd_error(const char * format,...)111 void gd_error(const char *format, ...)
112 {
113 va_list args;
114
115 va_start(args, format);
116 _gd_error_ex(GD_WARNING, format, args);
117 va_end(args);
118 }
gd_error_ex(int priority,const char * format,...)119 void gd_error_ex(int priority, const char *format, ...)
120 {
121 va_list args;
122
123 va_start(args, format);
124 _gd_error_ex(priority, format, args);
125 va_end(args);
126 }
127
128 /*
129 Function: gdSetErrorMethod
130 */
gdSetErrorMethod(gdErrorMethod error_method)131 BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod error_method)
132 {
133 gd_error_method = error_method;
134 }
135
136 /*
137 Function: gdClearErrorMethod
138 */
gdClearErrorMethod(void)139 BGD_DECLARE(void) gdClearErrorMethod(void)
140 {
141 gd_error_method = gd_stderr_error;
142 }
143
144 static void gdImageBrushApply (gdImagePtr im, int x, int y);
145 static void gdImageTileApply (gdImagePtr im, int x, int y);
146
147 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
148
149 /**
150 * Group: Creation and Destruction
151 */
152
153 /*
154 Function: gdImageCreate
155
156 gdImageCreate is called to create palette-based images, with no
157 more than 256 colors. The image must eventually be destroyed using
158 gdImageDestroy().
159
160 Parameters:
161
162 sx - The image width.
163 sy - The image height.
164
165 Returns:
166
167 A pointer to the new image or NULL if an error occurred.
168
169 Example:
170 (start code)
171
172 gdImagePtr im;
173 im = gdImageCreate(64, 64);
174 // ... Use the image ...
175 gdImageDestroy(im);
176
177 (end code)
178
179 See Also:
180
181 <gdImageCreateTrueColor>
182
183 */
gdImageCreate(int sx,int sy)184 BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
185 {
186 int i;
187 gdImagePtr im;
188
189 if (overflow2(sx, sy)) {
190 return NULL;
191 }
192
193 if (overflow2(sizeof (unsigned char *), sy)) {
194 return NULL;
195 }
196 if (overflow2(sizeof (unsigned char), sx)) {
197 return NULL;
198 }
199
200 im = (gdImage *) gdCalloc(1, sizeof(gdImage));
201 if (!im) {
202 return NULL;
203 }
204
205 /* Row-major ever since gd 1.3 */
206 im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
207 if (!im->pixels) {
208 gdFree(im);
209 return NULL;
210 }
211
212 im->polyInts = 0;
213 im->polyAllocated = 0;
214 im->brush = 0;
215 im->tile = 0;
216 im->style = 0;
217 for (i = 0; (i < sy); i++) {
218 /* Row-major ever since gd 1.3 */
219 im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char));
220 if (!im->pixels[i]) {
221 for (--i ; i >= 0; i--) {
222 gdFree(im->pixels[i]);
223 }
224 gdFree(im->pixels);
225 gdFree(im);
226 return NULL;
227 }
228
229 }
230 im->sx = sx;
231 im->sy = sy;
232 im->colorsTotal = 0;
233 im->transparent = (-1);
234 im->interlace = 0;
235 im->thick = 1;
236 im->AA = 0;
237 for (i = 0; (i < gdMaxColors); i++) {
238 im->open[i] = 1;
239 };
240 im->trueColor = 0;
241 im->tpixels = 0;
242 im->cx1 = 0;
243 im->cy1 = 0;
244 im->cx2 = im->sx - 1;
245 im->cy2 = im->sy - 1;
246 im->res_x = GD_RESOLUTION;
247 im->res_y = GD_RESOLUTION;
248 im->interpolation = NULL;
249 im->interpolation_id = GD_BILINEAR_FIXED;
250 return im;
251 }
252
253
254
255 /*
256 Function: gdImageCreateTrueColor
257
258 <gdImageCreateTrueColor> is called to create truecolor images,
259 with an essentially unlimited number of colors. Invoke
260 <gdImageCreateTrueColor> with the x and y dimensions of the
261 desired image. <gdImageCreateTrueColor> returns a <gdImagePtr>
262 to the new image, or NULL if unable to allocate the image. The
263 image must eventually be destroyed using <gdImageDestroy>().
264
265 Truecolor images are always filled with black at creation
266 time. There is no concept of a "background" color index.
267
268 Parameters:
269
270 sx - The image width.
271 sy - The image height.
272
273 Returns:
274
275 A pointer to the new image or NULL if an error occurred.
276
277 Example:
278 (start code)
279
280 gdImagePtr im;
281 im = gdImageCreateTrueColor(64, 64);
282 // ... Use the image ...
283 gdImageDestroy(im);
284
285 (end code)
286
287 See Also:
288
289 <gdImageCreateTrueColor>
290
291 */
gdImageCreateTrueColor(int sx,int sy)292 BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
293 {
294 int i;
295 gdImagePtr im;
296
297 if (overflow2(sx, sy)) {
298 return NULL;
299 }
300 if (overflow2(sizeof (int *), sy)) {
301 return 0;
302 }
303 if (overflow2(sizeof(int), sx)) {
304 return NULL;
305 }
306
307 im = (gdImage *) gdMalloc (sizeof (gdImage));
308 if (!im) {
309 return 0;
310 }
311 memset (im, 0, sizeof (gdImage));
312
313 im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
314 if (!im->tpixels) {
315 gdFree(im);
316 return 0;
317 }
318 im->polyInts = 0;
319 im->polyAllocated = 0;
320 im->brush = 0;
321 im->tile = 0;
322 im->style = 0;
323 for (i = 0; (i < sy); i++) {
324 im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int));
325 if (!im->tpixels[i]) {
326 /* 2.0.34 */
327 i--;
328 while (i >= 0) {
329 gdFree(im->tpixels[i]);
330 i--;
331 }
332 gdFree(im->tpixels);
333 gdFree(im);
334 return 0;
335 }
336 }
337 im->sx = sx;
338 im->sy = sy;
339 im->transparent = (-1);
340 im->interlace = 0;
341 im->trueColor = 1;
342 /* 2.0.2: alpha blending is now on by default, and saving of alpha is
343 off by default. This allows font antialiasing to work as expected
344 on the first try in JPEGs -- quite important -- and also allows
345 for smaller PNGs when saving of alpha channel is not really
346 desired, which it usually isn't! */
347 im->saveAlphaFlag = 0;
348 im->alphaBlendingFlag = 1;
349 im->thick = 1;
350 im->AA = 0;
351 im->cx1 = 0;
352 im->cy1 = 0;
353 im->cx2 = im->sx - 1;
354 im->cy2 = im->sy - 1;
355 im->res_x = GD_RESOLUTION;
356 im->res_y = GD_RESOLUTION;
357 im->interpolation = NULL;
358 im->interpolation_id = GD_BILINEAR_FIXED;
359 return im;
360 }
361
362 /*
363 Function: gdImageDestroy
364
365 <gdImageDestroy> is used to free the memory associated with an
366 image. It is important to invoke <gdImageDestroy> before exiting
367 your program or assigning a new image to a <gdImagePtr> variable.
368
369 Parameters:
370
371 im - Pointer to the gdImage to delete.
372
373 Returns:
374
375 Nothing.
376
377 Example:
378 (start code)
379
380 gdImagePtr im;
381 im = gdImageCreate(10, 10);
382 // ... Use the image ...
383 // Now destroy it
384 gdImageDestroy(im);
385
386 (end code)
387
388 */
389
gdImageDestroy(gdImagePtr im)390 BGD_DECLARE(void) gdImageDestroy (gdImagePtr im)
391 {
392 int i;
393 if (im->pixels) {
394 for (i = 0; (i < im->sy); i++) {
395 gdFree (im->pixels[i]);
396 }
397 gdFree (im->pixels);
398 }
399 if (im->tpixels) {
400 for (i = 0; (i < im->sy); i++) {
401 gdFree (im->tpixels[i]);
402 }
403 gdFree (im->tpixels);
404 }
405 if (im->polyInts) {
406 gdFree (im->polyInts);
407 }
408 if (im->style) {
409 gdFree (im->style);
410 }
411 gdFree (im);
412 }
413
414 /**
415 * Group: Color
416 */
417
418 /**
419 * Function: gdImageColorClosest
420 *
421 * Gets the closest color of the image
422 *
423 * This is a simplified variant of <gdImageColorClosestAlpha> where the alpha
424 * channel is always opaque.
425 *
426 * Parameters:
427 * im - The image.
428 * r - The value of the red component.
429 * g - The value of the green component.
430 * b - The value of the blue component.
431 *
432 * Returns:
433 * The closest color already available in the palette for palette images;
434 * the color value of the given components for truecolor images.
435 *
436 * See also:
437 * - <gdImageColorExact>
438 */
gdImageColorClosest(gdImagePtr im,int r,int g,int b)439 BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b)
440 {
441 return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
442 }
443
444 /**
445 * Function: gdImageColorClosestAlpha
446 *
447 * Gets the closest color of the image
448 *
449 * Parameters:
450 * im - The image.
451 * r - The value of the red component.
452 * g - The value of the green component.
453 * b - The value of the blue component.
454 * a - The value of the alpha component.
455 *
456 * Returns:
457 * The closest color already available in the palette for palette images;
458 * the color value of the given components for truecolor images.
459 *
460 * See also:
461 * - <gdImageColorExactAlpha>
462 */
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)463 BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
464 {
465 int i;
466 long rd, gd, bd, ad;
467 int ct = (-1);
468 int first = 1;
469 long mindist = 0;
470 if (im->trueColor) {
471 return gdTrueColorAlpha (r, g, b, a);
472 }
473 for (i = 0; (i < (im->colorsTotal)); i++) {
474 long dist;
475 if (im->open[i]) {
476 continue;
477 }
478 rd = (im->red[i] - r);
479 gd = (im->green[i] - g);
480 bd = (im->blue[i] - b);
481 /* gd 2.02: whoops, was - b (thanks to David Marwood) */
482 /* gd 2.16: was blue rather than alpha! Geez! Thanks to
483 Artur Jakub Jerzak */
484 ad = (im->alpha[i] - a);
485 dist = rd * rd + gd * gd + bd * bd + ad * ad;
486 if (first || (dist < mindist)) {
487 mindist = dist;
488 ct = i;
489 first = 0;
490 }
491 }
492 return ct;
493 }
494
495 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
496 * on colour conversion to/from RBG and HWB colour systems.
497 * It has been modified to return the converted value as a * parameter.
498 */
499
500 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
501 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
502 #define HWB_UNDEFINED -1
503 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
504
505 #define MIN(a,b) ((a)<(b)?(a):(b))
506 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
507 #define MAX(a,b) ((a)<(b)?(b):(a))
508 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
509
510
511 /*
512 * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
513 * red always maps to 6 in this implementation. Therefore UNDEFINED can be
514 * defined as 0 in situations where only unsigned numbers are desired.
515 */
516 typedef struct {
517 float R, G, B;
518 }
519 RGBType;
520 typedef struct {
521 float H, W, B;
522 }
523 HWBType;
524
525 static HWBType *
RGB_to_HWB(RGBType RGB,HWBType * HWB)526 RGB_to_HWB (RGBType RGB, HWBType * HWB)
527 {
528
529 /*
530 * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
531 * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
532 */
533
534 float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
535 int i;
536
537 w = MIN3 (R, G, B);
538 v = MAX3 (R, G, B);
539 b = 1 - v;
540 if (v == w)
541 RETURN_HWB (HWB_UNDEFINED, w, b);
542 f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
543 i = (R == w) ? 3 : ((G == w) ? 5 : 1);
544 RETURN_HWB (i - f / (v - w), w, b);
545
546 }
547
548 static float
HWB_Diff(int r1,int g1,int b1,int r2,int g2,int b2)549 HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
550 {
551 RGBType RGB1, RGB2;
552 HWBType HWB1, HWB2;
553 float diff;
554
555 SETUP_RGB (RGB1, r1, g1, b1);
556 SETUP_RGB (RGB2, r2, g2, b2);
557
558 RGB_to_HWB (RGB1, &HWB1);
559 RGB_to_HWB (RGB2, &HWB2);
560
561 /*
562 * I made this bit up; it seems to produce OK results, and it is certainly
563 * more visually correct than the current RGB metric. (PJW)
564 */
565
566 if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
567 diff = 0; /* Undefined hues always match... */
568 } else {
569 diff = fabs (HWB1.H - HWB2.H);
570 if (diff > 3) {
571 diff = 6 - diff; /* Remember, it's a colour circle */
572 }
573 }
574
575 diff =
576 diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B -
577 HWB2.B) * (HWB1.B -
578 HWB2.B);
579
580 return diff;
581 }
582
583
584 #if 0
585 /*
586 * This is not actually used, but is here for completeness, in case someone wants to
587 * use the HWB stuff for anything else...
588 */
589 static RGBType *
590 HWB_to_RGB (HWBType HWB, RGBType * RGB)
591 {
592
593 /*
594 * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
595 * RGB are each returned on [0, 1].
596 */
597
598 float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
599 int i;
600
601 v = 1 - b;
602 if (h == HWB_UNDEFINED)
603 RETURN_RGB (v, v, v);
604 i = floor (h);
605 f = h - i;
606 if (i & 1)
607 f = 1 - f; /* if i is odd */
608 n = w + f * (v - w); /* linear interpolation between w and v */
609 switch (i) {
610 case 6:
611 case 0:
612 RETURN_RGB (v, n, w);
613 case 1:
614 RETURN_RGB (n, v, w);
615 case 2:
616 RETURN_RGB (w, v, n);
617 case 3:
618 RETURN_RGB (w, n, v);
619 case 4:
620 RETURN_RGB (n, w, v);
621 case 5:
622 RETURN_RGB (v, w, n);
623 }
624
625 return RGB;
626
627 }
628 #endif
629
630 /*
631 Function: gdImageColorClosestHWB
632 */
gdImageColorClosestHWB(gdImagePtr im,int r,int g,int b)633 BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
634 {
635 int i;
636 /* long rd, gd, bd; */
637 int ct = (-1);
638 int first = 1;
639 float mindist = 0;
640 if (im->trueColor) {
641 return gdTrueColor (r, g, b);
642 }
643 for (i = 0; (i < (im->colorsTotal)); i++) {
644 float dist;
645 if (im->open[i]) {
646 continue;
647 }
648 dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
649 if (first || (dist < mindist)) {
650 mindist = dist;
651 ct = i;
652 first = 0;
653 }
654 }
655 return ct;
656 }
657
658 /**
659 * Function: gdImageColorExact
660 *
661 * Gets the exact color of the image
662 *
663 * This is a simplified variant of <gdImageColorExactAlpha> where the alpha
664 * channel is always opaque.
665 *
666 * Parameters:
667 * im - The image.
668 * r - The value of the red component.
669 * g - The value of the green component.
670 * b - The value of the blue component.
671 *
672 * Returns:
673 * The exact color already available in the palette for palette images; if
674 * there is no exact color, -1 is returned.
675 * For truecolor images the color value of the given components is returned.
676 *
677 * See also:
678 * - <gdImageColorClosest>
679 */
gdImageColorExact(gdImagePtr im,int r,int g,int b)680 BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b)
681 {
682 return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
683 }
684
685 /**
686 * Function: gdImageColorExactAlpha
687 *
688 * Gets the exact color of the image
689 *
690 * Parameters:
691 * im - The image.
692 * r - The value of the red component.
693 * g - The value of the green component.
694 * b - The value of the blue component.
695 * a - The value of the alpha component.
696 *
697 * Returns:
698 * The exact color already available in the palette for palette images; if
699 * there is no exact color, -1 is returned.
700 * For truecolor images the color value of the given components is returned.
701 *
702 * See also:
703 * - <gdImageColorClosestAlpha>
704 * - <gdTrueColorAlpha>
705 */
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)706 BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
707 {
708 int i;
709 if (im->trueColor) {
710 return gdTrueColorAlpha (r, g, b, a);
711 }
712 for (i = 0; (i < (im->colorsTotal)); i++) {
713 if (im->open[i]) {
714 continue;
715 }
716 if ((im->red[i] == r) &&
717 (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
718 return i;
719 }
720 }
721 return -1;
722 }
723
724 /**
725 * Function: gdImageColorAllocate
726 *
727 * Allocates a color
728 *
729 * This is a simplified variant of <gdImageColorAllocateAlpha> where the alpha
730 * channel is always opaque.
731 *
732 * Parameters:
733 * im - The image.
734 * r - The value of the red component.
735 * g - The value of the green component.
736 * b - The value of the blue component.
737 *
738 * Returns:
739 * The color value.
740 *
741 * See also:
742 * - <gdImageColorDeallocate>
743 */
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)744 BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
745 {
746 return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
747 }
748
749 /**
750 * Function: gdImageColorAllocateAlpha
751 *
752 * Allocates a color
753 *
754 * This is typically used for palette images, but can be used for truecolor
755 * images as well.
756 *
757 * Parameters:
758 * im - The image.
759 * r - The value of the red component.
760 * g - The value of the green component.
761 * b - The value of the blue component.
762 *
763 * Returns:
764 * The color value.
765 *
766 * See also:
767 * - <gdImageColorDeallocate>
768 */
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)769 BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
770 {
771 int i;
772 int ct = (-1);
773 if (im->trueColor) {
774 return gdTrueColorAlpha (r, g, b, a);
775 }
776 for (i = 0; (i < (im->colorsTotal)); i++) {
777 if (im->open[i]) {
778 ct = i;
779 break;
780 }
781 }
782 if (ct == (-1)) {
783 ct = im->colorsTotal;
784 if (ct == gdMaxColors) {
785 return -1;
786 }
787 im->colorsTotal++;
788 }
789 im->red[ct] = r;
790 im->green[ct] = g;
791 im->blue[ct] = b;
792 im->alpha[ct] = a;
793 im->open[ct] = 0;
794 return ct;
795 }
796
797 /*
798 Function: gdImageColorResolve
799
800 gdImageColorResolve is an alternative for the code fragment
801 (start code)
802 if ((color=gdImageColorExact(im,R,G,B)) < 0)
803 if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
804 color=gdImageColorClosest(im,R,G,B);
805 (end code)
806 in a single function. Its advantage is that it is guaranteed to
807 return a color index in one search over the color table.
808 */
809
gdImageColorResolve(gdImagePtr im,int r,int g,int b)810 BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b)
811 {
812 return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
813 }
814
815 /*
816 Function: gdImageColorResolveAlpha
817 */
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)818 BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
819 {
820 int c;
821 int ct = -1;
822 int op = -1;
823 long rd, gd, bd, ad, dist;
824 long mindist = 4 * 255 * 255; /* init to max poss dist */
825 if (im->trueColor) {
826 return gdTrueColorAlpha (r, g, b, a);
827 }
828
829 for (c = 0; c < im->colorsTotal; c++) {
830 if (im->open[c]) {
831 op = c; /* Save open slot */
832 continue; /* Color not in use */
833 }
834 if (c == im->transparent) {
835 /* don't ever resolve to the color that has
836 * been designated as the transparent color */
837 continue;
838 }
839 rd = (long) (im->red[c] - r);
840 gd = (long) (im->green[c] - g);
841 bd = (long) (im->blue[c] - b);
842 ad = (long) (im->alpha[c] - a);
843 dist = rd * rd + gd * gd + bd * bd + ad * ad;
844 if (dist < mindist) {
845 if (dist == 0) {
846 return c; /* Return exact match color */
847 }
848 mindist = dist;
849 ct = c;
850 }
851 }
852 /* no exact match. We now know closest, but first try to allocate exact */
853 if (op == -1) {
854 op = im->colorsTotal;
855 if (op == gdMaxColors) {
856 /* No room for more colors */
857 return ct; /* Return closest available color */
858 }
859 im->colorsTotal++;
860 }
861 im->red[op] = r;
862 im->green[op] = g;
863 im->blue[op] = b;
864 im->alpha[op] = a;
865 im->open[op] = 0;
866 return op; /* Return newly allocated color */
867 }
868
869 /**
870 * Function: gdImageColorDeallocate
871 *
872 * Removes a palette entry
873 *
874 * This is a no-op for truecolor images.
875 *
876 * Parameters:
877 * im - The image.
878 * color - The palette index.
879 *
880 * See also:
881 * - <gdImageColorAllocate>
882 * - <gdImageColorAllocateAlpha>
883 */
gdImageColorDeallocate(gdImagePtr im,int color)884 BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color)
885 {
886 if (im->trueColor || (color >= gdMaxColors) || (color < 0)) {
887 return;
888 }
889 /* Mark it open. */
890 im->open[color] = 1;
891 }
892
893 /**
894 * Function: gdImageColorTransparent
895 *
896 * Sets the transparent color of the image
897 *
898 * Parameter:
899 * im - The image.
900 * color - The color.
901 *
902 * See also:
903 * - <gdImageGetTransparent>
904 */
gdImageColorTransparent(gdImagePtr im,int color)905 BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color)
906 {
907 if (color < 0) {
908 return;
909 }
910
911 if (!im->trueColor) {
912 if (color >= gdMaxColors) {
913 return;
914 }
915 if (im->transparent != -1) {
916 im->alpha[im->transparent] = gdAlphaOpaque;
917 }
918 im->alpha[color] = gdAlphaTransparent;
919 }
920 im->transparent = color;
921 }
922
923 /*
924 Function: gdImagePaletteCopy
925 */
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)926 BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
927 {
928 int i;
929 int x, y, p;
930 int xlate[256];
931 if (to->trueColor) {
932 return;
933 }
934 if (from->trueColor) {
935 return;
936 }
937
938 for (i = 0; i < 256; i++) {
939 xlate[i] = -1;
940 };
941
942 for (y = 0; y < (to->sy); y++) {
943 for (x = 0; x < (to->sx); x++) {
944 /* Optimization: no gdImageGetPixel */
945 p = to->pixels[y][x];
946 if (xlate[p] == -1) {
947 /* This ought to use HWB, but we don't have an alpha-aware
948 version of that yet. */
949 xlate[p] =
950 gdImageColorClosestAlpha (from, to->red[p], to->green[p],
951 to->blue[p], to->alpha[p]);
952 /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
953 /* p, to->red[p], to->green[p], to->blue[p], to->alpha[p], */
954 /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
955 };
956 /* Optimization: no gdImageSetPixel */
957 to->pixels[y][x] = xlate[p];
958 };
959 };
960
961 for (i = 0; (i < (from->colorsTotal)); i++) {
962 /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
963 to->red[i] = from->red[i];
964 to->blue[i] = from->blue[i];
965 to->green[i] = from->green[i];
966 to->alpha[i] = from->alpha[i];
967 to->open[i] = 0;
968 };
969
970 for (i = from->colorsTotal; (i < to->colorsTotal); i++) {
971 to->open[i] = 1;
972 };
973
974 to->colorsTotal = from->colorsTotal;
975
976 }
977
978 /*
979 Function: gdImageColorReplace
980 */
gdImageColorReplace(gdImagePtr im,int src,int dst)981 BGD_DECLARE(int) gdImageColorReplace (gdImagePtr im, int src, int dst)
982 {
983 register int x, y;
984 int n = 0;
985
986 if (src == dst) {
987 return 0;
988 }
989
990 #define REPLACING_LOOP(pixel) do { \
991 for (y = im->cy1; y <= im->cy2; y++) { \
992 for (x = im->cx1; x <= im->cx2; x++) { \
993 if (pixel(im, x, y) == src) { \
994 gdImageSetPixel(im, x, y, dst); \
995 n++; \
996 } \
997 } \
998 } \
999 } while (0)
1000
1001 if (im->trueColor) {
1002 REPLACING_LOOP(gdImageTrueColorPixel);
1003 } else {
1004 REPLACING_LOOP(gdImagePalettePixel);
1005 }
1006
1007 #undef REPLACING_LOOP
1008
1009 return n;
1010 }
1011
1012 /*
1013 Function: gdImageColorReplaceThreshold
1014 */
gdImageColorReplaceThreshold(gdImagePtr im,int src,int dst,float threshold)1015 BGD_DECLARE(int) gdImageColorReplaceThreshold (gdImagePtr im, int src, int dst, float threshold)
1016 {
1017 register int x, y;
1018 int n = 0;
1019
1020 if (src == dst) {
1021 return 0;
1022 }
1023
1024 #define REPLACING_LOOP(pixel) do { \
1025 for (y = im->cy1; y <= im->cy2; y++) { \
1026 for (x = im->cx1; x <= im->cx2; x++) { \
1027 if (gdColorMatch(im, src, pixel(im, x, y), threshold)) { \
1028 gdImageSetPixel(im, x, y, dst); \
1029 n++; \
1030 } \
1031 } \
1032 } \
1033 } while (0)
1034
1035 if (im->trueColor) {
1036 REPLACING_LOOP(gdImageTrueColorPixel);
1037 } else {
1038 REPLACING_LOOP(gdImagePalettePixel);
1039 }
1040
1041 #undef REPLACING_LOOP
1042
1043 return n;
1044 }
1045
colorCmp(const void * x,const void * y)1046 static int colorCmp (const void *x, const void *y)
1047 {
1048 int a = *(int const *)x;
1049 int b = *(int const *)y;
1050 return (a > b) - (a < b);
1051 }
1052
1053 /*
1054 Function: gdImageColorReplaceArray
1055 */
gdImageColorReplaceArray(gdImagePtr im,int len,int * src,int * dst)1056 BGD_DECLARE(int) gdImageColorReplaceArray (gdImagePtr im, int len, int *src, int *dst)
1057 {
1058 register int x, y;
1059 int c, *d, *base;
1060 int i, n = 0;
1061
1062 if (len <= 0 || src == dst) {
1063 return 0;
1064 }
1065 if (len == 1) {
1066 return gdImageColorReplace(im, src[0], dst[0]);
1067 }
1068 if (overflow2(len, sizeof(int)<<1)) {
1069 return -1;
1070 }
1071 base = (int *)gdMalloc(len * (sizeof(int)<<1));
1072 if (!base) {
1073 return -1;
1074 }
1075 for (i = 0; i < len; i++) {
1076 base[(i<<1)] = src[i];
1077 base[(i<<1)+1] = dst[i];
1078 }
1079 qsort(base, len, sizeof(int)<<1, colorCmp);
1080
1081 #define REPLACING_LOOP(pixel) do { \
1082 for (y = im->cy1; y <= im->cy2; y++) { \
1083 for (x = im->cx1; x <= im->cx2; x++) { \
1084 c = pixel(im, x, y); \
1085 if ( (d = (int *)bsearch(&c, base, len, sizeof(int)<<1, colorCmp)) ) { \
1086 gdImageSetPixel(im, x, y, d[1]); \
1087 n++; \
1088 } \
1089 } \
1090 } \
1091 } while (0)
1092
1093 if (im->trueColor) {
1094 REPLACING_LOOP(gdImageTrueColorPixel);
1095 } else {
1096 REPLACING_LOOP(gdImagePalettePixel);
1097 }
1098
1099 #undef REPLACING_LOOP
1100
1101 gdFree(base);
1102 return n;
1103 }
1104
1105 /*
1106 Function: gdImageColorReplaceCallback
1107 */
gdImageColorReplaceCallback(gdImagePtr im,gdCallbackImageColor callback)1108 BGD_DECLARE(int) gdImageColorReplaceCallback (gdImagePtr im, gdCallbackImageColor callback)
1109 {
1110 int c, d, n = 0;
1111
1112 if (!callback) {
1113 return 0;
1114 }
1115 if (im->trueColor) {
1116 register int x, y;
1117
1118 for (y = im->cy1; y <= im->cy2; y++) {
1119 for (x = im->cx1; x <= im->cx2; x++) {
1120 c = gdImageTrueColorPixel(im, x, y);
1121 if ( (d = callback(im, c)) != c) {
1122 gdImageSetPixel(im, x, y, d);
1123 n++;
1124 }
1125 }
1126 }
1127 } else { /* palette */
1128 int *sarr, *darr;
1129 int k, len = 0;
1130
1131 sarr = (int *)gdCalloc(im->colorsTotal, sizeof(int));
1132 if (!sarr) {
1133 return -1;
1134 }
1135 for (c = 0; c < im->colorsTotal; c++) {
1136 if (!im->open[c]) {
1137 sarr[len++] = c;
1138 }
1139 }
1140 darr = (int *)gdCalloc(len, sizeof(int));
1141 if (!darr) {
1142 gdFree(sarr);
1143 return -1;
1144 }
1145 for (k = 0; k < len; k++) {
1146 darr[k] = callback(im, sarr[k]);
1147 }
1148 n = gdImageColorReplaceArray(im, k, sarr, darr);
1149 gdFree(darr);
1150 gdFree(sarr);
1151 }
1152 return n;
1153 }
1154
1155 /* 2.0.10: before the drawing routines, some code to clip points that are
1156 * outside the drawing window. Nick Atty (nick@canalplan.org.uk)
1157 *
1158 * This is the Sutherland Hodgman Algorithm, as implemented by
1159 * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's
1160 * Journal, January 1996, pp107-110 and 116-117
1161 *
1162 * Given the end points of a line, and a bounding rectangle (which we
1163 * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
1164 * the edges of the rectangle if the line should be drawn at all,
1165 * otherwise return a failure code */
1166
1167 /* this does "one-dimensional" clipping: note that the second time it
1168 is called, all the x parameters refer to height and the y to width
1169 - the comments ignore this (if you can understand it when it's
1170 looking at the X parameters, it should become clear what happens on
1171 the second call!) The code is simplified from that in the article,
1172 as we know that gd images always start at (0,0) */
1173
1174 /* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't
1175 necessarily start at 0. */
1176
1177 static int
clip_1d(int * x0,int * y0,int * x1,int * y1,int mindim,int maxdim)1178 clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
1179 {
1180 double m; /* gradient of line */
1181 if (*x0 < mindim) {
1182 /* start of line is left of window */
1183 if (*x1 < mindim) /* as is the end, so the line never cuts the window */
1184 return 0;
1185 m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
1186 /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
1187 *y0 -= (int)(m * (*x0 - mindim));
1188 *x0 = mindim;
1189 /* now, perhaps, adjust the far end of the line as well */
1190 if (*x1 > maxdim) {
1191 *y1 += m * (maxdim - *x1);
1192 *x1 = maxdim;
1193 }
1194 return 1;
1195 }
1196 if (*x0 > maxdim) {
1197 /* start of line is right of window -
1198 complement of above */
1199 if (*x1 > maxdim) /* as is the end, so the line misses the window */
1200 return 0;
1201 m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
1202 *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right
1203 boundary */
1204 *x0 = maxdim;
1205 /* now, perhaps, adjust the end of the line */
1206 if (*x1 < mindim) {
1207 *y1 -= (int)(m * (*x1 - mindim));
1208 *x1 = mindim;
1209 }
1210 return 1;
1211 }
1212 /* the final case - the start of the line is inside the window */
1213 if (*x1 > maxdim) {
1214 /* other end is outside to the right */
1215 m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
1216 *y1 += (int)(m * (maxdim - *x1));
1217 *x1 = maxdim;
1218 return 1;
1219 }
1220 if (*x1 < mindim) {
1221 /* other end is outside to the left */
1222 m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
1223 *y1 -= (int)(m * (*x1 - mindim));
1224 *x1 = mindim;
1225 return 1;
1226 }
1227 /* only get here if both points are inside the window */
1228 return 1;
1229 }
1230
1231 /* end of line clipping code */
1232
1233 /**
1234 * Group: Pixels
1235 */
1236
1237 /*
1238 Function: gdImageSetPixel
1239 */
gdImageSetPixel(gdImagePtr im,int x,int y,int color)1240 BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color)
1241 {
1242 int p;
1243 switch (color) {
1244 case gdStyled:
1245 if (!im->style) {
1246 /* Refuse to draw if no style is set. */
1247 return;
1248 } else {
1249 p = im->style[im->stylePos++];
1250 }
1251 if (p != (gdTransparent)) {
1252 gdImageSetPixel (im, x, y, p);
1253 }
1254 im->stylePos = im->stylePos % im->styleLength;
1255 break;
1256 case gdStyledBrushed:
1257 if (!im->style) {
1258 /* Refuse to draw if no style is set. */
1259 return;
1260 }
1261 p = im->style[im->stylePos++];
1262 if ((p != gdTransparent) && (p != 0)) {
1263 gdImageSetPixel (im, x, y, gdBrushed);
1264 }
1265 im->stylePos = im->stylePos % im->styleLength;
1266 break;
1267 case gdBrushed:
1268 gdImageBrushApply (im, x, y);
1269 break;
1270 case gdTiled:
1271 gdImageTileApply (im, x, y);
1272 break;
1273 case gdAntiAliased:
1274 /* This shouldn't happen (2.0.26) because we just call
1275 gdImageAALine now, but do something sane. */
1276 gdImageSetPixel(im, x, y, im->AA_color);
1277 break;
1278 default:
1279 if (gdImageBoundsSafeMacro (im, x, y)) {
1280 if (im->trueColor) {
1281 switch (im->alphaBlendingFlag) {
1282 default:
1283 case gdEffectReplace:
1284 im->tpixels[y][x] = color;
1285 break;
1286 case gdEffectAlphaBlend:
1287 case gdEffectNormal:
1288 im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
1289 break;
1290 case gdEffectOverlay :
1291 im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
1292 break;
1293 case gdEffectMultiply :
1294 im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color);
1295 break;
1296 }
1297 } else {
1298 im->pixels[y][x] = color;
1299 }
1300 }
1301 break;
1302 }
1303 }
1304
1305 static void
gdImageBrushApply(gdImagePtr im,int x,int y)1306 gdImageBrushApply (gdImagePtr im, int x, int y)
1307 {
1308 int lx, ly;
1309 int hy;
1310 int hx;
1311 int x1, y1, x2, y2;
1312 int srcx, srcy;
1313 if (!im->brush) {
1314 return;
1315 }
1316 hy = gdImageSY (im->brush) / 2;
1317 y1 = y - hy;
1318 y2 = y1 + gdImageSY (im->brush);
1319 hx = gdImageSX (im->brush) / 2;
1320 x1 = x - hx;
1321 x2 = x1 + gdImageSX (im->brush);
1322 srcy = 0;
1323 if (im->trueColor) {
1324 if (im->brush->trueColor) {
1325 for (ly = y1; (ly < y2); ly++) {
1326 srcx = 0;
1327 for (lx = x1; (lx < x2); lx++) {
1328 int p;
1329 p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
1330 /* 2.0.9, Thomas Winzig: apply simple full transparency */
1331 if (p != gdImageGetTransparent (im->brush)) {
1332 gdImageSetPixel (im, lx, ly, p);
1333 }
1334 srcx++;
1335 }
1336 srcy++;
1337 }
1338 } else {
1339 /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
1340 for pointing out the issue) */
1341 for (ly = y1; (ly < y2); ly++) {
1342 srcx = 0;
1343 for (lx = x1; (lx < x2); lx++) {
1344 int p, tc;
1345 p = gdImageGetPixel (im->brush, srcx, srcy);
1346 tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
1347 /* 2.0.9, Thomas Winzig: apply simple full transparency */
1348 if (p != gdImageGetTransparent (im->brush)) {
1349 gdImageSetPixel (im, lx, ly, tc);
1350 }
1351 srcx++;
1352 }
1353 srcy++;
1354 }
1355 }
1356 } else {
1357 for (ly = y1; (ly < y2); ly++) {
1358 srcx = 0;
1359 for (lx = x1; (lx < x2); lx++) {
1360 int p;
1361 p = gdImageGetPixel (im->brush, srcx, srcy);
1362 /* Allow for non-square brushes! */
1363 if (p != gdImageGetTransparent (im->brush)) {
1364 /* Truecolor brush. Very slow
1365 on a palette destination. */
1366 if (im->brush->trueColor) {
1367 gdImageSetPixel (im, lx, ly,
1368 gdImageColorResolveAlpha (im,
1369 gdTrueColorGetRed
1370 (p),
1371 gdTrueColorGetGreen
1372 (p),
1373 gdTrueColorGetBlue
1374 (p),
1375 gdTrueColorGetAlpha
1376 (p)));
1377 } else {
1378 gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
1379 }
1380 }
1381 srcx++;
1382 }
1383 srcy++;
1384 }
1385 }
1386 }
1387
1388 static void
gdImageTileApply(gdImagePtr im,int x,int y)1389 gdImageTileApply (gdImagePtr im, int x, int y)
1390 {
1391 gdImagePtr tile = im->tile;
1392 int srcx, srcy;
1393 int p;
1394 if (!tile) {
1395 return;
1396 }
1397 srcx = x % gdImageSX (tile);
1398 srcy = y % gdImageSY (tile);
1399 if (im->trueColor) {
1400 p = gdImageGetPixel (tile, srcx, srcy);
1401 if (p != gdImageGetTransparent (tile)) {
1402 if (!tile->trueColor) {
1403 p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
1404 }
1405 gdImageSetPixel (im, x, y, p);
1406 }
1407 } else {
1408 p = gdImageGetPixel (tile, srcx, srcy);
1409 /* Allow for transparency */
1410 if (p != gdImageGetTransparent (tile)) {
1411 if (tile->trueColor) {
1412 /* Truecolor tile. Very slow
1413 on a palette destination. */
1414 gdImageSetPixel (im, x, y,
1415 gdImageColorResolveAlpha (im,
1416 gdTrueColorGetRed
1417 (p),
1418 gdTrueColorGetGreen
1419 (p),
1420 gdTrueColorGetBlue
1421 (p),
1422 gdTrueColorGetAlpha
1423 (p)));
1424 } else {
1425 gdImageSetPixel (im, x, y, im->tileColorMap[p]);
1426 }
1427 }
1428 }
1429 }
1430
1431 /**
1432 * Function: gdImageGetPixel
1433 *
1434 * Gets a pixel color as stored in the image.
1435 *
1436 * Parameters:
1437 * im - The image.
1438 * x - The x-coordinate.
1439 * y - The y-coordinate.
1440 *
1441 * See also:
1442 * - <gdImageGetTrueColorPixel>
1443 * - <gdImagePalettePixel>
1444 * - <gdImageTrueColorPixel>
1445 */
gdImageGetPixel(gdImagePtr im,int x,int y)1446 BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y)
1447 {
1448 if (gdImageBoundsSafeMacro (im, x, y)) {
1449 if (im->trueColor) {
1450 return im->tpixels[y][x];
1451 } else {
1452 return im->pixels[y][x];
1453 }
1454 } else {
1455 return 0;
1456 }
1457 }
1458
1459 /**
1460 * Function: gdImageGetTrueColorPixel
1461 *
1462 * Gets a pixel color always as truecolor value.
1463 *
1464 * Parameters:
1465 * im - The image.
1466 * x - The x-coordinate.
1467 * y - The y-coordinate.
1468 *
1469 * See also:
1470 * - <gdImageGetPixel>
1471 * - <gdImageTrueColorPixel>
1472 */
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)1473 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
1474 {
1475 int p = gdImageGetPixel (im, x, y);
1476 if (!im->trueColor) {
1477 return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
1478 (im->transparent == p) ? gdAlphaTransparent :
1479 im->alpha[p]);
1480 } else {
1481 return p;
1482 }
1483 }
1484
1485 /**
1486 * Group: Primitives
1487 */
1488
1489 /*
1490 Function: gdImageAABlend
1491
1492 NO-OP, kept for library compatibility.
1493 */
gdImageAABlend(gdImagePtr im)1494 BGD_DECLARE(void) gdImageAABlend (gdImagePtr im)
1495 {
1496 (void)im;
1497 }
1498
1499 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);
1500
1501 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
1502 int color);
1503
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1504 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1505 {
1506 if (im->thick > 1) {
1507 int thickhalf = im->thick >> 1;
1508 _gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1509 } else {
1510 if (x2 < x1) {
1511 int t = x2;
1512 x2 = x1;
1513 x1 = t;
1514 }
1515
1516 for (; x1 <= x2; x1++) {
1517 gdImageSetPixel(im, x1, y, col);
1518 }
1519 }
1520 return;
1521 }
1522
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1523 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1524 {
1525 if (im->thick > 1) {
1526 int thickhalf = im->thick >> 1;
1527 gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1528 } else {
1529 if (y2 < y1) {
1530 int t = y1;
1531 y1 = y2;
1532 y2 = t;
1533 }
1534
1535 for (; y1 <= y2; y1++) {
1536 gdImageSetPixel(im, x, y1, col);
1537 }
1538 }
1539 return;
1540 }
1541
1542 /*
1543 Function: gdImageLine
1544
1545 Bresenham as presented in Foley & Van Dam.
1546 */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1547 BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1548 {
1549 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1550 int wid;
1551 int w, wstart;
1552 int thick;
1553
1554 if (color == gdAntiAliased) {
1555 /*
1556 gdAntiAliased passed as color: use the much faster, much cheaper
1557 and equally attractive gdImageAALine implementation. That
1558 clips too, so don't clip twice.
1559 */
1560 gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1561 return;
1562 }
1563 /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
1564 points need to be drawn. 2.0.26, TBB: clip to edges of clipping
1565 rectangle. We were getting away with this because gdImageSetPixel
1566 is used for actual drawing, but this is still more efficient and opens
1567 the way to skip per-pixel bounds checking in the future. */
1568
1569 if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
1570 return;
1571 if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
1572 return;
1573 thick = im->thick;
1574
1575 dx = abs (x2 - x1);
1576 dy = abs (y2 - y1);
1577
1578 if (dx == 0) {
1579 gdImageVLine(im, x1, y1, y2, color);
1580 return;
1581 } else if (dy == 0) {
1582 gdImageHLine(im, y1, x1, x2, color);
1583 return;
1584 }
1585
1586 if (dy <= dx) {
1587 /* More-or-less horizontal. use wid for vertical stroke */
1588 /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1589
1590 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1591 TBB: but watch out for /0! */
1592 double ac = cos (atan2 (dy, dx));
1593 if (ac != 0) {
1594 wid = thick / ac;
1595 } else {
1596 wid = 1;
1597 }
1598 if (wid == 0) {
1599 wid = 1;
1600 }
1601 d = 2 * dy - dx;
1602 incr1 = 2 * dy;
1603 incr2 = 2 * (dy - dx);
1604 if (x1 > x2) {
1605 x = x2;
1606 y = y2;
1607 ydirflag = (-1);
1608 xend = x1;
1609 } else {
1610 x = x1;
1611 y = y1;
1612 ydirflag = 1;
1613 xend = x2;
1614 }
1615
1616 /* Set up line thickness */
1617 wstart = y - wid / 2;
1618 for (w = wstart; w < wstart + wid; w++)
1619 gdImageSetPixel (im, x, w, color);
1620
1621 if (((y2 - y1) * ydirflag) > 0) {
1622 while (x < xend) {
1623 x++;
1624 if (d < 0) {
1625 d += incr1;
1626 } else {
1627 y++;
1628 d += incr2;
1629 }
1630 wstart = y - wid / 2;
1631 for (w = wstart; w < wstart + wid; w++)
1632 gdImageSetPixel (im, x, w, color);
1633 }
1634 } else {
1635 while (x < xend) {
1636 x++;
1637 if (d < 0) {
1638 d += incr1;
1639 } else {
1640 y--;
1641 d += incr2;
1642 }
1643 wstart = y - wid / 2;
1644 for (w = wstart; w < wstart + wid; w++)
1645 gdImageSetPixel (im, x, w, color);
1646 }
1647 }
1648 } else {
1649 /* More-or-less vertical. use wid for horizontal stroke */
1650 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1651 TBB: but watch out for /0! */
1652 double as = sin (atan2 (dy, dx));
1653 if (as != 0) {
1654 wid = thick / as;
1655 } else {
1656 wid = 1;
1657 }
1658 if (wid == 0)
1659 wid = 1;
1660
1661 d = 2 * dx - dy;
1662 incr1 = 2 * dx;
1663 incr2 = 2 * (dx - dy);
1664 if (y1 > y2) {
1665 y = y2;
1666 x = x2;
1667 yend = y1;
1668 xdirflag = (-1);
1669 } else {
1670 y = y1;
1671 x = x1;
1672 yend = y2;
1673 xdirflag = 1;
1674 }
1675
1676 /* Set up line thickness */
1677 wstart = x - wid / 2;
1678 for (w = wstart; w < wstart + wid; w++)
1679 gdImageSetPixel (im, w, y, color);
1680
1681 if (((x2 - x1) * xdirflag) > 0) {
1682 while (y < yend) {
1683 y++;
1684 if (d < 0) {
1685 d += incr1;
1686 } else {
1687 x++;
1688 d += incr2;
1689 }
1690 wstart = x - wid / 2;
1691 for (w = wstart; w < wstart + wid; w++)
1692 gdImageSetPixel (im, w, y, color);
1693 }
1694 } else {
1695 while (y < yend) {
1696 y++;
1697 if (d < 0) {
1698 d += incr1;
1699 } else {
1700 x--;
1701 d += incr2;
1702 }
1703 wstart = x - wid / 2;
1704 for (w = wstart; w < wstart + wid; w++)
1705 gdImageSetPixel (im, w, y, color);
1706 }
1707 }
1708 }
1709
1710 }
1711 static void dashedSet (gdImagePtr im, int x, int y, int color,
1712 int *onP, int *dashStepP, int wid, int vert);
1713
1714 /*
1715 Function: gdImageDashedLine
1716 */
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1717 BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1718 {
1719 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1720 int dashStep = 0;
1721 int on = 1;
1722 int wid;
1723 int vert;
1724 int thick = im->thick;
1725
1726 dx = abs (x2 - x1);
1727 dy = abs (y2 - y1);
1728 if (dy <= dx) {
1729 /* More-or-less horizontal. use wid for vertical stroke */
1730 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1731 TBB: but watch out for /0! */
1732 double as = sin (atan2 (dy, dx));
1733 if (as != 0) {
1734 wid = thick / as;
1735 } else {
1736 wid = 1;
1737 }
1738 vert = 1;
1739
1740 d = 2 * dy - dx;
1741 incr1 = 2 * dy;
1742 incr2 = 2 * (dy - dx);
1743 if (x1 > x2) {
1744 x = x2;
1745 y = y2;
1746 ydirflag = (-1);
1747 xend = x1;
1748 } else {
1749 x = x1;
1750 y = y1;
1751 ydirflag = 1;
1752 xend = x2;
1753 }
1754 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1755 if (((y2 - y1) * ydirflag) > 0) {
1756 while (x < xend) {
1757 x++;
1758 if (d < 0) {
1759 d += incr1;
1760 } else {
1761 y++;
1762 d += incr2;
1763 }
1764 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1765 }
1766 } else {
1767 while (x < xend) {
1768 x++;
1769 if (d < 0) {
1770 d += incr1;
1771 } else {
1772 y--;
1773 d += incr2;
1774 }
1775 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1776 }
1777 }
1778 } else {
1779 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1780 TBB: but watch out for /0! */
1781 double as = sin (atan2 (dy, dx));
1782 if (as != 0) {
1783 wid = thick / as;
1784 } else {
1785 wid = 1;
1786 }
1787 vert = 0;
1788
1789 d = 2 * dx - dy;
1790 incr1 = 2 * dx;
1791 incr2 = 2 * (dx - dy);
1792 if (y1 > y2) {
1793 y = y2;
1794 x = x2;
1795 yend = y1;
1796 xdirflag = (-1);
1797 } else {
1798 y = y1;
1799 x = x1;
1800 yend = y2;
1801 xdirflag = 1;
1802 }
1803 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1804 if (((x2 - x1) * xdirflag) > 0) {
1805 while (y < yend) {
1806 y++;
1807 if (d < 0) {
1808 d += incr1;
1809 } else {
1810 x++;
1811 d += incr2;
1812 }
1813 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1814 }
1815 } else {
1816 while (y < yend) {
1817 y++;
1818 if (d < 0) {
1819 d += incr1;
1820 } else {
1821 x--;
1822 d += incr2;
1823 }
1824 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1825 }
1826 }
1827 }
1828 }
1829
1830 static void
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1831 dashedSet (gdImagePtr im, int x, int y, int color,
1832 int *onP, int *dashStepP, int wid, int vert)
1833 {
1834 int dashStep = *dashStepP;
1835 int on = *onP;
1836 int w, wstart;
1837
1838 dashStep++;
1839 if (dashStep == gdDashSize) {
1840 dashStep = 0;
1841 on = !on;
1842 }
1843 if (on) {
1844 if (vert) {
1845 wstart = y - wid / 2;
1846 for (w = wstart; w < wstart + wid; w++)
1847 gdImageSetPixel (im, x, w, color);
1848 } else {
1849 wstart = x - wid / 2;
1850 for (w = wstart; w < wstart + wid; w++)
1851 gdImageSetPixel (im, w, y, color);
1852 }
1853 }
1854 *dashStepP = dashStep;
1855 *onP = on;
1856 }
1857
1858 /*
1859 Function: gdImageBoundsSafe
1860 */
gdImageBoundsSafe(gdImagePtr im,int x,int y)1861 BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y)
1862 {
1863 return gdImageBoundsSafeMacro (im, x, y);
1864 }
1865
1866 /**
1867 * Function: gdImageChar
1868 *
1869 * Draws a single character.
1870 *
1871 * Parameters:
1872 * im - The image to draw onto.
1873 * f - The raster font.
1874 * x - The x coordinate of the upper left pixel.
1875 * y - The y coordinate of the upper left pixel.
1876 * c - The character.
1877 * color - The color.
1878 *
1879 * Variants:
1880 * - <gdImageCharUp>
1881 *
1882 * See also:
1883 * - <gdFontPtr>
1884 */
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1885 BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1886 {
1887 int cx, cy;
1888 int px, py;
1889 int fline;
1890 const int xuppper = (x > INT_MAX - f->w) ? INT_MAX : x + f->w;
1891 const int yuppper = (y > INT_MAX - f->h) ? INT_MAX : y + f->h;
1892 cx = 0;
1893 cy = 0;
1894 #ifdef CHARSET_EBCDIC
1895 c = ASC (c);
1896 #endif /*CHARSET_EBCDIC */
1897 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1898 return;
1899 }
1900 fline = (c - f->offset) * f->h * f->w;
1901 for (py = y; py < yuppper; py++) {
1902 for (px = x; px < xuppper; px++) {
1903 if (f->data[fline + cy * f->w + cx]) {
1904 gdImageSetPixel (im, px, py, color);
1905 }
1906 cx++;
1907 }
1908 cx = 0;
1909 cy++;
1910 }
1911 }
1912
1913 /**
1914 * Function: gdImageCharUp
1915 */
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1916 BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1917 {
1918 int cx, cy;
1919 int px, py;
1920 int fline;
1921 const int xuppper = (x > INT_MAX - f->h) ? INT_MAX : x + f->h;
1922 const int ylower = (y < INT_MIN + f->w) ? INT_MIN : y - f->w;
1923 cx = 0;
1924 cy = 0;
1925 #ifdef CHARSET_EBCDIC
1926 c = ASC (c);
1927 #endif /*CHARSET_EBCDIC */
1928 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1929 return;
1930 }
1931 fline = (c - f->offset) * f->h * f->w;
1932 for (py = y; py > ylower; py--) {
1933 for (px = x; px < xuppper; px++) {
1934 if (f->data[fline + cy * f->w + cx]) {
1935 gdImageSetPixel (im, px, py, color);
1936 }
1937 cy++;
1938 }
1939 cy = 0;
1940 cx++;
1941 }
1942 }
1943
1944 /**
1945 * Function: gdImageString
1946 *
1947 * Draws a character string.
1948 *
1949 * Parameters:
1950 * im - The image to draw onto.
1951 * f - The raster font.
1952 * x - The x coordinate of the upper left pixel.
1953 * y - The y coordinate of the upper left pixel.
1954 * c - The character string.
1955 * color - The color.
1956 *
1957 * Variants:
1958 * - <gdImageStringUp>
1959 * - <gdImageString16>
1960 * - <gdImageStringUp16>
1961 *
1962 * See also:
1963 * - <gdFontPtr>
1964 * - <gdImageStringTTF>
1965 */
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1966 BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f,
1967 int x, int y, unsigned char *s, int color)
1968 {
1969 int i;
1970 int l;
1971 l = strlen ((char *) s);
1972 for (i = 0; (i < l); i++) {
1973 gdImageChar (im, f, x, y, s[i], color);
1974 x += f->w;
1975 }
1976 }
1977
1978 /**
1979 * Function: gdImageStringUp
1980 */
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1981 BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f,
1982 int x, int y, unsigned char *s, int color)
1983 {
1984 int i;
1985 int l;
1986 l = strlen ((char *) s);
1987 for (i = 0; (i < l); i++) {
1988 gdImageCharUp (im, f, x, y, s[i], color);
1989 y -= f->w;
1990 }
1991 }
1992
1993 static int strlen16 (unsigned short *s);
1994
1995 /**
1996 * Function: gdImageString16
1997 */
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1998 BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f,
1999 int x, int y, unsigned short *s, int color)
2000 {
2001 int i;
2002 int l;
2003 l = strlen16 (s);
2004 for (i = 0; (i < l); i++) {
2005 gdImageChar (im, f, x, y, s[i], color);
2006 x += f->w;
2007 }
2008 }
2009
2010 /**
2011 * Function: gdImageStringUp16
2012 */
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)2013 BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
2014 int x, int y, unsigned short *s, int color)
2015 {
2016 int i;
2017 int l;
2018 l = strlen16 (s);
2019 for (i = 0; (i < l); i++) {
2020 gdImageCharUp (im, f, x, y, s[i], color);
2021 y -= f->w;
2022 }
2023 }
2024
2025 static int
strlen16(unsigned short * s)2026 strlen16 (unsigned short *s)
2027 {
2028 int len = 0;
2029 while (*s) {
2030 s++;
2031 len++;
2032 }
2033 return len;
2034 }
2035
2036 #ifndef HAVE_LSQRT
2037 /* If you don't have a nice square root function for longs, you can use
2038 ** this hack
2039 */
2040 long
lsqrt(long n)2041 lsqrt (long n)
2042 {
2043 long result = (long) sqrt ((double) n);
2044 return result;
2045 }
2046 #endif
2047
2048 /* s and e are integers modulo 360 (degrees), with 0 degrees
2049 being the rightmost extreme and degrees changing clockwise.
2050 cx and cy are the center in pixels; w and h are the horizontal
2051 and vertical diameter in pixels. */
2052
2053 /*
2054 Function: gdImageArc
2055 */
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)2056 BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
2057 int color)
2058 {
2059 gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
2060 }
2061
2062 /*
2063 Function: gdImageFilledArc
2064 */
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)2065 BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
2066 int color, int style)
2067 {
2068 gdPoint pts[363];
2069 int i, pti;
2070 int lx = 0, ly = 0;
2071 int fx = 0, fy = 0;
2072 int startx = -1, starty = -1, endx = -1, endy = -1;
2073
2074 if ((s % 360) == (e % 360)) {
2075 s = 0;
2076 e = 360;
2077 } else {
2078 if (s > 360) {
2079 s = s % 360;
2080 }
2081
2082 if (e > 360) {
2083 e = e % 360;
2084 }
2085
2086 while (s < 0) {
2087 s += 360;
2088 }
2089
2090 while (e < s) {
2091 e += 360;
2092 }
2093
2094 if (s == e) {
2095 s = 0;
2096 e = 360;
2097 }
2098 }
2099
2100 for (i = s, pti = 1; (i <= e); i++, pti++) {
2101 int x, y;
2102 x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
2103 y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
2104 if (i != s) {
2105 if (!(style & gdChord)) {
2106 if (style & gdNoFill) {
2107 gdImageLine (im, lx, ly, x, y, color);
2108 } else {
2109 if (y == ly) {
2110 pti--; /* don't add this point */
2111 if (((i > 270 || i < 90) && x > lx) || ((i > 90 && i < 270) && x < lx)) {
2112 /* replace the old x coord, if increasing on the
2113 right side or decreasing on the left side */
2114 pts[pti].x = x;
2115 }
2116 } else {
2117 pts[pti].x = x;
2118 pts[pti].y = y;
2119 }
2120 }
2121 }
2122 } else {
2123 fx = x;
2124 fy = y;
2125
2126 if (!(style & (gdChord | gdNoFill))) {
2127 pts[0].x = cx;
2128 pts[0].y = cy;
2129 pts[pti].x = startx = x;
2130 pts[pti].y = starty = y;
2131 }
2132 }
2133 lx = x;
2134 ly = y;
2135 }
2136 if (style & gdChord) {
2137 if (style & gdNoFill) {
2138 if (style & gdEdged) {
2139 gdImageLine (im, cx, cy, lx, ly, color);
2140 gdImageLine (im, cx, cy, fx, fy, color);
2141 }
2142 gdImageLine (im, fx, fy, lx, ly, color);
2143 } else {
2144 pts[0].x = fx;
2145 pts[0].y = fy;
2146 pts[1].x = lx;
2147 pts[1].y = ly;
2148 pts[2].x = cx;
2149 pts[2].y = cy;
2150 gdImageFilledPolygon (im, pts, 3, color);
2151 }
2152 } else {
2153 if (style & gdNoFill) {
2154 if (style & gdEdged) {
2155 gdImageLine (im, cx, cy, lx, ly, color);
2156 gdImageLine (im, cx, cy, fx, fy, color);
2157 }
2158 } else {
2159 if (e - s < 360) {
2160 if (pts[1].x != startx && pts[1].y == starty) {
2161 /* start point has been removed due to y-coord fix => insert it */
2162 for (i = pti; i > 1; i--) {
2163 pts[i].x = pts[i-1].x;
2164 pts[i].y = pts[i-1].y;
2165 }
2166 pts[1].x = startx;
2167 pts[1].y = starty;
2168 pti++;
2169 }
2170 if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
2171 /* end point has been removed due to y-coord fix => insert it */
2172 pts[pti].x = endx;
2173 pts[pti].y = endy;
2174 pti++;
2175 }
2176 }
2177 pts[pti].x = cx;
2178 pts[pti].y = cy;
2179 gdImageFilledPolygon(im, pts, pti+1, color);
2180 }
2181 }
2182 }
2183
2184 /*
2185 Function: gdImageEllipse
2186 */
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)2187 BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
2188 {
2189 int x=0,mx1=0,mx2=0,my1=0,my2=0;
2190 int64_t aq,bq,dx,dy,r,rx,ry,a,b;
2191
2192 a=w>>1;
2193 b=h>>1;
2194 gdImageSetPixel(im,mx+a, my, c);
2195 gdImageSetPixel(im,mx-a, my, c);
2196 mx1 = mx-a;
2197 my1 = my;
2198 mx2 = mx+a;
2199 my2 = my;
2200
2201 aq = a * a;
2202 bq = b * b;
2203 dx = aq << 1;
2204 dy = bq << 1;
2205 r = a * bq;
2206 rx = r << 1;
2207 ry = 0;
2208 x = a;
2209 while (x > 0) {
2210 if (r > 0) {
2211 my1++;
2212 my2--;
2213 ry +=dx;
2214 r -=ry;
2215 }
2216 if (r <= 0) {
2217 x--;
2218 mx1++;
2219 mx2--;
2220 rx -=dy;
2221 r +=rx;
2222 }
2223 gdImageSetPixel(im,mx1, my1, c);
2224 gdImageSetPixel(im,mx1, my2, c);
2225 gdImageSetPixel(im,mx2, my1, c);
2226 gdImageSetPixel(im,mx2, my2, c);
2227 }
2228 }
2229
2230
2231 /*
2232 Function: gdImageFilledEllipse
2233 */
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)2234 BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
2235 {
2236 int x=0,mx1=0,mx2=0,my1=0,my2=0;
2237 int64_t aq,bq,dx,dy,r,rx,ry,a,b;
2238 int i;
2239 int old_y2;
2240
2241 a=w>>1;
2242 b=h>>1;
2243
2244 for (x = mx-a; x <= mx+a; x++) {
2245 gdImageSetPixel(im, x, my, c);
2246 }
2247
2248 mx1 = mx-a;
2249 my1 = my;
2250 mx2 = mx+a;
2251 my2 = my;
2252
2253 aq = a * a;
2254 bq = b * b;
2255 dx = aq << 1;
2256 dy = bq << 1;
2257 r = a * bq;
2258 rx = r << 1;
2259 ry = 0;
2260 x = a;
2261 old_y2=-2;
2262 while (x > 0) {
2263 if (r > 0) {
2264 my1++;
2265 my2--;
2266 ry +=dx;
2267 r -=ry;
2268 }
2269 if (r <= 0) {
2270 x--;
2271 mx1++;
2272 mx2--;
2273 rx -=dy;
2274 r +=rx;
2275 }
2276
2277 if(old_y2!=my2) {
2278 for(i=mx1; i<=mx2; i++) {
2279 gdImageSetPixel(im,i,my2,c);
2280 gdImageSetPixel(im,i,my1,c);
2281 }
2282 }
2283 old_y2 = my2;
2284 }
2285 }
2286
2287 /*
2288 Function: gdImageFillToBorder
2289 */
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)2290 BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
2291 {
2292 int lastBorder;
2293 /* Seek left */
2294 int leftLimit, rightLimit;
2295 int i;
2296 int restoreAlphaBleding;
2297
2298 if (border < 0 || color < 0) {
2299 /* Refuse to fill to a non-solid border */
2300 return;
2301 }
2302
2303 if (!im->trueColor) {
2304 if (color > (im->colorsTotal - 1) || border > (im->colorsTotal - 1)) {
2305 return;
2306 }
2307 }
2308
2309 leftLimit = (-1);
2310
2311 restoreAlphaBleding = im->alphaBlendingFlag;
2312 im->alphaBlendingFlag = 0;
2313
2314 if (x >= im->sx) {
2315 x = im->sx - 1;
2316 } else if (x < 0) {
2317 x = 0;
2318 }
2319 if (y >= im->sy) {
2320 y = im->sy - 1;
2321 } else if (y < 0) {
2322 y = 0;
2323 }
2324
2325 for (i = x; (i >= 0); i--) {
2326 if (gdImageGetPixel (im, i, y) == border) {
2327 break;
2328 }
2329 gdImageSetPixel (im, i, y, color);
2330 leftLimit = i;
2331 }
2332 if (leftLimit == (-1)) {
2333 im->alphaBlendingFlag = restoreAlphaBleding;
2334 return;
2335 }
2336 /* Seek right */
2337 rightLimit = x;
2338 for (i = (x + 1); (i < im->sx); i++) {
2339 if (gdImageGetPixel (im, i, y) == border) {
2340 break;
2341 }
2342 gdImageSetPixel (im, i, y, color);
2343 rightLimit = i;
2344 }
2345 /* Look at lines above and below and start paints */
2346 /* Above */
2347 if (y > 0) {
2348 lastBorder = 1;
2349 for (i = leftLimit; (i <= rightLimit); i++) {
2350 int c;
2351 c = gdImageGetPixel (im, i, y - 1);
2352 if (lastBorder) {
2353 if ((c != border) && (c != color)) {
2354 gdImageFillToBorder (im, i, y - 1, border, color);
2355 lastBorder = 0;
2356 }
2357 } else if ((c == border) || (c == color)) {
2358 lastBorder = 1;
2359 }
2360 }
2361 }
2362 /* Below */
2363 if (y < ((im->sy) - 1)) {
2364 lastBorder = 1;
2365 for (i = leftLimit; (i <= rightLimit); i++) {
2366 int c = gdImageGetPixel (im, i, y + 1);
2367 if (lastBorder) {
2368 if ((c != border) && (c != color)) {
2369 gdImageFillToBorder (im, i, y + 1, border, color);
2370 lastBorder = 0;
2371 }
2372 } else if ((c == border) || (c == color)) {
2373 lastBorder = 1;
2374 }
2375 }
2376 }
2377 im->alphaBlendingFlag = restoreAlphaBleding;
2378 }
2379
2380 /*
2381 * set the pixel at (x,y) and its 4-connected neighbors
2382 * with the same pixel value to the new pixel value nc (new color).
2383 * A 4-connected neighbor: pixel above, below, left, or right of a pixel.
2384 * ideas from comp.graphics discussions.
2385 * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
2386 * contain the same color as the color to fill. To do not bloat normal filling
2387 * code I added a 2nd private function.
2388 */
2389
gdImageTileGet(gdImagePtr im,int x,int y)2390 static int gdImageTileGet (gdImagePtr im, int x, int y)
2391 {
2392 int srcx, srcy;
2393 int tileColor,p;
2394 if (!im->tile) {
2395 return -1;
2396 }
2397 srcx = x % gdImageSX(im->tile);
2398 srcy = y % gdImageSY(im->tile);
2399 p = gdImageGetPixel(im->tile, srcx, srcy);
2400 if (p == im->tile->transparent) {
2401 tileColor = im->transparent;
2402 } else if (im->trueColor) {
2403 if (im->tile->trueColor) {
2404 tileColor = p;
2405 } else {
2406 tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
2407 }
2408 } else {
2409 if (im->tile->trueColor) {
2410 tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
2411 } else {
2412 tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
2413 }
2414 }
2415 return tileColor;
2416 }
2417
2418
2419
2420 /* horizontal segment of scan line y */
2421 struct seg {
2422 int y, xl, xr, dy;
2423 };
2424
2425 /* max depth of stack */
2426 #define FILL_MAX ((int)(im->sy*im->sx)/4)
2427 #define FILL_PUSH(Y, XL, XR, DY) \
2428 if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
2429 {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
2430
2431 #define FILL_POP(Y, XL, XR, DY) \
2432 {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
2433
2434 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
2435
2436 /*
2437 Function: gdImageFill
2438 */
gdImageFill(gdImagePtr im,int x,int y,int nc)2439 BGD_DECLARE(void) gdImageFill(gdImagePtr im, int x, int y, int nc)
2440 {
2441 int l, x1, x2, dy;
2442 int oc; /* old pixel value */
2443 int wx2,wy2;
2444
2445 int alphablending_bak;
2446
2447 /* stack of filled segments */
2448 /* struct seg stack[FILL_MAX],*sp = stack; */
2449 struct seg *stack;
2450 struct seg *sp;
2451
2452 if (!im->trueColor && nc > (im->colorsTotal - 1)) {
2453 return;
2454 }
2455
2456 alphablending_bak = im->alphaBlendingFlag;
2457 im->alphaBlendingFlag = 0;
2458
2459 if (nc==gdTiled) {
2460 _gdImageFillTiled(im,x,y,nc);
2461 im->alphaBlendingFlag = alphablending_bak;
2462 return;
2463 }
2464
2465 wx2=im->sx;
2466 wy2=im->sy;
2467 oc = gdImageGetPixel(im, x, y);
2468 if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
2469 im->alphaBlendingFlag = alphablending_bak;
2470 return;
2471 }
2472
2473 /* Do not use the 4 neighbors implementation with
2474 * small images
2475 */
2476 if (im->sx < 4) {
2477 int ix = x, iy = y, c;
2478 do {
2479 do {
2480 c = gdImageGetPixel(im, ix, iy);
2481 if (c != oc) {
2482 goto done;
2483 }
2484 gdImageSetPixel(im, ix, iy, nc);
2485 } while(ix++ < (im->sx -1));
2486 ix = x;
2487 } while(iy++ < (im->sy -1));
2488 goto done;
2489 }
2490
2491 if(overflow2(im->sy, im->sx)) {
2492 return;
2493 }
2494
2495 if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
2496 return;
2497 }
2498
2499 stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
2500 if (!stack) {
2501 return;
2502 }
2503 sp = stack;
2504
2505 /* required! */
2506 FILL_PUSH(y,x,x,1);
2507 /* seed segment (popped 1st) */
2508 FILL_PUSH(y+1, x, x, -1);
2509 while (sp>stack) {
2510 FILL_POP(y, x1, x2, dy);
2511
2512 for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
2513 gdImageSetPixel(im,x, y, nc);
2514 }
2515 if (x>=x1) {
2516 goto skip;
2517 }
2518 l = x+1;
2519
2520 /* leak on left? */
2521 if (l<x1) {
2522 FILL_PUSH(y, l, x1-1, -dy);
2523 }
2524 x = x1+1;
2525 do {
2526 for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
2527 gdImageSetPixel(im, x, y, nc);
2528 }
2529 FILL_PUSH(y, l, x-1, dy);
2530 /* leak on right? */
2531 if (x>x2+1) {
2532 FILL_PUSH(y, x2+1, x-1, -dy);
2533 }
2534 skip:
2535 for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
2536
2537 l = x;
2538 } while (x<=x2);
2539 }
2540
2541 gdFree(stack);
2542
2543 done:
2544 im->alphaBlendingFlag = alphablending_bak;
2545 }
2546
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2547 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2548 {
2549 int l, x1, x2, dy;
2550 int oc; /* old pixel value */
2551 int wx2,wy2;
2552 /* stack of filled segments */
2553 struct seg *stack;
2554 struct seg *sp;
2555 char *pts;
2556
2557 if (!im->tile) {
2558 return;
2559 }
2560
2561 wx2=im->sx;
2562 wy2=im->sy;
2563
2564 if(overflow2(im->sy, im->sx)) {
2565 return;
2566 }
2567
2568 if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
2569 return;
2570 }
2571
2572 pts = (char *) gdCalloc(im->sy * im->sx, sizeof(char));
2573 if (!pts) {
2574 return;
2575 }
2576
2577 stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
2578 if (!stack) {
2579 gdFree(pts);
2580 return;
2581 }
2582 sp = stack;
2583
2584 oc = gdImageGetPixel(im, x, y);
2585
2586 /* required! */
2587 FILL_PUSH(y,x,x,1);
2588 /* seed segment (popped 1st) */
2589 FILL_PUSH(y+1, x, x, -1);
2590 while (sp>stack) {
2591 FILL_POP(y, x1, x2, dy);
2592 for (x=x1; x>=0 && (!pts[y + x*wy2] && gdImageGetPixel(im,x,y)==oc); x--) {
2593 nc = gdImageTileGet(im,x,y);
2594 pts[y + x*wy2]=1;
2595 gdImageSetPixel(im,x, y, nc);
2596 }
2597 if (x>=x1) {
2598 goto skip;
2599 }
2600 l = x+1;
2601
2602 /* leak on left? */
2603 if (l<x1) {
2604 FILL_PUSH(y, l, x1-1, -dy);
2605 }
2606 x = x1+1;
2607 do {
2608 for (; x<wx2 && (!pts[y + x*wy2] && gdImageGetPixel(im,x, y)==oc) ; x++) {
2609 if (pts[y + x*wy2]) {
2610 /* we should never be here */
2611 break;
2612 }
2613 nc = gdImageTileGet(im,x,y);
2614 pts[y + x*wy2]=1;
2615 gdImageSetPixel(im, x, y, nc);
2616 }
2617 FILL_PUSH(y, l, x-1, dy);
2618 /* leak on right? */
2619 if (x>x2+1) {
2620 FILL_PUSH(y, x2+1, x-1, -dy);
2621 }
2622 skip:
2623 for (x++; x<=x2 && (pts[y + x*wy2] || gdImageGetPixel(im,x, y)!=oc); x++);
2624 l = x;
2625 } while (x<=x2);
2626 }
2627
2628 gdFree(pts);
2629 gdFree(stack);
2630 }
2631
2632 /**
2633 * Function: gdImageRectangle
2634 *
2635 * Draws a rectangle.
2636 *
2637 * Parameters:
2638 * im - The image.
2639 * x1 - The x-coordinate of one of the corners.
2640 * y1 - The y-coordinate of one of the corners.
2641 * x2 - The x-coordinate of another corner.
2642 * y2 - The y-coordinate of another corner.
2643 * color - The color.
2644 *
2645 * See also:
2646 * - <gdImageFilledRectangle>
2647 */
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2648 BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2649 {
2650 int thick = im->thick;
2651
2652 if (x1 == x2 && y1 == y2 && thick == 1) {
2653 gdImageSetPixel(im, x1, y1, color);
2654 return;
2655 }
2656
2657 if (y2 < y1) {
2658 int t = y1;
2659 y1 = y2;
2660 y2 = t;
2661 }
2662
2663 if (x2 < x1) {
2664 int t = x1;
2665 x1 = x2;
2666 x2 = t;
2667 }
2668
2669 if (thick > 1) {
2670 int cx, cy, x1ul, y1ul, x2lr, y2lr;
2671 int half = thick >> 1;
2672 x1ul = x1 - half;
2673 y1ul = y1 - half;
2674
2675 x2lr = x2 + half;
2676 y2lr = y2 + half;
2677
2678 cy = y1ul + thick;
2679 while (cy-- > y1ul) {
2680 cx = x1ul - 1;
2681 while (cx++ < x2lr) {
2682 gdImageSetPixel(im, cx, cy, color);
2683 }
2684 }
2685
2686 cy = y2lr - thick;
2687 while (cy++ < y2lr) {
2688 cx = x1ul - 1;
2689 while (cx++ < x2lr) {
2690 gdImageSetPixel(im, cx, cy, color);
2691 }
2692 }
2693
2694 cy = y1ul + thick - 1;
2695 while (cy++ < y2lr -thick) {
2696 cx = x1ul - 1;
2697 while (cx++ < x1ul + thick) {
2698 gdImageSetPixel(im, cx, cy, color);
2699 }
2700 }
2701
2702 cy = y1ul + thick - 1;
2703 while (cy++ < y2lr -thick) {
2704 cx = x2lr - thick - 1;
2705 while (cx++ < x2lr) {
2706 gdImageSetPixel(im, cx, cy, color);
2707 }
2708 }
2709
2710 return;
2711 } else {
2712 if (x1 == x2 || y1 == y2) {
2713 gdImageLine(im, x1, y1, x2, y2, color);
2714 } else {
2715 gdImageLine(im, x1, y1, x2, y1, color);
2716 gdImageLine(im, x1, y2, x2, y2, color);
2717 gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2718 gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2719 }
2720 }
2721 }
2722
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2723 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2724 int color)
2725 {
2726 int x, y;
2727
2728 if (x1 == x2 && y1 == y2) {
2729 gdImageSetPixel(im, x1, y1, color);
2730 return;
2731 }
2732
2733 if (x1 > x2) {
2734 x = x1;
2735 x1 = x2;
2736 x2 = x;
2737 }
2738
2739 if (y1 > y2) {
2740 y = y1;
2741 y1 = y2;
2742 y2 = y;
2743 }
2744
2745 if (x1 < 0) {
2746 x1 = 0;
2747 }
2748
2749 if (x2 >= gdImageSX(im)) {
2750 x2 = gdImageSX(im) - 1;
2751 }
2752
2753 if (y1 < 0) {
2754 y1 = 0;
2755 }
2756
2757 if (y2 >= gdImageSY(im)) {
2758 y2 = gdImageSY(im) - 1;
2759 }
2760
2761 for (x = x1; (x <= x2); x++) {
2762 for (y = y1; (y <= y2); y++) {
2763 gdImageSetPixel (im, x, y, color);
2764 }
2765 }
2766 }
2767
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2768 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2769 int color)
2770 {
2771 int x, y;
2772
2773 if (x1 == x2 && y1 == y2) {
2774 gdImageSetPixel(im, x1, y1, color);
2775 return;
2776 }
2777
2778 if (x1 > x2) {
2779 x = x1;
2780 x1 = x2;
2781 x2 = x;
2782 }
2783
2784 if (y1 > y2) {
2785 y = y1;
2786 y1 = y2;
2787 y2 = y;
2788 }
2789
2790 if (x1 < 0) {
2791 x1 = 0;
2792 }
2793
2794 if (x2 >= gdImageSX(im)) {
2795 x2 = gdImageSX(im) - 1;
2796 }
2797
2798 if (y1 < 0) {
2799 y1 = 0;
2800 }
2801
2802 if (y2 >= gdImageSY(im)) {
2803 y2 = gdImageSY(im) - 1;
2804 }
2805
2806 for (y = y1; (y <= y2); y++) {
2807 for (x = x1; (x <= x2); x++) {
2808 gdImageSetPixel (im, x, y, color);
2809 }
2810 }
2811 }
2812
2813 /*
2814 Function: gdImageFilledRectangle
2815 */
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2816 BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2817 int color)
2818 {
2819 _gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2820 }
2821
2822 /**
2823 * Group: Cloning and Copying
2824 */
2825
2826 /**
2827 * Function: gdImageClone
2828 *
2829 * Clones an image
2830 *
2831 * Creates an exact duplicate of the given image.
2832 *
2833 * Parameters:
2834 * src - The source image.
2835 *
2836 * Returns:
2837 * The cloned image on success, NULL on failure.
2838 */
gdImageClone(gdImagePtr src)2839 BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src) {
2840 gdImagePtr dst;
2841 register int i, x;
2842
2843 if (src->trueColor) {
2844 dst = gdImageCreateTrueColor(src->sx , src->sy);
2845 } else {
2846 dst = gdImageCreate(src->sx , src->sy);
2847 }
2848
2849 if (dst == NULL) {
2850 return NULL;
2851 }
2852
2853 if (src->trueColor == 0) {
2854 dst->colorsTotal = src->colorsTotal;
2855 for (i = 0; i < gdMaxColors; i++) {
2856 dst->red[i] = src->red[i];
2857 dst->green[i] = src->green[i];
2858 dst->blue[i] = src->blue[i];
2859 dst->alpha[i] = src->alpha[i];
2860 dst->open[i] = src->open[i];
2861 }
2862 for (i = 0; i < src->sy; i++) {
2863 for (x = 0; x < src->sx; x++) {
2864 dst->pixels[i][x] = src->pixels[i][x];
2865 }
2866 }
2867 } else {
2868 for (i = 0; i < src->sy; i++) {
2869 for (x = 0; x < src->sx; x++) {
2870 dst->tpixels[i][x] = src->tpixels[i][x];
2871 }
2872 }
2873 }
2874
2875 dst->interlace = src->interlace;
2876
2877 dst->alphaBlendingFlag = src->alphaBlendingFlag;
2878 dst->saveAlphaFlag = src->saveAlphaFlag;
2879 dst->AA = src->AA;
2880 dst->AA_color = src->AA_color;
2881 dst->AA_dont_blend = src->AA_dont_blend;
2882
2883 dst->cx1 = src->cx1;
2884 dst->cy1 = src->cy1;
2885 dst->cx2 = src->cx2;
2886 dst->cy2 = src->cy2;
2887
2888 dst->res_x = src->res_x;
2889 dst->res_y = src->res_y;
2890
2891 dst->paletteQuantizationMethod = src->paletteQuantizationMethod;
2892 dst->paletteQuantizationSpeed = src->paletteQuantizationSpeed;
2893 dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
2894 dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
2895
2896 dst->interpolation_id = src->interpolation_id;
2897 dst->interpolation = src->interpolation;
2898
2899 if (src->brush) {
2900 dst->brush = gdImageClone(src->brush);
2901 }
2902
2903 if (src->tile) {
2904 dst->tile = gdImageClone(src->tile);
2905 }
2906
2907 if (src->style) {
2908 gdImageSetStyle(dst, src->style, src->styleLength);
2909 dst->stylePos = src->stylePos;
2910 }
2911
2912 for (i = 0; i < gdMaxColors; i++) {
2913 dst->brushColorMap[i] = src->brushColorMap[i];
2914 dst->tileColorMap[i] = src->tileColorMap[i];
2915 }
2916
2917 if (src->polyAllocated > 0) {
2918 dst->polyAllocated = src->polyAllocated;
2919 for (i = 0; i < src->polyAllocated; i++) {
2920 dst->polyInts[i] = src->polyInts[i];
2921 }
2922 }
2923
2924 return dst;
2925 }
2926
2927 /**
2928 * Function: gdImageCopy
2929 *
2930 * Copy an area of an image to another image
2931 *
2932 * Parameters:
2933 * dst - The destination image.
2934 * src - The source image.
2935 * dstX - The x-coordinate of the upper left corner to copy to.
2936 * dstY - The y-coordinate of the upper left corner to copy to.
2937 * srcX - The x-coordinate of the upper left corner to copy from.
2938 * srcY - The y-coordinate of the upper left corner to copy from.
2939 * w - The width of the area to copy.
2940 * h - The height of the area to copy.
2941 *
2942 * See also:
2943 * - <gdImageCopyMerge>
2944 * - <gdImageCopyMergeGray>
2945 */
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2946 BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
2947 int srcY, int w, int h)
2948 {
2949 int c;
2950 int x, y;
2951 int tox, toy;
2952 int i;
2953 int colorMap[gdMaxColors];
2954
2955 if (dst->trueColor) {
2956 /* 2.0: much easier when the destination is truecolor. */
2957 /* 2.0.10: needs a transparent-index check that is still valid if
2958 * * the source is not truecolor. Thanks to Frank Warmerdam.
2959 */
2960
2961 if (src->trueColor) {
2962 for (y = 0; (y < h); y++) {
2963 for (x = 0; (x < w); x++) {
2964 int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2965 if (c != src->transparent) {
2966 gdImageSetPixel (dst, dstX + x, dstY + y, c);
2967 }
2968 }
2969 }
2970 } else {
2971 /* source is palette based */
2972 for (y = 0; (y < h); y++) {
2973 for (x = 0; (x < w); x++) {
2974 int c = gdImageGetPixel (src, srcX + x, srcY + y);
2975 if (c != src->transparent) {
2976 gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2977 }
2978 }
2979 }
2980 }
2981 return;
2982 }
2983
2984 for (i = 0; (i < gdMaxColors); i++) {
2985 colorMap[i] = (-1);
2986 }
2987 toy = dstY;
2988 for (y = srcY; (y < (srcY + h)); y++) {
2989 tox = dstX;
2990 for (x = srcX; (x < (srcX + w)); x++) {
2991 int nc;
2992 int mapTo;
2993 c = gdImageGetPixel (src, x, y);
2994 /* Added 7/24/95: support transparent copies */
2995 if (gdImageGetTransparent (src) == c) {
2996 tox++;
2997 continue;
2998 }
2999 /* Have we established a mapping for this color? */
3000 if (src->trueColor) {
3001 /* 2.05: remap to the palette available in the
3002 destination image. This is slow and
3003 works badly, but it beats crashing! Thanks
3004 to Padhrig McCarthy. */
3005 mapTo = gdImageColorResolveAlpha (dst,
3006 gdTrueColorGetRed (c),
3007 gdTrueColorGetGreen (c),
3008 gdTrueColorGetBlue (c),
3009 gdTrueColorGetAlpha (c));
3010 } else if (colorMap[c] == (-1)) {
3011 /* If it's the same image, mapping is trivial */
3012 if (dst == src) {
3013 nc = c;
3014 } else {
3015 /* Get best match possible. This
3016 function never returns error. */
3017 nc = gdImageColorResolveAlpha (dst,
3018 src->red[c], src->green[c],
3019 src->blue[c], src->alpha[c]);
3020 }
3021 colorMap[c] = nc;
3022 mapTo = colorMap[c];
3023 } else {
3024 mapTo = colorMap[c];
3025 }
3026 gdImageSetPixel (dst, tox, toy, mapTo);
3027 tox++;
3028 }
3029 toy++;
3030 }
3031 }
3032
3033 /**
3034 * Function: gdImageCopyMerge
3035 *
3036 * Copy an area of an image to another image ignoring alpha
3037 *
3038 * The source area will be copied to the destination are by merging the pixels.
3039 *
3040 * Note:
3041 * This function is a substitute for real alpha channel operations,
3042 * so it doesn't pay attention to the alpha channel.
3043 *
3044 * Parameters:
3045 * dst - The destination image.
3046 * src - The source image.
3047 * dstX - The x-coordinate of the upper left corner to copy to.
3048 * dstY - The y-coordinate of the upper left corner to copy to.
3049 * srcX - The x-coordinate of the upper left corner to copy from.
3050 * srcY - The y-coordinate of the upper left corner to copy from.
3051 * w - The width of the area to copy.
3052 * h - The height of the area to copy.
3053 * pct - The percentage in range 0..100.
3054 *
3055 * See also:
3056 * - <gdImageCopy>
3057 * - <gdImageCopyMergeGray>
3058 */
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)3059 BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3060 int srcX, int srcY, int w, int h, int pct)
3061 {
3062
3063 int c, dc;
3064 int x, y;
3065 int tox, toy;
3066 int ncR, ncG, ncB;
3067 toy = dstY;
3068 for (y = srcY; (y < (srcY + h)); y++) {
3069 tox = dstX;
3070 for (x = srcX; (x < (srcX + w)); x++) {
3071 int nc;
3072 c = gdImageGetPixel (src, x, y);
3073 /* Added 7/24/95: support transparent copies */
3074 if (gdImageGetTransparent (src) == c) {
3075 tox++;
3076 continue;
3077 }
3078 /* If it's the same image, mapping is trivial */
3079 if (dst == src) {
3080 nc = c;
3081 } else {
3082 dc = gdImageGetPixel (dst, tox, toy);
3083
3084 ncR = gdImageRed (src, c) * (pct / 100.0)
3085 + gdImageRed (dst, dc) * ((100 - pct) / 100.0);
3086 ncG = gdImageGreen (src, c) * (pct / 100.0)
3087 + gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
3088 ncB = gdImageBlue (src, c) * (pct / 100.0)
3089 + gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
3090
3091 /* Find a reasonable color */
3092 nc = gdImageColorResolve (dst, ncR, ncG, ncB);
3093 }
3094 gdImageSetPixel (dst, tox, toy, nc);
3095 tox++;
3096 }
3097 toy++;
3098 }
3099 }
3100
3101 /**
3102 * Function: gdImageCopyMergeGray
3103 *
3104 * Copy an area of an image to another image ignoring alpha
3105 *
3106 * The source area will be copied to the grayscaled destination area by merging
3107 * the pixels.
3108 *
3109 * Note:
3110 * This function is a substitute for real alpha channel operations,
3111 * so it doesn't pay attention to the alpha channel.
3112 *
3113 * Parameters:
3114 * dst - The destination image.
3115 * src - The source image.
3116 * dstX - The x-coordinate of the upper left corner to copy to.
3117 * dstY - The y-coordinate of the upper left corner to copy to.
3118 * srcX - The x-coordinate of the upper left corner to copy from.
3119 * srcY - The y-coordinate of the upper left corner to copy from.
3120 * w - The width of the area to copy.
3121 * h - The height of the area to copy.
3122 * pct - The percentage of the source color intensity in range 0..100.
3123 *
3124 * See also:
3125 * - <gdImageCopy>
3126 * - <gdImageCopyMerge>
3127 */
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)3128 BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3129 int srcX, int srcY, int w, int h, int pct)
3130 {
3131
3132 int c, dc;
3133 int x, y;
3134 int tox, toy;
3135 int ncR, ncG, ncB;
3136 float g;
3137 toy = dstY;
3138 for (y = srcY; (y < (srcY + h)); y++) {
3139 tox = dstX;
3140 for (x = srcX; (x < (srcX + w)); x++) {
3141 int nc;
3142 c = gdImageGetPixel (src, x, y);
3143 /* Added 7/24/95: support transparent copies */
3144 if (gdImageGetTransparent (src) == c) {
3145 tox++;
3146 continue;
3147 }
3148 /*
3149 * If it's the same image, mapping is NOT trivial since we
3150 * merge with greyscale target, but if pct is 100, the grey
3151 * value is not used, so it becomes trivial. pjw 2.0.12.
3152 */
3153 if (dst == src && pct == 100) {
3154 nc = c;
3155 } else {
3156 dc = gdImageGetPixel (dst, tox, toy);
3157 g = 0.29900 * gdImageRed(dst, dc)
3158 + 0.58700 * gdImageGreen(dst, dc) + 0.11400 * gdImageBlue(dst, dc);
3159
3160 ncR = gdImageRed (src, c) * (pct / 100.0)
3161 + g * ((100 - pct) / 100.0);
3162 ncG = gdImageGreen (src, c) * (pct / 100.0)
3163 + g * ((100 - pct) / 100.0);
3164 ncB = gdImageBlue (src, c) * (pct / 100.0)
3165 + g * ((100 - pct) / 100.0);
3166
3167 /* First look for an exact match */
3168 nc = gdImageColorExact (dst, ncR, ncG, ncB);
3169 if (nc == (-1)) {
3170 /* No, so try to allocate it */
3171 nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
3172 /* If we're out of colors, go for the
3173 closest color */
3174 if (nc == (-1)) {
3175 nc = gdImageColorClosest (dst, ncR, ncG, ncB);
3176 }
3177 }
3178 }
3179 gdImageSetPixel (dst, tox, toy, nc);
3180 tox++;
3181 }
3182 toy++;
3183 }
3184 }
3185
3186 /**
3187 * Function: gdImageCopyResized
3188 *
3189 * Copy a resized area from an image to another image
3190 *
3191 * If the source and destination area differ in size, the area will be resized
3192 * using nearest-neighbor interpolation.
3193 *
3194 * Parameters:
3195 * dst - The destination image.
3196 * src - The source image.
3197 * dstX - The x-coordinate of the upper left corner to copy to.
3198 * dstY - The y-coordinate of the upper left corner to copy to.
3199 * srcX - The x-coordinate of the upper left corner to copy from.
3200 * srcY - The y-coordinate of the upper left corner to copy from.
3201 * dstW - The width of the area to copy to.
3202 * dstH - The height of the area to copy to.
3203 * srcW - The width of the area to copy from.
3204 * srcH - The height of the area to copy from.
3205 *
3206 * See also:
3207 * - <gdImageCopyResampled>
3208 * - <gdImageScale>
3209 */
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)3210 BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3211 int srcX, int srcY, int dstW, int dstH, int srcW,
3212 int srcH)
3213 {
3214 int c;
3215 int x, y;
3216 int tox, toy;
3217 int ydest;
3218 int i;
3219 int colorMap[gdMaxColors];
3220 /* Stretch vectors */
3221 int *stx;
3222 int *sty;
3223 /* We only need to use floating point to determine the correct
3224 stretch vector for one line's worth. */
3225 if (overflow2(sizeof (int), srcW)) {
3226 return;
3227 }
3228 if (overflow2(sizeof (int), srcH)) {
3229 return;
3230 }
3231 stx = (int *) gdMalloc (sizeof (int) * srcW);
3232 if (!stx) {
3233 return;
3234 }
3235
3236 sty = (int *) gdMalloc (sizeof (int) * srcH);
3237 if (!sty) {
3238 gdFree(stx);
3239 return;
3240 }
3241
3242 /* Fixed by Mao Morimoto 2.0.16 */
3243 for (i = 0; (i < srcW); i++) {
3244 stx[i] = dstW * (i + 1) / srcW - dstW * i / srcW;
3245 }
3246 for (i = 0; (i < srcH); i++) {
3247 sty[i] = dstH * (i + 1) / srcH - dstH * i / srcH;
3248 }
3249 for (i = 0; (i < gdMaxColors); i++) {
3250 colorMap[i] = (-1);
3251 }
3252 toy = dstY;
3253 for (y = srcY; (y < (srcY + srcH)); y++) {
3254 for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
3255 tox = dstX;
3256 for (x = srcX; (x < (srcX + srcW)); x++) {
3257 int nc = 0;
3258 int mapTo;
3259 if (!stx[x - srcX]) {
3260 continue;
3261 }
3262 if (dst->trueColor) {
3263 /* 2.0.9: Thorben Kundinger: Maybe the source image is not
3264 a truecolor image */
3265 if (!src->trueColor) {
3266 int tmp = gdImageGetPixel (src, x, y);
3267 mapTo = gdImageGetTrueColorPixel (src, x, y);
3268 if (gdImageGetTransparent (src) == tmp) {
3269 /* 2.0.21, TK: not tox++ */
3270 tox += stx[x - srcX];
3271 continue;
3272 }
3273 } else {
3274 /* TK: old code follows */
3275 mapTo = gdImageGetTrueColorPixel (src, x, y);
3276 /* Added 7/24/95: support transparent copies */
3277 if (gdImageGetTransparent (src) == mapTo) {
3278 /* 2.0.21, TK: not tox++ */
3279 tox += stx[x - srcX];
3280 continue;
3281 }
3282 }
3283 } else {
3284 c = gdImageGetPixel (src, x, y);
3285 /* Added 7/24/95: support transparent copies */
3286 if (gdImageGetTransparent (src) == c) {
3287 tox += stx[x - srcX];
3288 continue;
3289 }
3290 if (src->trueColor) {
3291 /* Remap to the palette available in the
3292 destination image. This is slow and
3293 works badly. */
3294 mapTo = gdImageColorResolveAlpha (dst,
3295 gdTrueColorGetRed (c),
3296 gdTrueColorGetGreen
3297 (c),
3298 gdTrueColorGetBlue
3299 (c),
3300 gdTrueColorGetAlpha
3301 (c));
3302 } else {
3303 /* Have we established a mapping for this color? */
3304 if (colorMap[c] == (-1)) {
3305 /* If it's the same image, mapping is trivial */
3306 if (dst == src) {
3307 nc = c;
3308 } else {
3309 /* Find or create the best match */
3310 /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
3311 nc = gdImageColorResolveAlpha (dst,
3312 gdImageRed (src,
3313 c),
3314 gdImageGreen
3315 (src, c),
3316 gdImageBlue (src,
3317 c),
3318 gdImageAlpha
3319 (src, c));
3320 }
3321 colorMap[c] = nc;
3322 }
3323 mapTo = colorMap[c];
3324 }
3325 }
3326 for (i = 0; (i < stx[x - srcX]); i++) {
3327 gdImageSetPixel (dst, tox, toy, mapTo);
3328 tox++;
3329 }
3330 }
3331 toy++;
3332 }
3333 }
3334 gdFree (stx);
3335 gdFree (sty);
3336 }
3337
3338 /**
3339 * Function: gdImageCopyRotated
3340 *
3341 * Copy a rotated area from an image to another image
3342 *
3343 * The area is counter-clockwise rotated using nearest-neighbor interpolation.
3344 *
3345 * Parameters:
3346 * dst - The destination image.
3347 * src - The source image.
3348 * dstX - The x-coordinate of the center of the area to copy to.
3349 * dstY - The y-coordinate of the center of the area to copy to.
3350 * srcX - The x-coordinate of the upper left corner to copy from.
3351 * srcY - The y-coordinate of the upper left corner to copy from.
3352 * srcW - The width of the area to copy from.
3353 * srcH - The height of the area to copy from.
3354 * angle - The angle in degrees.
3355 *
3356 * See also:
3357 * - <gdImageRotateInterpolated>
3358 */
gdImageCopyRotated(gdImagePtr dst,gdImagePtr src,double dstX,double dstY,int srcX,int srcY,int srcWidth,int srcHeight,int angle)3359 BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst,
3360 gdImagePtr src,
3361 double dstX, double dstY,
3362 int srcX, int srcY,
3363 int srcWidth, int srcHeight, int angle)
3364 {
3365 double dx, dy;
3366 double radius = sqrt (srcWidth * srcWidth + srcHeight * srcHeight);
3367 double aCos = cos (angle * .0174532925);
3368 double aSin = sin (angle * .0174532925);
3369 double scX = srcX + ((double) srcWidth) / 2;
3370 double scY = srcY + ((double) srcHeight) / 2;
3371 int cmap[gdMaxColors];
3372 int i;
3373
3374 /*
3375 2.0.34: transparency preservation. The transparentness of
3376 the transparent color is more important than its hue.
3377 */
3378 if (src->transparent != -1) {
3379 if (dst->transparent == -1) {
3380 dst->transparent = src->transparent;
3381 }
3382 }
3383
3384 for (i = 0; (i < gdMaxColors); i++) {
3385 cmap[i] = (-1);
3386 }
3387 for (dy = dstY - radius; (dy <= dstY + radius); dy++) {
3388 for (dx = dstX - radius; (dx <= dstX + radius); dx++) {
3389 double sxd = (dx - dstX) * aCos - (dy - dstY) * aSin;
3390 double syd = (dy - dstY) * aCos + (dx - dstX) * aSin;
3391 int sx = sxd + scX;
3392 int sy = syd + scY;
3393 if ((sx >= srcX) && (sx < srcX + srcWidth) &&
3394 (sy >= srcY) && (sy < srcY + srcHeight)) {
3395 int c = gdImageGetPixel (src, sx, sy);
3396 /* 2.0.34: transparency wins */
3397 if (c == src->transparent) {
3398 gdImageSetPixel (dst, dx, dy, dst->transparent);
3399 } else if (!src->trueColor) {
3400 /* Use a table to avoid an expensive
3401 lookup on every single pixel */
3402 if (cmap[c] == -1) {
3403 cmap[c] = gdImageColorResolveAlpha (dst,
3404 gdImageRed (src, c),
3405 gdImageGreen (src,
3406 c),
3407 gdImageBlue (src,
3408 c),
3409 gdImageAlpha (src,
3410 c));
3411 }
3412 gdImageSetPixel (dst, dx, dy, cmap[c]);
3413 } else {
3414 gdImageSetPixel (dst,
3415 dx, dy,
3416 gdImageColorResolveAlpha (dst,
3417 gdImageRed (src,
3418 c),
3419 gdImageGreen
3420 (src, c),
3421 gdImageBlue (src,
3422 c),
3423 gdImageAlpha
3424 (src, c)));
3425 }
3426 }
3427 }
3428 }
3429 }
3430
3431 /* When gd 1.x was first created, floating point was to be avoided.
3432 These days it is often faster than table lookups or integer
3433 arithmetic. The routine below is shamelessly, gloriously
3434 floating point. TBB */
3435
3436 /* 2.0.10: cast instead of floor() yields 35% performance improvement.
3437 Thanks to John Buckman. */
3438
3439 #define floor2(exp) ((long) exp)
3440 /*#define floor2(exp) floor(exp)*/
3441
3442 /**
3443 * Function: gdImageCopyResampled
3444 *
3445 * Copy a resampled area from an image to another image
3446 *
3447 * If the source and destination area differ in size, the area will be resized
3448 * using bilinear interpolation for truecolor images, and nearest-neighbor
3449 * interpolation for palette images.
3450 *
3451 * Parameters:
3452 * dst - The destination image.
3453 * src - The source image.
3454 * dstX - The x-coordinate of the upper left corner to copy to.
3455 * dstY - The y-coordinate of the upper left corner to copy to.
3456 * srcX - The x-coordinate of the upper left corner to copy from.
3457 * srcY - The y-coordinate of the upper left corner to copy from.
3458 * dstW - The width of the area to copy to.
3459 * dstH - The height of the area to copy to.
3460 * srcW - The width of the area to copy from.
3461 * srcH - The height of the area to copy from.
3462 *
3463 * See also:
3464 * - <gdImageCopyResized>
3465 * - <gdImageScale>
3466 */
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)3467 BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
3468 gdImagePtr src,
3469 int dstX, int dstY,
3470 int srcX, int srcY,
3471 int dstW, int dstH, int srcW, int srcH)
3472 {
3473 int x, y;
3474 double sy1, sy2, sx1, sx2;
3475
3476 if (!dst->trueColor) {
3477 gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
3478 return;
3479 }
3480 for (y = dstY; (y < dstY + dstH); y++) {
3481 sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
3482 sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
3483 for (x = dstX; (x < dstX + dstW); x++) {
3484 double sx, sy;
3485 double spixels = 0;
3486 double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
3487 double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
3488 sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
3489 sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
3490 sy = sy1;
3491 do {
3492 double yportion;
3493 if (floor_cast(sy) == floor_cast(sy1)) {
3494 yportion = 1.0f - (sy - floor_cast(sy));
3495 if (yportion > sy2 - sy1) {
3496 yportion = sy2 - sy1;
3497 }
3498 sy = floor_cast(sy);
3499 } else if (sy == floorf(sy2)) {
3500 yportion = sy2 - floor_cast(sy2);
3501 } else {
3502 yportion = 1.0f;
3503 }
3504 sx = sx1;
3505 do {
3506 double xportion;
3507 double pcontribution;
3508 int p;
3509 if (floorf(sx) == floor_cast(sx1)) {
3510 xportion = 1.0f - (sx - floor_cast(sx));
3511 if (xportion > sx2 - sx1) {
3512 xportion = sx2 - sx1;
3513 }
3514 sx = floor_cast(sx);
3515 } else if (sx == floorf(sx2)) {
3516 xportion = sx2 - floor_cast(sx2);
3517 } else {
3518 xportion = 1.0f;
3519 }
3520 pcontribution = xportion * yportion;
3521 p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
3522
3523 alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
3524 red += gdTrueColorGetRed (p) * alpha_factor;
3525 green += gdTrueColorGetGreen (p) * alpha_factor;
3526 blue += gdTrueColorGetBlue (p) * alpha_factor;
3527 alpha += gdTrueColorGetAlpha (p) * pcontribution;
3528 alpha_sum += alpha_factor;
3529 contrib_sum += pcontribution;
3530 spixels += xportion * yportion;
3531 sx += 1.0f;
3532 }
3533 while (sx < sx2);
3534
3535 sy += 1.0f;
3536 }
3537
3538 while (sy < sy2);
3539
3540 if (spixels != 0.0f) {
3541 red /= spixels;
3542 green /= spixels;
3543 blue /= spixels;
3544 alpha /= spixels;
3545 alpha += 0.5;
3546 }
3547 if ( alpha_sum != 0.0f) {
3548 if( contrib_sum != 0.0f) {
3549 alpha_sum /= contrib_sum;
3550 }
3551 red /= alpha_sum;
3552 green /= alpha_sum;
3553 blue /= alpha_sum;
3554 }
3555 /* Clamping to allow for rounding errors above */
3556 if (red > 255.0f) {
3557 red = 255.0f;
3558 }
3559 if (green > 255.0f) {
3560 green = 255.0f;
3561 }
3562 if (blue > 255.0f) {
3563 blue = 255.0f;
3564 }
3565 if (alpha > gdAlphaMax) {
3566 alpha = gdAlphaMax;
3567 }
3568 gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
3569 }
3570 }
3571 }
3572
3573 /**
3574 * Group: Polygons
3575 */
3576
3577 /**
3578 * Function: gdImagePolygon
3579 *
3580 * Draws a closed polygon
3581 *
3582 * Parameters:
3583 * im - The image.
3584 * p - The vertices as array of <gdPoint>s.
3585 * n - The number of vertices.
3586 * c - The color.
3587 *
3588 * See also:
3589 * - <gdImageOpenPolygon>
3590 * - <gdImageFilledPolygon>
3591 */
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)3592 BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3593 {
3594 if (n <= 0) {
3595 return;
3596 }
3597
3598
3599 gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
3600 gdImageOpenPolygon (im, p, n, c);
3601 }
3602
3603 /**
3604 * Function: gdImageOpenPolygon
3605 *
3606 * Draws an open polygon
3607 *
3608 * Parameters:
3609 * im - The image.
3610 * p - The vertices as array of <gdPoint>s.
3611 * n - The number of vertices.
3612 * c - The color
3613 *
3614 * See also:
3615 * - <gdImagePolygon>
3616 */
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)3617 BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3618 {
3619 int i;
3620 int lx, ly;
3621 if (n <= 0) {
3622 return;
3623 }
3624
3625
3626 lx = p->x;
3627 ly = p->y;
3628 for (i = 1; (i < n); i++) {
3629 p++;
3630 gdImageLine (im, lx, ly, p->x, p->y, c);
3631 lx = p->x;
3632 ly = p->y;
3633 }
3634
3635 }
3636
3637 /* THANKS to Kirsten Schulz for the polygon fixes! */
3638
3639 /* The intersection finding technique of this code could be improved */
3640 /* by remembering the previous intertersection, and by using the slope. */
3641 /* That could help to adjust intersections to produce a nice */
3642 /* interior_extrema. */
3643
3644 /**
3645 * Function: gdImageFilledPolygon
3646 *
3647 * Draws a filled polygon
3648 *
3649 * The polygon is filled using the even-odd fillrule what can leave unfilled
3650 * regions inside of self-intersecting polygons. This behavior might change in
3651 * a future version.
3652 *
3653 * Parameters:
3654 * im - The image.
3655 * p - The vertices as array of <gdPoint>s.
3656 * n - The number of vertices.
3657 * c - The color
3658 *
3659 * See also:
3660 * - <gdImagePolygon>
3661 */
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)3662 BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3663 {
3664 int i;
3665 int j;
3666 int index;
3667 int y;
3668 int miny, maxy, pmaxy;
3669 int x1, y1;
3670 int x2, y2;
3671 int ind1, ind2;
3672 int ints;
3673 int fill_color;
3674 if (n <= 0) {
3675 return;
3676 }
3677
3678 if (c == gdAntiAliased) {
3679 fill_color = im->AA_color;
3680 } else {
3681 fill_color = c;
3682 }
3683 if (!im->polyAllocated) {
3684 if (overflow2(sizeof (int), n)) {
3685 return;
3686 }
3687 im->polyInts = (int *) gdMalloc (sizeof (int) * n);
3688 if (!im->polyInts) {
3689 return;
3690 }
3691 im->polyAllocated = n;
3692 }
3693 if (im->polyAllocated < n) {
3694 while (im->polyAllocated < n) {
3695 im->polyAllocated *= 2;
3696 }
3697 if (overflow2(sizeof (int), im->polyAllocated)) {
3698 return;
3699 }
3700 im->polyInts = (int *) gdReallocEx (im->polyInts,
3701 sizeof (int) * im->polyAllocated);
3702 if (!im->polyInts) {
3703 return;
3704 }
3705 }
3706 miny = p[0].y;
3707 maxy = p[0].y;
3708 for (i = 1; (i < n); i++) {
3709 if (p[i].y < miny) {
3710 miny = p[i].y;
3711 }
3712 if (p[i].y > maxy) {
3713 maxy = p[i].y;
3714 }
3715 }
3716 /* necessary special case: horizontal line */
3717 if (n > 1 && miny == maxy) {
3718 x1 = x2 = p[0].x;
3719 for (i = 1; (i < n); i++) {
3720 if (p[i].x < x1) {
3721 x1 = p[i].x;
3722 } else if (p[i].x > x2) {
3723 x2 = p[i].x;
3724 }
3725 }
3726 gdImageLine(im, x1, miny, x2, miny, c);
3727 return;
3728 }
3729 pmaxy = maxy;
3730 /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
3731 /* 2.0.26: clipping rectangle is even better */
3732 if (miny < im->cy1) {
3733 miny = im->cy1;
3734 }
3735 if (maxy > im->cy2) {
3736 maxy = im->cy2;
3737 }
3738 /* Fix in 1.3: count a vertex only once */
3739 for (y = miny; (y <= maxy); y++) {
3740 ints = 0;
3741 for (i = 0; (i < n); i++) {
3742 if (!i) {
3743 ind1 = n - 1;
3744 ind2 = 0;
3745 } else {
3746 ind1 = i - 1;
3747 ind2 = i;
3748 }
3749 y1 = p[ind1].y;
3750 y2 = p[ind2].y;
3751 if (y1 < y2) {
3752 x1 = p[ind1].x;
3753 x2 = p[ind2].x;
3754 } else if (y1 > y2) {
3755 y2 = p[ind1].y;
3756 y1 = p[ind2].y;
3757 x2 = p[ind1].x;
3758 x1 = p[ind2].x;
3759 } else {
3760 continue;
3761 }
3762
3763 /* Do the following math as float intermediately, and round to ensure
3764 * that Polygon and FilledPolygon for the same set of points have the
3765 * same footprint. */
3766
3767 if ((y >= y1) && (y < y2)) {
3768 im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
3769 (float) (y2 - y1) + 0.5 + x1);
3770 } else if ((y == pmaxy) && (y == y2)) {
3771 im->polyInts[ints++] = x2;
3772 }
3773 }
3774 /*
3775 2.0.26: polygons pretty much always have less than 100 points,
3776 and most of the time they have considerably less. For such trivial
3777 cases, insertion sort is a good choice. Also a good choice for
3778 future implementations that may wish to indirect through a table.
3779 */
3780 for (i = 1; (i < ints); i++) {
3781 index = im->polyInts[i];
3782 j = i;
3783 while ((j > 0) && (im->polyInts[j - 1] > index)) {
3784 im->polyInts[j] = im->polyInts[j - 1];
3785 j--;
3786 }
3787 im->polyInts[j] = index;
3788 }
3789 for (i = 0; (i < (ints-1)); i += 2) {
3790 /* 2.0.29: back to gdImageLine to prevent segfaults when
3791 performing a pattern fill */
3792 gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
3793 fill_color);
3794 }
3795 }
3796 /* If we are drawing this AA, then redraw the border with AA lines. */
3797 /* This doesn't work as well as I'd like, but it doesn't clash either. */
3798 if (c == gdAntiAliased) {
3799 gdImagePolygon (im, p, n, c);
3800 }
3801 }
3802
3803 /**
3804 * Group: other
3805 */
3806
3807 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
3808
3809 /**
3810 * Function: gdImageSetStyle
3811 *
3812 * Sets the style for following drawing operations
3813 *
3814 * Parameters:
3815 * im - The image.
3816 * style - An array of color values.
3817 * noOfPixel - The number of color values.
3818 */
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)3819 BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
3820 {
3821 if (im->style) {
3822 gdFree (im->style);
3823 }
3824 if (overflow2(sizeof (int), noOfPixels)) {
3825 return;
3826 }
3827 im->style = (int *) gdMalloc (sizeof (int) * noOfPixels);
3828 if (!im->style) {
3829 return;
3830 }
3831 memcpy (im->style, style, sizeof (int) * noOfPixels);
3832 im->styleLength = noOfPixels;
3833 im->stylePos = 0;
3834 }
3835
3836 /**
3837 * Function: gdImageSetThickness
3838 *
3839 * Sets the thickness for following drawing operations
3840 *
3841 * Parameters:
3842 * im - The image.
3843 * thickness - The thickness in pixels.
3844 */
gdImageSetThickness(gdImagePtr im,int thickness)3845 BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness)
3846 {
3847 im->thick = thickness;
3848 }
3849
3850 /**
3851 * Function: gdImageSetBrush
3852 *
3853 * Sets the brush for following drawing operations
3854 *
3855 * Parameters:
3856 * im - The image.
3857 * brush - The brush image.
3858 */
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)3859 BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
3860 {
3861 int i;
3862 im->brush = brush;
3863 if ((!im->trueColor) && (!im->brush->trueColor)) {
3864 for (i = 0; (i < gdImageColorsTotal (brush)); i++) {
3865 int index;
3866 index = gdImageColorResolveAlpha (im,
3867 gdImageRed (brush, i),
3868 gdImageGreen (brush, i),
3869 gdImageBlue (brush, i),
3870 gdImageAlpha (brush, i));
3871 im->brushColorMap[i] = index;
3872 }
3873 }
3874 }
3875
3876 /*
3877 Function: gdImageSetTile
3878 */
gdImageSetTile(gdImagePtr im,gdImagePtr tile)3879 BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile)
3880 {
3881 int i;
3882 im->tile = tile;
3883 if ((!im->trueColor) && (!im->tile->trueColor)) {
3884 for (i = 0; (i < gdImageColorsTotal (tile)); i++) {
3885 int index;
3886 index = gdImageColorResolveAlpha (im,
3887 gdImageRed (tile, i),
3888 gdImageGreen (tile, i),
3889 gdImageBlue (tile, i),
3890 gdImageAlpha (tile, i));
3891 im->tileColorMap[i] = index;
3892 }
3893 }
3894 }
3895
3896 /**
3897 * Function: gdImageSetAntiAliased
3898 *
3899 * Set the color for subsequent anti-aliased drawing
3900 *
3901 * If <gdAntiAliased> is passed as color to drawing operations that support
3902 * anti-aliased drawing (such as <gdImageLine> and <gdImagePolygon>), the actual
3903 * color to be used can be set with this function.
3904 *
3905 * Example: draw an anti-aliased blue line:
3906 * | gdImageSetAntiAliased(im, gdTrueColorAlpha(0, 0, gdBlueMax, gdAlphaOpaque));
3907 * | gdImageLine(im, 10,10, 20,20, gdAntiAliased);
3908 *
3909 * Parameters:
3910 * im - The image.
3911 * c - The color.
3912 *
3913 * See also:
3914 * - <gdImageSetAntiAliasedDontBlend>
3915 */
gdImageSetAntiAliased(gdImagePtr im,int c)3916 BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c)
3917 {
3918 im->AA = 1;
3919 im->AA_color = c;
3920 im->AA_dont_blend = -1;
3921 }
3922
3923 /**
3924 * Function: gdImageSetAntiAliasedDontBlend
3925 *
3926 * Set the color and "dont_blend" color for subsequent anti-aliased drawing
3927 *
3928 * This extended variant of <gdImageSetAntiAliased> allows to also specify a
3929 * (background) color that will not be blended in anti-aliased drawing
3930 * operations.
3931 *
3932 * Parameters:
3933 * im - The image.
3934 * c - The color.
3935 * dont_blend - Whether to blend.
3936 */
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)3937 BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
3938 {
3939 im->AA = 1;
3940 im->AA_color = c;
3941 im->AA_dont_blend = dont_blend;
3942 }
3943
3944 /**
3945 * Function: gdImageInterlace
3946 *
3947 * Sets whether an image is interlaced
3948 *
3949 * This is relevant only when saving the image in a format that supports
3950 * interlacing.
3951 *
3952 * Parameters:
3953 * im - The image.
3954 * interlaceArg - Whether the image is interlaced.
3955 *
3956 * See also:
3957 * - <gdImageGetInterlaced>
3958 */
gdImageInterlace(gdImagePtr im,int interlaceArg)3959 BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg)
3960 {
3961 im->interlace = interlaceArg;
3962 }
3963
3964 /**
3965 * Function: gdImageCompare
3966 *
3967 * Compare two images
3968 *
3969 * Parameters:
3970 * im1 - An image.
3971 * im2 - Another image.
3972 *
3973 * Returns:
3974 * A bitmask of <Image Comparison> flags where each set flag signals
3975 * which attributes of the images are different.
3976 */
gdImageCompare(gdImagePtr im1,gdImagePtr im2)3977 BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2)
3978 {
3979 int x, y;
3980 int p1, p2;
3981 int cmpStatus = 0;
3982 int sx, sy;
3983
3984 if (im1->interlace != im2->interlace) {
3985 cmpStatus |= GD_CMP_INTERLACE;
3986 }
3987
3988 if (im1->transparent != im2->transparent) {
3989 cmpStatus |= GD_CMP_TRANSPARENT;
3990 }
3991
3992 if (im1->trueColor != im2->trueColor) {
3993 cmpStatus |= GD_CMP_TRUECOLOR;
3994 }
3995
3996 sx = im1->sx;
3997 if (im1->sx != im2->sx) {
3998 cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
3999 if (im2->sx < im1->sx) {
4000 sx = im2->sx;
4001 }
4002 }
4003
4004 sy = im1->sy;
4005 if (im1->sy != im2->sy) {
4006 cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
4007 if (im2->sy < im1->sy) {
4008 sy = im2->sy;
4009 }
4010 }
4011
4012 if (im1->colorsTotal != im2->colorsTotal) {
4013 cmpStatus |= GD_CMP_NUM_COLORS;
4014 }
4015
4016 for (y = 0; (y < sy); y++) {
4017 for (x = 0; (x < sx); x++) {
4018 p1 =
4019 im1->trueColor ? gdImageTrueColorPixel (im1, x,
4020 y) :
4021 gdImagePalettePixel (im1, x, y);
4022 p2 =
4023 im2->trueColor ? gdImageTrueColorPixel (im2, x,
4024 y) :
4025 gdImagePalettePixel (im2, x, y);
4026 if (gdImageRed (im1, p1) != gdImageRed (im2, p2)) {
4027 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4028 break;
4029 }
4030 if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2)) {
4031 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4032 break;
4033 }
4034 if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2)) {
4035 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4036 break;
4037 }
4038 #if 0
4039 /* Soon we'll add alpha channel to palettes */
4040 if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2)) {
4041 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4042 break;
4043 }
4044 #endif
4045 }
4046 if (cmpStatus & GD_CMP_COLOR) {
4047 break;
4048 };
4049 }
4050
4051 return cmpStatus;
4052 }
4053
4054
4055 /* Thanks to Frank Warmerdam for this superior implementation
4056 of gdAlphaBlend(), which merges alpha in the
4057 destination color much better. */
4058
4059 /**
4060 * Function: gdAlphaBlend
4061 *
4062 * Blend two colors
4063 *
4064 * Parameters:
4065 * dst - The color to blend onto.
4066 * src - The color to blend.
4067 *
4068 * See also:
4069 * - <gdImageAlphaBlending>
4070 * - <gdLayerOverlay>
4071 * - <gdLayerMultiply>
4072 */
gdAlphaBlend(int dst,int src)4073 BGD_DECLARE(int) gdAlphaBlend (int dst, int src)
4074 {
4075 int src_alpha = gdTrueColorGetAlpha(src);
4076 int dst_alpha, alpha, red, green, blue;
4077 int src_weight, dst_weight, tot_weight;
4078
4079 /* -------------------------------------------------------------------- */
4080 /* Simple cases we want to handle fast. */
4081 /* -------------------------------------------------------------------- */
4082 if( src_alpha == gdAlphaOpaque )
4083 return src;
4084
4085 dst_alpha = gdTrueColorGetAlpha(dst);
4086 if( src_alpha == gdAlphaTransparent )
4087 return dst;
4088 if( dst_alpha == gdAlphaTransparent )
4089 return src;
4090
4091 /* -------------------------------------------------------------------- */
4092 /* What will the source and destination alphas be? Note that */
4093 /* the destination weighting is substantially reduced as the */
4094 /* overlay becomes quite opaque. */
4095 /* -------------------------------------------------------------------- */
4096 src_weight = gdAlphaTransparent - src_alpha;
4097 dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
4098 tot_weight = src_weight + dst_weight;
4099
4100 /* -------------------------------------------------------------------- */
4101 /* What red, green and blue result values will we use? */
4102 /* -------------------------------------------------------------------- */
4103 alpha = src_alpha * dst_alpha / gdAlphaMax;
4104
4105 red = (gdTrueColorGetRed(src) * src_weight
4106 + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
4107 green = (gdTrueColorGetGreen(src) * src_weight
4108 + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
4109 blue = (gdTrueColorGetBlue(src) * src_weight
4110 + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
4111
4112 /* -------------------------------------------------------------------- */
4113 /* Return merged result. */
4114 /* -------------------------------------------------------------------- */
4115 return ((alpha << 24) + (red << 16) + (green << 8) + blue);
4116 }
4117
4118 static int gdAlphaOverlayColor (int src, int dst, int max );
4119
4120 /**
4121 * Function: gdLayerOverlay
4122 *
4123 * Overlay two colors
4124 *
4125 * Parameters:
4126 * dst - The color to overlay onto.
4127 * src - The color to overlay.
4128 *
4129 * See also:
4130 * - <gdImageAlphaBlending>
4131 * - <gdAlphaBlend>
4132 * - <gdLayerMultiply>
4133 */
gdLayerOverlay(int dst,int src)4134 BGD_DECLARE(int) gdLayerOverlay (int dst, int src)
4135 {
4136 int a1, a2;
4137 a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
4138 a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
4139 return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
4140 (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
4141 (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
4142 (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
4143 );
4144 }
4145
4146 /* Apply 'overlay' effect - background pixels are colourised by the foreground colour */
gdAlphaOverlayColor(int src,int dst,int max)4147 static int gdAlphaOverlayColor (int src, int dst, int max )
4148 {
4149 dst = dst << 1;
4150 if( dst > max ) {
4151 /* in the "light" zone */
4152 return dst + (src << 1) - (dst * src / max) - max;
4153 } else {
4154 /* in the "dark" zone */
4155 return dst * src / max;
4156 }
4157 }
4158
4159 /**
4160 * Function: gdLayerMultiply
4161 *
4162 * Overlay two colors with multiply effect
4163 *
4164 * Parameters:
4165 * dst - The color to overlay onto.
4166 * src - The color to overlay.
4167 *
4168 * See also:
4169 * - <gdImageAlphaBlending>
4170 * - <gdAlphaBlend>
4171 * - <gdLayerOverlay>
4172 */
gdLayerMultiply(int dst,int src)4173 BGD_DECLARE(int) gdLayerMultiply (int dst, int src)
4174 {
4175 int a1, a2, r1, r2, g1, g2, b1, b2;
4176 a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
4177 a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
4178
4179 r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
4180 r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
4181 g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
4182 g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
4183 b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
4184 b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
4185
4186 a1 = gdAlphaMax - a1;
4187 a2 = gdAlphaMax - a2;
4188 return ( ((a1*a2/gdAlphaMax) << 24) +
4189 ((r1*r2/gdRedMax) << 16) +
4190 ((g1*g2/gdGreenMax) << 8) +
4191 ((b1*b2/gdBlueMax))
4192 );
4193 }
4194
4195 /**
4196 * Function: gdImageAlphaBlending
4197 *
4198 * Set the effect for subsequent drawing operations
4199 *
4200 * Note that the effect is used for truecolor images only.
4201 *
4202 * Parameters:
4203 * im - The image.
4204 * alphaBlendingArg - The effect.
4205 *
4206 * See also:
4207 * - <Effects>
4208 */
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)4209 BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
4210 {
4211 im->alphaBlendingFlag = alphaBlendingArg;
4212 }
4213
4214 /**
4215 * Function: gdImageSaveAlpha
4216 *
4217 * Sets the save alpha flag
4218 *
4219 * The save alpha flag specifies whether the alpha channel of the pixels should
4220 * be saved. This is supported only for image formats that support full alpha
4221 * transparency, e.g. PNG.
4222 */
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)4223 BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
4224 {
4225 im->saveAlphaFlag = saveAlphaArg;
4226 }
4227
4228 /**
4229 * Function: gdImageSetClip
4230 *
4231 * Sets the clipping rectangle
4232 *
4233 * The clipping rectangle restricts the drawing area for following drawing
4234 * operations.
4235 *
4236 * Parameters:
4237 * im - The image.
4238 * x1 - The x-coordinate of the upper left corner.
4239 * y1 - The y-coordinate of the upper left corner.
4240 * x2 - The x-coordinate of the lower right corner.
4241 * y2 - The y-coordinate of the lower right corner.
4242 *
4243 * See also:
4244 * - <gdImageGetClip>
4245 */
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)4246 BGD_DECLARE(void) gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
4247 {
4248 if (x1 < 0) {
4249 x1 = 0;
4250 }
4251 if (x1 >= im->sx) {
4252 x1 = im->sx - 1;
4253 }
4254 if (x2 < 0) {
4255 x2 = 0;
4256 }
4257 if (x2 >= im->sx) {
4258 x2 = im->sx - 1;
4259 }
4260 if (y1 < 0) {
4261 y1 = 0;
4262 }
4263 if (y1 >= im->sy) {
4264 y1 = im->sy - 1;
4265 }
4266 if (y2 < 0) {
4267 y2 = 0;
4268 }
4269 if (y2 >= im->sy) {
4270 y2 = im->sy - 1;
4271 }
4272 im->cx1 = x1;
4273 im->cy1 = y1;
4274 im->cx2 = x2;
4275 im->cy2 = y2;
4276 }
4277
4278 /**
4279 * Function: gdImageGetClip
4280 *
4281 * Gets the current clipping rectangle
4282 *
4283 * Parameters:
4284 * im - The image.
4285 * x1P - (out) The x-coordinate of the upper left corner.
4286 * y1P - (out) The y-coordinate of the upper left corner.
4287 * x2P - (out) The x-coordinate of the lower right corner.
4288 * y2P - (out) The y-coordinate of the lower right corner.
4289 *
4290 * See also:
4291 * - <gdImageSetClip>
4292 */
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)4293 BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
4294 {
4295 *x1P = im->cx1;
4296 *y1P = im->cy1;
4297 *x2P = im->cx2;
4298 *y2P = im->cy2;
4299 }
4300
4301 /**
4302 * Function: gdImageSetResolution
4303 *
4304 * Sets the resolution of an image.
4305 *
4306 * Parameters:
4307 * im - The image.
4308 * res_x - The horizontal resolution in DPI.
4309 * res_y - The vertical resolution in DPI.
4310 *
4311 * See also:
4312 * - <gdImageResolutionX>
4313 * - <gdImageResolutionY>
4314 */
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)4315 BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
4316 {
4317 if (res_x > 0) im->res_x = res_x;
4318 if (res_y > 0) im->res_y = res_y;
4319 }
4320
4321 /*
4322 * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
4323 * */
4324 #define BLEND_COLOR(a, nc, c, cc) \
4325 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
4326
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)4327 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
4328 {
4329 int dr,dg,db,p,r,g,b;
4330
4331 /* 2.0.34: watch out for out of range calls */
4332 if (!gdImageBoundsSafeMacro(im, x, y)) {
4333 return;
4334 }
4335 p = gdImageGetPixel(im,x,y);
4336 /* TBB: we have to implement the dont_blend stuff to provide
4337 the full feature set of the old implementation */
4338 if ((p == color)
4339 || ((p == im->AA_dont_blend)
4340 && (t != 0x00))) {
4341 return;
4342 }
4343 dr = gdTrueColorGetRed(color);
4344 dg = gdTrueColorGetGreen(color);
4345 db = gdTrueColorGetBlue(color);
4346
4347 r = gdTrueColorGetRed(p);
4348 g = gdTrueColorGetGreen(p);
4349 b = gdTrueColorGetBlue(p);
4350
4351 BLEND_COLOR(t, dr, r, dr);
4352 BLEND_COLOR(t, dg, g, dg);
4353 BLEND_COLOR(t, db, b, db);
4354 im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
4355 }
4356
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)4357 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
4358 {
4359 /* keep them as 32bits */
4360 long x, y, inc, frac;
4361 long dx, dy,tmp;
4362 int w, wid, wstart;
4363 int thick = im->thick;
4364
4365 if (!im->trueColor) {
4366 /* TBB: don't crash when the image is of the wrong type */
4367 gdImageLine(im, x1, y1, x2, y2, col);
4368 return;
4369 }
4370
4371 /* TBB: use the clipping rectangle */
4372 if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
4373 return;
4374 if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
4375 return;
4376
4377 dx = x2 - x1;
4378 dy = y2 - y1;
4379
4380 if (dx == 0 && dy == 0) {
4381 /* TBB: allow setting points */
4382 gdImageSetPixel(im, x1, y1, col);
4383 return;
4384 } else {
4385 double ag;
4386 /* Cast the long to an int to avoid compiler warnings about truncation.
4387 * This isn't a problem as computed dy/dx values came from ints above. */
4388 ag = fabs(abs((int)dy) < abs((int)dx) ? cos(atan2(dy, dx)) : sin(atan2(dy, dx)));
4389 if (ag != 0) {
4390 wid = thick / ag;
4391 } else {
4392 wid = 1;
4393 }
4394 if (wid == 0) {
4395 wid = 1;
4396 }
4397 }
4398
4399 /* Axis aligned lines */
4400 if (dx == 0) {
4401 gdImageVLine(im, x1, y1, y2, col);
4402 return;
4403 } else if (dy == 0) {
4404 gdImageHLine(im, y1, x1, x2, col);
4405 return;
4406 }
4407
4408 if (abs((int)dx) > abs((int)dy)) {
4409 if (dx < 0) {
4410 tmp = x1;
4411 x1 = x2;
4412 x2 = tmp;
4413 tmp = y1;
4414 y1 = y2;
4415 y2 = tmp;
4416 dx = x2 - x1;
4417 dy = y2 - y1;
4418 }
4419 y = y1;
4420 inc = (dy * 65536) / dx;
4421 frac = 0;
4422 /* TBB: set the last pixel for consistency (<=) */
4423 for (x = x1 ; x <= x2 ; x++) {
4424 wstart = y - wid / 2;
4425 for (w = wstart; w < wstart + wid; w++) {
4426 gdImageSetAAPixelColor(im, x , w , col , (frac >> 8) & 0xFF);
4427 gdImageSetAAPixelColor(im, x , w + 1 , col, (~frac >> 8) & 0xFF);
4428 }
4429 frac += inc;
4430 if (frac >= 65536) {
4431 frac -= 65536;
4432 y++;
4433 } else if (frac < 0) {
4434 frac += 65536;
4435 y--;
4436 }
4437 }
4438 } else {
4439 if (dy < 0) {
4440 tmp = x1;
4441 x1 = x2;
4442 x2 = tmp;
4443 tmp = y1;
4444 y1 = y2;
4445 y2 = tmp;
4446 dx = x2 - x1;
4447 dy = y2 - y1;
4448 }
4449 x = x1;
4450 inc = (dx * 65536) / dy;
4451 frac = 0;
4452 /* TBB: set the last pixel for consistency (<=) */
4453 for (y = y1 ; y <= y2 ; y++) {
4454 wstart = x - wid / 2;
4455 for (w = wstart; w < wstart + wid; w++) {
4456 gdImageSetAAPixelColor(im, w , y , col, (frac >> 8) & 0xFF);
4457 gdImageSetAAPixelColor(im, w + 1, y, col, (~frac >> 8) & 0xFF);
4458 }
4459 frac += inc;
4460 if (frac >= 65536) {
4461 frac -= 65536;
4462 x++;
4463 } else if (frac < 0) {
4464 frac += 65536;
4465 x--;
4466 }
4467 }
4468 }
4469 }
4470
4471
4472 /**
4473 * Function: gdImagePaletteToTrueColor
4474 *
4475 * Convert a palette image to true color
4476 *
4477 * Parameters:
4478 * src - The image.
4479 *
4480 * Returns:
4481 * Non-zero if the conversion succeeded, zero otherwise.
4482 *
4483 * See also:
4484 * - <gdImageTrueColorToPalette>
4485 */
gdImagePaletteToTrueColor(gdImagePtr src)4486 BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src)
4487 {
4488 unsigned int y;
4489 unsigned int yy;
4490
4491 if (src == NULL) {
4492 return 0;
4493 }
4494
4495 if (src->trueColor == 1) {
4496 return 1;
4497 } else {
4498 unsigned int x;
4499 const unsigned int sy = gdImageSY(src);
4500 const unsigned int sx = gdImageSX(src);
4501
4502 src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
4503 if (src->tpixels == NULL) {
4504 return 0;
4505 }
4506
4507 for (y = 0; y < sy; y++) {
4508 const unsigned char *src_row = src->pixels[y];
4509 int * dst_row;
4510
4511 /* no need to calloc it, we overwrite all pxl anyway */
4512 src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
4513 if (src->tpixels[y] == NULL) {
4514 goto clean_on_error;
4515 }
4516
4517 dst_row = src->tpixels[y];
4518 for (x = 0; x < sx; x++) {
4519 const unsigned char c = *(src_row + x);
4520 if (c == src->transparent) {
4521 *(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
4522 } else {
4523 *(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
4524 }
4525 }
4526 }
4527 }
4528
4529 /* free old palette buffer (y is sy) */
4530 for (yy = 0; yy < y; yy++) {
4531 gdFree(src->pixels[yy]);
4532 }
4533 gdFree(src->pixels);
4534 src->trueColor = 1;
4535 src->pixels = NULL;
4536 src->alphaBlendingFlag = 0;
4537 src->saveAlphaFlag = 1;
4538
4539 if (src->transparent >= 0) {
4540 const unsigned char c = src->transparent;
4541 src->transparent = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
4542 }
4543
4544 return 1;
4545
4546 clean_on_error:
4547 /* free new true color buffer (y is not allocated, have failed) */
4548 for (yy = 0; yy < y; yy++) {
4549 gdFree(src->tpixels[yy]);
4550 }
4551 gdFree(src->tpixels);
4552 return 0;
4553 }
4554