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