1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <zlib.h>
6 #include "gd.h"
7 #include "gdhelpers.h"
8
9 #ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */
10 #define CHARSET_EBCDIC
11 #define __attribute__(any) /*nothing */
12 #endif
13 /*_OSD_POSIX*/
14
15 #ifndef CHARSET_EBCDIC
16 #define ASC(ch) ch
17 #else /*CHARSET_EBCDIC */
18 #define ASC(ch) gd_toascii[(unsigned char)ch]
19 static const unsigned char gd_toascii[256] =
20 {
21 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
22 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */
23 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
24 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */
25 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
26 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */
27 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
28 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */
29 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
30 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
31 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
32 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */
33 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
34 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
35 /*-/........^,%_>?*/
36 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
37 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */
38 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
39 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */
40 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
41 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */
42 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
43 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */
44 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
45 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */
46 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
47 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */
48 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
49 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */
50 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
51 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */
52 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
53 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
54 };
55 #endif /*CHARSET_EBCDIC */
56
57 extern int gdCosT[];
58 extern int gdSinT[];
59
60 static void gdImageBrushApply (gdImagePtr im, int x, int y);
61 static void gdImageTileApply (gdImagePtr im, int x, int y);
62
63 gdImagePtr
gdImageCreate(int sx,int sy)64 gdImageCreate (int sx, int sy)
65 {
66 int i;
67 gdImagePtr im;
68
69 if (overflow2(sx, sy)) {
70 return NULL;
71 }
72
73 if (overflow2(sizeof (unsigned char *), sy)) {
74 return NULL;
75 }
76 if (overflow2(sizeof (unsigned char), sx)) {
77 return NULL;
78 }
79
80 im = (gdImage *) gdMalloc (sizeof (gdImage));
81 memset (im, 0, sizeof (gdImage));
82 /* Row-major ever since gd 1.3 */
83 im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
84 im->polyInts = 0;
85 im->polyAllocated = 0;
86 im->brush = 0;
87 im->tile = 0;
88 im->style = 0;
89 for (i = 0; (i < sy); i++)
90 {
91 /* Row-major ever since gd 1.3 */
92 im->pixels[i] = (unsigned char *) gdCalloc (
93 sx, sizeof (unsigned char));
94 }
95 im->sx = sx;
96 im->sy = sy;
97 im->colorsTotal = 0;
98 im->transparent = (-1);
99 im->interlace = 0;
100 im->thick = 1;
101 for (i = 0; (i < gdMaxColors); i++)
102 {
103 im->open[i] = 1;
104 im->red[i] = 0;
105 im->green[i] = 0;
106 im->blue[i] = 0;
107 };
108 im->trueColor = 0;
109 im->tpixels = 0;
110 im->clip = 0;
111 return im;
112 }
113
114 gdImagePtr
gdImageCreateTrueColor(int sx,int sy)115 gdImageCreateTrueColor (int sx, int sy)
116 {
117 int i;
118 gdImagePtr im;
119 unsigned long cpa_size;
120
121 if (overflow2(sx, sy)) {
122 return NULL;
123 }
124
125 if (overflow2(sizeof (int *), sy)) {
126 return NULL;
127 }
128
129 if (overflow2(sizeof(int), sx)) {
130 return NULL;
131 }
132
133 im = (gdImage *) gdMalloc (sizeof (gdImage));
134 if (im == 0) return 0;
135 memset (im, 0, sizeof (gdImage));
136
137 cpa_size = sizeof (int) * (unsigned long) sx * (unsigned long) sy;
138 im->_tpixels = (int *) gdMalloc (cpa_size);
139 if (im->_tpixels == 0)
140 {
141 gdFree (im);
142 return 0;
143 }
144 memset (im->_tpixels, 0, cpa_size);
145
146 im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
147 if (im->tpixels == 0)
148 {
149 gdFree (im->_tpixels);
150 gdFree (im);
151 return 0;
152 }
153 for (i = 0; i < sy; i++) im->tpixels[i] = im->_tpixels + (i * sx);
154
155 im->polyInts = 0;
156 im->polyAllocated = 0;
157 im->brush = 0;
158 im->tile = 0;
159 im->style = 0;
160 im->sx = sx;
161 im->sy = sy;
162 im->transparent = (-1);
163 im->interlace = 0;
164 im->trueColor = 1;
165 im->saveAlphaFlag = 1;
166 im->alphaBlendingFlag = 0;
167 im->thick = 1;
168 im->clip = 0;
169 return im;
170 }
171
172 void
gdImageDestroy(gdImagePtr im)173 gdImageDestroy (gdImagePtr im)
174 {
175 int i;
176 if (im->pixels)
177 {
178 for (i = 0; (i < im->sy); i++)
179 {
180 gdFree (im->pixels[i]);
181 }
182 gdFree (im->pixels);
183 }
184 if (im->tpixels)
185 {
186 gdFree (im->_tpixels);
187 gdFree (im->tpixels);
188 }
189 if (im->polyInts)
190 {
191 gdFree (im->polyInts);
192 }
193 if (im->style)
194 {
195 gdFree (im->style);
196 }
197 if (im->clip)
198 {
199 gdClipSetFree (im);
200 }
201 gdFree (im);
202 }
203
204 int
gdImageColorClosest(gdImagePtr im,int r,int g,int b)205 gdImageColorClosest (gdImagePtr im, int r, int g, int b)
206 {
207 return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
208 }
209
210 int
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)211 gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
212 {
213 int i;
214 long rd, gd, bd, ad;
215 int ct = (-1);
216 int first = 1;
217 long mindist = 0;
218 if (im->trueColor)
219 {
220 return gdTrueColorAlpha (r, g, b, a);
221 }
222 for (i = 0; (i < (im->colorsTotal)); i++)
223 {
224 long dist;
225 if (im->open[i])
226 {
227 continue;
228 }
229 rd = (im->red[i] - r);
230 gd = (im->green[i] - g);
231 bd = (im->blue[i] - b);
232 ad = (im->blue[i] - b);
233 dist = rd * rd + gd * gd + bd * bd + ad * ad;
234 if (first || (dist < mindist))
235 {
236 mindist = dist;
237 ct = i;
238 first = 0;
239 }
240 }
241 return ct;
242 }
243
244 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
245 * on colour conversion to/from RBG and HWB colour systems.
246 * It has been modified to return the converted value as a * parameter.
247 */
248
249 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
250 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
251 #define HWB_UNDEFINED -1
252 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
253
254 #define MIN(a,b) ((a)<(b)?(a):(b))
255 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
256 #define MAX(a,b) ((a)<(b)?(b):(a))
257 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
258
259
260 /*
261 * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
262 * red always maps to 6 in this implementation. Therefore UNDEFINED can be
263 * defined as 0 in situations where only unsigned numbers are desired.
264 */
265 typedef struct
266 {
267 float R, G, B;
268 }
269 RGBType;
270 typedef struct
271 {
272 float H, W, B;
273 }
274 HWBType;
275
276 #if 0
277 static HWBType *
278 RGB_to_HWB (RGBType RGB, HWBType * HWB)
279 {
280
281 /*
282 * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
283 * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
284 */
285
286 float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
287 int i;
288
289 w = MIN3 (R, G, B);
290 v = MAX3 (R, G, B);
291 b = 1 - v;
292 if (v == w)
293 RETURN_HWB (HWB_UNDEFINED, w, b);
294 f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
295 i = (R == w) ? 3 : ((G == w) ? 5 : 1);
296 RETURN_HWB (i - f / (v - w), w, b);
297
298 }
299
300 static float
301 HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
302 {
303 RGBType RGB1, RGB2;
304 HWBType HWB1, HWB2;
305 float diff;
306
307 SETUP_RGB (RGB1, r1, g1, b1);
308 SETUP_RGB (RGB2, r2, g2, b2);
309
310 RGB_to_HWB (RGB1, &HWB1);
311 RGB_to_HWB (RGB2, &HWB2);
312
313 /*
314 * I made this bit up; it seems to produce OK results, and it is certainly
315 * more visually correct than the current RGB metric. (PJW)
316 */
317
318 if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED))
319 {
320 diff = 0; /* Undefined hues always match... */
321 }
322 else
323 {
324 diff = abs (HWB1.H - HWB2.H);
325 if (diff > 3)
326 {
327 diff = 6 - diff; /* Remember, it's a colour circle */
328 }
329 }
330
331 diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
332
333 return diff;
334 }
335
336 /*
337 * This is not actually used, but is here for completeness, in case someone wants to
338 * use the HWB stuff for anything else...
339 */
340 static RGBType *
341 HWB_to_RGB (HWBType HWB, RGBType * RGB)
342 {
343
344 /*
345 * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
346 * RGB are each returned on [0, 1].
347 */
348
349 float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
350 int i;
351
352 v = 1 - b;
353 if (h == HWB_UNDEFINED)
354 RETURN_RGB (v, v, v);
355 i = floor (h);
356 f = h - i;
357 if (i & 1)
358 f = 1 - f; /* if i is odd */
359 n = w + f * (v - w); /* linear interpolation between w and v */
360 switch (i)
361 {
362 case 6:
363 case 0:
364 RETURN_RGB (v, n, w);
365 case 1:
366 RETURN_RGB (n, v, w);
367 case 2:
368 RETURN_RGB (w, v, n);
369 case 3:
370 RETURN_RGB (w, n, v);
371 case 4:
372 RETURN_RGB (n, w, v);
373 case 5:
374 RETURN_RGB (v, w, n);
375 }
376
377 return RGB;
378
379 }
380 #endif
381
382 #if 0
383 int
384 gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
385 {
386 int i;
387 /* long rd, gd, bd; */
388 int ct = (-1);
389 int first = 1;
390 float mindist = 0;
391 if (im->trueColor)
392 {
393 return gdTrueColor (r, g, b);
394 }
395 for (i = 0; (i < (im->colorsTotal)); i++)
396 {
397 float dist;
398 if (im->open[i])
399 {
400 continue;
401 }
402 dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
403 if (first || (dist < mindist))
404 {
405 mindist = dist;
406 ct = i;
407 first = 0;
408 }
409 }
410 return ct;
411 }
412 #endif
413
414 int
gdImageColorExact(gdImagePtr im,int r,int g,int b)415 gdImageColorExact (gdImagePtr im, int r, int g, int b)
416 {
417 return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
418 }
419
420 int
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)421 gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
422 {
423 int i;
424 if (im->trueColor)
425 {
426 return gdTrueColorAlpha (r, g, b, a);
427 }
428 for (i = 0; (i < (im->colorsTotal)); i++)
429 {
430 if (im->open[i])
431 {
432 continue;
433 }
434 if ((im->red[i] == r) &&
435 (im->green[i] == g) &&
436 (im->blue[i] == b) &&
437 (im->alpha[i] == a))
438 {
439 return i;
440 }
441 }
442 return -1;
443 }
444
445 int
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)446 gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
447 {
448 return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
449 }
450
451 int
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)452 gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
453 {
454 int i;
455 int ct = (-1);
456 if (im->trueColor)
457 {
458 return gdTrueColorAlpha (r, g, b, a);
459 }
460 for (i = 0; (i < (im->colorsTotal)); i++)
461 {
462 if (im->open[i])
463 {
464 ct = i;
465 break;
466 }
467 }
468 if (ct == (-1))
469 {
470 ct = im->colorsTotal;
471 if (ct == gdMaxColors)
472 {
473 return -1;
474 }
475 im->colorsTotal++;
476 }
477 im->red[ct] = r;
478 im->green[ct] = g;
479 im->blue[ct] = b;
480 im->alpha[ct] = a;
481 im->open[ct] = 0;
482 return ct;
483 }
484
485 /*
486 * gdImageColorResolve is an alternative for the code fragment:
487 *
488 * if ((color=gdImageColorExact(im,R,G,B)) < 0)
489 * if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
490 * color=gdImageColorClosest(im,R,G,B);
491 *
492 * in a single function. Its advantage is that it is guaranteed to
493 * return a color index in one search over the color table.
494 */
495
496 int
gdImageColorResolve(gdImagePtr im,int r,int g,int b)497 gdImageColorResolve (gdImagePtr im, int r, int g, int b)
498 {
499 return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
500 }
501
502 int
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)503 gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
504 {
505 int c;
506 int ct = -1;
507 int op = -1;
508 long rd, gd, bd, ad, dist;
509 long mindist = 4 * 255 * 255; /* init to max poss dist */
510 if (im->trueColor)
511 {
512 return gdTrueColorAlpha (r, g, b, a);
513 }
514
515 for (c = 0; c < im->colorsTotal; c++)
516 {
517 if (im->open[c])
518 {
519 op = c; /* Save open slot */
520 continue; /* Color not in use */
521 }
522 rd = (long) (im->red[c] - r);
523 gd = (long) (im->green[c] - g);
524 bd = (long) (im->blue[c] - b);
525 ad = (long) (im->alpha[c] - a);
526 dist = rd * rd + gd * gd + bd * bd + ad * ad;
527 if (dist < mindist)
528 {
529 if (dist == 0)
530 {
531 return c; /* Return exact match color */
532 }
533 mindist = dist;
534 ct = c;
535 }
536 }
537 /* no exact match. We now know closest, but first try to allocate exact */
538 if (op == -1)
539 {
540 op = im->colorsTotal;
541 if (op == gdMaxColors)
542 { /* No room for more colors */
543 return ct; /* Return closest available color */
544 }
545 im->colorsTotal++;
546 }
547 im->red[op] = r;
548 im->green[op] = g;
549 im->blue[op] = b;
550 im->alpha[op] = a;
551 im->open[op] = 0;
552 return op; /* Return newly allocated color */
553 }
554
555 void
gdImageColorDeallocate(gdImagePtr im,int color)556 gdImageColorDeallocate (gdImagePtr im, int color)
557 {
558 if (im->trueColor)
559 {
560 return;
561 }
562 /* Mark it open. */
563 im->open[color] = 1;
564 }
565
566 void
gdImageColorTransparent(gdImagePtr im,int color)567 gdImageColorTransparent (gdImagePtr im, int color)
568 {
569 if (!im->trueColor)
570 {
571 if (im->transparent != -1)
572 {
573 im->alpha[im->transparent] = gdAlphaOpaque;
574 }
575 if (color != -1)
576 {
577 im->alpha[color] = gdAlphaTransparent;
578 }
579 }
580 im->transparent = color;
581 }
582
583 void
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)584 gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
585 {
586 int i;
587 int x, y, p;
588 int xlate[256];
589 if (to->trueColor)
590 {
591 return;
592 }
593 if (from->trueColor)
594 {
595 return;
596 }
597
598 for (i = 0; i < 256; i++)
599 {
600 xlate[i] = -1;
601 };
602
603 for (x = 0; x < (to->sx); x++)
604 {
605 for (y = 0; y < (to->sy); y++)
606 {
607 p = gdImageGetPixel (to, x, y);
608 if (xlate[p] == -1)
609 {
610 /* This ought to use HWB, but we don't have an alpha-aware
611 version of that yet. */
612 xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
613 /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
614 /* p, to->red[p], to->green[p], to->blue[p], to->alpha[p], */
615 /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
616 };
617 gdImageSetPixel (to, x, y, xlate[p]);
618 };
619 };
620
621 for (i = 0; (i < (from->colorsTotal)); i++)
622 {
623 /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
624 to->red[i] = from->red[i];
625 to->blue[i] = from->blue[i];
626 to->green[i] = from->green[i];
627 to->alpha[i] = from->alpha[i];
628 to->open[i] = 0;
629 };
630
631 for (i = from->colorsTotal; (i < to->colorsTotal); i++)
632 {
633 to->open[i] = 1;
634 };
635
636 to->colorsTotal = from->colorsTotal;
637
638 }
639
640 void
gdImageSetPixel(gdImagePtr im,int x,int y,int color)641 gdImageSetPixel (gdImagePtr im, int x, int y, int color)
642 {
643 int p;
644 switch (color)
645 {
646 case gdStyled:
647 if (!im->style)
648 {
649 /* Refuse to draw if no style is set. */
650 return;
651 }
652 else
653 {
654 p = im->style[im->stylePos++];
655 }
656 if (p != (gdTransparent))
657 {
658 gdImageSetPixel (im, x, y, p);
659 }
660 im->stylePos = im->stylePos % im->styleLength;
661 break;
662 case gdStyledBrushed:
663 if (!im->style)
664 {
665 /* Refuse to draw if no style is set. */
666 return;
667 }
668 p = im->style[im->stylePos++];
669 if ((p != gdTransparent) && (p != 0))
670 {
671 gdImageSetPixel (im, x, y, gdBrushed);
672 }
673 im->stylePos = im->stylePos % im->styleLength;
674 break;
675 case gdBrushed:
676 gdImageBrushApply (im, x, y);
677 break;
678 case gdTiled:
679 gdImageTileApply (im, x, y);
680 break;
681 default:
682 if (gdImageBoundsSafe (im, x, y))
683 {
684 if (im->trueColor)
685 {
686 if (im->alphaBlendingFlag)
687 {
688 im->tpixels[y][x] =
689 gdAlphaBlend (im->tpixels[y][x],
690 color);
691 }
692 else
693 {
694 im->tpixels[y][x] = color;
695 }
696 }
697 else
698 {
699 im->pixels[y][x] = color;
700 }
701 }
702 break;
703 }
704 }
705
706 static int
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)707 gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
708 {
709 int p = gdImageGetPixel (im, x, y);
710 if (!im->trueColor)
711 {
712 return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
713 (im->transparent == p) ? gdAlphaTransparent :
714 gdAlphaOpaque);
715 }
716 else
717 {
718 return p;
719 }
720 }
721
722 static void
gdImageBrushApply(gdImagePtr im,int x,int y)723 gdImageBrushApply (gdImagePtr im, int x, int y)
724 {
725 int lx, ly;
726 int hy;
727 int hx;
728 int x1, y1, x2, y2;
729 int srcx, srcy;
730 if (!im->brush)
731 {
732 return;
733 }
734 hy = gdImageSY (im->brush) / 2;
735 y1 = y - hy;
736 y2 = y1 + gdImageSY (im->brush);
737 hx = gdImageSX (im->brush) / 2;
738 x1 = x - hx;
739 x2 = x1 + gdImageSX (im->brush);
740 srcy = 0;
741 if (im->trueColor)
742 {
743 for (ly = y1; (ly < y2); ly++)
744 {
745 srcx = 0;
746 for (lx = x1; (lx < x2); lx++)
747 {
748 int p;
749 p = gdImageGetTrueColorPixel (
750 im->brush, srcx, srcy);
751 gdImageSetPixel (im, lx, ly,
752 p);
753 srcx++;
754 }
755 srcy++;
756 }
757 }
758 else
759 {
760 for (ly = y1; (ly < y2); ly++)
761 {
762 srcx = 0;
763 for (lx = x1; (lx < x2); lx++)
764 {
765 int p;
766 p = gdImageGetPixel (im->brush, srcx, srcy);
767 /* Allow for non-square brushes! */
768 if (p != gdImageGetTransparent (im->brush))
769 {
770 /* Truecolor brush. Very slow
771 on a palette destination. */
772 if (im->brush->trueColor)
773 {
774 gdImageSetPixel (im, lx, ly,
775 gdImageColorResolveAlpha (
776 im,
777 gdTrueColorGetRed (p),
778 gdTrueColorGetGreen (p),
779 gdTrueColorGetBlue (p),
780 gdTrueColorGetAlpha (p)));
781 }
782 else
783 {
784 gdImageSetPixel (im, lx, ly,
785 im->brushColorMap[p]);
786 }
787 }
788 srcx++;
789 }
790 srcy++;
791 }
792 }
793 }
794
795 static void
gdImageTileApply(gdImagePtr im,int x,int y)796 gdImageTileApply (gdImagePtr im, int x, int y)
797 {
798 int srcx, srcy;
799 int p=0;
800 if (!im->tile)
801 {
802 return;
803 }
804 srcx = x % gdImageSX (im->tile);
805 srcy = y % gdImageSY (im->tile);
806 if (im->trueColor)
807 {
808 p = gdImageGetTrueColorPixel (im->tile, srcx, srcy);
809 gdImageSetPixel (im, x, y, p);
810 }
811 else
812 {
813 /* Allow for transparency */
814 if (p != gdImageGetTransparent (im->tile))
815 {
816 if (im->tile->trueColor)
817 {
818 /* Truecolor tile. Very slow
819 on a palette destination. */
820 gdImageSetPixel (im, x, y,
821 gdImageColorResolveAlpha (
822 im,
823 gdTrueColorGetRed (p),
824 gdTrueColorGetGreen (p),
825 gdTrueColorGetBlue (p),
826 gdTrueColorGetAlpha (p)));
827 }
828 else
829 {
830 gdImageSetPixel (im, x, y,
831 im->tileColorMap[p]);
832 }
833 }
834 }
835 }
836
837 int
gdImageGetPixel(gdImagePtr im,int x,int y)838 gdImageGetPixel (gdImagePtr im, int x, int y)
839 {
840 if (gdImageBoundsSafe (im, x, y))
841 {
842 if (im->trueColor)
843 {
844 return im->tpixels[y][x];
845 }
846 else
847 {
848 return im->pixels[y][x];
849 }
850 }
851 else
852 {
853 return 0;
854 }
855 }
856
857 /* Bresenham as presented in Foley & Van Dam */
858 void
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)859 gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
860 {
861 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
862 int wid;
863 int w, wstart;
864 int thick = im->thick;
865 dx = abs (x2 - x1);
866 dy = abs (y2 - y1);
867 if (dy <= dx)
868 {
869 /* More-or-less horizontal. use wid for vertical stroke */
870 wid = thick * cos (atan2 (dy, dx));
871 if (wid == 0)
872 wid = 1;
873
874 d = 2 * dy - dx;
875 incr1 = 2 * dy;
876 incr2 = 2 * (dy - dx);
877 if (x1 > x2)
878 {
879 x = x2;
880 y = y2;
881 ydirflag = (-1);
882 xend = x1;
883 }
884 else
885 {
886 x = x1;
887 y = y1;
888 ydirflag = 1;
889 xend = x2;
890 }
891
892 /* Set up line thickness */
893 wstart = y - wid / 2;
894 for (w = wstart; w < wstart + wid; w++)
895 gdImageSetPixel (im, x, w, color);
896
897 if (((y2 - y1) * ydirflag) > 0)
898 {
899 while (x < xend)
900 {
901 x++;
902 if (d < 0)
903 {
904 d += incr1;
905 }
906 else
907 {
908 y++;
909 d += incr2;
910 }
911 wstart = y - wid / 2;
912 for (w = wstart; w < wstart + wid; w++)
913 gdImageSetPixel (im, x, w, color);
914 }
915 }
916 else
917 {
918 while (x < xend)
919 {
920 x++;
921 if (d < 0)
922 {
923 d += incr1;
924 }
925 else
926 {
927 y--;
928 d += incr2;
929 }
930 wstart = y - wid / 2;
931 for (w = wstart; w < wstart + wid; w++)
932 gdImageSetPixel (im, x, w, color);
933 }
934 }
935 }
936 else
937 {
938 /* More-or-less vertical. use wid for horizontal stroke */
939 wid = thick * sin (atan2 (dy, dx));
940 if (wid == 0)
941 wid = 1;
942
943 d = 2 * dx - dy;
944 incr1 = 2 * dx;
945 incr2 = 2 * (dx - dy);
946 if (y1 > y2)
947 {
948 y = y2;
949 x = x2;
950 yend = y1;
951 xdirflag = (-1);
952 }
953 else
954 {
955 y = y1;
956 x = x1;
957 yend = y2;
958 xdirflag = 1;
959 }
960
961 /* Set up line thickness */
962 wstart = x - wid / 2;
963 for (w = wstart; w < wstart + wid; w++)
964 gdImageSetPixel (im, w, y, color);
965
966 if (((x2 - x1) * xdirflag) > 0)
967 {
968 while (y < yend)
969 {
970 y++;
971 if (d < 0)
972 {
973 d += incr1;
974 }
975 else
976 {
977 x++;
978 d += incr2;
979 }
980 wstart = x - wid / 2;
981 for (w = wstart; w < wstart + wid; w++)
982 gdImageSetPixel (im, w, y, color);
983 }
984 }
985 else
986 {
987 while (y < yend)
988 {
989 y++;
990 if (d < 0)
991 {
992 d += incr1;
993 }
994 else
995 {
996 x--;
997 d += incr2;
998 }
999 wstart = x - wid / 2;
1000 for (w = wstart; w < wstart + wid; w++)
1001 gdImageSetPixel (im, w, y, color);
1002 }
1003 }
1004 }
1005 }
1006 static void dashedSet (gdImagePtr im, int x, int y, int color,
1007 int *onP, int *dashStepP, int wid, int vert);
1008
1009 void
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1010 gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1011 {
1012 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1013 int dashStep = 0;
1014 int on = 1;
1015 int wid;
1016 int vert;
1017 int thick = im->thick;
1018
1019 dx = abs (x2 - x1);
1020 dy = abs (y2 - y1);
1021 if (dy <= dx)
1022 {
1023 /* More-or-less horizontal. use wid for vertical stroke */
1024 wid = thick * sin (atan2 (dy, dx));
1025 vert = 1;
1026
1027 d = 2 * dy - dx;
1028 incr1 = 2 * dy;
1029 incr2 = 2 * (dy - dx);
1030 if (x1 > x2)
1031 {
1032 x = x2;
1033 y = y2;
1034 ydirflag = (-1);
1035 xend = x1;
1036 }
1037 else
1038 {
1039 x = x1;
1040 y = y1;
1041 ydirflag = 1;
1042 xend = x2;
1043 }
1044 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1045 if (((y2 - y1) * ydirflag) > 0)
1046 {
1047 while (x < xend)
1048 {
1049 x++;
1050 if (d < 0)
1051 {
1052 d += incr1;
1053 }
1054 else
1055 {
1056 y++;
1057 d += incr2;
1058 }
1059 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1060 }
1061 }
1062 else
1063 {
1064 while (x < xend)
1065 {
1066 x++;
1067 if (d < 0)
1068 {
1069 d += incr1;
1070 }
1071 else
1072 {
1073 y--;
1074 d += incr2;
1075 }
1076 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1077 }
1078 }
1079 }
1080 else
1081 {
1082 /* More-or-less vertical. use wid for horizontal stroke */
1083 wid = thick * sin (atan2 (dy, dx));
1084 vert = 0;
1085
1086 d = 2 * dx - dy;
1087 incr1 = 2 * dx;
1088 incr2 = 2 * (dx - dy);
1089 if (y1 > y2)
1090 {
1091 y = y2;
1092 x = x2;
1093 yend = y1;
1094 xdirflag = (-1);
1095 }
1096 else
1097 {
1098 y = y1;
1099 x = x1;
1100 yend = y2;
1101 xdirflag = 1;
1102 }
1103 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1104 if (((x2 - x1) * xdirflag) > 0)
1105 {
1106 while (y < yend)
1107 {
1108 y++;
1109 if (d < 0)
1110 {
1111 d += incr1;
1112 }
1113 else
1114 {
1115 x++;
1116 d += incr2;
1117 }
1118 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1119 }
1120 }
1121 else
1122 {
1123 while (y < yend)
1124 {
1125 y++;
1126 if (d < 0)
1127 {
1128 d += incr1;
1129 }
1130 else
1131 {
1132 x--;
1133 d += incr2;
1134 }
1135 dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1136 }
1137 }
1138 }
1139 }
1140
1141 static void
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1142 dashedSet (gdImagePtr im, int x, int y, int color,
1143 int *onP, int *dashStepP, int wid, int vert)
1144 {
1145 int dashStep = *dashStepP;
1146 int on = *onP;
1147 int w, wstart;
1148
1149 dashStep++;
1150 if (dashStep == gdDashSize)
1151 {
1152 dashStep = 0;
1153 on = !on;
1154 }
1155 if (on)
1156 {
1157 if (vert)
1158 {
1159 wstart = y - wid / 2;
1160 for (w = wstart; w < wstart + wid; w++)
1161 gdImageSetPixel (im, x, w, color);
1162 }
1163 else
1164 {
1165 wstart = x - wid / 2;
1166 for (w = wstart; w < wstart + wid; w++)
1167 gdImageSetPixel (im, w, y, color);
1168 }
1169 }
1170 *dashStepP = dashStep;
1171 *onP = on;
1172 }
1173 #ifdef ORIGINAL_BOUNDS_SAFE
1174 int
gdImageBoundsSafe(gdImagePtr im,int x,int y)1175 gdImageBoundsSafe (gdImagePtr im, int x, int y)
1176 {
1177 return (!(((y < 0) || (y >= im->sy)) ||
1178 ((x < 0) || (x >= im->sx))));
1179 }
1180 #endif /* ORIGINAL_BOUNDS_SAFE */
1181 void
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1182 gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y,
1183 int c, int color)
1184 {
1185 int cx, cy;
1186 int px, py;
1187 int fline;
1188 cx = 0;
1189 cy = 0;
1190 #ifdef CHARSET_EBCDIC
1191 c = ASC (c);
1192 #endif /*CHARSET_EBCDIC */
1193 if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1194 {
1195 return;
1196 }
1197 fline = (c - f->offset) * f->h * f->w;
1198 for (py = y; (py < (y + f->h)); py++)
1199 {
1200 for (px = x; (px < (x + f->w)); px++)
1201 {
1202 if (f->data[fline + cy * f->w + cx])
1203 {
1204 gdImageSetPixel (im, px, py, color);
1205 }
1206 cx++;
1207 }
1208 cx = 0;
1209 cy++;
1210 }
1211 }
1212
1213 void
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1214 gdImageCharUp (gdImagePtr im, gdFontPtr f,
1215 int x, int y, int c, int color)
1216 {
1217 int cx, cy;
1218 int px, py;
1219 int fline;
1220 cx = 0;
1221 cy = 0;
1222 #ifdef CHARSET_EBCDIC
1223 c = ASC (c);
1224 #endif /*CHARSET_EBCDIC */
1225 if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1226 {
1227 return;
1228 }
1229 fline = (c - f->offset) * f->h * f->w;
1230 for (py = y; (py > (y - f->w)); py--)
1231 {
1232 for (px = x; (px < (x + f->h)); px++)
1233 {
1234 if (f->data[fline + cy * f->w + cx])
1235 {
1236 gdImageSetPixel (im, px, py, color);
1237 }
1238 cy++;
1239 }
1240 cy = 0;
1241 cx++;
1242 }
1243 }
1244
1245 void
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1246 gdImageString (gdImagePtr im, gdFontPtr f,
1247 int x, int y, unsigned char *s, int color)
1248 {
1249 int i;
1250 int l;
1251 l = strlen ((char *) s);
1252 for (i = 0; (i < l); i++)
1253 {
1254 gdImageChar (im, f, x, y, s[i], color);
1255 x += f->w;
1256 }
1257 }
1258
1259 void
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1260 gdImageStringUp (gdImagePtr im, gdFontPtr f,
1261 int x, int y, unsigned char *s, int color)
1262 {
1263 int i;
1264 int l;
1265 l = strlen ((char *) s);
1266 for (i = 0; (i < l); i++)
1267 {
1268 gdImageCharUp (im, f, x, y, s[i], color);
1269 y -= f->w;
1270 }
1271 }
1272
1273 static int strlen16 (unsigned short *s);
1274
1275 void
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1276 gdImageString16 (gdImagePtr im, gdFontPtr f,
1277 int x, int y, unsigned short *s, int color)
1278 {
1279 int i;
1280 int l;
1281 l = strlen16 (s);
1282 for (i = 0; (i < l); i++)
1283 {
1284 gdImageChar (im, f, x, y, s[i], color);
1285 x += f->w;
1286 }
1287 }
1288
1289 void
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1290 gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
1291 int x, int y, unsigned short *s, int color)
1292 {
1293 int i;
1294 int l;
1295 l = strlen16 (s);
1296 for (i = 0; (i < l); i++)
1297 {
1298 gdImageCharUp (im, f, x, y, s[i], color);
1299 y -= f->w;
1300 }
1301 }
1302
1303 static int
strlen16(unsigned short * s)1304 strlen16 (unsigned short *s)
1305 {
1306 int len = 0;
1307 while (*s)
1308 {
1309 s++;
1310 len++;
1311 }
1312 return len;
1313 }
1314
1315 #if 0
1316 /* If you don't have a nice square root function for longs, you can use
1317 ** this hack
1318 */
1319 static long
1320 lsqrt (long n)
1321 {
1322 long result = (long) sqrt ((double) n);
1323 return result;
1324 }
1325 #endif
1326
1327 /* s and e are integers modulo 360 (degrees), with 0 degrees
1328 being the rightmost extreme and degrees changing clockwise.
1329 cx and cy are the center in pixels; w and h are the horizontal
1330 and vertical diameter in pixels. Nice interface, but slow.
1331 See gd_arc_f_buggy.c for a better version that doesn't
1332 seem to be bug-free yet. */
1333
1334 void
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1335 gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1336 {
1337 gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
1338 }
1339
1340 void
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1341 gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1342 {
1343 gdPoint pts[3];
1344 int i;
1345 int lx = 0, ly = 0;
1346 int fx=0, fy=0;
1347 int w2, h2;
1348 w2 = w / 2;
1349 h2 = h / 2;
1350
1351 if ((s % 360) == (e % 360)) {
1352 s = 0; e = 360;
1353 } else {
1354 if (s > 360) {
1355 s = s % 360;
1356 }
1357
1358 if (e > 360) {
1359 e = e % 360;
1360 }
1361
1362 while (s < 0) {
1363 s += 360;
1364 }
1365
1366 while (e < s) {
1367 e += 360;
1368 }
1369
1370 if (s == e) {
1371 s = 0; e = 360;
1372 }
1373 }
1374
1375 for (i = s; (i <= e); i++)
1376 {
1377 int x, y;
1378 x = ((long) gdCosT[i % 360] * (long) w2 / 1024) + cx;
1379 y = ((long) gdSinT[i % 360] * (long) h2 / 1024) + cy;
1380 if (i != s)
1381 {
1382 if (!(style & gdChord))
1383 {
1384 if (style & gdNoFill)
1385 {
1386 gdImageLine (im, lx, ly, x, y, color);
1387 }
1388 else
1389 {
1390 /* This is expensive! */
1391 pts[0].x = lx;
1392 pts[0].y = ly;
1393 pts[1].x = x;
1394 pts[1].y = y;
1395 pts[2].x = cx;
1396 pts[2].y = cy;
1397 gdImageFilledPolygon (im, pts, 3, color);
1398 }
1399 }
1400 }
1401 else
1402 {
1403 fx = x;
1404 fy = y;
1405 }
1406 lx = x;
1407 ly = y;
1408 }
1409 if (style & gdChord)
1410 {
1411 if (style & gdNoFill)
1412 {
1413 if (style & gdEdged)
1414 {
1415 gdImageLine (im, cx, cy, lx, ly, color);
1416 gdImageLine (im, cx, cy, fx, fy, color);
1417 }
1418 gdImageLine (im, fx, fy, lx, ly, color);
1419 }
1420 else
1421 {
1422 pts[0].x = fx;
1423 pts[0].y = fy;
1424 pts[1].x = lx;
1425 pts[1].y = ly;
1426 pts[2].x = cx;
1427 pts[2].y = cy;
1428 gdImageFilledPolygon (im, pts, 3, color);
1429 }
1430 }
1431 else
1432 {
1433 if (style & gdNoFill)
1434 {
1435 if (style & gdEdged)
1436 {
1437 gdImageLine (im, cx, cy, lx, ly, color);
1438 gdImageLine (im, cx, cy, fx, fy, color);
1439 }
1440 }
1441 }
1442 }
1443
1444 void
gdImageFilledEllipse(gdImagePtr im,int cx,int cy,int w,int h,int color)1445 gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h, int color)
1446 {
1447 gdImageFilledArc (im, cx, cy, w, h, 0, 360, color, gdPie);
1448 }
1449
1450 void
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1451 gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1452 {
1453 int lastBorder;
1454 /* Seek left */
1455 int leftLimit, rightLimit;
1456 int i;
1457 if (!gdImageBoundsSafe (im, x, y)) return;
1458 leftLimit = (-1);
1459 if (border < 0)
1460 {
1461 /* Refuse to fill to a non-solid border */
1462 return;
1463 }
1464 for (i = x; (i >= 0); i--)
1465 {
1466 if (gdImageGetPixel (im, i, y) == border)
1467 {
1468 break;
1469 }
1470 gdImageSetPixel (im, i, y, color);
1471 leftLimit = i;
1472 }
1473 if (leftLimit == (-1))
1474 {
1475 return;
1476 }
1477 /* Seek right */
1478 rightLimit = x;
1479 for (i = (x + 1); (i < im->sx); i++)
1480 {
1481 if (gdImageGetPixel (im, i, y) == border)
1482 {
1483 break;
1484 }
1485 gdImageSetPixel (im, i, y, color);
1486 rightLimit = i;
1487 }
1488 /* Look at lines above and below and start paints */
1489 /* Above */
1490 if (y > 0)
1491 {
1492 lastBorder = 1;
1493 for (i = leftLimit; (i <= rightLimit); i++)
1494 {
1495 int c;
1496 c = gdImageGetPixel (im, i, y - 1);
1497 if (lastBorder)
1498 {
1499 if ((c != border) && (c != color))
1500 {
1501 gdImageFillToBorder (im, i, y - 1,
1502 border, color);
1503 lastBorder = 0;
1504 }
1505 }
1506 else if ((c == border) || (c == color))
1507 {
1508 lastBorder = 1;
1509 }
1510 }
1511 }
1512 /* Below */
1513 if (y < ((im->sy) - 1))
1514 {
1515 lastBorder = 1;
1516 for (i = leftLimit; (i <= rightLimit); i++)
1517 {
1518 int c;
1519 c = gdImageGetPixel (im, i, y + 1);
1520 if (lastBorder)
1521 {
1522 if ((c != border) && (c != color))
1523 {
1524 gdImageFillToBorder (im, i, y + 1,
1525 border, color);
1526 lastBorder = 0;
1527 }
1528 }
1529 else if ((c == border) || (c == color))
1530 {
1531 lastBorder = 1;
1532 }
1533 }
1534 }
1535 }
1536
1537 void
gdImageFill(gdImagePtr im,int x,int y,int color)1538 gdImageFill (gdImagePtr im, int x, int y, int color)
1539 {
1540 int lastBorder;
1541 int old;
1542 int leftLimit, rightLimit;
1543 int i;
1544 if (!gdImageBoundsSafe (im, x, y)) return;
1545 old = gdImageGetPixel (im, x, y);
1546 if (color == gdTiled)
1547 {
1548 /* Tile fill -- got to watch out! */
1549 int p, tileColor;
1550 int srcx, srcy;
1551 if (!im->tile)
1552 {
1553 return;
1554 }
1555 /* Refuse to flood-fill with a transparent pattern --
1556 I can't do it without allocating another image */
1557 if (gdImageGetTransparent (im->tile) != (-1))
1558 {
1559 return;
1560 }
1561 srcx = x % gdImageSX (im->tile);
1562 srcy = y % gdImageSY (im->tile);
1563 p = gdImageGetPixel (im->tile, srcx, srcy);
1564 if (im->trueColor)
1565 {
1566 tileColor = p;
1567 }
1568 else
1569 {
1570 if (im->tile->trueColor)
1571 {
1572 tileColor = gdImageColorResolveAlpha (im,
1573 gdTrueColorGetRed (p),
1574 gdTrueColorGetGreen (p),
1575 gdTrueColorGetBlue (p),
1576 gdTrueColorGetAlpha (p));
1577 }
1578 else
1579 {
1580 tileColor = im->tileColorMap[p];
1581 }
1582 }
1583 if (old == tileColor)
1584 {
1585 /* Nothing to be done */
1586 return;
1587 }
1588 }
1589 else
1590 {
1591 if (old == color)
1592 {
1593 /* Nothing to be done */
1594 return;
1595 }
1596 }
1597 /* Seek left */
1598 leftLimit = (-1);
1599 for (i = x; (i >= 0); i--)
1600 {
1601 if (gdImageGetPixel (im, i, y) != old)
1602 {
1603 break;
1604 }
1605 gdImageSetPixel (im, i, y, color);
1606 leftLimit = i;
1607 }
1608 if (leftLimit == (-1))
1609 {
1610 return;
1611 }
1612 /* Seek right */
1613 rightLimit = x;
1614 for (i = (x + 1); (i < im->sx); i++)
1615 {
1616 if (gdImageGetPixel (im, i, y) != old)
1617 {
1618 break;
1619 }
1620 gdImageSetPixel (im, i, y, color);
1621 rightLimit = i;
1622 }
1623 /* Look at lines above and below and start paints */
1624 /* Above */
1625 if (y > 0)
1626 {
1627 lastBorder = 1;
1628 for (i = leftLimit; (i <= rightLimit); i++)
1629 {
1630 int c;
1631 c = gdImageGetPixel (im, i, y - 1);
1632 if (lastBorder)
1633 {
1634 if (c == old)
1635 {
1636 gdImageFill (im, i, y - 1, color);
1637 lastBorder = 0;
1638 }
1639 }
1640 else if (c != old)
1641 {
1642 lastBorder = 1;
1643 }
1644 }
1645 }
1646 /* Below */
1647 if (y < ((im->sy) - 1))
1648 {
1649 lastBorder = 1;
1650 for (i = leftLimit; (i <= rightLimit); i++)
1651 {
1652 int c;
1653 c = gdImageGetPixel (im, i, y + 1);
1654 if (lastBorder)
1655 {
1656 if (c == old)
1657 {
1658 gdImageFill (im, i, y + 1, color);
1659 lastBorder = 0;
1660 }
1661 }
1662 else if (c != old)
1663 {
1664 lastBorder = 1;
1665 }
1666 }
1667 }
1668 }
1669
1670 void
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1671 gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1672 {
1673 int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2,
1674 y2v = y2;
1675 int thick = im->thick;
1676 if (thick > 1)
1677 {
1678 int half = thick / 2;
1679 int half1 = thick - half;
1680
1681 if (y1 < y2)
1682 {
1683 y1v = y1h - half;
1684 y2v = y2h + half1 - 1;
1685 }
1686 else
1687 {
1688 y1v = y1h + half1 - 1;
1689 y2v = y2h - half;
1690 }
1691 }
1692
1693 gdImageLine (im, x1h, y1h, x2h, y1h, color);
1694 gdImageLine (im, x1h, y2h, x2h, y2h, color);
1695 gdImageLine (im, x1v, y1v, x1v, y2v, color);
1696 gdImageLine (im, x2v, y1v, x2v, y2v, color);
1697 }
1698
1699 void
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1700 gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1701 {
1702 int x, y;
1703 for (y = y1; (y <= y2); y++)
1704 {
1705 for (x = x1; (x <= x2); x++)
1706 {
1707 gdImageSetPixel (im, x, y, color);
1708 }
1709 }
1710 }
1711
1712 void
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)1713 gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
1714 {
1715 int c;
1716 int x, y;
1717 int tox, toy;
1718 int i;
1719 int colorMap[gdMaxColors];
1720 if (dst->trueColor)
1721 {
1722 /* 2.0: much easier when the destination is truecolor. */
1723 for (y = 0; (y < h); y++)
1724 {
1725 for (x = 0; (x < w); x++)
1726 {
1727 int c = gdImageGetTrueColorPixel (src, srcX + x,
1728 srcY + y);
1729 if (c != src->transparent)
1730 {
1731 gdImageSetPixel (dst,
1732 dstX + x,
1733 dstY + y,
1734 c);
1735 }
1736 }
1737 }
1738 return;
1739 }
1740 for (i = 0; (i < gdMaxColors); i++)
1741 {
1742 colorMap[i] = (-1);
1743 }
1744 toy = dstY;
1745 for (y = srcY; (y < (srcY + h)); y++)
1746 {
1747 tox = dstX;
1748 for (x = srcX; (x < (srcX + w)); x++)
1749 {
1750 int nc;
1751 c = gdImageGetPixel (src, x, y);
1752 /* Added 7/24/95: support transparent copies */
1753 if (gdImageGetTransparent (src) == c)
1754 {
1755 tox++;
1756 continue;
1757 }
1758 /* Have we established a mapping for this color? */
1759 if (colorMap[c] == (-1))
1760 {
1761 /* If it's the same image, mapping is trivial */
1762 if (dst == src)
1763 {
1764 nc = c;
1765 }
1766 else
1767 {
1768 /* Get best match possible. This
1769 function never returns error. */
1770 nc = gdImageColorResolveAlpha (
1771 dst,
1772 src->red[c], src->green[c],
1773 src->blue[c], src->alpha[c]);
1774 }
1775 colorMap[c] = nc;
1776 }
1777 gdImageSetPixel (dst, tox, toy, colorMap[c]);
1778 tox++;
1779 }
1780 toy++;
1781 }
1782 }
1783
1784 /* This function is a substitute for real alpha channel operations,
1785 so it doesn't pay attention to the alpha channel. */
1786 void
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)1787 gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
1788 {
1789
1790 int c, dc;
1791 int x, y;
1792 int tox, toy;
1793 int ncR, ncG, ncB;
1794 toy = dstY;
1795 for (y = srcY; (y < (srcY + h)); y++)
1796 {
1797 tox = dstX;
1798 for (x = srcX; (x < (srcX + w)); x++)
1799 {
1800 int nc;
1801 c = gdImageGetPixel (src, x, y);
1802 /* Added 7/24/95: support transparent copies */
1803 if (gdImageGetTransparent (src) == c)
1804 {
1805 tox++;
1806 continue;
1807 }
1808 /* If it's the same image, mapping is trivial */
1809 if (dst == src)
1810 {
1811 nc = c;
1812 }
1813 else
1814 {
1815 dc = gdImageGetPixel (dst, tox, toy);
1816
1817 ncR = gdImageRed (src, c) * (pct / 100.0)
1818 + gdImageRed (dst, dc) * ((100 - pct) / 100.0);
1819 ncG = gdImageGreen (src, c) * (pct / 100.0)
1820 + gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
1821 ncB = gdImageBlue (src, c) * (pct / 100.0)
1822 + gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
1823
1824 /* Find a reasonable color */
1825 nc = gdImageColorResolve (dst, ncR, ncG, ncB);
1826 }
1827 gdImageSetPixel (dst, tox, toy, nc);
1828 tox++;
1829 }
1830 toy++;
1831 }
1832 }
1833
1834 /* This function is a substitute for real alpha channel operations,
1835 so it doesn't pay attention to the alpha channel. */
1836 void
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)1837 gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
1838 {
1839
1840 int c, dc;
1841 int x, y;
1842 int tox, toy;
1843 int ncR, ncG, ncB;
1844 float g;
1845 toy = dstY;
1846 for (y = srcY; (y < (srcY + h)); y++)
1847 {
1848 tox = dstX;
1849 for (x = srcX; (x < (srcX + w)); x++)
1850 {
1851 int nc;
1852 c = gdImageGetPixel (src, x, y);
1853 /* Added 7/24/95: support transparent copies */
1854 if (gdImageGetTransparent (src) == c)
1855 {
1856 tox++;
1857 continue;
1858 }
1859 /* If it's the same image, mapping is trivial */
1860 if (dst == src)
1861 {
1862 nc = c;
1863 }
1864 else
1865 {
1866 dc = gdImageGetPixel (dst, tox, toy);
1867 g = 0.29900 * dst->red[dc]
1868 + 0.58700 * dst->green[dc]
1869 + 0.11400 * dst->blue[dc];
1870
1871 ncR = gdImageRed (src, c) * (pct / 100.0)
1872 + gdImageRed (dst, dc) * g *
1873 ((100 - pct) / 100.0);
1874 ncG = gdImageGreen (src, c) * (pct / 100.0)
1875 + gdImageGreen (dst, dc) * g *
1876 ((100 - pct) / 100.0);
1877 ncB = gdImageBlue (src, c) * (pct / 100.0)
1878 + gdImageBlue (dst, dc) * g *
1879 ((100 - pct) / 100.0);
1880
1881 /* First look for an exact match */
1882 nc = gdImageColorExact (dst, ncR, ncG, ncB);
1883 if (nc == (-1))
1884 {
1885 /* No, so try to allocate it */
1886 nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
1887 /* If we're out of colors, go for the
1888 closest color */
1889 if (nc == (-1))
1890 {
1891 nc = gdImageColorClosest (dst, ncR, ncG, ncB);
1892 }
1893 }
1894 }
1895 gdImageSetPixel (dst, tox, toy, nc);
1896 tox++;
1897 }
1898 toy++;
1899 }
1900 }
1901
1902 void
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)1903 gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
1904 {
1905 int c;
1906 int x, y;
1907 int tox, toy;
1908 int ydest;
1909 int i;
1910 int colorMap[gdMaxColors];
1911 /* Stretch vectors */
1912 int *stx;
1913 int *sty;
1914 /* We only need to use floating point to determine the correct
1915 stretch vector for one line's worth. */
1916 double accum;
1917 stx = (int *) gdMalloc (sizeof (int) * srcW);
1918 sty = (int *) gdMalloc (sizeof (int) * srcH);
1919 accum = 0;
1920 for (i = 0; (i < srcW); i++)
1921 {
1922 int got;
1923 accum += (double) dstW / (double) srcW;
1924 got = (int) floor (accum);
1925 stx[i] = got;
1926 accum -= got;
1927 }
1928 accum = 0;
1929 for (i = 0; (i < srcH); i++)
1930 {
1931 int got;
1932 accum += (double) dstH / (double) srcH;
1933 got = (int) floor (accum);
1934 sty[i] = got;
1935 accum -= got;
1936 }
1937 for (i = 0; (i < gdMaxColors); i++)
1938 {
1939 colorMap[i] = (-1);
1940 }
1941 toy = dstY;
1942 for (y = srcY; (y < (srcY + srcH)); y++)
1943 {
1944 for (ydest = 0; (ydest < sty[y - srcY]); ydest++)
1945 {
1946 tox = dstX;
1947 for (x = srcX; (x < (srcX + srcW)); x++)
1948 {
1949 int nc=0;
1950 int mapTo;
1951 if (!stx[x - srcX])
1952 {
1953 continue;
1954 }
1955 if (dst->trueColor)
1956 {
1957 mapTo = gdImageGetTrueColorPixel (src, x, y);
1958 /* Added 7/24/95: support transparent copies */
1959 if (gdImageGetTransparent (src) == mapTo)
1960 {
1961 tox++;
1962 continue;
1963 }
1964 }
1965 else
1966 {
1967 c = gdImageGetPixel (src, x, y);
1968 /* Added 7/24/95: support transparent copies */
1969 if (gdImageGetTransparent (src) == c)
1970 {
1971 tox += stx[x - srcX];
1972 continue;
1973 }
1974 if (src->trueColor)
1975 {
1976 /* Remap to the palette available in the
1977 destination image. This is slow and
1978 works badly. */
1979 mapTo = gdImageColorResolveAlpha (dst,
1980 gdTrueColorGetRed (c),
1981 gdTrueColorGetGreen (c),
1982 gdTrueColorGetBlue (c),
1983 gdTrueColorGetAlpha (c));
1984 }
1985 else
1986 {
1987 /* Have we established a mapping for this color? */
1988 if (colorMap[c] == (-1))
1989 {
1990 /* If it's the same image, mapping is trivial */
1991 if (dst == src)
1992 {
1993 nc = c;
1994 }
1995 else
1996 {
1997 /* Find or create the best match */
1998 nc = gdImageColorResolveAlpha (dst,
1999 gdTrueColorGetRed (c),
2000 gdTrueColorGetGreen (c),
2001 gdTrueColorGetBlue (c),
2002 gdTrueColorGetAlpha (c));
2003 }
2004 colorMap[c] = nc;
2005 }
2006 mapTo = colorMap[c];
2007 }
2008 }
2009 for (i = 0; (i < stx[x - srcX]); i++)
2010 {
2011 gdImageSetPixel (dst, tox, toy, mapTo);
2012 tox++;
2013 }
2014 }
2015 toy++;
2016 }
2017 }
2018 gdFree (stx);
2019 gdFree (sty);
2020 }
2021
2022 /* When gd 1.x was first created, floating point was to be avoided.
2023 These days it is often faster than table lookups or integer
2024 arithmetic. The routine below is shamelessly, gloriously
2025 floating point. TBB */
2026
2027 void
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2028 gdImageCopyResampled (gdImagePtr dst,
2029 gdImagePtr src,
2030 int dstX, int dstY,
2031 int srcX, int srcY,
2032 int dstW, int dstH,
2033 int srcW, int srcH)
2034 {
2035 int x, y;
2036 if (!dst->trueColor)
2037 {
2038 gdImageCopyResized (
2039 dst, src, dstX, dstY, srcX, srcY, dstW, dstH,
2040 srcW, srcH);
2041 return;
2042 }
2043 for (y = dstY; (y < dstY + dstH); y++)
2044 {
2045 for (x = dstX; (x < dstX + dstW); x++)
2046 {
2047 float sy1, sy2, sx1, sx2;
2048 float sx, sy;
2049 float spixels = 0;
2050 float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2051 sy1 = ((float) y - (float) dstY) * (float) srcH /
2052 (float) dstH;
2053 sy2 = ((float) (y + 1) - (float) dstY) * (float) srcH /
2054 (float) dstH;
2055 sy = sy1;
2056 do
2057 {
2058 float yportion;
2059 if (floor (sy) == floor (sy1))
2060 {
2061 yportion = 1.0 - (sy - floor (sy));
2062 if (yportion > sy2 - sy1)
2063 {
2064 yportion = sy2 - sy1;
2065 }
2066 sy = floor (sy);
2067 }
2068 else if (sy == floor (sy2))
2069 {
2070 yportion = sy2 - floor (sy2);
2071 }
2072 else
2073 {
2074 yportion = 1.0;
2075 }
2076 sx1 = ((float) x - (float) dstX) * (float) srcW /
2077 dstW;
2078 sx2 = ((float) (x + 1) - (float) dstX) * (float) srcW /
2079 dstW;
2080 sx = sx1;
2081 do
2082 {
2083 float xportion;
2084 float pcontribution;
2085 int p;
2086 if (floor (sx) == floor (sx1))
2087 {
2088 xportion = 1.0 - (sx - floor (sx));
2089 if (xportion > sx2 - sx1)
2090 {
2091 xportion = sx2 - sx1;
2092 }
2093 sx = floor (sx);
2094 }
2095 else if (sx == floor (sx2))
2096 {
2097 xportion = sx2 - floor (sx2);
2098 }
2099 else
2100 {
2101 xportion = 1.0;
2102 }
2103 pcontribution = xportion * yportion;
2104 p = gdImageGetTrueColorPixel (
2105 src,
2106 (int) sx,
2107 (int) sy);
2108 red += gdTrueColorGetRed (p) * pcontribution;
2109 green += gdTrueColorGetGreen (p) * pcontribution;
2110 blue += gdTrueColorGetBlue (p) * pcontribution;
2111 alpha += gdTrueColorGetAlpha (p) * pcontribution;
2112 spixels += xportion * yportion;
2113 sx += 1.0;
2114 }
2115 while (sx < sx2);
2116 sy += 1.0;
2117 }
2118 while (sy < sy2);
2119 if (spixels != 0.0)
2120 {
2121 red /= spixels;
2122 green /= spixels;
2123 blue /= spixels;
2124 alpha /= spixels;
2125 }
2126 /* Clamping to allow for rounding errors above */
2127 if (red > 255.0)
2128 {
2129 red = 255.0;
2130 }
2131 if (green > 255.0)
2132 {
2133 green = 255.0;
2134 }
2135 if (blue > 255.0)
2136 {
2137 blue = 255.0;
2138 }
2139 if (alpha > gdAlphaMax)
2140 {
2141 alpha = gdAlphaMax;
2142 }
2143 gdImageSetPixel (dst,
2144 x, y,
2145 gdTrueColorAlpha ((int) red,
2146 (int) green,
2147 (int) blue,
2148 (int) alpha));
2149 }
2150 }
2151 }
2152
2153 gdImagePtr
gdImageCreateFromXbm(FILE * fd)2154 gdImageCreateFromXbm (FILE * fd)
2155 {
2156 gdImagePtr im;
2157 int bit;
2158 int w, h;
2159 int bytes;
2160 int ch;
2161 int i, x, y;
2162 char *sp;
2163 char s[161];
2164 if (!fgets (s, 160, fd))
2165 {
2166 return 0;
2167 }
2168 sp = &s[0];
2169 /* Skip #define */
2170 sp = strchr (sp, ' ');
2171 if (!sp)
2172 {
2173 return 0;
2174 }
2175 /* Skip width label */
2176 sp++;
2177 sp = strchr (sp, ' ');
2178 if (!sp)
2179 {
2180 return 0;
2181 }
2182 /* Get width */
2183 w = atoi (sp + 1);
2184 if (!w)
2185 {
2186 return 0;
2187 }
2188 if (!fgets (s, 160, fd))
2189 {
2190 return 0;
2191 }
2192 sp = s;
2193 /* Skip #define */
2194 sp = strchr (sp, ' ');
2195 if (!sp)
2196 {
2197 return 0;
2198 }
2199 /* Skip height label */
2200 sp++;
2201 sp = strchr (sp, ' ');
2202 if (!sp)
2203 {
2204 return 0;
2205 }
2206 /* Get height */
2207 h = atoi (sp + 1);
2208 if (!h)
2209 {
2210 return 0;
2211 }
2212
2213 /* The X protocol request CreatePixmap puts an upper bound
2214 of 16 bit to the size.
2215 see, e.g. moz#424333, fdo#48961, rhbz#1086714 */
2216 if (w < 0 || w > SHRT_MAX || h < 0 || h > SHRT_MAX)
2217 {
2218 return 0;
2219 }
2220
2221 /* Skip declaration line */
2222 if (!fgets (s, 160, fd))
2223 {
2224 return 0;
2225 }
2226 bytes = (w * h / 8) + 1;
2227 im = gdImageCreate (w, h);
2228 if (!im) {
2229 return 0;
2230 }
2231
2232 gdImageColorAllocate (im, 255, 255, 255);
2233 gdImageColorAllocate (im, 0, 0, 0);
2234 x = 0;
2235 y = 0;
2236 for (i = 0; (i < bytes); i++)
2237 {
2238 char h[3];
2239 int b;
2240 /* Skip spaces, commas, CRs, 0x */
2241 while (1)
2242 {
2243 ch = getc (fd);
2244 if (ch == EOF)
2245 {
2246 goto fail;
2247 }
2248 if (ch == 'x')
2249 {
2250 break;
2251 }
2252 }
2253 /* Get hex value */
2254 ch = getc (fd);
2255 if (ch == EOF)
2256 {
2257 goto fail;
2258 }
2259 h[0] = ch;
2260 ch = getc (fd);
2261 if (ch == EOF)
2262 {
2263 goto fail;
2264 }
2265 h[1] = ch;
2266 h[2] = '\0';
2267 if (sscanf (h, "%x", &b) != 1)
2268 {
2269 goto fail;
2270 }
2271 for (bit = 1; (bit <= 128); (bit = bit << 1))
2272 {
2273 gdImageSetPixel (im, x++, y, (b & bit) ? 1 : 0);
2274 if (x == im->sx)
2275 {
2276 x = 0;
2277 y++;
2278 if (y == im->sy)
2279 {
2280 return im;
2281 }
2282 /* Fix 8/8/95 */
2283 break;
2284 }
2285 }
2286 }
2287 /* Shouldn't happen */
2288 fprintf (stderr, "Error: bug in gdImageCreateFromXbm!\n");
2289 fail:
2290 gdImageDestroy (im);
2291 return 0;
2292 }
2293
2294 void
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2295 gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2296 {
2297 int i;
2298 int lx, ly;
2299 if (!n)
2300 {
2301 return;
2302 }
2303 lx = p->x;
2304 ly = p->y;
2305 gdImageLine (im, lx, ly, p[n - 1].x, p[n - 1].y, c);
2306 for (i = 1; (i < n); i++)
2307 {
2308 p++;
2309 gdImageLine (im, lx, ly, p->x, p->y, c);
2310 lx = p->x;
2311 ly = p->y;
2312 }
2313 }
2314
2315 static int gdCompareInt (const void *a, const void *b);
2316
2317 /* THANKS to Kirsten Schulz for the polygon fixes! */
2318
2319 /* The intersection finding technique of this code could be improved */
2320 /* by remembering the previous intertersection, and by using the slope. */
2321 /* That could help to adjust intersections to produce a nice */
2322 /* interior_extrema. */
2323
2324 void
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2325 gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2326 {
2327 int i;
2328 int y;
2329 int miny, maxy;
2330 int x1, y1;
2331 int x2, y2;
2332 int ind1, ind2;
2333 int ints;
2334 if (!n)
2335 {
2336 return;
2337 }
2338 if (!im->polyAllocated)
2339 {
2340 im->polyInts = (int *) gdMalloc (sizeof (int) * n);
2341 im->polyAllocated = n;
2342 }
2343 if (im->polyAllocated < n)
2344 {
2345 while (im->polyAllocated < n)
2346 {
2347 im->polyAllocated *= 2;
2348 }
2349 im->polyInts = (int *) gdRealloc (im->polyInts,
2350 sizeof (int) * im->polyAllocated);
2351 }
2352 miny = p[0].y;
2353 maxy = p[0].y;
2354 for (i = 1; (i < n); i++)
2355 {
2356 if (p[i].y < miny)
2357 {
2358 miny = p[i].y;
2359 }
2360 if (p[i].y > maxy)
2361 {
2362 maxy = p[i].y;
2363 }
2364 }
2365 /* Fix in 1.3: count a vertex only once */
2366 for (y = miny; (y <= maxy); y++)
2367 {
2368 /*1.4 int interLast = 0; */
2369 /* int dirLast = 0; */
2370 /* int interFirst = 1; */
2371 ints = 0;
2372 for (i = 0; (i < n); i++)
2373 {
2374 if (!i)
2375 {
2376 ind1 = n - 1;
2377 ind2 = 0;
2378 }
2379 else
2380 {
2381 ind1 = i - 1;
2382 ind2 = i;
2383 }
2384 y1 = p[ind1].y;
2385 y2 = p[ind2].y;
2386 if (y1 < y2)
2387 {
2388 x1 = p[ind1].x;
2389 x2 = p[ind2].x;
2390 }
2391 else if (y1 > y2)
2392 {
2393 y2 = p[ind1].y;
2394 y1 = p[ind2].y;
2395 x2 = p[ind1].x;
2396 x1 = p[ind2].x;
2397 }
2398 else
2399 {
2400 continue;
2401 }
2402 if ((y >= y1) && (y < y2))
2403 {
2404 im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
2405 }
2406 else if ((y == maxy) && (y > y1) && (y <= y2))
2407 {
2408 im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
2409 }
2410 }
2411 qsort (im->polyInts, ints, sizeof (int), gdCompareInt);
2412
2413 for (i = 0; (i < (ints)); i += 2)
2414 {
2415 gdImageLine (im, im->polyInts[i], y,
2416 im->polyInts[i + 1], y, c);
2417 }
2418 }
2419 }
2420
2421 int
gdCompareInt(const void * a,const void * b)2422 gdCompareInt (const void *a, const void *b)
2423 {
2424 return (*(const int *) a) - (*(const int *) b);
2425 }
2426
2427 void
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2428 gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2429 {
2430 if (im->style)
2431 {
2432 gdFree (im->style);
2433 }
2434 im->style = (int *)
2435 gdMalloc (sizeof (int) * noOfPixels);
2436 memcpy (im->style, style, sizeof (int) * noOfPixels);
2437 im->styleLength = noOfPixels;
2438 im->stylePos = 0;
2439 }
2440
2441 void
gdImageSetThickness(gdImagePtr im,int thickness)2442 gdImageSetThickness (gdImagePtr im, int thickness)
2443 {
2444 im->thick = thickness;
2445 }
2446
2447 void
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2448 gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2449 {
2450 int i;
2451 im->brush = brush;
2452 if ((!im->trueColor) && (!im->brush->trueColor))
2453 {
2454 for (i = 0; (i < gdImageColorsTotal (brush)); i++)
2455 {
2456 int index;
2457 index = gdImageColorResolveAlpha (im,
2458 gdImageRed (brush, i),
2459 gdImageGreen (brush, i),
2460 gdImageBlue (brush, i),
2461 gdImageAlpha (brush, i));
2462 im->brushColorMap[i] = index;
2463 }
2464 }
2465 }
2466
2467 void
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2468 gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2469 {
2470 int i;
2471 im->tile = tile;
2472 if ((!im->trueColor) && (!im->tile->trueColor))
2473 {
2474 for (i = 0; (i < gdImageColorsTotal (tile)); i++)
2475 {
2476 int index;
2477 index = gdImageColorResolveAlpha (im,
2478 gdImageRed (tile, i),
2479 gdImageGreen (tile, i),
2480 gdImageBlue (tile, i),
2481 gdImageAlpha (tile, i));
2482 im->tileColorMap[i] = index;
2483 }
2484 }
2485 }
2486
2487 void
gdImageInterlace(gdImagePtr im,int interlaceArg)2488 gdImageInterlace (gdImagePtr im, int interlaceArg)
2489 {
2490 im->interlace = interlaceArg;
2491 }
2492
2493 int
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2494 gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2495 {
2496 int x, y;
2497 int p1, p2;
2498 int cmpStatus = 0;
2499 int sx, sy;
2500
2501 if (im1->interlace != im2->interlace)
2502 {
2503 cmpStatus |= GD_CMP_INTERLACE;
2504 }
2505
2506 if (im1->transparent != im2->transparent)
2507 {
2508 cmpStatus |= GD_CMP_TRANSPARENT;
2509 }
2510
2511 if (im1->trueColor != im2->trueColor)
2512 {
2513 cmpStatus |= GD_CMP_TRUECOLOR;
2514 }
2515
2516 sx = im1->sx;
2517 if (im1->sx != im2->sx)
2518 {
2519 cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2520 if (im2->sx < im1->sx)
2521 {
2522 sx = im2->sx;
2523 }
2524 }
2525
2526 sy = im1->sy;
2527 if (im1->sy != im2->sy)
2528 {
2529 cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2530 if (im2->sy < im1->sy)
2531 {
2532 sy = im2->sy;
2533 }
2534 }
2535
2536 if (im1->colorsTotal != im2->colorsTotal)
2537 {
2538 cmpStatus |= GD_CMP_NUM_COLORS;
2539 }
2540
2541 for (y = 0; (y < sy); y++)
2542 {
2543 for (x = 0; (x < sx); x++)
2544 {
2545 p1 = im1->pixels[y][x];
2546 p2 = im2->pixels[y][x];
2547 if (gdImageRed (im1, p1) != gdImageRed (im2, p2))
2548 {
2549 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2550 break;
2551 }
2552 if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2))
2553 {
2554 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2555 break;
2556 }
2557 if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2))
2558 {
2559 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2560 break;
2561 }
2562 #if 0
2563 /* Soon we'll add alpha channel to palettes */
2564 if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2))
2565 {
2566 cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2567 break;
2568 }
2569 #endif
2570 }
2571 if (cmpStatus & GD_CMP_COLOR)
2572 {
2573 break;
2574 };
2575 }
2576
2577 return cmpStatus;
2578 }
2579
2580 int
gdAlphaBlend(int dst,int src)2581 gdAlphaBlend (int dst, int src)
2582 {
2583 return (((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2584 gdTrueColorGetRed (src) / gdAlphaMax) +
2585 (gdTrueColorGetAlpha (src) *
2586 gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
2587 ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2588 gdTrueColorGetGreen (src) / gdAlphaMax) +
2589 (gdTrueColorGetAlpha (src) *
2590 gdTrueColorGetGreen (dst)) / gdAlphaMax) << 8) +
2591 (((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2592 gdTrueColorGetBlue (src) / gdAlphaMax) +
2593 (gdTrueColorGetAlpha (src) *
2594 gdTrueColorGetBlue (dst)) / gdAlphaMax));
2595 }
2596
2597 void
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)2598 gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
2599 {
2600 im->alphaBlendingFlag = alphaBlendingArg;
2601 }
2602
2603 void
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)2604 gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
2605 {
2606 im->saveAlphaFlag = saveAlphaArg;
2607 }
2608