xref: /php-src/ext/gd/libgd/gd_filter.c (revision aba070e6)
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