xref: /PHP-7.0/ext/gd/libgd/gd_filter.c (revision 499f5480)
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 			new_a = gdImageAlpha(srcback, pxl);
268 
269 			for (j=0; j<3; j++) {
270 				int yv = MIN(MAX(y - 1 + j, 0), src->sy - 1);
271 				for (i=0; i<3; i++) {
272 				        pxl = f(srcback, MIN(MAX(x - 1 + i, 0), src->sx - 1), yv);
273 					new_r += (float)gdImageRed(srcback, pxl) * filter[j][i];
274 					new_g += (float)gdImageGreen(srcback, pxl) * filter[j][i];
275 					new_b += (float)gdImageBlue(srcback, pxl) * filter[j][i];
276 				}
277 			}
278 
279 			new_r = (new_r/filter_div)+offset;
280 			new_g = (new_g/filter_div)+offset;
281 			new_b = (new_b/filter_div)+offset;
282 
283 			new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
284 			new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
285 			new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
286 
287 			new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
288 			if (new_pxl == -1) {
289 				new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
290 			}
291 			gdImageSetPixel (src, x, y, new_pxl);
292 		}
293 	}
294 	gdImageDestroy(srcback);
295 	return 1;
296 }
297 
gdImageSelectiveBlur(gdImagePtr src)298 int gdImageSelectiveBlur( gdImagePtr src)
299 {
300 	int         x, y, i, j;
301 	float       new_r, new_g, new_b;
302 	int         new_pxl, cpxl, pxl, new_a=0;
303 	float flt_r [3][3];
304 	float flt_g [3][3];
305 	float flt_b [3][3];
306 	float flt_r_sum, flt_g_sum, flt_b_sum;
307 
308 	gdImagePtr srcback;
309 	typedef int (*FuncPtr)(gdImagePtr, int, int);
310 	FuncPtr f;
311 
312 	if (src==NULL) {
313 		return 0;
314 	}
315 
316 	/* We need the orinal image with each safe neoghb. pixel */
317 	srcback = gdImageCreateTrueColor (src->sx, src->sy);
318 	if (srcback==NULL) {
319 		return 0;
320 	}
321 	gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
322 
323 	f = GET_PIXEL_FUNCTION(src);
324 
325 	for(y = 0; y<src->sy; y++) {
326 		for (x=0; x<src->sx; x++) {
327 		      flt_r_sum = flt_g_sum = flt_b_sum = 0.0;
328 			cpxl = f(src, x, y);
329 
330 			for (j=0; j<3; j++) {
331 				for (i=0; i<3; i++) {
332 					if ((j == 1) && (i == 1)) {
333 						flt_r[1][1] = flt_g[1][1] = flt_b[1][1] = 0.5;
334 					} else {
335 						pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
336 						new_a = gdImageAlpha(srcback, pxl);
337 
338 						new_r = ((float)gdImageRed(srcback, cpxl)) - ((float)gdImageRed (srcback, pxl));
339 
340 						if (new_r < 0.0f) {
341 							new_r = -new_r;
342 						}
343 						if (new_r != 0) {
344 							flt_r[j][i] = 1.0f/new_r;
345 						} else {
346 							flt_r[j][i] = 1.0f;
347 						}
348 
349 						new_g = ((float)gdImageGreen(srcback, cpxl)) - ((float)gdImageGreen(srcback, pxl));
350 
351 						if (new_g < 0.0f) {
352 							new_g = -new_g;
353 						}
354 						if (new_g != 0) {
355 							flt_g[j][i] = 1.0f/new_g;
356 						} else {
357 							flt_g[j][i] = 1.0f;
358 						}
359 
360 						new_b = ((float)gdImageBlue(srcback, cpxl)) - ((float)gdImageBlue(srcback, pxl));
361 
362 						if (new_b < 0.0f) {
363 							new_b = -new_b;
364 						}
365 						if (new_b != 0) {
366 							flt_b[j][i] = 1.0f/new_b;
367 						} else {
368 							flt_b[j][i] = 1.0f;
369 						}
370 					}
371 
372 					flt_r_sum += flt_r[j][i];
373 					flt_g_sum += flt_g[j][i];
374 					flt_b_sum += flt_b [j][i];
375 				}
376 			}
377 
378 			for (j=0; j<3; j++) {
379 				for (i=0; i<3; i++) {
380 					if (flt_r_sum != 0.0) {
381 						flt_r[j][i] /= flt_r_sum;
382 					}
383 					if (flt_g_sum != 0.0) {
384 						flt_g[j][i] /= flt_g_sum;
385 					}
386 					if (flt_b_sum != 0.0) {
387 						flt_b [j][i] /= flt_b_sum;
388 					}
389 				}
390 			}
391 
392 			new_r = new_g = new_b = 0.0;
393 
394 			for (j=0; j<3; j++) {
395 				for (i=0; i<3; i++) {
396 					pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
397 					new_r += (float)gdImageRed(srcback, pxl) * flt_r[j][i];
398 					new_g += (float)gdImageGreen(srcback, pxl) * flt_g[j][i];
399 					new_b += (float)gdImageBlue(srcback, pxl) * flt_b[j][i];
400 				}
401 			}
402 
403 			new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
404 			new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
405 			new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
406 			new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
407 			if (new_pxl == -1) {
408 				new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
409 			}
410 			gdImageSetPixel (src, x, y, new_pxl);
411 		}
412 	}
413 	gdImageDestroy(srcback);
414 	return 1;
415 }
416 
gdImageEdgeDetectQuick(gdImagePtr src)417 int gdImageEdgeDetectQuick(gdImagePtr src)
418 {
419 	float filter[3][3] =	{{-1.0,0.0,-1.0},
420 				{0.0,4.0,0.0},
421 				{-1.0,0.0,-1.0}};
422 
423 	return gdImageConvolution(src, filter, 1, 127);
424 }
425 
gdImageGaussianBlur(gdImagePtr im)426 int gdImageGaussianBlur(gdImagePtr im)
427 {
428 	float filter[3][3] =	{{1.0,2.0,1.0},
429 				{2.0,4.0,2.0},
430 				{1.0,2.0,1.0}};
431 
432 	return gdImageConvolution(im, filter, 16, 0);
433 }
434 
gdImageEmboss(gdImagePtr im)435 int gdImageEmboss(gdImagePtr im)
436 {
437 /*
438 	float filter[3][3] =	{{1.0,1.0,1.0},
439 				{0.0,0.0,0.0},
440 				{-1.0,-1.0,-1.0}};
441 */
442 	float filter[3][3] =	{{ 1.5, 0.0, 0.0},
443 				 { 0.0, 0.0, 0.0},
444 				 { 0.0, 0.0,-1.5}};
445 
446 	return gdImageConvolution(im, filter, 1, 127);
447 }
448 
gdImageMeanRemoval(gdImagePtr im)449 int gdImageMeanRemoval(gdImagePtr im)
450 {
451 	float filter[3][3] =	{{-1.0,-1.0,-1.0},
452 				{-1.0,9.0,-1.0},
453 				{-1.0,-1.0,-1.0}};
454 
455 	return gdImageConvolution(im, filter, 1, 0);
456 }
457 
gdImageSmooth(gdImagePtr im,float weight)458 int gdImageSmooth(gdImagePtr im, float weight)
459 {
460 	float filter[3][3] =	{{1.0,1.0,1.0},
461 				{1.0,0.0,1.0},
462 				{1.0,1.0,1.0}};
463 
464 	filter[1][1] = weight;
465 
466 	return gdImageConvolution(im, filter, weight+8, 0);
467 }
468 /* End filters function */
469