How to stop GD2 from washing away the colors upon resizing images?

Fer picture Fer · Apr 24, 2011 · Viewed 12.2k times · Source

I have developed a photo sharing community site using CodeIgniter 1.7. Photos that are uploaded by members are automatically resized in a number of formats, for which I use the CodeIgniter Image Manipulation class. This class is built into the framework and basically a wrapper around multiple image manipulation libraries, such as GD, GD2, ImageMagick, and NETPBM. On my host, I can only make use of GD2, so that's where this question will be about.

On to my problem. Here is an example of a resized photo on my site. Note that the original was very large, over 3000px wide:

http://www.jungledragon.com/image/195/female_impala_close-up.html

Now, look at that same image, also resized, just a bit larger at Flickr:

http://www.flickr.com/photos/fledder/3763538865/in/set-72157621744113979

See the dramatic difference? I'm trying to bridge that huge gap. The first thing I did was to apply a sharpen filter to the images. You can see the result here:

enter image description here

Although still not perfect, it at least approaches the sharpness level of the Flickr image. The remaining problem is that the colors are washed away, as if their saturation is decreased. This happens before the sharpening filter already, so it must be in GD2.

This issue is vitally important to me, but I don't know where to look. I've found some .NET threads talking about chroma sub sampling but I don't know what to do with that information in my setup. I'm looking for any solution that works within the constraints of my setup.

Update: Hereby the original file, exactly as I uploaded it both to my site and Flickr:

http://www.jungledragon.com/img/DSC07275.jpg

Update 2: I'm shocked. In a good way. It took me a lot of pain to install ImageMagick but after switching to it (which was a matter of setting 'imagemagick' as the library to use at the Code Igniter image manipulation class, the result of the test image is as follow:

enter image description here

ImageMagick's resizing is doing it exactly as intended. The colors are preserved, and the sharpness is there. Yes, I disabled my custom sharpening routine since it is no longer needed due to ImageMagick. On top of that, the process is a lot faster and less memory hungry too. And here comes another great part: I cannot explain it, but I did absolutely nothing to tell ImageMagick to use a specific color profile, which was suggested by user @Alix. In my testing so far it looks like the color information is respected with or without an embedded profile. The output simply is a smaller version of the input. Is ImageMagick really that smart or am I dreaming?

Answer

Alix Axel picture Alix Axel · Apr 25, 2011

I've managed to further test this with Imagick:

Imagick sRGB Test

The left half of the image was processed with Imagick and the sRGB_IEC61966-2-1_no_black_scaling.icc color profile, the right half has no color profile associated and shows exactly the same if processed with Imagick or GD; here is the code I used:

header('Content-type: image/jpeg');

$image = new Imagick('/path/to/DSC07275.jpg');

if (($srgb = file_get_contents('http://www.color.org/sRGB_IEC61966-2-1_no_black_scaling.icc')) !== false)
{
    $image->profileImage('icc', $srgb);
    $image->setImageColorSpace(Imagick::COLORSPACE_SRGB);
}

$image->thumbnailImage(1024, 0);

echo $image;

Here is a comparison of the several sRGB profiles available on the color.org website:

sRGB Comparison

It seems to me that the third profile produces the most vivid results, other than that I have no idea how one would make a definitive choice.


EDIT: Apparently, Imagick comes with a bundled sRGB profile, so you don't need to download the one from the Image Color Consortium website, the following code should handle all scenarios:

header('Content-type: image/jpeg');

$image = new Imagick('/path/to/DSC07275.jpg');
$version = $image->getVersion();
$profile = 'http://www.color.org/sRGB_IEC61966-2-1_no_black_scaling.icc';

if ((is_array($version) === true) && (array_key_exists('versionString', $version) === true))
{
    $version = preg_replace('~ImageMagick ([^-]*).*~', '$1', $version['versionString']);

    if (is_file(sprintf('/usr/share/ImageMagick-%s/config/sRGB.icm', $version)) === true)
    {
        $profile = sprintf('/usr/share/ImageMagick-%s/config/sRGB.icm', $version);
    }
}

if (($srgb = file_get_contents($profile)) !== false)
{
    $image->profileImage('icc', $srgb);
    $image->setImageColorSpace(Imagick::COLORSPACE_SRGB);
}

$image->thumbnailImage(1024, 0);

echo $image;