Some image filters for PHP GD

2011-07-23

I have recently written a few image filters for PHP GD: grayscale, invert colors and sepia tone. I can’t take all the credit for these functions. I found the method to get the RGB value for a pixel in the PHP documentation, and I have rewritten the sepia filter from another language. I wrote the two other functions myself. I guessed a little when I wrote the function for grayscale, but I think it looks quite good. There is an example and the function itself for each filter. This is the original image used in my examples:

Original Image

Original Image

Grayscale

Grayscale

Grayscale

<?php
function image_filter_grayscale(&$image){
	$width = imagesx($image);
	$height = imagesy($image);
	for($x = 0; $x < $width; $x++){
		for($y = 0; $y < $height; $y++){
			$rgb = imagecolorat($image, $x, $y);
			$r = ($rgb>>16)&0xFF;
			$g = ($rgb>>8)&0xFF;
			$b = $rgb&0xFF;
			$bw = (int)(($r+$g+$b)/3);
			$color = imagecolorallocate($image, $bw, $bw, $bw);
			imagesetpixel($image, $x, $y, $color);
		}
	}
}
?>

Inverted Colors

Inverted Colors

Inverted Colors

<?php
function image_filter_invert(&$image){
	$width = imagesx($image);
	$height = imagesy($image);
	for($x = 0; $x < $width; $x++){
		for($y = 0; $y < $height; $y++){
			$rgb = imagecolorat($image, $x, $y);
			$r = 0xFF-(($rgb>>16)&0xFF);
			$g = 0xFF-(($rgb>>8)&0xFF);
			$b = 0xFF-($rgb&0xFF);
			$color = imagecolorallocate($image, $r, $g, $b);
			imagesetpixel($image, $x, $y, $color);
		}
	}
}

?>

Sepia Tone

Sepia Tone

Sepia Tone

<?php
function image_filter_sepia(&$image){
	$width = imagesx($image);
	$height = imagesy($image);
	for($_x = 0; $_x < $width; $_x++){
		for($_y = 0; $_y < $height; $_y++){
			$rgb = imagecolorat($image, $_x, $_y);
			$r = ($rgb>>16)&0xFF;
			$g = ($rgb>>8)&0xFF;
			$b = $rgb&0xFF;

			$y = $r*0.299 + $g*0.587 + $b*0.114;
			$i = 0.15*0xFF;
			$q = -0.001*0xFF;

			$r = $y + 0.956*$i + 0.621*$q;
			$g = $y - 0.272*$i - 0.647*$q;
			$b = $y - 1.105*$i + 1.702*$q;

			if($r<0||$r>0xFF){$r=($r<0)?0:0xFF;}
			if($g<0||$g>0xFF){$g=($g<0)?0:0xFF;}
			if($b<0||$b>0xFF){$b=($b<0)?0:0xFF;}

			$color = imagecolorallocate($image, $r, $g, $b);
			imagesetpixel($image, $_x, $_y, $color);
		}
	}
}
?>

The image object is sent as a reference to the functions. Here is an example on how to call them:

<?php
header("Content-type: image/png");

$image = imagecreatefrompng("logo.png");

image_filter_grayscale($image);
image_filter_invert($image);
image_filter_sepia($image);

imagepng($image);
imagedestroy($image);
?>

If there is something wrong with the functions, or if you have a better way of doing it, please leave a comment.

  • Your sepia method is definitely better than others I’ve seen to do this. Slower, but better results.

    However, for the grayscale and inverted ones, why not just use the built in functions? The PHP imagefilter function supports IMG_FILTER_GRAYSCALE and IMG_FILTER_NEGATE for these, and they are super-fast.

  • It started when I wanted to play around with image manipulation. A couple of my earlier experiments was negative and grayscale, as they are easy to implement and understand. But you are quite right that one should use the built-in functions if possible.