Desaturate Images With PHP

Tuesday, September 6, 2011 - 19:11

To desaturate an image means to remove all non-greyscale colours from it, essentially creating a black and white version. To do this you can use the function imagecopymergegray(), which is part of the GD image library. This function is a little difficult to figure out, but what is does is sample one image into another and optionally changing the amount of colours that are kept during the sampling process. The function can be made to sample just a section of the image, or the whole thing. The parameters of the function are as follows.

  • $dest - The destination image link resource.
  • $source - The source image link resource.
  • $dest_x - x-coordinate of in the destination image to place the copied greyscale sample.
  • $dest_y - y-coordinate of in the destination image to place the copied greyscale sample.
  • $source_x - x-coordinate of in the source image to copy the greyscale sample from.
  • $source_y - y-coordinate of in the source image to copy the greyscale sample from.
  • $source_width - The width of the sampled section from the source image.
  • $source_height - The height of the sampled section from the source image.
  • $pct - The percentage of colour to copy into the destination image. 0 here means fully greyscale and 100 means unchanged.

The following snippet of code will take a colour image (called mycolourimage.jpg) and convert it to a greyscale version and then save it to a new file (mygreyscaleimage.png in this case).

1
2
3
4
5
6
7
8
9
10
11
12
13
// Create image instances
$src = imagecreatefromjpeg('mycolourimage.jpg');
$dest = imagecreatefromjpeg('mycolourimage.jpg');
 
// Greyscale operation
imagecopymergegray($dest, $src, 0, 0, 0, 0, imagesx($src), imagesy($src), 0);
 
// Save the greyscale image file
imagePNG($dest, 'mygreyscaleimage.png', 0);
 
// Remove original images from memory.
imagedestroy($dest);
imagedestroy($src);

You might notice that in the above code we are opening the initial image file twice. This is so that the function can have a source and a destination file to work from. As a test I tried to create an image using imagecreatetruecolor() but this doesn't work when creating true greyscale image. An alternative to opening two images is to open once and use it twice as the source and destination resources. The above code can therefore be simplified into the following.

1
2
3
4
$src = imagecreatefromjpeg('mycolourimage.jpg');
imagecopymergegray($src, $src, 0, 0, 0, 0, imagesx($src), imagesy($src), 0);
imagePNG($src, 'mygreyscaleimage.png', 0);
imagedestroy($src);

An alternative (and much simpler) mechanism for creating greyscale images is to use the imagefilter() function and pass the constant IMG_FILTER_GRAYSCALE as a parameter. The following snippet shows this mechanism in action.

1
2
3
4
5
6
7
$image = imagecreatefromjpeg('mycolourimage.jpg');
imagefilter($image, IMG_FILTER_GRAYSCALE);
 
// Save the image.
imagePNG($image, 'mygreyscaleimage.png', 0);
 
imagedestroy($image);

I actually used this code within a WordPress site recently, which took the featured image of a post and converted it into greyscale. This was for a special greyscale to colour fading effect, but it needed the greyscale images to be created when needed so is a good real world example of the above code in action. Much of the following code snippet is involved in finding out the filename of the image file and making sure that it doesn't exist before the potentially expensive image manipulation. The other main difference is that we are loading the image using wp_load_image(), rather than imagecreatefromjpeg(). This is because the WordPress function is file format aware and will use the relevant function to create the image resource.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$post_id = $post->ID;
 
// Get thumbnail ID
$post_thumbnail_id = get_post_thumbnail_id($post_id);
 
// Find thumbnail locations
$image_src = wp_get_attachment_image_src($post_thumbnail_id, 'thumbnail');
$image_src_path = dirname($image_src[0]);
$image_src_filename = basename($image_src[0]);
 
// Create greyscale filename
$image_src_extention_loc = (strripos($image_src_filename, '.') - strlen($image_src_filename));
$bw_image_filename = substr($image_src_filename, 0, $image_src_extention_loc) . '_bw' . substr($image_src_filename, $image_src_extention_loc);
 
// Get the local path of the image
$wpcontent_image_path = dirname(get_attached_file($post_thumbnail_id));
 
if (!file_exists($wpcontent_image_path . '/' . $bw_image_filename)) {
    // Create greyscale image
    $bw_image = wp_load_image($wpcontent_image_path . '/' . $image_src_filename);
 
    // Apply greyscale filter
    imagefilter($bw_image, IMG_FILTER_GRAYSCALE);
 
    // Save the image.
    imagejpeg($bw_image, $wpcontent_image_path . '/' . $bw_image_filename, 100);
 
    imagedestroy($bw_image);
}
echo '<img src="'  . $image_src_path . '/' . $image_src_filename . '" />';
echo '<img src="'  . $image_src_path . '/' . $bw_image_filename . '" />';

The code above will print out the colour image followed by the greyscale one and should go into The Loop section of your template files.

Category: 
philipnorton42's picture

Philip Norton

Phil is the founder and administrator of #! code and is an IT professional working in the North West of the UK.
Google+ | Twitter

Add new comment