1
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "gdhelpers.h"
7 #include "gd_errors.h"
8
9 #include "php.h"
10
11 #ifdef _MSC_VER
12 # if _MSC_VER >= 1300
13 /* in MSVC.NET these are available but only for __cplusplus and not _MSC_EXTENSIONS */
14 # if !defined(_MSC_EXTENSIONS) && defined(__cplusplus)
15 # define HAVE_FABSF 1
16 extern float fabsf(float x);
17 # define HAVE_FLOORF 1
18 extern float floorf(float x);
19 # endif /*MSVC.NET */
20 # endif /* MSC */
21 #endif
22 #ifndef HAVE_FABSF
23 # define HAVE_FABSF 0
24 #endif
25 #ifndef HAVE_FLOORF
26 # define HAVE_FLOORF 0
27 #endif
28 #if HAVE_FABSF == 0
29 /* float fabsf(float x); */
30 # ifndef fabsf
31 # define fabsf(x) ((float)(fabs(x)))
32 # endif
33 #endif
34 #if HAVE_FLOORF == 0
35 # ifndef floorf
36 /* float floorf(float x);*/
37 # define floorf(x) ((float)(floor(x)))
38 # endif
39 #endif
40
41 #ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */
42 #define CHARSET_EBCDIC
43 #define __attribute__(any) /*nothing */
44 #endif
45 /*_OSD_POSIX*/
46
47 #ifndef CHARSET_EBCDIC
48 #define ASC(ch) ch
49 #else /*CHARSET_EBCDIC */
50 #define ASC(ch) gd_toascii[(unsigned char)ch]
51 static const unsigned char gd_toascii[256] =
52 {
53 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
54 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */
55 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
56 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */
57 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
58 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */
59 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
60 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */
61 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
62 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
63 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
64 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */
65 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
66 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
67 /*-/........^,%_>?*/
68 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
69 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */
70 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
71 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */
72 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
73 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */
74 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
75 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */
76 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
77 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */
78 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
79 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */
80 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
81 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */
82 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
83 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */
84 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
85 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
86 };
87 #endif /*CHARSET_EBCDIC */
88
89 /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
90 #define floor_cast(exp) ((long) exp)
91
92 extern int gdCosT[];
93 extern int gdSinT[];
94
95 /**
96 * Group: Error Handling
97 */
98
gd_stderr_error(int priority,const char * format,va_list args)99 void gd_stderr_error(int priority, const char *format, va_list args)
100 {
101 switch (priority) {
102 case GD_ERROR:
103 fputs("GD Error: ", stderr);
104 break;
105 case GD_WARNING:
106 fputs("GD Warning: ", stderr);
107 break;
108 case GD_NOTICE:
109 fputs("GD Notice: ", stderr);
110 break;
111 #ifndef PHP_WIN32
112 case GD_INFO:
113 fputs("GD Info: ", stderr);
114 break;
115 case GD_DEBUG:
116 fputs("GD Debug: ", stderr);
117 break;
118 #endif
119 }
120 vfprintf(stderr, format, args);
121 fflush(stderr);
122 }
123
124 static gdErrorMethod gd_error_method = gd_stderr_error;
125
_gd_error_ex(int priority,const char * format,va_list args)126 static void _gd_error_ex(int priority, const char *format, va_list args)
127 {
128 if (gd_error_method) {
129 gd_error_method(priority, format, args);
130 }
131 }
132
gd_error(const char * format,...)133 void gd_error(const char *format, ...)
134 {
135 va_list args;
136
137 va_start(args, format);
138 _gd_error_ex(GD_WARNING, format, args);
139 va_end(args);
140 }
gd_error_ex(int priority,const char * format,...)141 void gd_error_ex(int priority, const char *format, ...)
142 {
143 va_list args;
144
145 va_start(args, format);
146 _gd_error_ex(priority, format, args);
147 va_end(args);
148 }
149
150 /*
151 Function: gdSetErrorMethod
152 */
gdSetErrorMethod(gdErrorMethod error_method)153 void gdSetErrorMethod(gdErrorMethod error_method)
154 {
155 gd_error_method = error_method;
156 }
157
158 /*
159 Function: gdClearErrorMethod
160 */
gdClearErrorMethod(void)161 void gdClearErrorMethod(void)
162 {
163 gd_error_method = gd_stderr_error;
164 }
165
166 static void gdImageBrushApply(gdImagePtr im, int x, int y);
167 static void gdImageTileApply(gdImagePtr im, int x, int y);
168 static int gdAlphaOverlayColor(int src, int dst, int max);
169 int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
170
gdImageCreate(int sx,int sy)171 gdImagePtr gdImageCreate (int sx, int sy)
172 {
173 int i;
174 gdImagePtr im;
175
176 if (overflow2(sx, sy)) {
177 return NULL;
178 }
179 if (overflow2(sizeof(unsigned char *), sy)) {
180 return NULL;
181 }
182 if (overflow2(sizeof(unsigned char), sx)) {
183 return NULL;
184 }
185
186 im = (gdImage *) gdCalloc(1, sizeof(gdImage));
187
188 /* Row-major ever since gd 1.3 */
189 im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
190 im->polyInts = 0;
191 im->polyAllocated = 0;
192 im->brush = 0;
193 im->tile = 0;
194 im->style = 0;
195 for (i = 0; i < sy; i++) {
196 /* Row-major ever since gd 1.3 */
197 im->pixels[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
198 }
199 im->sx = sx;
200 im->sy = sy;
201 im->colorsTotal = 0;
202 im->transparent = (-1);
203 im->interlace = 0;
204 im->thick = 1;
205 im->AA = 0;
206 for (i = 0; i < gdMaxColors; i++) {
207 im->open[i] = 1;
208 im->red[i] = 0;
209 im->green[i] = 0;
210 im->blue[i] = 0;
211 }
212 im->trueColor = 0;
213 im->tpixels = 0;
214 im->cx1 = 0;
215 im->cy1 = 0;
216 im->cx2 = im->sx - 1;
217 im->cy2 = im->sy - 1;
218 im->res_x = GD_RESOLUTION;
219 im->res_y = GD_RESOLUTION;
220 im->interpolation = NULL;
221 im->interpolation_id = GD_BILINEAR_FIXED;
222 return im;
223 }
224
gdImageCreateTrueColor(int sx,int sy)225 gdImagePtr gdImageCreateTrueColor (int sx, int sy)
226 {
227 int i;
228 gdImagePtr im;
229
230 if (overflow2(sx, sy)) {
231 return NULL;
232 }
233 if (overflow2(sizeof(int *), sy)) {
234 return NULL;
235 }
236 if (overflow2(sizeof(int), sx)) {
237 return NULL;
238 }
239
240 im = (gdImage *) gdMalloc(sizeof(gdImage));
241 memset(im, 0, sizeof(gdImage));
242 im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
243 im->polyInts = 0;
244 im->polyAllocated = 0;
245 im->brush = 0;
246 im->tile = 0;
247 im->style = 0;
248 for (i = 0; i < sy; i++) {
249 im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
250 }
251 im->sx = sx;
252 im->sy = sy;
253 im->transparent = (-1);
254 im->interlace = 0;
255 im->trueColor = 1;
256 /* 2.0.2: alpha blending is now on by default, and saving of alpha is
257 * off by default. This allows font antialiasing to work as expected
258 * on the first try in JPEGs -- quite important -- and also allows
259 * for smaller PNGs when saving of alpha channel is not really
260 * desired, which it usually isn't!
261 */
262 im->saveAlphaFlag = 0;
263 im->alphaBlendingFlag = 1;
264 im->thick = 1;
265 im->AA = 0;
266 im->cx1 = 0;
267 im->cy1 = 0;
268 im->cx2 = im->sx - 1;
269 im->cy2 = im->sy - 1;
270 im->res_x = GD_RESOLUTION;
271 im->res_y = GD_RESOLUTION;
272 im->interpolation = NULL;
273 im->interpolation_id = GD_BILINEAR_FIXED;
274 return im;
275 }
276
gdImageDestroy(gdImagePtr im)277 void gdImageDestroy (gdImagePtr im)
278 {
279 int i;
280 if (im->pixels) {
281 for (i = 0; i < im->sy; i++) {
282 gdFree(im->pixels[i]);
283 }
284 gdFree(im->pixels);
285 }
286 if (im->tpixels) {
287 for (i = 0; i < im->sy; i++) {
288 gdFree(im->tpixels[i]);
289 }
290 gdFree(im->tpixels);
291 }
292 if (im->polyInts) {
293 gdFree(im->polyInts);
294 }
295 if (im->style) {
296 gdFree(im->style);
297 }
298 gdFree(im);
299 }
300
gdImageColorClosest(gdImagePtr im,int r,int g,int b)301 int gdImageColorClosest (gdImagePtr im, int r, int g, int b)
302 {
303 return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
304 }
305
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)306 int gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
307 {
308 int i;
309 long rd, gd, bd, ad;
310 int ct = (-1);
311 int first = 1;
312 long mindist = 0;
313
314 if (im->trueColor) {
315 return gdTrueColorAlpha(r, g, b, a);
316 }
317 for (i = 0; i < im->colorsTotal; i++) {
318 long dist;
319 if (im->open[i]) {
320 continue;
321 }
322 rd = im->red[i] - r;
323 gd = im->green[i] - g;
324 bd = im->blue[i] - b;
325 /* gd 2.02: whoops, was - b (thanks to David Marwood) */
326 ad = im->alpha[i] - a;
327 dist = rd * rd + gd * gd + bd * bd + ad * ad;
328 if (first || (dist < mindist)) {
329 mindist = dist;
330 ct = i;
331 first = 0;
332 }
333 }
334 return ct;
335 }
336
337 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
338 * on colour conversion to/from RBG and HWB colour systems.
339 * It has been modified to return the converted value as a * parameter.
340 */
341
342 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
343 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
344 #define HWB_UNDEFINED -1
345 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0f; s.G = g/255.0f; s.B = b/255.0f;}
346
347 #ifndef MIN
348 #define MIN(a,b) ((a)<(b)?(a):(b))
349 #endif
350 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
351 #ifndef MAX
352 #define MAX(a,b) ((a)<(b)?(b):(a))
353 #endif
354 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
355
356
357 /*
358 * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
359 * red always maps to 6 in this implementation. Therefore UNDEFINED can be
360 * defined as 0 in situations where only unsigned numbers are desired.
361 */
362 typedef struct
363 {
364 float R, G, B;
365 }
366 RGBType;
367 typedef struct
368 {
369 float H, W, B;
370 }
371 HWBType;
372
RGB_to_HWB(RGBType RGB,HWBType * HWB)373 static HWBType * RGB_to_HWB (RGBType RGB, HWBType * HWB)
374 {
375 /*
376 * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
377 * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
378 */
379
380 float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
381 int i;
382
383 w = MIN3 (R, G, B);
384 v = MAX3 (R, G, B);
385 b = 1 - v;
386 if (v == w) {
387 RETURN_HWB(HWB_UNDEFINED, w, b);
388 }
389 f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
390 i = (R == w) ? 3 : ((G == w) ? 5 : 1);
391
392 RETURN_HWB(i - f / (v - w), w, b);
393 }
394
HWB_Diff(int r1,int g1,int b1,int r2,int g2,int b2)395 static float HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
396 {
397 RGBType RGB1, RGB2;
398 HWBType HWB1, HWB2;
399 float diff;
400
401 SETUP_RGB(RGB1, r1, g1, b1);
402 SETUP_RGB(RGB2, r2, g2, b2);
403
404 RGB_to_HWB(RGB1, &HWB1);
405 RGB_to_HWB(RGB2, &HWB2);
406
407 /*
408 * I made this bit up; it seems to produce OK results, and it is certainly
409 * more visually correct than the current RGB metric. (PJW)
410 */
411
412 if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
413 diff = 0.0f; /* Undefined hues always match... */
414 } else {
415 diff = fabsf(HWB1.H - HWB2.H);
416 if (diff > 3.0f) {
417 diff = 6.0f - diff; /* Remember, it's a colour circle */
418 }
419 }
420
421 diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
422
423 return diff;
424 }
425
426
427 #if 0
428 /*
429 * This is not actually used, but is here for completeness, in case someone wants to
430 * use the HWB stuff for anything else...
431 */
432 static RGBType * HWB_to_RGB (HWBType HWB, RGBType * RGB)
433 {
434 /*
435 * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
436 * RGB are each returned on [0, 1].
437 */
438
439 float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
440 int i;
441
442 v = 1 - b;
443 if (h == HWB_UNDEFINED) {
444 RETURN_RGB(v, v, v);
445 }
446 i = floor(h);
447 f = h - i;
448 if (i & 1) {
449 f = 1 - f; /* if i is odd */
450 }
451 n = w + f * (v - w); /* linear interpolation between w and v */
452 switch (i) {
453 case 6:
454 case 0:
455 RETURN_RGB(v, n, w);
456 case 1:
457 RETURN_RGB(n, v, w);
458 case 2:
459 RETURN_RGB(w, v, n);
460 case 3:
461 RETURN_RGB(w, n, v);
462 case 4:
463 RETURN_RGB(n, w, v);
464 case 5:
465 RETURN_RGB(v, w, n);
466 }
467
468 return RGB;
469 }
470 #endif
471
gdImageColorClosestHWB(gdImagePtr im,int r,int g,int b)472 int gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
473 {
474 int i;
475 /* long rd, gd, bd; */
476 int ct = (-1);
477 int first = 1;
478 float mindist = 0;
479 if (im->trueColor) {
480 return gdTrueColor(r, g, b);
481 }
482 for (i = 0; i < im->colorsTotal; i++) {
483 float dist;
484 if (im->open[i]) {
485 continue;
486 }
487 dist = HWB_Diff(im->red[i], im->green[i], im->blue[i], r, g, b);
488 if (first || (dist < mindist)) {
489 mindist = dist;
490 ct = i;
491 first = 0;
492 }
493 }
494 return ct;
495 }
496
gdImageColorExact(gdImagePtr im,int r,int g,int b)497 int gdImageColorExact (gdImagePtr im, int r, int g, int b)
498 {
499 return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
500 }
501
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)502 int gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
503 {
504 int i;
505 if (im->trueColor) {
506 return gdTrueColorAlpha(r, g, b, a);
507 }
508 for (i = 0; i < im->colorsTotal; i++) {
509 if (im->open[i]) {
510 continue;
511 }
512 if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
513 return i;
514 }
515 }
516 return -1;
517 }
518
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)519 int gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
520 {
521 return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
522 }
523
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)524 int gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
525 {
526 int i;
527 int ct = (-1);
528 if (im->trueColor) {
529 return gdTrueColorAlpha(r, g, b, a);
530 }
531 for (i = 0; i < im->colorsTotal; i++) {
532 if (im->open[i]) {
533 ct = i;
534 break;
535 }
536 }
537 if (ct == (-1)) {
538 ct = im->colorsTotal;
539 if (ct == gdMaxColors) {
540 return -1;
541 }
542 im->colorsTotal++;
543 }
544 im->red[ct] = r;
545 im->green[ct] = g;
546 im->blue[ct] = b;
547 im->alpha[ct] = a;
548 im->open[ct] = 0;
549
550 return ct;
551 }
552
553 /*
554 * gdImageColorResolve is an alternative for the code fragment:
555 *
556 * if ((color=gdImageColorExact(im,R,G,B)) < 0)
557 * if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
558 * color=gdImageColorClosest(im,R,G,B);
559 *
560 * in a single function. Its advantage is that it is guaranteed to
561 * return a color index in one search over the color table.
562 */
563
gdImageColorResolve(gdImagePtr im,int r,int g,int b)564 int gdImageColorResolve (gdImagePtr im, int r, int g, int b)
565 {
566 return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);
567 }
568
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)569 int gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
570 {
571 int c;
572 int ct = -1;
573 int op = -1;
574 long rd, gd, bd, ad, dist;
575 long mindist = 4 * 255 * 255; /* init to max poss dist */
576 if (im->trueColor)
577 {
578 return gdTrueColorAlpha (r, g, b, a);
579 }
580
581 for (c = 0; c < im->colorsTotal; c++)
582 {
583 if (im->open[c])
584 {
585 op = c; /* Save open slot */
586 continue; /* Color not in use */
587 }
588 if (c == im->transparent)
589 {
590 /* don't ever resolve to the color that has
591 * been designated as the transparent color */
592 continue;
593 }
594 rd = (long) (im->red[c] - r);
595 gd = (long) (im->green[c] - g);
596 bd = (long) (im->blue[c] - b);
597 ad = (long) (im->alpha[c] - a);
598 dist = rd * rd + gd * gd + bd * bd + ad * ad;
599 if (dist < mindist)
600 {
601 if (dist == 0)
602 {
603 return c; /* Return exact match color */
604 }
605 mindist = dist;
606 ct = c;
607 }
608 }
609 /* no exact match. We now know closest, but first try to allocate exact */
610 if (op == -1)
611 {
612 op = im->colorsTotal;
613 if (op == gdMaxColors)
614 { /* No room for more colors */
615 return ct; /* Return closest available color */
616 }
617 im->colorsTotal++;
618 }
619 im->red[op] = r;
620 im->green[op] = g;
621 im->blue[op] = b;
622 im->alpha[op] = a;
623 im->open[op] = 0;
624 return op; /* Return newly allocated color */
625 }
626
gdImageColorDeallocate(gdImagePtr im,int color)627 void gdImageColorDeallocate (gdImagePtr im, int color)
628 {
629 if (im->trueColor) {
630 return;
631 }
632 /* Mark it open. */
633 im->open[color] = 1;
634 }
635
gdImageColorTransparent(gdImagePtr im,int color)636 void gdImageColorTransparent (gdImagePtr im, int color)
637 {
638 if (color < 0) {
639 return;
640 }
641 if (!im->trueColor) {
642 if((color >= im->colorsTotal)) {
643 return;
644 }
645 /* Make the old transparent color opaque again */
646 if (im->transparent != -1) {
647 im->alpha[im->transparent] = gdAlphaOpaque;
648 }
649 im->alpha[color] = gdAlphaTransparent;
650 }
651 im->transparent = color;
652 }
653
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)654 void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
655 {
656 int i;
657 int x, y, p;
658 int xlate[256];
659 if (to->trueColor || from->trueColor) {
660 return;
661 }
662
663 for (i = 0; i < 256; i++) {
664 xlate[i] = -1;
665 }
666
667 for (y = 0; y < to->sy; y++) {
668 for (x = 0; x < to->sx; x++) {
669 p = gdImageGetPixel(to, x, y);
670 if (xlate[p] == -1) {
671 /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */
672 xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
673 }
674 gdImageSetPixel(to, x, y, xlate[p]);
675 }
676 }
677
678 for (i = 0; i < from->colorsTotal; i++) {
679 to->red[i] = from->red[i];
680 to->blue[i] = from->blue[i];
681 to->green[i] = from->green[i];
682 to->alpha[i] = from->alpha[i];
683 to->open[i] = 0;
684 }
685
686 for (i = from->colorsTotal; i < to->colorsTotal; i++) {
687 to->open[i] = 1;
688 }
689
690 to->colorsTotal = from->colorsTotal;
691 }
692
693 /* 2.0.10: before the drawing routines, some code to clip points that are
694 * outside the drawing window. Nick Atty (nick@canalplan.org.uk)
695 *
696 * This is the Sutherland Hodgman Algorithm, as implemented by
697 * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's
698 * Journal, January 1996, pp107-110 and 116-117
699 *
700 * Given the end points of a line, and a bounding rectangle (which we
701 * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
702 * the edges of the rectangle if the line should be drawn at all,
703 * otherwise return a failure code
704 */
705
706 /* this does "one-dimensional" clipping: note that the second time it
707 * is called, all the x parameters refer to height and the y to width
708 * - the comments ignore this (if you can understand it when it's
709 * looking at the X parameters, it should become clear what happens on
710 * the second call!) The code is simplified from that in the article,
711 * as we know that gd images always start at (0,0)
712 */
713
clip_1d(int * x0,int * y0,int * x1,int * y1,int maxdim)714 static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) {
715 double m; /* gradient of line */
716
717 if (*x0 < 0) { /* start of line is left of window */
718 if(*x1 < 0) { /* as is the end, so the line never cuts the window */
719 return 0;
720 }
721 m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
722 /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
723 *y0 -= (int)(m * *x0);
724 *x0 = 0;
725 /* now, perhaps, adjust the far end of the line as well */
726 if (*x1 > maxdim) {
727 *y1 += (int)(m * (maxdim - *x1));
728 *x1 = maxdim;
729 }
730 return 1;
731 }
732 if (*x0 > maxdim) { /* start of line is right of window - complement of above */
733 if (*x1 > maxdim) { /* as is the end, so the line misses the window */
734 return 0;
735 }
736 m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
737 *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right boundary */
738 *x0 = maxdim;
739 /* now, perhaps, adjust the end of the line */
740 if (*x1 < 0) {
741 *y1 -= (int)(m * *x1);
742 *x1 = 0;
743 }
744 return 1;
745 }
746 /* the final case - the start of the line is inside the window */
747 if (*x1 > maxdim) { /* other end is outside to the right */
748 m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
749 *y1 += (int)(m * (maxdim - *x1));
750 *x1 = maxdim;
751 return 1;
752 }
753 if (*x1 < 0) { /* other end is outside to the left */
754 m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
755 *y1 -= (int)(m * *x1);
756 *x1 = 0;
757 return 1;
758 }
759 /* only get here if both points are inside the window */
760 return 1;
761 }
762
gdImageSetPixel(gdImagePtr im,int x,int y,int color)763 void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
764 {
765 int p;
766 switch (color) {
767 case gdStyled:
768 if (!im->style) {
769 /* Refuse to draw if no style is set. */
770 return;
771 } else {
772 p = im->style[im->stylePos++];
773 }
774 if (p != gdTransparent) {
775 gdImageSetPixel(im, x, y, p);
776 }
777 im->stylePos = im->stylePos % im->styleLength;
778 break;
779 case gdStyledBrushed:
780 if (!im->style) {
781 /* Refuse to draw if no style is set. */
782 return;
783 }
784 p = im->style[im->stylePos++];
785 if (p != gdTransparent && p != 0) {
786 gdImageSetPixel(im, x, y, gdBrushed);
787 }
788 im->stylePos = im->stylePos % im->styleLength;
789 break;
790 case gdBrushed:
791 gdImageBrushApply(im, x, y);
792 break;
793 case gdTiled:
794 gdImageTileApply(im, x, y);
795 break;
796 case gdAntiAliased:
797 /* This shouldn't happen (2.0.26) because we just call
798 gdImageAALine now, but do something sane. */
799 gdImageSetPixel(im, x, y, im->AA_color);
800 break;
801 default:
802 if (gdImageBoundsSafe(im, x, y)) {
803 if (im->trueColor) {
804 switch (im->alphaBlendingFlag) {
805 default:
806 case gdEffectReplace:
807 im->tpixels[y][x] = color;
808 break;
809 case gdEffectAlphaBlend:
810 case gdEffectNormal:
811 im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
812 break;
813 case gdEffectOverlay :
814 im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
815 break;
816 case gdEffectMultiply :
817 im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color);
818 break;
819 }
820 } else {
821 im->pixels[y][x] = color;
822 }
823 }
824 break;
825 }
826 }
827
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)828 int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
829 {
830 int p = gdImageGetPixel(im, x, y);
831
832 if (!im->trueColor) {
833 return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : im->alpha[p]);
834 } else {
835 return p;
836 }
837 }
838
gdImageBrushApply(gdImagePtr im,int x,int y)839 static void gdImageBrushApply (gdImagePtr im, int x, int y)
840 {
841 int lx, ly;
842 int hy, hx;
843 int x1, y1, x2, y2;
844 int srcx, srcy;
845
846 if (!im->brush) {
847 return;
848 }
849
850 hy = gdImageSY(im->brush) / 2;
851 y1 = y - hy;
852 y2 = y1 + gdImageSY(im->brush);
853 hx = gdImageSX(im->brush) / 2;
854 x1 = x - hx;
855 x2 = x1 + gdImageSX(im->brush);
856 srcy = 0;
857
858 if (im->trueColor) {
859 if (im->brush->trueColor) {
860 for (ly = y1; ly < y2; ly++) {
861 srcx = 0;
862 for (lx = x1; (lx < x2); lx++) {
863 int p;
864 p = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
865 /* 2.0.9, Thomas Winzig: apply simple full transparency */
866 if (p != gdImageGetTransparent(im->brush)) {
867 gdImageSetPixel(im, lx, ly, p);
868 }
869 srcx++;
870 }
871 srcy++;
872 }
873 } else {
874 /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */
875 for (ly = y1; ly < y2; ly++) {
876 srcx = 0;
877 for (lx = x1; lx < x2; lx++) {
878 int p, tc;
879 p = gdImageGetPixel(im->brush, srcx, srcy);
880 tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
881 /* 2.0.9, Thomas Winzig: apply simple full transparency */
882 if (p != gdImageGetTransparent(im->brush)) {
883 gdImageSetPixel(im, lx, ly, tc);
884 }
885 srcx++;
886 }
887 srcy++;
888 }
889 }
890 } else {
891 for (ly = y1; ly < y2; ly++) {
892 srcx = 0;
893 for (lx = x1; lx < x2; lx++) {
894 int p;
895 p = gdImageGetPixel(im->brush, srcx, srcy);
896 /* Allow for non-square brushes! */
897 if (p != gdImageGetTransparent(im->brush)) {
898 /* Truecolor brush. Very slow on a palette destination. */
899 if (im->brush->trueColor) {
900 gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p),
901 gdTrueColorGetGreen(p),
902 gdTrueColorGetBlue(p),
903 gdTrueColorGetAlpha(p)));
904 } else {
905 gdImageSetPixel(im, lx, ly, im->brushColorMap[p]);
906 }
907 }
908 srcx++;
909 }
910 srcy++;
911 }
912 }
913 }
914
gdImageTileApply(gdImagePtr im,int x,int y)915 static void gdImageTileApply (gdImagePtr im, int x, int y)
916 {
917 gdImagePtr tile = im->tile;
918 int srcx, srcy;
919 int p;
920 if (!tile) {
921 return;
922 }
923 srcx = x % gdImageSX(tile);
924 srcy = y % gdImageSY(tile);
925 if (im->trueColor) {
926 p = gdImageGetPixel(tile, srcx, srcy);
927 if (p != gdImageGetTransparent (tile)) {
928 if (!tile->trueColor) {
929 p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
930 }
931 gdImageSetPixel(im, x, y, p);
932 }
933 } else {
934 p = gdImageGetPixel(tile, srcx, srcy);
935 /* Allow for transparency */
936 if (p != gdImageGetTransparent(tile)) {
937 if (tile->trueColor) {
938 /* Truecolor tile. Very slow on a palette destination. */
939 gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im,
940 gdTrueColorGetRed(p),
941 gdTrueColorGetGreen(p),
942 gdTrueColorGetBlue(p),
943 gdTrueColorGetAlpha(p)));
944 } else {
945 gdImageSetPixel(im, x, y, im->tileColorMap[p]);
946 }
947 }
948 }
949 }
950
951
gdImageTileGet(gdImagePtr im,int x,int y)952 static int gdImageTileGet (gdImagePtr im, int x, int y)
953 {
954 int srcx, srcy;
955 int tileColor,p;
956 if (!im->tile) {
957 return -1;
958 }
959 srcx = x % gdImageSX(im->tile);
960 srcy = y % gdImageSY(im->tile);
961 p = gdImageGetPixel(im->tile, srcx, srcy);
962
963 if (im->trueColor) {
964 if (im->tile->trueColor) {
965 tileColor = p;
966 } else {
967 tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
968 }
969 } else {
970 if (im->tile->trueColor) {
971 tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
972 } else {
973 tileColor = p;
974 tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
975 }
976 }
977 return tileColor;
978 }
979
980
gdImageGetPixel(gdImagePtr im,int x,int y)981 int gdImageGetPixel (gdImagePtr im, int x, int y)
982 {
983 if (gdImageBoundsSafe(im, x, y)) {
984 if (im->trueColor) {
985 return im->tpixels[y][x];
986 } else {
987 return im->pixels[y][x];
988 }
989 } else {
990 return 0;
991 }
992 }
993
gdImageAABlend(gdImagePtr im)994 void gdImageAABlend (gdImagePtr im)
995 {
996 (void)im;
997 }
998
999 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color);
1000
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1001 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1002 {
1003 if (im->thick > 1) {
1004 int thickhalf = im->thick >> 1;
1005 _gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1006 } else {
1007 if (x2 < x1) {
1008 int t = x2;
1009 x2 = x1;
1010 x1 = t;
1011 }
1012
1013 for (;x1 <= x2; x1++) {
1014 gdImageSetPixel(im, x1, y, col);
1015 }
1016 }
1017 return;
1018 }
1019
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1020 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1021 {
1022 if (im->thick > 1) {
1023 int thickhalf = im->thick >> 1;
1024 gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1025 } else {
1026 if (y2 < y1) {
1027 int t = y1;
1028 y1 = y2;
1029 y2 = t;
1030 }
1031
1032 for (;y1 <= y2; y1++) {
1033 gdImageSetPixel(im, x, y1, col);
1034 }
1035 }
1036 return;
1037 }
1038
1039 /* Bresenham as presented in Foley & Van Dam */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1040 void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1041 {
1042 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1043 int wid;
1044 int w, wstart;
1045 int thick = im->thick;
1046
1047 if (color == gdAntiAliased) {
1048 /*
1049 gdAntiAliased passed as color: use the much faster, much cheaper
1050 and equally attractive gdImageAALine implementation. That
1051 clips too, so don't clip twice.
1052 */
1053 gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1054 return;
1055 }
1056
1057 /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1058 if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1059 return;
1060 }
1061
1062 dx = abs (x2 - x1);
1063 dy = abs (y2 - y1);
1064
1065 if (dx == 0) {
1066 gdImageVLine(im, x1, y1, y2, color);
1067 return;
1068 } else if (dy == 0) {
1069 gdImageHLine(im, y1, x1, x2, color);
1070 return;
1071 }
1072
1073 if (dy <= dx) {
1074 /* More-or-less horizontal. use wid for vertical stroke */
1075 /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1076 if ((dx == 0) && (dy == 0)) {
1077 wid = 1;
1078 } else {
1079 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1080 TBB: but watch out for /0! */
1081 double ac = cos (atan2 (dy, dx));
1082 if (ac != 0) {
1083 wid = thick / ac;
1084 } else {
1085 wid = 1;
1086 }
1087 if (wid == 0) {
1088 wid = 1;
1089 }
1090 }
1091 d = 2 * dy - dx;
1092 incr1 = 2 * dy;
1093 incr2 = 2 * (dy - dx);
1094 if (x1 > x2) {
1095 x = x2;
1096 y = y2;
1097 ydirflag = (-1);
1098 xend = x1;
1099 } else {
1100 x = x1;
1101 y = y1;
1102 ydirflag = 1;
1103 xend = x2;
1104 }
1105
1106 /* Set up line thickness */
1107 wstart = y - wid / 2;
1108 for (w = wstart; w < wstart + wid; w++) {
1109 gdImageSetPixel(im, x, w, color);
1110 }
1111
1112 if (((y2 - y1) * ydirflag) > 0) {
1113 while (x < xend) {
1114 x++;
1115 if (d < 0) {
1116 d += incr1;
1117 } else {
1118 y++;
1119 d += incr2;
1120 }
1121 wstart = y - wid / 2;
1122 for (w = wstart; w < wstart + wid; w++) {
1123 gdImageSetPixel (im, x, w, color);
1124 }
1125 }
1126 } else {
1127 while (x < xend) {
1128 x++;
1129 if (d < 0) {
1130 d += incr1;
1131 } else {
1132 y--;
1133 d += incr2;
1134 }
1135 wstart = y - wid / 2;
1136 for (w = wstart; w < wstart + wid; w++) {
1137 gdImageSetPixel (im, x, w, color);
1138 }
1139 }
1140 }
1141 } else {
1142 /* More-or-less vertical. use wid for horizontal stroke */
1143 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1144 TBB: but watch out for /0! */
1145 double as = sin (atan2 (dy, dx));
1146 if (as != 0) {
1147 wid = thick / as;
1148 } else {
1149 wid = 1;
1150 }
1151 if (wid == 0) {
1152 wid = 1;
1153 }
1154
1155 d = 2 * dx - dy;
1156 incr1 = 2 * dx;
1157 incr2 = 2 * (dx - dy);
1158 if (y1 > y2) {
1159 y = y2;
1160 x = x2;
1161 yend = y1;
1162 xdirflag = (-1);
1163 } else {
1164 y = y1;
1165 x = x1;
1166 yend = y2;
1167 xdirflag = 1;
1168 }
1169
1170 /* Set up line thickness */
1171 wstart = x - wid / 2;
1172 for (w = wstart; w < wstart + wid; w++) {
1173 gdImageSetPixel (im, w, y, color);
1174 }
1175
1176 if (((x2 - x1) * xdirflag) > 0) {
1177 while (y < yend) {
1178 y++;
1179 if (d < 0) {
1180 d += incr1;
1181 } else {
1182 x++;
1183 d += incr2;
1184 }
1185 wstart = x - wid / 2;
1186 for (w = wstart; w < wstart + wid; w++) {
1187 gdImageSetPixel (im, w, y, color);
1188 }
1189 }
1190 } else {
1191 while (y < yend) {
1192 y++;
1193 if (d < 0) {
1194 d += incr1;
1195 } else {
1196 x--;
1197 d += incr2;
1198 }
1199 wstart = x - wid / 2;
1200 for (w = wstart; w < wstart + wid; w++) {
1201 gdImageSetPixel (im, w, y, color);
1202 }
1203 }
1204 }
1205 }
1206 }
1207
1208
1209 /*
1210 * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1211 * */
1212 #define BLEND_COLOR(a, nc, c, cc) \
1213 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
1214
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)1215 inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
1216 {
1217 int dr,dg,db,p,r,g,b;
1218 dr = gdTrueColorGetRed(color);
1219 dg = gdTrueColorGetGreen(color);
1220 db = gdTrueColorGetBlue(color);
1221
1222 p = gdImageGetPixel(im,x,y);
1223 r = gdTrueColorGetRed(p);
1224 g = gdTrueColorGetGreen(p);
1225 b = gdTrueColorGetBlue(p);
1226
1227 BLEND_COLOR(t, dr, r, dr);
1228 BLEND_COLOR(t, dg, g, dg);
1229 BLEND_COLOR(t, db, b, db);
1230 im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
1231 }
1232
1233 /*
1234 * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1235 **/
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)1236 void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
1237 {
1238 /* keep them as 32bits */
1239 long x, y, inc, frac;
1240 long dx, dy,tmp;
1241
1242 if (!im->trueColor) {
1243 /* TBB: don't crash when the image is of the wrong type */
1244 gdImageLine(im, x1, y1, x2, y2, col);
1245 return;
1246 }
1247
1248 /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1249 if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1250 return;
1251 }
1252
1253 dx = x2 - x1;
1254 dy = y2 - y1;
1255
1256 if (dx == 0 && dy == 0) {
1257 return;
1258 }
1259 if (abs(dx) > abs(dy)) {
1260 if (dx < 0) {
1261 tmp = x1;
1262 x1 = x2;
1263 x2 = tmp;
1264 tmp = y1;
1265 y1 = y2;
1266 y2 = tmp;
1267 dx = x2 - x1;
1268 dy = y2 - y1;
1269 }
1270 y = y1;
1271 inc = (dy * 65536) / dx;
1272 frac = 0;
1273 for (x = x1; x <= x2; x++) {
1274 gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1275 if (y + 1 < im->sy) {
1276 gdImageSetAAPixelColor(im, x, y + 1, col, (~frac >> 8) & 0xFF);
1277 }
1278 frac += inc;
1279 if (frac >= 65536) {
1280 frac -= 65536;
1281 y++;
1282 } else if (frac < 0) {
1283 frac += 65536;
1284 y--;
1285 }
1286 }
1287 } else {
1288 if (dy < 0) {
1289 tmp = x1;
1290 x1 = x2;
1291 x2 = tmp;
1292 tmp = y1;
1293 y1 = y2;
1294 y2 = tmp;
1295 dx = x2 - x1;
1296 dy = y2 - y1;
1297 }
1298 x = x1;
1299 inc = (dx * 65536) / dy;
1300 frac = 0;
1301 for (y = y1; y <= y2; y++) {
1302 gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1303 if (x + 1 < im->sx) {
1304 gdImageSetAAPixelColor(im, x + 1, y, col, (~frac >> 8) & 0xFF);
1305 }
1306 frac += inc;
1307 if (frac >= 65536) {
1308 frac -= 65536;
1309 x++;
1310 } else if (frac < 0) {
1311 frac += 65536;
1312 x--;
1313 }
1314 }
1315 }
1316 }
1317
1318 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
1319
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1320 void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1321 {
1322 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1323 int dashStep = 0;
1324 int on = 1;
1325 int wid;
1326 int vert;
1327 int thick = im->thick;
1328
1329 dx = abs(x2 - x1);
1330 dy = abs(y2 - y1);
1331 if (dy <= dx) {
1332 /* More-or-less horizontal. use wid for vertical stroke */
1333 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1334 TBB: but watch out for /0! */
1335 double as = sin(atan2(dy, dx));
1336 if (as != 0) {
1337 wid = thick / as;
1338 } else {
1339 wid = 1;
1340 }
1341 vert = 1;
1342
1343 d = 2 * dy - dx;
1344 incr1 = 2 * dy;
1345 incr2 = 2 * (dy - dx);
1346 if (x1 > x2) {
1347 x = x2;
1348 y = y2;
1349 ydirflag = (-1);
1350 xend = x1;
1351 } else {
1352 x = x1;
1353 y = y1;
1354 ydirflag = 1;
1355 xend = x2;
1356 }
1357 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1358 if (((y2 - y1) * ydirflag) > 0) {
1359 while (x < xend) {
1360 x++;
1361 if (d < 0) {
1362 d += incr1;
1363 } else {
1364 y++;
1365 d += incr2;
1366 }
1367 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1368 }
1369 } else {
1370 while (x < xend) {
1371 x++;
1372 if (d < 0) {
1373 d += incr1;
1374 } else {
1375 y--;
1376 d += incr2;
1377 }
1378 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1379 }
1380 }
1381 } else {
1382 /* 2.0.12: Michael Schwartz: divide rather than multiply;
1383 TBB: but watch out for /0! */
1384 double as = sin (atan2 (dy, dx));
1385 if (as != 0) {
1386 wid = thick / as;
1387 } else {
1388 wid = 1;
1389 }
1390 vert = 0;
1391
1392 d = 2 * dx - dy;
1393 incr1 = 2 * dx;
1394 incr2 = 2 * (dx - dy);
1395 if (y1 > y2) {
1396 y = y2;
1397 x = x2;
1398 yend = y1;
1399 xdirflag = (-1);
1400 } else {
1401 y = y1;
1402 x = x1;
1403 yend = y2;
1404 xdirflag = 1;
1405 }
1406 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1407 if (((x2 - x1) * xdirflag) > 0) {
1408 while (y < yend) {
1409 y++;
1410 if (d < 0) {
1411 d += incr1;
1412 } else {
1413 x++;
1414 d += incr2;
1415 }
1416 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1417 }
1418 } else {
1419 while (y < yend) {
1420 y++;
1421 if (d < 0) {
1422 d += incr1;
1423 } else {
1424 x--;
1425 d += incr2;
1426 }
1427 dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1428 }
1429 }
1430 }
1431 }
1432
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1433 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
1434 {
1435 int dashStep = *dashStepP;
1436 int on = *onP;
1437 int w, wstart;
1438
1439 dashStep++;
1440 if (dashStep == gdDashSize) {
1441 dashStep = 0;
1442 on = !on;
1443 }
1444 if (on) {
1445 if (vert) {
1446 wstart = y - wid / 2;
1447 for (w = wstart; w < wstart + wid; w++) {
1448 gdImageSetPixel(im, x, w, color);
1449 }
1450 } else {
1451 wstart = x - wid / 2;
1452 for (w = wstart; w < wstart + wid; w++) {
1453 gdImageSetPixel(im, w, y, color);
1454 }
1455 }
1456 }
1457 *dashStepP = dashStep;
1458 *onP = on;
1459 }
1460
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1461 void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1462 {
1463 int cx, cy;
1464 int px, py;
1465 int fline;
1466 cx = 0;
1467 cy = 0;
1468 #ifdef CHARSET_EBCDIC
1469 c = ASC (c);
1470 #endif /*CHARSET_EBCDIC */
1471 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1472 return;
1473 }
1474 fline = (c - f->offset) * f->h * f->w;
1475 for (py = y; (py < (y + f->h)); py++) {
1476 for (px = x; (px < (x + f->w)); px++) {
1477 if (f->data[fline + cy * f->w + cx]) {
1478 gdImageSetPixel(im, px, py, color);
1479 }
1480 cx++;
1481 }
1482 cx = 0;
1483 cy++;
1484 }
1485 }
1486
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1487 void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1488 {
1489 int cx, cy;
1490 int px, py;
1491 int fline;
1492 cx = 0;
1493 cy = 0;
1494 #ifdef CHARSET_EBCDIC
1495 c = ASC (c);
1496 #endif /*CHARSET_EBCDIC */
1497 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1498 return;
1499 }
1500 fline = (c - f->offset) * f->h * f->w;
1501 for (py = y; py > (y - f->w); py--) {
1502 for (px = x; px < (x + f->h); px++) {
1503 if (f->data[fline + cy * f->w + cx]) {
1504 gdImageSetPixel(im, px, py, color);
1505 }
1506 cy++;
1507 }
1508 cy = 0;
1509 cx++;
1510 }
1511 }
1512
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1513 void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1514 {
1515 int i;
1516 int l;
1517 l = strlen ((char *) s);
1518 for (i = 0; (i < l); i++) {
1519 gdImageChar(im, f, x, y, s[i], color);
1520 x += f->w;
1521 }
1522 }
1523
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1524 void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1525 {
1526 int i;
1527 int l;
1528 l = strlen ((char *) s);
1529 for (i = 0; (i < l); i++) {
1530 gdImageCharUp(im, f, x, y, s[i], color);
1531 y -= f->w;
1532 }
1533 }
1534
1535 static int strlen16 (unsigned short *s);
1536
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1537 void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1538 {
1539 int i;
1540 int l;
1541 l = strlen16(s);
1542 for (i = 0; (i < l); i++) {
1543 gdImageChar(im, f, x, y, s[i], color);
1544 x += f->w;
1545 }
1546 }
1547
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1548 void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1549 {
1550 int i;
1551 int l;
1552 l = strlen16(s);
1553 for (i = 0; i < l; i++) {
1554 gdImageCharUp(im, f, x, y, s[i], color);
1555 y -= f->w;
1556 }
1557 }
1558
strlen16(unsigned short * s)1559 static int strlen16 (unsigned short *s)
1560 {
1561 int len = 0;
1562 while (*s) {
1563 s++;
1564 len++;
1565 }
1566 return len;
1567 }
1568
1569 #ifndef HAVE_LSQRT
1570 /* If you don't have a nice square root function for longs, you can use
1571 ** this hack
1572 */
lsqrt(long n)1573 long lsqrt (long n)
1574 {
1575 long result = (long) sqrt ((double) n);
1576 return result;
1577 }
1578 #endif
1579
1580 /* s and e are integers modulo 360 (degrees), with 0 degrees
1581 being the rightmost extreme and degrees changing clockwise.
1582 cx and cy are the center in pixels; w and h are the horizontal
1583 and vertical diameter in pixels. */
1584
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1585 void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1586 {
1587 gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
1588 }
1589
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1590 void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1591 {
1592 gdPoint pts[363];
1593 int i, pti;
1594 int lx = 0, ly = 0;
1595 int fx = 0, fy = 0;
1596 int startx, starty, endx, endy;
1597
1598 if ((s % 360) == (e % 360)) {
1599 s = 0; e = 360;
1600 } else {
1601 if (s > 360) {
1602 s = s % 360;
1603 }
1604
1605 if (e > 360) {
1606 e = e % 360;
1607 }
1608
1609 while (s < 0) {
1610 s += 360;
1611 }
1612
1613 while (e < s) {
1614 e += 360;
1615 }
1616 if (s == e) {
1617 s = 0; e = 360;
1618 }
1619 }
1620
1621 for (i = s, pti = 1; i <= e; i++, pti++) {
1622 int x, y;
1623 x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
1624 y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
1625 if (i != s) {
1626 if (!(style & gdChord)) {
1627 if (style & gdNoFill) {
1628 gdImageLine(im, lx, ly, x, y, color);
1629 } else {
1630 if (y == ly) {
1631 pti--; /* don't add this point */
1632 if (((i > 270 || i < 90) && x > lx) || ((i > 90 && i < 270) && x < lx)) {
1633 /* replace the old x coord, if increasing on the
1634 right side or decreasing on the left side */
1635 pts[pti].x = x;
1636 }
1637 } else {
1638 pts[pti].x = x;
1639 pts[pti].y = y;
1640 }
1641 }
1642 }
1643 } else {
1644 fx = x;
1645 fy = y;
1646 if (!(style & (gdChord | gdNoFill))) {
1647 pts[0].x = cx;
1648 pts[0].y = cy;
1649 pts[pti].x = startx = x;
1650 pts[pti].y = starty = y;
1651 }
1652 }
1653 lx = x;
1654 ly = y;
1655 }
1656 if (style & gdChord) {
1657 if (style & gdNoFill) {
1658 if (style & gdEdged) {
1659 gdImageLine(im, cx, cy, lx, ly, color);
1660 gdImageLine(im, cx, cy, fx, fy, color);
1661 }
1662 gdImageLine(im, fx, fy, lx, ly, color);
1663 } else {
1664 pts[0].x = fx;
1665 pts[0].y = fy;
1666 pts[1].x = lx;
1667 pts[1].y = ly;
1668 pts[2].x = cx;
1669 pts[2].y = cy;
1670 gdImageFilledPolygon(im, pts, 3, color);
1671 }
1672 } else {
1673 if (style & gdNoFill) {
1674 if (style & gdEdged) {
1675 gdImageLine(im, cx, cy, lx, ly, color);
1676 gdImageLine(im, cx, cy, fx, fy, color);
1677 }
1678 } else {
1679 if (e - s < 360) {
1680 if (pts[1].x != startx && pts[1].y == starty) {
1681 /* start point has been removed due to y-coord fix => insert it */
1682 for (i = pti; i > 1; i--) {
1683 pts[i].x = pts[i-1].x;
1684 pts[i].y = pts[i-1].y;
1685 }
1686 pts[1].x = startx;
1687 pts[1].y = starty;
1688 pti++;
1689 }
1690 if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
1691 /* end point has been removed due to y-coord fix => insert it */
1692 pts[pti].x = endx;
1693 pts[pti].y = endy;
1694 pti++;
1695 }
1696 }
1697 pts[pti].x = cx;
1698 pts[pti].y = cy;
1699 gdImageFilledPolygon(im, pts, pti+1, color);
1700 }
1701 }
1702 }
1703
1704 /**
1705 * Integer Ellipse functions (gdImageEllipse and gdImageFilledEllipse)
1706 * Function added by Pierre-Alain Joye 02/08/2003 (paj@pearfr.org)
1707 * See the ellipse function simplification for the equation
1708 * as well as the midpoint algorithm.
1709 */
1710
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1711 void gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
1712 {
1713 int x=0,mx1=0,mx2=0,my1=0,my2=0;
1714 long aq,bq,dx,dy,r,rx,ry,a,b;
1715
1716 a=w>>1;
1717 b=h>>1;
1718 gdImageSetPixel(im,mx+a, my, c);
1719 gdImageSetPixel(im,mx-a, my, c);
1720 mx1 = mx-a;my1 = my;
1721 mx2 = mx+a;my2 = my;
1722
1723 aq = a * a;
1724 bq = b * b;
1725 dx = aq << 1;
1726 dy = bq << 1;
1727 r = a * bq;
1728 rx = r << 1;
1729 ry = 0;
1730 x = a;
1731 while (x > 0){
1732 if (r > 0) {
1733 my1++;my2--;
1734 ry +=dx;
1735 r -=ry;
1736 }
1737 if (r <= 0){
1738 x--;
1739 mx1++;mx2--;
1740 rx -=dy;
1741 r +=rx;
1742 }
1743 gdImageSetPixel(im,mx1, my1, c);
1744 gdImageSetPixel(im,mx1, my2, c);
1745 gdImageSetPixel(im,mx2, my1, c);
1746 gdImageSetPixel(im,mx2, my2, c);
1747 }
1748 }
1749
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1750 void gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
1751 {
1752 int x=0,mx1=0,mx2=0,my1=0,my2=0;
1753 long aq,bq,dx,dy,r,rx,ry,a,b;
1754 int i;
1755 int old_y2;
1756
1757 a=w>>1;
1758 b=h>>1;
1759
1760 for (x = mx-a; x <= mx+a; x++) {
1761 gdImageSetPixel(im, x, my, c);
1762 }
1763
1764 mx1 = mx-a;my1 = my;
1765 mx2 = mx+a;my2 = my;
1766
1767 aq = a * a;
1768 bq = b * b;
1769 dx = aq << 1;
1770 dy = bq << 1;
1771 r = a * bq;
1772 rx = r << 1;
1773 ry = 0;
1774 x = a;
1775 old_y2=-2;
1776 while (x > 0){
1777 if (r > 0) {
1778 my1++;my2--;
1779 ry +=dx;
1780 r -=ry;
1781 }
1782 if (r <= 0){
1783 x--;
1784 mx1++;mx2--;
1785 rx -=dy;
1786 r +=rx;
1787 }
1788 if(old_y2!=my2){
1789 for(i=mx1;i<=mx2;i++){
1790 gdImageSetPixel(im,i,my1,c);
1791 gdImageSetPixel(im,i,my2,c);
1792 }
1793 }
1794 old_y2 = my2;
1795 }
1796 }
1797
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1798 void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1799 {
1800 int lastBorder;
1801 /* Seek left */
1802 int leftLimit = -1, rightLimit;
1803 int i, restoreAlphaBlending = 0;
1804
1805 if (border < 0 || color < 0) {
1806 /* Refuse to fill to a non-solid border */
1807 return;
1808 }
1809
1810 if (!im->trueColor) {
1811 if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) {
1812 return;
1813 }
1814 }
1815
1816 restoreAlphaBlending = im->alphaBlendingFlag;
1817 im->alphaBlendingFlag = 0;
1818
1819 if (x >= im->sx) {
1820 x = im->sx - 1;
1821 } else if (x < 0) {
1822 x = 0;
1823 }
1824 if (y >= im->sy) {
1825 y = im->sy - 1;
1826 } else if (y < 0) {
1827 y = 0;
1828 }
1829
1830 for (i = x; i >= 0; i--) {
1831 if (gdImageGetPixel(im, i, y) == border) {
1832 break;
1833 }
1834 gdImageSetPixel(im, i, y, color);
1835 leftLimit = i;
1836 }
1837 if (leftLimit == -1) {
1838 im->alphaBlendingFlag = restoreAlphaBlending;
1839 return;
1840 }
1841 /* Seek right */
1842 rightLimit = x;
1843 for (i = (x + 1); i < im->sx; i++) {
1844 if (gdImageGetPixel(im, i, y) == border) {
1845 break;
1846 }
1847 gdImageSetPixel(im, i, y, color);
1848 rightLimit = i;
1849 }
1850 /* Look at lines above and below and start paints */
1851 /* Above */
1852 if (y > 0) {
1853 lastBorder = 1;
1854 for (i = leftLimit; i <= rightLimit; i++) {
1855 int c = gdImageGetPixel(im, i, y - 1);
1856 if (lastBorder) {
1857 if ((c != border) && (c != color)) {
1858 gdImageFillToBorder(im, i, y - 1, border, color);
1859 lastBorder = 0;
1860 }
1861 } else if ((c == border) || (c == color)) {
1862 lastBorder = 1;
1863 }
1864 }
1865 }
1866
1867 /* Below */
1868 if (y < ((im->sy) - 1)) {
1869 lastBorder = 1;
1870 for (i = leftLimit; i <= rightLimit; i++) {
1871 int c = gdImageGetPixel(im, i, y + 1);
1872
1873 if (lastBorder) {
1874 if ((c != border) && (c != color)) {
1875 gdImageFillToBorder(im, i, y + 1, border, color);
1876 lastBorder = 0;
1877 }
1878 } else if ((c == border) || (c == color)) {
1879 lastBorder = 1;
1880 }
1881 }
1882 }
1883 im->alphaBlendingFlag = restoreAlphaBlending;
1884 }
1885
1886 /*
1887 * set the pixel at (x,y) and its 4-connected neighbors
1888 * with the same pixel value to the new pixel value nc (new color).
1889 * A 4-connected neighbor: pixel above, below, left, or right of a pixel.
1890 * ideas from comp.graphics discussions.
1891 * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
1892 * contain the same color as the color to fill. To do not bloat normal filling
1893 * code I added a 2nd private function.
1894 */
1895
1896 /* horizontal segment of scan line y */
1897 struct seg {int y, xl, xr, dy;};
1898
1899 /* max depth of stack */
1900 #define FILL_MAX ((int)(im->sy*im->sx)/4)
1901 #define FILL_PUSH(Y, XL, XR, DY) \
1902 if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
1903 {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
1904
1905 #define FILL_POP(Y, XL, XR, DY) \
1906 {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
1907
1908 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
1909
gdImageFill(gdImagePtr im,int x,int y,int nc)1910 void gdImageFill(gdImagePtr im, int x, int y, int nc)
1911 {
1912 int l, x1, x2, dy;
1913 int oc; /* old pixel value */
1914 int wx2,wy2;
1915
1916 int alphablending_bak;
1917
1918 /* stack of filled segments */
1919 /* struct seg stack[FILL_MAX],*sp = stack;; */
1920 struct seg *stack = NULL;
1921 struct seg *sp;
1922
1923 if (!im->trueColor && nc > (im->colorsTotal -1)) {
1924 return;
1925 }
1926
1927 alphablending_bak = im->alphaBlendingFlag;
1928 im->alphaBlendingFlag = 0;
1929
1930 if (nc==gdTiled){
1931 _gdImageFillTiled(im,x,y,nc);
1932 im->alphaBlendingFlag = alphablending_bak;
1933 return;
1934 }
1935
1936 wx2=im->sx;wy2=im->sy;
1937 oc = gdImageGetPixel(im, x, y);
1938 if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
1939 im->alphaBlendingFlag = alphablending_bak;
1940 return;
1941 }
1942
1943 /* Do not use the 4 neighbors implementation with
1944 * small images
1945 */
1946 if (im->sx < 4) {
1947 int ix = x, iy = y, c;
1948 do {
1949 do {
1950 c = gdImageGetPixel(im, ix, iy);
1951 if (c != oc) {
1952 goto done;
1953 }
1954 gdImageSetPixel(im, ix, iy, nc);
1955 } while(ix++ < (im->sx -1));
1956 ix = x;
1957 } while(iy++ < (im->sy -1));
1958 goto done;
1959 }
1960
1961 stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
1962 sp = stack;
1963
1964 /* required! */
1965 FILL_PUSH(y,x,x,1);
1966 /* seed segment (popped 1st) */
1967 FILL_PUSH(y+1, x, x, -1);
1968 while (sp>stack) {
1969 FILL_POP(y, x1, x2, dy);
1970
1971 for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
1972 gdImageSetPixel(im,x, y, nc);
1973 }
1974 if (x>=x1) {
1975 goto skip;
1976 }
1977 l = x+1;
1978
1979 /* leak on left? */
1980 if (l<x1) {
1981 FILL_PUSH(y, l, x1-1, -dy);
1982 }
1983 x = x1+1;
1984 do {
1985 for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
1986 gdImageSetPixel(im, x, y, nc);
1987 }
1988 FILL_PUSH(y, l, x-1, dy);
1989 /* leak on right? */
1990 if (x>x2+1) {
1991 FILL_PUSH(y, x2+1, x-1, -dy);
1992 }
1993 skip: for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
1994
1995 l = x;
1996 } while (x<=x2);
1997 }
1998
1999 efree(stack);
2000
2001 done:
2002 im->alphaBlendingFlag = alphablending_bak;
2003 }
2004
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2005 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2006 {
2007 int i, l, x1, x2, dy;
2008 int oc; /* old pixel value */
2009 int wx2,wy2;
2010 /* stack of filled segments */
2011 struct seg *stack;
2012 struct seg *sp;
2013 char **pts;
2014
2015 if (!im->tile) {
2016 return;
2017 }
2018
2019 wx2=im->sx;wy2=im->sy;
2020
2021 nc = gdImageTileGet(im,x,y);
2022
2023 pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
2024 for (i = 0; i < im->sy + 1; i++) {
2025 pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
2026 }
2027
2028 stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2029 sp = stack;
2030
2031 oc = gdImageGetPixel(im, x, y);
2032
2033 /* required! */
2034 FILL_PUSH(y,x,x,1);
2035 /* seed segment (popped 1st) */
2036 FILL_PUSH(y+1, x, x, -1);
2037 while (sp>stack) {
2038 FILL_POP(y, x1, x2, dy);
2039 for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
2040 nc = gdImageTileGet(im,x,y);
2041 pts[y][x] = 1;
2042 gdImageSetPixel(im,x, y, nc);
2043 }
2044 if (x>=x1) {
2045 goto skip;
2046 }
2047 l = x+1;
2048
2049 /* leak on left? */
2050 if (l<x1) {
2051 FILL_PUSH(y, l, x1-1, -dy);
2052 }
2053 x = x1+1;
2054 do {
2055 for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
2056 nc = gdImageTileGet(im,x,y);
2057 pts[y][x] = 1;
2058 gdImageSetPixel(im, x, y, nc);
2059 }
2060 FILL_PUSH(y, l, x-1, dy);
2061 /* leak on right? */
2062 if (x>x2+1) {
2063 FILL_PUSH(y, x2+1, x-1, -dy);
2064 }
2065 skip: for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
2066 l = x;
2067 } while (x<=x2);
2068 }
2069
2070 for(i = 0; i < im->sy + 1; i++) {
2071 efree(pts[i]);
2072 }
2073
2074 efree(pts);
2075 efree(stack);
2076 }
2077
2078
2079
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2080 void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2081 {
2082 int thick = im->thick;
2083 int t;
2084
2085 if (x1 == x2 && y1 == y2 && thick == 1) {
2086 gdImageSetPixel(im, x1, y1, color);
2087 return;
2088 }
2089
2090 if (y2 < y1) {
2091 t=y1;
2092 y1 = y2;
2093 y2 = t;
2094 }
2095
2096 if (x2 < x1) {
2097 t = x1;
2098 x1 = x2;
2099 x2 = t;
2100 }
2101
2102 if (thick > 1) {
2103 int cx, cy, x1ul, y1ul, x2lr, y2lr;
2104 int half = thick >> 1;
2105
2106 x1ul = x1 - half;
2107 y1ul = y1 - half;
2108
2109 x2lr = x2 + half;
2110 y2lr = y2 + half;
2111
2112 cy = y1ul + thick;
2113 while (cy-- > y1ul) {
2114 cx = x1ul - 1;
2115 while (cx++ < x2lr) {
2116 gdImageSetPixel(im, cx, cy, color);
2117 }
2118 }
2119
2120 cy = y2lr - thick;
2121 while (cy++ < y2lr) {
2122 cx = x1ul - 1;
2123 while (cx++ < x2lr) {
2124 gdImageSetPixel(im, cx, cy, color);
2125 }
2126 }
2127
2128 cy = y1ul + thick - 1;
2129 while (cy++ < y2lr -thick) {
2130 cx = x1ul - 1;
2131 while (cx++ < x1ul + thick) {
2132 gdImageSetPixel(im, cx, cy, color);
2133 }
2134 }
2135
2136 cy = y1ul + thick - 1;
2137 while (cy++ < y2lr -thick) {
2138 cx = x2lr - thick - 1;
2139 while (cx++ < x2lr) {
2140 gdImageSetPixel(im, cx, cy, color);
2141 }
2142 }
2143
2144 return;
2145 } else {
2146 if (x1 == x2 || y1 == y2) {
2147 gdImageLine(im, x1, y1, x2, y2, color);
2148 } else {
2149 gdImageLine(im, x1, y1, x2, y1, color);
2150 gdImageLine(im, x1, y2, x2, y2, color);
2151 gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2152 gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2153 }
2154 }
2155 }
2156
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2157 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2158 {
2159 int x, y;
2160
2161 if (x1 == x2 && y1 == y2) {
2162 gdImageSetPixel(im, x1, y1, color);
2163 return;
2164 }
2165
2166 if (x1 > x2) {
2167 x = x1;
2168 x1 = x2;
2169 x2 = x;
2170 }
2171
2172 if (y1 > y2) {
2173 y = y1;
2174 y1 = y2;
2175 y2 = y;
2176 }
2177
2178 if (x1 < 0) {
2179 x1 = 0;
2180 }
2181
2182 if (x2 >= gdImageSX(im)) {
2183 x2 = gdImageSX(im) - 1;
2184 }
2185
2186 if (y1 < 0) {
2187 y1 = 0;
2188 }
2189
2190 if (y2 >= gdImageSY(im)) {
2191 y2 = gdImageSY(im) - 1;
2192 }
2193
2194 for (x = x1; (x <= x2); x++) {
2195 for (y = y1; (y <= y2); y++) {
2196 gdImageSetPixel (im, x, y, color);
2197 }
2198 }
2199 }
2200
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2201 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2202 {
2203 int x, y;
2204
2205 if (x1 == x2 && y1 == y2) {
2206 gdImageSetPixel(im, x1, y1, color);
2207 return;
2208 }
2209
2210 if (x1 > x2) {
2211 x = x1;
2212 x1 = x2;
2213 x2 = x;
2214 }
2215
2216 if (y1 > y2) {
2217 y = y1;
2218 y1 = y2;
2219 y2 = y;
2220 }
2221
2222 if (x1 < 0) {
2223 x1 = 0;
2224 }
2225
2226 if (x2 >= gdImageSX(im)) {
2227 x2 = gdImageSX(im) - 1;
2228 }
2229
2230 if (y1 < 0) {
2231 y1 = 0;
2232 }
2233
2234 if (y2 >= gdImageSY(im)) {
2235 y2 = gdImageSY(im) - 1;
2236 }
2237
2238 for (y = y1; (y <= y2); y++) {
2239 for (x = x1; (x <= x2); x++) {
2240 gdImageSetPixel (im, x, y, color);
2241 }
2242 }
2243 }
2244
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2245 void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2246 {
2247 _gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2248 }
2249
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2250 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
2251 {
2252 int c;
2253 int x, y;
2254 int tox, toy;
2255 int i;
2256 int colorMap[gdMaxColors];
2257
2258 if (dst->trueColor) {
2259 /* 2.0: much easier when the destination is truecolor. */
2260 /* 2.0.10: needs a transparent-index check that is still valid if
2261 * the source is not truecolor. Thanks to Frank Warmerdam.
2262 */
2263
2264 if (src->trueColor) {
2265 for (y = 0; (y < h); y++) {
2266 for (x = 0; (x < w); x++) {
2267 int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2268 if (c != src->transparent) {
2269 gdImageSetPixel (dst, dstX + x, dstY + y, c);
2270 }
2271 }
2272 }
2273 } else {
2274 /* source is palette based */
2275 for (y = 0; (y < h); y++) {
2276 for (x = 0; (x < w); x++) {
2277 int c = gdImageGetPixel (src, srcX + x, srcY + y);
2278 if (c != src->transparent) {
2279 gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2280 }
2281 }
2282 }
2283 }
2284 return;
2285 }
2286
2287 /* Palette based to palette based */
2288 for (i = 0; i < gdMaxColors; i++) {
2289 colorMap[i] = (-1);
2290 }
2291 toy = dstY;
2292 for (y = srcY; y < (srcY + h); y++) {
2293 tox = dstX;
2294 for (x = srcX; x < (srcX + w); x++) {
2295 int nc;
2296 int mapTo;
2297 c = gdImageGetPixel (src, x, y);
2298 /* Added 7/24/95: support transparent copies */
2299 if (gdImageGetTransparent (src) == c) {
2300 tox++;
2301 continue;
2302 }
2303 /* Have we established a mapping for this color? */
2304 if (src->trueColor) {
2305 /* 2.05: remap to the palette available in the destination image. This is slow and
2306 * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
2307 */
2308 mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
2309 } else if (colorMap[c] == (-1)) {
2310 /* If it's the same image, mapping is trivial */
2311 if (dst == src) {
2312 nc = c;
2313 } else {
2314 /* Get best match possible. This function never returns error. */
2315 nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
2316 }
2317 colorMap[c] = nc;
2318 mapTo = colorMap[c];
2319 } else {
2320 mapTo = colorMap[c];
2321 }
2322 gdImageSetPixel (dst, tox, toy, mapTo);
2323 tox++;
2324 }
2325 toy++;
2326 }
2327 }
2328
2329 /* This function is a substitute for real alpha channel operations,
2330 so it doesn't pay attention to the alpha channel. */
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2331 void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2332 {
2333 int c, dc;
2334 int x, y;
2335 int tox, toy;
2336 int ncR, ncG, ncB;
2337 toy = dstY;
2338
2339 for (y = srcY; y < (srcY + h); y++) {
2340 tox = dstX;
2341 for (x = srcX; x < (srcX + w); x++) {
2342 int nc;
2343 c = gdImageGetPixel(src, x, y);
2344 /* Added 7/24/95: support transparent copies */
2345 if (gdImageGetTransparent(src) == c) {
2346 tox++;
2347 continue;
2348 }
2349 /* If it's the same image, mapping is trivial */
2350 if (dst == src) {
2351 nc = c;
2352 } else {
2353 dc = gdImageGetPixel(dst, tox, toy);
2354
2355 ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
2356 ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
2357 ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
2358
2359 /* Find a reasonable color */
2360 nc = gdImageColorResolve (dst, ncR, ncG, ncB);
2361 }
2362 gdImageSetPixel (dst, tox, toy, nc);
2363 tox++;
2364 }
2365 toy++;
2366 }
2367 }
2368
2369 /* This function is a substitute for real alpha channel operations,
2370 so it doesn't pay attention to the alpha channel. */
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2371 void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2372 {
2373 int c, dc;
2374 int x, y;
2375 int tox, toy;
2376 int ncR, ncG, ncB;
2377 float g;
2378 toy = dstY;
2379
2380 for (y = srcY; (y < (srcY + h)); y++) {
2381 tox = dstX;
2382 for (x = srcX; (x < (srcX + w)); x++) {
2383 int nc;
2384 c = gdImageGetPixel (src, x, y);
2385 /* Added 7/24/95: support transparent copies */
2386 if (gdImageGetTransparent(src) == c) {
2387 tox++;
2388 continue;
2389 }
2390
2391 /*
2392 * If it's the same image, mapping is NOT trivial since we
2393 * merge with greyscale target, but if pct is 100, the grey
2394 * value is not used, so it becomes trivial. pjw 2.0.12.
2395 */
2396 if (dst == src && pct == 100) {
2397 nc = c;
2398 } else {
2399 dc = gdImageGetPixel(dst, tox, toy);
2400 g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
2401
2402 ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2403 ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2404 ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2405
2406
2407 /* First look for an exact match */
2408 nc = gdImageColorExact(dst, ncR, ncG, ncB);
2409 if (nc == (-1)) {
2410 /* No, so try to allocate it */
2411 nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
2412 /* If we're out of colors, go for the closest color */
2413 if (nc == (-1)) {
2414 nc = gdImageColorClosest(dst, ncR, ncG, ncB);
2415 }
2416 }
2417 }
2418 gdImageSetPixel(dst, tox, toy, nc);
2419 tox++;
2420 }
2421 toy++;
2422 }
2423 }
2424
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2425 void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2426 {
2427 int c;
2428 int x, y;
2429 int tox, toy;
2430 int ydest;
2431 int i;
2432 int colorMap[gdMaxColors];
2433 /* Stretch vectors */
2434 int *stx, *sty;
2435
2436 if (overflow2(sizeof(int), srcW)) {
2437 return;
2438 }
2439 if (overflow2(sizeof(int), srcH)) {
2440 return;
2441 }
2442
2443 stx = (int *) gdMalloc (sizeof (int) * srcW);
2444 sty = (int *) gdMalloc (sizeof (int) * srcH);
2445
2446 /* Fixed by Mao Morimoto 2.0.16 */
2447 for (i = 0; (i < srcW); i++) {
2448 stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
2449 }
2450 for (i = 0; (i < srcH); i++) {
2451 sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
2452 }
2453 for (i = 0; (i < gdMaxColors); i++) {
2454 colorMap[i] = (-1);
2455 }
2456 toy = dstY;
2457 for (y = srcY; (y < (srcY + srcH)); y++) {
2458 for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
2459 tox = dstX;
2460 for (x = srcX; (x < (srcX + srcW)); x++) {
2461 int nc = 0;
2462 int mapTo;
2463 if (!stx[x - srcX]) {
2464 continue;
2465 }
2466 if (dst->trueColor) {
2467 /* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
2468 if (!src->trueColor) {
2469 int tmp = gdImageGetPixel (src, x, y);
2470 mapTo = gdImageGetTrueColorPixel (src, x, y);
2471 if (gdImageGetTransparent (src) == tmp) {
2472 /* 2.0.21, TK: not tox++ */
2473 tox += stx[x - srcX];
2474 continue;
2475 }
2476 } else {
2477 /* TK: old code follows */
2478 mapTo = gdImageGetTrueColorPixel (src, x, y);
2479 /* Added 7/24/95: support transparent copies */
2480 if (gdImageGetTransparent (src) == mapTo) {
2481 /* 2.0.21, TK: not tox++ */
2482 tox += stx[x - srcX];
2483 continue;
2484 }
2485 }
2486 } else {
2487 c = gdImageGetPixel (src, x, y);
2488 /* Added 7/24/95: support transparent copies */
2489 if (gdImageGetTransparent (src) == c) {
2490 tox += stx[x - srcX];
2491 continue;
2492 }
2493 if (src->trueColor) {
2494 /* Remap to the palette available in the destination image. This is slow and works badly. */
2495 mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
2496 gdTrueColorGetGreen(c),
2497 gdTrueColorGetBlue(c),
2498 gdTrueColorGetAlpha (c));
2499 } else {
2500 /* Have we established a mapping for this color? */
2501 if (colorMap[c] == (-1)) {
2502 /* If it's the same image, mapping is trivial */
2503 if (dst == src) {
2504 nc = c;
2505 } else {
2506 /* Find or create the best match */
2507 /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
2508 nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
2509 gdImageGreen(src, c),
2510 gdImageBlue(src, c),
2511 gdImageAlpha(src, c));
2512 }
2513 colorMap[c] = nc;
2514 }
2515 mapTo = colorMap[c];
2516 }
2517 }
2518 for (i = 0; (i < stx[x - srcX]); i++) {
2519 gdImageSetPixel (dst, tox, toy, mapTo);
2520 tox++;
2521 }
2522 }
2523 toy++;
2524 }
2525 }
2526 gdFree (stx);
2527 gdFree (sty);
2528 }
2529
2530 /* When gd 1.x was first created, floating point was to be avoided.
2531 These days it is often faster than table lookups or integer
2532 arithmetic. The routine below is shamelessly, gloriously
2533 floating point. TBB */
2534
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2535 void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2536 {
2537 int x, y;
2538 double sy1, sy2, sx1, sx2;
2539
2540 if (!dst->trueColor) {
2541 gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
2542 return;
2543 }
2544 for (y = dstY; (y < dstY + dstH); y++) {
2545 sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
2546 sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
2547 for (x = dstX; (x < dstX + dstW); x++) {
2548 double sx, sy;
2549 double spixels = 0;
2550 double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2551 double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
2552 sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
2553 sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
2554 sy = sy1;
2555 do {
2556 double yportion;
2557 if (floor_cast(sy) == floor_cast(sy1)) {
2558 yportion = 1.0f - (sy - floor_cast(sy));
2559 if (yportion > sy2 - sy1) {
2560 yportion = sy2 - sy1;
2561 }
2562 sy = floor_cast(sy);
2563 } else if (sy == floorf(sy2)) {
2564 yportion = sy2 - floor_cast(sy2);
2565 } else {
2566 yportion = 1.0f;
2567 }
2568 sx = sx1;
2569 do {
2570 double xportion;
2571 double pcontribution;
2572 int p;
2573 if (floorf(sx) == floor_cast(sx1)) {
2574 xportion = 1.0f - (sx - floor_cast(sx));
2575 if (xportion > sx2 - sx1) {
2576 xportion = sx2 - sx1;
2577 }
2578 sx = floor_cast(sx);
2579 } else if (sx == floorf(sx2)) {
2580 xportion = sx2 - floor_cast(sx2);
2581 } else {
2582 xportion = 1.0f;
2583 }
2584 pcontribution = xportion * yportion;
2585 p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
2586
2587 alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
2588 red += gdTrueColorGetRed (p) * alpha_factor;
2589 green += gdTrueColorGetGreen (p) * alpha_factor;
2590 blue += gdTrueColorGetBlue (p) * alpha_factor;
2591 alpha += gdTrueColorGetAlpha (p) * pcontribution;
2592 alpha_sum += alpha_factor;
2593 contrib_sum += pcontribution;
2594 spixels += xportion * yportion;
2595 sx += 1.0f;
2596 }
2597 while (sx < sx2);
2598
2599 sy += 1.0f;
2600 }
2601
2602 while (sy < sy2);
2603
2604 if (spixels != 0.0f) {
2605 red /= spixels;
2606 green /= spixels;
2607 blue /= spixels;
2608 alpha /= spixels;
2609 alpha += 0.5;
2610 }
2611 if ( alpha_sum != 0.0f) {
2612 if( contrib_sum != 0.0f) {
2613 alpha_sum /= contrib_sum;
2614 }
2615 red /= alpha_sum;
2616 green /= alpha_sum;
2617 blue /= alpha_sum;
2618 }
2619 /* Clamping to allow for rounding errors above */
2620 if (red > 255.0f) {
2621 red = 255.0f;
2622 }
2623 if (green > 255.0f) {
2624 green = 255.0f;
2625 }
2626 if (blue > 255.0f) {
2627 blue = 255.0f;
2628 }
2629 if (alpha > gdAlphaMax) {
2630 alpha = gdAlphaMax;
2631 }
2632 gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
2633 }
2634 }
2635 }
2636
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2637 void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2638 {
2639 if (n <= 0) {
2640 return;
2641 }
2642
2643
2644 gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
2645 gdImageOpenPolygon (im, p, n, c);
2646 }
2647
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2648 void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2649 {
2650 int i;
2651 int lx, ly;
2652
2653 if (n <= 0) {
2654 return;
2655 }
2656
2657 lx = p->x;
2658 ly = p->y;
2659 for (i = 1; i < n; i++) {
2660 p++;
2661 gdImageLine(im, lx, ly, p->x, p->y, c);
2662 lx = p->x;
2663 ly = p->y;
2664 }
2665 }
2666
2667 int gdCompareInt (const void *a, const void *b);
2668
2669 /* THANKS to Kirsten Schulz for the polygon fixes! */
2670
2671 /* The intersection finding technique of this code could be improved
2672 * by remembering the previous intertersection, and by using the slope.
2673 * That could help to adjust intersections to produce a nice
2674 * interior_extrema.
2675 */
2676
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2677 void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2678 {
2679 int i;
2680 int y;
2681 int miny, maxy, pmaxy;
2682 int x1, y1;
2683 int x2, y2;
2684 int ind1, ind2;
2685 int ints;
2686 int fill_color;
2687
2688 if (n <= 0) {
2689 return;
2690 }
2691
2692 if (overflow2(sizeof(int), n)) {
2693 return;
2694 }
2695
2696 if (c == gdAntiAliased) {
2697 fill_color = im->AA_color;
2698 } else {
2699 fill_color = c;
2700 }
2701
2702 if (!im->polyAllocated) {
2703 im->polyInts = (int *) gdMalloc(sizeof(int) * n);
2704 im->polyAllocated = n;
2705 }
2706 if (im->polyAllocated < n) {
2707 while (im->polyAllocated < n) {
2708 im->polyAllocated *= 2;
2709 }
2710 if (overflow2(sizeof(int), im->polyAllocated)) {
2711 return;
2712 }
2713 im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
2714 }
2715 miny = p[0].y;
2716 maxy = p[0].y;
2717 for (i = 1; i < n; i++) {
2718 if (p[i].y < miny) {
2719 miny = p[i].y;
2720 }
2721 if (p[i].y > maxy) {
2722 maxy = p[i].y;
2723 }
2724 }
2725 /* necessary special case: horizontal line */
2726 if (n > 1 && miny == maxy) {
2727 x1 = x2 = p[0].x;
2728 for (i = 1; (i < n); i++) {
2729 if (p[i].x < x1) {
2730 x1 = p[i].x;
2731 } else if (p[i].x > x2) {
2732 x2 = p[i].x;
2733 }
2734 }
2735 gdImageLine(im, x1, miny, x2, miny, c);
2736 return;
2737 }
2738 pmaxy = maxy;
2739 /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
2740 if (miny < 0) {
2741 miny = 0;
2742 }
2743 if (maxy >= gdImageSY(im)) {
2744 maxy = gdImageSY(im) - 1;
2745 }
2746
2747 /* Fix in 1.3: count a vertex only once */
2748 for (y = miny; y <= maxy; y++) {
2749 /*1.4 int interLast = 0; */
2750 /* int dirLast = 0; */
2751 /* int interFirst = 1; */
2752 ints = 0;
2753 for (i = 0; i < n; i++) {
2754 if (!i) {
2755 ind1 = n - 1;
2756 ind2 = 0;
2757 } else {
2758 ind1 = i - 1;
2759 ind2 = i;
2760 }
2761 y1 = p[ind1].y;
2762 y2 = p[ind2].y;
2763 if (y1 < y2) {
2764 x1 = p[ind1].x;
2765 x2 = p[ind2].x;
2766 } else if (y1 > y2) {
2767 y2 = p[ind1].y;
2768 y1 = p[ind2].y;
2769 x2 = p[ind1].x;
2770 x1 = p[ind2].x;
2771 } else {
2772 continue;
2773 }
2774 /* Do the following math as float intermediately, and round to ensure
2775 * that Polygon and FilledPolygon for the same set of points have the
2776 * same footprint.
2777 */
2778 if (y >= y1 && y < y2) {
2779 im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
2780 } else if (y == pmaxy && y == y2) {
2781 im->polyInts[ints++] = x2;
2782 }
2783 }
2784 qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2785
2786 for (i = 0; i < ints - 1; i += 2) {
2787 gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
2788 }
2789 }
2790
2791 /* If we are drawing this AA, then redraw the border with AA lines. */
2792 if (c == gdAntiAliased) {
2793 gdImagePolygon(im, p, n, c);
2794 }
2795 }
2796
gdCompareInt(const void * a,const void * b)2797 int gdCompareInt (const void *a, const void *b)
2798 {
2799 return (*(const int *) a) - (*(const int *) b);
2800 }
2801
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2802 void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2803 {
2804 if (im->style) {
2805 gdFree(im->style);
2806 }
2807 if (overflow2(sizeof (int), noOfPixels)) {
2808 return;
2809 }
2810 im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
2811 memcpy(im->style, style, sizeof(int) * noOfPixels);
2812 im->styleLength = noOfPixels;
2813 im->stylePos = 0;
2814 }
2815
gdImageSetThickness(gdImagePtr im,int thickness)2816 void gdImageSetThickness (gdImagePtr im, int thickness)
2817 {
2818 im->thick = thickness;
2819 }
2820
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2821 void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2822 {
2823 int i;
2824 im->brush = brush;
2825 if (!im->trueColor && !im->brush->trueColor) {
2826 for (i = 0; i < gdImageColorsTotal(brush); i++) {
2827 int index;
2828 index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
2829 im->brushColorMap[i] = index;
2830 }
2831 }
2832 }
2833
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2834 void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2835 {
2836 int i;
2837 im->tile = tile;
2838 if (!im->trueColor && !im->tile->trueColor) {
2839 for (i = 0; i < gdImageColorsTotal(tile); i++) {
2840 int index;
2841 index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
2842 im->tileColorMap[i] = index;
2843 }
2844 }
2845 }
2846
gdImageSetAntiAliased(gdImagePtr im,int c)2847 void gdImageSetAntiAliased (gdImagePtr im, int c)
2848 {
2849 im->AA = 1;
2850 im->AA_color = c;
2851 im->AA_dont_blend = -1;
2852 }
2853
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)2854 void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
2855 {
2856 im->AA = 1;
2857 im->AA_color = c;
2858 im->AA_dont_blend = dont_blend;
2859 }
2860
2861
gdImageInterlace(gdImagePtr im,int interlaceArg)2862 void gdImageInterlace (gdImagePtr im, int interlaceArg)
2863 {
2864 im->interlace = interlaceArg;
2865 }
2866
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2867 int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2868 {
2869 int x, y;
2870 int p1, p2;
2871 int cmpStatus = 0;
2872 int sx, sy;
2873
2874 if (im1->interlace != im2->interlace) {
2875 cmpStatus |= GD_CMP_INTERLACE;
2876 }
2877
2878 if (im1->transparent != im2->transparent) {
2879 cmpStatus |= GD_CMP_TRANSPARENT;
2880 }
2881
2882 if (im1->trueColor != im2->trueColor) {
2883 cmpStatus |= GD_CMP_TRUECOLOR;
2884 }
2885
2886 sx = im1->sx;
2887 if (im1->sx != im2->sx) {
2888 cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2889 if (im2->sx < im1->sx) {
2890 sx = im2->sx;
2891 }
2892 }
2893
2894 sy = im1->sy;
2895 if (im1->sy != im2->sy) {
2896 cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2897 if (im2->sy < im1->sy) {
2898 sy = im2->sy;
2899 }
2900 }
2901
2902 if (im1->colorsTotal != im2->colorsTotal) {
2903 cmpStatus |= GD_CMP_NUM_COLORS;
2904 }
2905
2906 for (y = 0; y < sy; y++) {
2907 for (x = 0; x < sx; x++) {
2908 p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
2909 p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
2910
2911 if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
2912 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2913 break;
2914 }
2915 if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
2916 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2917 break;
2918 }
2919 if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
2920 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2921 break;
2922 }
2923 #if 0
2924 /* Soon we'll add alpha channel to palettes */
2925 if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
2926 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2927 break;
2928 }
2929 #endif
2930 }
2931 if (cmpStatus & GD_CMP_COLOR) {
2932 break;
2933 }
2934 }
2935
2936 return cmpStatus;
2937 }
2938
gdAlphaBlend(int dst,int src)2939 int gdAlphaBlend (int dst, int src) {
2940 int src_alpha = gdTrueColorGetAlpha(src);
2941 int dst_alpha, alpha, red, green, blue;
2942 int src_weight, dst_weight, tot_weight;
2943
2944 /* -------------------------------------------------------------------- */
2945 /* Simple cases we want to handle fast. */
2946 /* -------------------------------------------------------------------- */
2947 if( src_alpha == gdAlphaOpaque )
2948 return src;
2949
2950 dst_alpha = gdTrueColorGetAlpha(dst);
2951 if( src_alpha == gdAlphaTransparent )
2952 return dst;
2953 if( dst_alpha == gdAlphaTransparent )
2954 return src;
2955
2956 /* -------------------------------------------------------------------- */
2957 /* What will the source and destination alphas be? Note that */
2958 /* the destination weighting is substantially reduced as the */
2959 /* overlay becomes quite opaque. */
2960 /* -------------------------------------------------------------------- */
2961 src_weight = gdAlphaTransparent - src_alpha;
2962 dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
2963 tot_weight = src_weight + dst_weight;
2964
2965 /* -------------------------------------------------------------------- */
2966 /* What red, green and blue result values will we use? */
2967 /* -------------------------------------------------------------------- */
2968 alpha = src_alpha * dst_alpha / gdAlphaMax;
2969
2970 red = (gdTrueColorGetRed(src) * src_weight
2971 + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
2972 green = (gdTrueColorGetGreen(src) * src_weight
2973 + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
2974 blue = (gdTrueColorGetBlue(src) * src_weight
2975 + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
2976
2977 /* -------------------------------------------------------------------- */
2978 /* Return merged result. */
2979 /* -------------------------------------------------------------------- */
2980 return ((alpha << 24) + (red << 16) + (green << 8) + blue);
2981
2982 }
2983
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)2984 void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
2985 {
2986 im->alphaBlendingFlag = alphaBlendingArg;
2987 }
2988
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)2989 void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
2990 {
2991 im->saveAlphaFlag = saveAlphaArg;
2992 }
2993
gdLayerOverlay(int dst,int src)2994 int gdLayerOverlay (int dst, int src)
2995 {
2996 int a1, a2;
2997 a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
2998 a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
2999 return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
3000 (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
3001 (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
3002 (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
3003 );
3004 }
3005
gdAlphaOverlayColor(int src,int dst,int max)3006 static int gdAlphaOverlayColor (int src, int dst, int max )
3007 {
3008 /* this function implements the algorithm
3009 *
3010 * for dst[rgb] < 0.5,
3011 * c[rgb] = 2.src[rgb].dst[rgb]
3012 * and for dst[rgb] > 0.5,
3013 * c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
3014 *
3015 */
3016
3017 dst = dst << 1;
3018 if( dst > max ) {
3019 /* in the "light" zone */
3020 return dst + (src << 1) - (dst * src / max) - max;
3021 } else {
3022 /* in the "dark" zone */
3023 return dst * src / max;
3024 }
3025 }
3026
gdLayerMultiply(int dst,int src)3027 int gdLayerMultiply (int dst, int src)
3028 {
3029 int a1, a2, r1, r2, g1, g2, b1, b2;
3030 a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
3031 a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3032
3033 r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
3034 r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
3035 g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
3036 g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
3037 b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
3038 b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
3039
3040 a1 = gdAlphaMax - a1;
3041 a2 = gdAlphaMax - a2;
3042 return ( ((a1*a2/gdAlphaMax) << 24) +
3043 ((r1*r2/gdRedMax) << 16) +
3044 ((g1*g2/gdGreenMax) << 8) +
3045 ((b1*b2/gdBlueMax))
3046 );
3047 }
3048
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)3049 void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
3050 {
3051 if (x1 < 0) {
3052 x1 = 0;
3053 }
3054 if (x1 >= im->sx) {
3055 x1 = im->sx - 1;
3056 }
3057 if (x2 < 0) {
3058 x2 = 0;
3059 }
3060 if (x2 >= im->sx) {
3061 x2 = im->sx - 1;
3062 }
3063 if (y1 < 0) {
3064 y1 = 0;
3065 }
3066 if (y1 >= im->sy) {
3067 y1 = im->sy - 1;
3068 }
3069 if (y2 < 0) {
3070 y2 = 0;
3071 }
3072 if (y2 >= im->sy) {
3073 y2 = im->sy - 1;
3074 }
3075 im->cx1 = x1;
3076 im->cy1 = y1;
3077 im->cx2 = x2;
3078 im->cy2 = y2;
3079 }
3080
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)3081 void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
3082 {
3083 *x1P = im->cx1;
3084 *y1P = im->cy1;
3085 *x2P = im->cx2;
3086 *y2P = im->cy2;
3087 }
3088
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)3089 void gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
3090 {
3091 if (res_x > 0) im->res_x = res_x;
3092 if (res_y > 0) im->res_y = res_y;
3093 }
3094
3095 /* convert a palette image to true color */
gdImagePaletteToTrueColor(gdImagePtr src)3096 int gdImagePaletteToTrueColor(gdImagePtr src)
3097 {
3098 unsigned int y;
3099 unsigned int yy;
3100
3101 if (src == NULL) {
3102 return 0;
3103 }
3104
3105 if (src->trueColor == 1) {
3106 return 1;
3107 } else {
3108 unsigned int x;
3109 const unsigned int sy = gdImageSY(src);
3110 const unsigned int sx = gdImageSX(src);
3111
3112 src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
3113 if (src->tpixels == NULL) {
3114 return 0;
3115 }
3116
3117 for (y = 0; y < sy; y++) {
3118 const unsigned char *src_row = src->pixels[y];
3119 int * dst_row;
3120
3121 /* no need to calloc it, we overwrite all pxl anyway */
3122 src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
3123 if (src->tpixels[y] == NULL) {
3124 goto clean_on_error;
3125 }
3126
3127 dst_row = src->tpixels[y];
3128 for (x = 0; x < sx; x++) {
3129 const unsigned char c = *(src_row + x);
3130 if (c == src->transparent) {
3131 *(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
3132 } else {
3133 *(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3134 }
3135 }
3136 }
3137 }
3138
3139 /* free old palette buffer (y is sy) */
3140 for (yy = 0; yy < y; yy++) {
3141 gdFree(src->pixels[yy]);
3142 }
3143 gdFree(src->pixels);
3144 src->trueColor = 1;
3145 src->pixels = NULL;
3146 src->alphaBlendingFlag = 0;
3147 src->saveAlphaFlag = 1;
3148
3149 if (src->transparent >= 0) {
3150 const unsigned char c = src->transparent;
3151 src->transparent = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3152 }
3153
3154 return 1;
3155
3156 clean_on_error:
3157 /* free new true color buffer (y is not allocated, have failed) */
3158 for (yy = 0; yy < y; yy++) {
3159 gdFree(src->tpixels[yy]);
3160 }
3161 gdFree(src->tpixels);
3162 return 0;
3163 }
3164
3165