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