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