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