1 #include "gd.h"
2
3 #include "gd_intern.h"
4
5 #ifdef _WIN32
6 # include <windows.h>
7 #else
8 # include <unistd.h>
9 #endif
10 #include <stdlib.h>
11 #include <time.h>
12
13 /* Filters function added on 2003/12
14 * by Pierre-Alain Joye (pierre@php.net)
15 *
16 * Scatter filter added in libgd 2.1.0
17 * by Kalle Sommer Nielsen (kalle@php.net)
18 **/
19
20 /* Begin filters function */
21 #define GET_PIXEL_FUNCTION(src)(src->trueColor?gdImageGetTrueColorPixel:gdImageGetPixel)
22
23 #ifdef _WIN32
24 # define GD_SCATTER_SEED() (unsigned int)(time(0) * GetCurrentProcessId())
25 #else
26 # define GD_SCATTER_SEED() (unsigned int)(time(0) * getpid())
27 #endif
28
gdImageScatter(gdImagePtr im,int sub,int plus)29 int gdImageScatter(gdImagePtr im, int sub, int plus)
30 {
31 gdScatter s;
32
33 s.sub = sub;
34 s.plus = plus;
35 s.num_colors = 0;
36 s.seed = GD_SCATTER_SEED();
37 return gdImageScatterEx(im, &s);
38 }
39
gdImageScatterColor(gdImagePtr im,int sub,int plus,int colors[],unsigned int num_colors)40 int gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors)
41 {
42 gdScatter s;
43
44 s.sub = sub;
45 s.plus = plus;
46 s.colors = colors;
47 s.num_colors = num_colors;
48 s.seed = GD_SCATTER_SEED();
49 return gdImageScatterEx(im, &s);
50 }
51
gdImageScatterEx(gdImagePtr im,gdScatterPtr scatter)52 int gdImageScatterEx(gdImagePtr im, gdScatterPtr scatter)
53 {
54 register int x, y;
55 int dest_x, dest_y;
56 int pxl, new_pxl;
57 unsigned int n;
58 int sub = scatter->sub, plus = scatter->plus;
59
60 if (plus == 0 && sub == 0) {
61 return 1;
62 }
63 else if (sub >= plus) {
64 return 0;
65 }
66
67 (void)srand(scatter->seed);
68
69 if (scatter->num_colors) {
70 for (y = 0; y < im->sy; y++) {
71 for (x = 0; x < im->sx; x++) {
72 dest_x = (int)(x + ((rand() % (plus - sub)) + sub));
73 dest_y = (int)(y + ((rand() % (plus - sub)) + sub));
74
75 if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
76 continue;
77 }
78
79 pxl = gdImageGetPixel(im, x, y);
80 new_pxl = gdImageGetPixel(im, dest_x, dest_y);
81
82 for (n = 0; n < scatter->num_colors; n++) {
83 if (pxl == scatter->colors[n]) {
84 gdImageSetPixel(im, dest_x, dest_y, pxl);
85 gdImageSetPixel(im, x, y, new_pxl);
86 }
87 }
88 }
89 }
90 }
91 else {
92 for (y = 0; y < im->sy; y++) {
93 for (x = 0; x < im->sx; x++) {
94 dest_x = (int)(x + ((rand() % (plus - sub)) + sub));
95 dest_y = (int)(y + ((rand() % (plus - sub)) + sub));
96
97 if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
98 continue;
99 }
100
101 pxl = gdImageGetPixel(im, x, y);
102 new_pxl = gdImageGetPixel(im, dest_x, dest_y);
103
104 gdImageSetPixel(im, dest_x, dest_y, pxl);
105 gdImageSetPixel(im, x, y, new_pxl);
106 }
107 }
108 }
109
110 return 1;
111 }
112
113 /* invert src image */
gdImageNegate(gdImagePtr src)114 int gdImageNegate(gdImagePtr src)
115 {
116 int x, y;
117 int r,g,b,a;
118 int new_pxl, pxl;
119 typedef int (*FuncPtr)(gdImagePtr, int, int);
120 FuncPtr f;
121
122 if (src==NULL) {
123 return 0;
124 }
125
126 f = GET_PIXEL_FUNCTION(src);
127
128 for (y=0; y<src->sy; ++y) {
129 for (x=0; x<src->sx; ++x) {
130 pxl = f (src, x, y);
131 r = gdImageRed(src, pxl);
132 g = gdImageGreen(src, pxl);
133 b = gdImageBlue(src, pxl);
134 a = gdImageAlpha(src, pxl);
135
136 new_pxl = gdImageColorAllocateAlpha(src, 255-r, 255-g, 255-b, a);
137 if (new_pxl == -1) {
138 new_pxl = gdImageColorClosestAlpha(src, 255-r, 255-g, 255-b, a);
139 }
140 gdImageSetPixel (src, x, y, new_pxl);
141 }
142 }
143 return 1;
144 }
145
146 /* Convert the image src to a grayscale image */
gdImageGrayScale(gdImagePtr src)147 int gdImageGrayScale(gdImagePtr src)
148 {
149 int x, y;
150 int r,g,b,a;
151 int new_pxl, pxl;
152 typedef int (*FuncPtr)(gdImagePtr, int, int);
153 FuncPtr f;
154 int alpha_blending;
155
156 f = GET_PIXEL_FUNCTION(src);
157
158 if (src==NULL) {
159 return 0;
160 }
161
162 alpha_blending = src->alphaBlendingFlag;
163 gdImageAlphaBlending(src, gdEffectReplace);
164
165 for (y=0; y<src->sy; ++y) {
166 for (x=0; x<src->sx; ++x) {
167 pxl = f (src, x, y);
168 r = gdImageRed(src, pxl);
169 g = gdImageGreen(src, pxl);
170 b = gdImageBlue(src, pxl);
171 a = gdImageAlpha(src, pxl);
172 r = g = b = (int) (.299 * r + .587 * g + .114 * b);
173
174 new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
175 if (new_pxl == -1) {
176 new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
177 }
178 gdImageSetPixel (src, x, y, new_pxl);
179 }
180 }
181 gdImageAlphaBlending(src, alpha_blending);
182
183 return 1;
184 }
185
186 /* Set the brightness level <level> for the image src */
gdImageBrightness(gdImagePtr src,int brightness)187 int gdImageBrightness(gdImagePtr src, int brightness)
188 {
189 int x, y;
190 int r,g,b,a;
191 int new_pxl, pxl;
192 typedef int (*FuncPtr)(gdImagePtr, int, int);
193 FuncPtr f;
194 f = GET_PIXEL_FUNCTION(src);
195
196 if (src==NULL || (brightness < -255 || brightness>255)) {
197 return 0;
198 }
199
200 if (brightness==0) {
201 return 1;
202 }
203
204 for (y=0; y<src->sy; ++y) {
205 for (x=0; x<src->sx; ++x) {
206 pxl = f (src, x, y);
207
208 r = gdImageRed(src, pxl);
209 g = gdImageGreen(src, pxl);
210 b = gdImageBlue(src, pxl);
211 a = gdImageAlpha(src, pxl);
212
213 r = r + brightness;
214 g = g + brightness;
215 b = b + brightness;
216
217 r = (r > 255)? 255 : ((r < 0)? 0:r);
218 g = (g > 255)? 255 : ((g < 0)? 0:g);
219 b = (b > 255)? 255 : ((b < 0)? 0:b);
220
221 new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);
222 if (new_pxl == -1) {
223 new_pxl = gdImageColorClosestAlpha(src, (int)r, (int)g, (int)b, a);
224 }
225 gdImageSetPixel (src, x, y, new_pxl);
226 }
227 }
228 return 1;
229 }
230
231
gdImageContrast(gdImagePtr src,double contrast)232 int gdImageContrast(gdImagePtr src, double contrast)
233 {
234 int x, y;
235 int r,g,b,a;
236 double rf,gf,bf;
237 int new_pxl, pxl;
238 typedef int (*FuncPtr)(gdImagePtr, int, int);
239
240 FuncPtr f;
241 f = GET_PIXEL_FUNCTION(src);
242
243 if (src==NULL) {
244 return 0;
245 }
246
247 contrast = (double)(100.0-contrast)/100.0;
248 contrast = contrast*contrast;
249
250 for (y=0; y<src->sy; ++y) {
251 for (x=0; x<src->sx; ++x) {
252 pxl = f(src, x, y);
253
254 r = gdImageRed(src, pxl);
255 g = gdImageGreen(src, pxl);
256 b = gdImageBlue(src, pxl);
257 a = gdImageAlpha(src, pxl);
258
259 rf = (double)r/255.0;
260 rf = rf-0.5;
261 rf = rf*contrast;
262 rf = rf+0.5;
263 rf = rf*255.0;
264
265 bf = (double)b/255.0;
266 bf = bf-0.5;
267 bf = bf*contrast;
268 bf = bf+0.5;
269 bf = bf*255.0;
270
271 gf = (double)g/255.0;
272 gf = gf-0.5;
273 gf = gf*contrast;
274 gf = gf+0.5;
275 gf = gf*255.0;
276
277 rf = (rf > 255.0)? 255.0 : ((rf < 0.0)? 0.0:rf);
278 gf = (gf > 255.0)? 255.0 : ((gf < 0.0)? 0.0:gf);
279 bf = (bf > 255.0)? 255.0 : ((bf < 0.0)? 0.0:bf);
280
281 new_pxl = gdImageColorAllocateAlpha(src, (int)rf, (int)gf, (int)bf, a);
282 if (new_pxl == -1) {
283 new_pxl = gdImageColorClosestAlpha(src, (int)rf, (int)gf, (int)bf, a);
284 }
285 gdImageSetPixel (src, x, y, new_pxl);
286 }
287 }
288 return 1;
289 }
290
291
gdImageColor(gdImagePtr src,const int red,const int green,const int blue,const int alpha)292 int gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha)
293 {
294 int x, y;
295 int new_pxl, pxl;
296 typedef int (*FuncPtr)(gdImagePtr, int, int);
297 FuncPtr f;
298
299 if (src == NULL) {
300 return 0;
301 }
302
303 f = GET_PIXEL_FUNCTION(src);
304
305 for (y=0; y<src->sy; ++y) {
306 for (x=0; x<src->sx; ++x) {
307 int r,g,b,a;
308
309 pxl = f(src, x, y);
310 r = gdImageRed(src, pxl);
311 g = gdImageGreen(src, pxl);
312 b = gdImageBlue(src, pxl);
313 a = gdImageAlpha(src, pxl);
314
315 r = r + red;
316 g = g + green;
317 b = b + blue;
318 a = a + alpha;
319
320 r = (r > 255)? 255 : ((r < 0)? 0 : r);
321 g = (g > 255)? 255 : ((g < 0)? 0 : g);
322 b = (b > 255)? 255 : ((b < 0)? 0 : b);
323 a = (a > 127)? 127 : ((a < 0)? 0 : a);
324
325 new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
326 if (new_pxl == -1) {
327 new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
328 }
329 gdImageSetPixel (src, x, y, new_pxl);
330 }
331 }
332 return 1;
333 }
334
gdImageConvolution(gdImagePtr src,float filter[3][3],float filter_div,float offset)335 int gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset)
336 {
337 int x, y, i, j, new_a;
338 float new_r, new_g, new_b;
339 int new_pxl, pxl=0;
340 gdImagePtr srcback;
341 typedef int (*FuncPtr)(gdImagePtr, int, int);
342 FuncPtr f;
343
344 if (src==NULL) {
345 return 0;
346 }
347
348 /* We need the orinal image with each safe neoghb. pixel */
349 srcback = gdImageCreateTrueColor (src->sx, src->sy);
350 if (srcback==NULL) {
351 return 0;
352 }
353
354 gdImageSaveAlpha(srcback, 1);
355 new_pxl = gdImageColorAllocateAlpha(srcback, 0, 0, 0, 127);
356 gdImageFill(srcback, 0, 0, new_pxl);
357
358 gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
359
360 f = GET_PIXEL_FUNCTION(src);
361
362 for ( y=0; y<src->sy; y++) {
363 for(x=0; x<src->sx; x++) {
364 new_r = new_g = new_b = 0;
365 pxl = f(srcback, x, y);
366 new_a = gdImageAlpha(srcback, pxl);
367
368 for (j=0; j<3; j++) {
369 int yv = MIN(MAX(y - 1 + j, 0), src->sy - 1);
370 for (i=0; i<3; i++) {
371 pxl = f(srcback, MIN(MAX(x - 1 + i, 0), src->sx - 1), yv);
372 new_r += (float)gdImageRed(srcback, pxl) * filter[j][i];
373 new_g += (float)gdImageGreen(srcback, pxl) * filter[j][i];
374 new_b += (float)gdImageBlue(srcback, pxl) * filter[j][i];
375 }
376 }
377
378 new_r = (new_r/filter_div)+offset;
379 new_g = (new_g/filter_div)+offset;
380 new_b = (new_b/filter_div)+offset;
381
382 new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
383 new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
384 new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
385
386 new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
387 if (new_pxl == -1) {
388 new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
389 }
390 gdImageSetPixel (src, x, y, new_pxl);
391 }
392 }
393 gdImageDestroy(srcback);
394 return 1;
395 }
396
gdImageSelectiveBlur(gdImagePtr src)397 int gdImageSelectiveBlur( gdImagePtr src)
398 {
399 int x, y, i, j;
400 float new_r, new_g, new_b;
401 int new_pxl, cpxl, pxl, new_a=0;
402 float flt_r [3][3];
403 float flt_g [3][3];
404 float flt_b [3][3];
405 float flt_r_sum, flt_g_sum, flt_b_sum;
406
407 gdImagePtr srcback;
408 typedef int (*FuncPtr)(gdImagePtr, int, int);
409 FuncPtr f;
410
411 if (src==NULL) {
412 return 0;
413 }
414
415 /* We need the orinal image with each safe neoghb. pixel */
416 srcback = gdImageCreateTrueColor (src->sx, src->sy);
417 if (srcback==NULL) {
418 return 0;
419 }
420 gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
421
422 f = GET_PIXEL_FUNCTION(src);
423
424 for(y = 0; y<src->sy; y++) {
425 for (x=0; x<src->sx; x++) {
426 flt_r_sum = flt_g_sum = flt_b_sum = 0.0;
427 cpxl = f(src, x, y);
428
429 for (j=0; j<3; j++) {
430 for (i=0; i<3; i++) {
431 if ((j == 1) && (i == 1)) {
432 flt_r[1][1] = flt_g[1][1] = flt_b[1][1] = 0.5;
433 } else {
434 pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
435 new_a = gdImageAlpha(srcback, pxl);
436
437 new_r = ((float)gdImageRed(srcback, cpxl)) - ((float)gdImageRed (srcback, pxl));
438
439 if (new_r < 0.0f) {
440 new_r = -new_r;
441 }
442 if (new_r != 0) {
443 flt_r[j][i] = 1.0f/new_r;
444 } else {
445 flt_r[j][i] = 1.0f;
446 }
447
448 new_g = ((float)gdImageGreen(srcback, cpxl)) - ((float)gdImageGreen(srcback, pxl));
449
450 if (new_g < 0.0f) {
451 new_g = -new_g;
452 }
453 if (new_g != 0) {
454 flt_g[j][i] = 1.0f/new_g;
455 } else {
456 flt_g[j][i] = 1.0f;
457 }
458
459 new_b = ((float)gdImageBlue(srcback, cpxl)) - ((float)gdImageBlue(srcback, pxl));
460
461 if (new_b < 0.0f) {
462 new_b = -new_b;
463 }
464 if (new_b != 0) {
465 flt_b[j][i] = 1.0f/new_b;
466 } else {
467 flt_b[j][i] = 1.0f;
468 }
469 }
470
471 flt_r_sum += flt_r[j][i];
472 flt_g_sum += flt_g[j][i];
473 flt_b_sum += flt_b [j][i];
474 }
475 }
476
477 for (j=0; j<3; j++) {
478 for (i=0; i<3; i++) {
479 if (flt_r_sum != 0.0) {
480 flt_r[j][i] /= flt_r_sum;
481 }
482 if (flt_g_sum != 0.0) {
483 flt_g[j][i] /= flt_g_sum;
484 }
485 if (flt_b_sum != 0.0) {
486 flt_b [j][i] /= flt_b_sum;
487 }
488 }
489 }
490
491 new_r = new_g = new_b = 0.0;
492
493 for (j=0; j<3; j++) {
494 for (i=0; i<3; i++) {
495 pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
496 new_r += (float)gdImageRed(srcback, pxl) * flt_r[j][i];
497 new_g += (float)gdImageGreen(srcback, pxl) * flt_g[j][i];
498 new_b += (float)gdImageBlue(srcback, pxl) * flt_b[j][i];
499 }
500 }
501
502 new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
503 new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
504 new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
505 new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
506 if (new_pxl == -1) {
507 new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
508 }
509 gdImageSetPixel (src, x, y, new_pxl);
510 }
511 }
512 gdImageDestroy(srcback);
513 return 1;
514 }
515
gdImageEdgeDetectQuick(gdImagePtr src)516 int gdImageEdgeDetectQuick(gdImagePtr src)
517 {
518 float filter[3][3] = {{-1.0,0.0,-1.0},
519 {0.0,4.0,0.0},
520 {-1.0,0.0,-1.0}};
521
522 return gdImageConvolution(src, filter, 1, 127);
523 }
524
gdImageGaussianBlur(gdImagePtr im)525 int gdImageGaussianBlur(gdImagePtr im)
526 {
527 float filter[3][3] = {{1.0,2.0,1.0},
528 {2.0,4.0,2.0},
529 {1.0,2.0,1.0}};
530
531 return gdImageConvolution(im, filter, 16, 0);
532 }
533
gdImageEmboss(gdImagePtr im)534 int gdImageEmboss(gdImagePtr im)
535 {
536 /*
537 float filter[3][3] = {{1.0,1.0,1.0},
538 {0.0,0.0,0.0},
539 {-1.0,-1.0,-1.0}};
540 */
541 float filter[3][3] = {{ 1.5, 0.0, 0.0},
542 { 0.0, 0.0, 0.0},
543 { 0.0, 0.0,-1.5}};
544
545 return gdImageConvolution(im, filter, 1, 127);
546 }
547
gdImageMeanRemoval(gdImagePtr im)548 int gdImageMeanRemoval(gdImagePtr im)
549 {
550 float filter[3][3] = {{-1.0,-1.0,-1.0},
551 {-1.0,9.0,-1.0},
552 {-1.0,-1.0,-1.0}};
553
554 return gdImageConvolution(im, filter, 1, 0);
555 }
556
gdImageSmooth(gdImagePtr im,float weight)557 int gdImageSmooth(gdImagePtr im, float weight)
558 {
559 float filter[3][3] = {{1.0,1.0,1.0},
560 {1.0,0.0,1.0},
561 {1.0,1.0,1.0}};
562
563 filter[1][1] = weight;
564
565 return gdImageConvolution(im, filter, weight+8, 0);
566 }
567 /* End filters function */
568