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