CMYK Images And Browsers And ImageMagick
Dealing with user-uploaded images in web applications has become dead simple - yet not simple enough. JPEG knows profiles and color spaces not every renderer understands correctly. This post illustrates how CMYK JPGs present accross browsers and how one can easily avoid those problems. (And show a neat trick to speed up ImageMagick on multi-core systems.)
Source Of All Evil: Colorspaces
CMYK Across Browsers
As you can see, Firefox and Chrome render the CMYK Image close enough to what Adobe Photoshop thought the RGB version should look like. Safari on the other hand is losing color. Internet Explorer 8 is, well, showing a broken image - IE8 cannot display CMYK JPGs.
Looks like we might want to convert CMYK to RGB, just in case…
Convert CMYK to RGB
Both RGB versions look fairly similar. Photshop used the sRGB profile, ImageMagick was told to use the AdobeRGB1998 profile. Close enough. I'm a developer, not a designer… ☺
ImageMagick
Whenever I have to deal with image processing, I call up my old buddy IMagick. IMagick is a PECL (PHP extension) wrapping ImageMagick. It offers a much nicer API than wrangling those exec('convert -resize …');
calls by hand. I haven't used GDLib or command line ImageMagick in years - and I'm missing neither. Of course I haven't dealt with shared hosting environments in years either.
Adobe RGB Profiles
To be able to convert the color profiles of your JPEGs, you need an ICC Color Profile, obtainable from Adobe (download links at the very bottom). Download and extract the AdobeRGB1998.icc file from the archive.
You could ignore the profile, but you'd not be too happy about the colors of the converted images. (Feel free to experiment with other ICCs, though!)
Getting Down To Code
The following few lines convert the input image to the RGB colorspace and apply the AdobeRGB1998 profile (for better colors). Since all browsers (including Internet Explorer 8) display grayscale images just fine, we don't need to blow up their file size by converting them to RGB.
if ($im->getImageColorspace() != IMagick::COLORSPACE_RGB
&& $im->getImageColorspace() != IMagick::COLORSPACE_GRAY) {
$icc_rgb = file_get_contents(__DIR__ . '/AdobeRGB1998.icc');
$im->profileImage('icc', $icc_rgb);
$im->setImageColorspace(IMagick::COLORSPACE_RGB);
}
// do some fun stuff like resizing, cropping or whatever
$im->writeImage(__DIR__ . '/output.jpg');
Optimizing For Multi-Core Hardware
ImageMagick has its downsides, though. One of them being a bad threading implementation. Running the above script on a 24 core machine (fun toy to play with, btw.) I got an execution time of 3 seconds (at a load of 0.5). Running the same script on my 4 year old MacBook pro with only 2 cores took 1 second. Tested with time php test.php
, if you care.
The problem is ImageMagick's very very bad threading implementation. For the command line one can specify export MAGICK_THREAD_LIMIT=2
. IMagick knows IMagick::setResourceLimit() but lacks IMagick::RESOURCETYPE_THREADS.
Lucky us, we can have a look at the ImageMagick source to find out what the value of IMagick::RESOURCETYPE_THREADS
would be. (int) 6 according to resource_.h. Putting that into action:
Imagick::setResourceLimit(6, 1);
$im = new IMagick(__DIR__ .'/input.jpg');
if ($im->getImageColorspace() != IMagick::COLORSPACE_RGB
&& $im->getImageColorspace() != IMagick::COLORSPACE_GRAY) {
$icc_rgb = file_get_contents(__DIR__ . '/AdobeRGB1998.icc');
$im->profileImage('icc', $icc_rgb);
$im->setImageColorspace(IMagick::COLORSPACE_RGB);
}
// do some fun stuff like resizing, cropping or whatever
$im->writeImage(__DIR__ . '/output.jpg');
And we get an execution time of 0.18 seconds (which is about 17 times faster). Awesome, done for the day. ☺
By the way: this wouldn't have been necessary, if we had compiled ImageMagick --without-threads
.
The author does not allow comments to this entry
Comments
Display comments as Linear | Threaded
Sara on :
Thanks! I will try to "limit ImageMagick to single thread"
Also, imagick::FILTER_CATROM is faster than Imagick::FILTER_LANCZOS and produces nearly the same result.
One question:
Where do I find AdobeRGB1998.icc, and how do I install it?
Regards