Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.
When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB Show archive.org snapshot . We want to get rid of the metadata, as it might contain sensitive information like GPS coordinates. Since we cannot be sure that every browser is able to display the user provided color profile, we recommend converting it to a well known color space (like sRGB) and thus removing all other color profiles.
The following article guides you through the implementation of the color profile conversion with ImageMagick Show archive.org snapshot and CarrierWave Show archive.org snapshot .
TL;DR: If you don't convert the image before stripping the metadata and profiles, it will be displayed with wrong colors on your website. Always set a color profile after using ImageMagick's -strip
method.
Image with the "eciRGB" Format (original) | original image -strip ped |
original image converted to "sRGB" before -strip
|
---|---|---|
The profile conversion - metadata stripping pipeline
- Chose an appropriate target color profile like sRGB2014.icc from the International Color Consortium Show archive.org snapshot
- Convert all uploaded images to that color profile
- Strip all metadata from the image - including all profiles
- Re-attach the (e.g. sRGB) profile information to the image
With ImageMagick
With ImageMagick, it can be achieved like this:
convert original.jpg -profile sRGB2014.icc -strip -set profile sRGB2014.icc version.jpg
Use mogrify
if you want to alter the original image. If you are using Carrierwave, this image processor might come in handy:
def convert_to_srgb
if /^image/.match?(content_type)
manipulate! do |image|
image.combine_options do |c|
c.profile('path/to/sRGB2014.icc')
c.strip
c.set('profile', 'path/to/sRGB2014.icc')
end
image = yield(image) if block_given?
image
end
end
end
With this conversion in place, user provided images should be displayed correctly in all major browsers. Only Firefox Mobile on Android does not seem to use the attached profile.
Note
-profile
triggers an (expensive) image conversion each time it is called. It implies-set profile
.-set profile
only adds the profile's metadata to the image.
With libvips
See our libvips with CarrierWave card for:
Testing
ImageMagick provides a compare
utility which can be used to measure color differences between two images. You just have to resize and convert them to the same dimensions and color profile (which should be different from both used profiles for this purpose).
With Imagemagick:
mogrify -resize '500x500' -profile sRGB_v4_ICC_preference.icc original.jpg
convert -resize '500x500' -profile sRGB_v4_ICC_preference.icc version.jpg
compare original.jpg version.jpg -metric PHASH /dev/null
With Ruby / CarrierWave
def normalize_image!(image)
# For images to be comparable with ImageMagick, they must
# be of the same size and color profile.
image.manipulate! do |m|
m.combine_options do |c|
c.resize '500x500'
c.profile 'sRGB_v4_ICC_preference.icc'
end
end
end
def color_difference!(image, other_image)
normalize_image!(image)
normalize_image!(other_image)
compare = ['compare']
compare << image.path
compare << other_image.path
compare << '-metric'
compare << 'PHASH' # See https://imagemagick.org/script/command-line-options.php#metric
compare << '/dev/null'
# For reasons, the color difference is written to STDERR
stdout, stderr, status = MiniMagick::Shell.new.execute(compare)
color_difference = stderr.to_f
color_difference
end
# A spec might look like this, given original and version to be CarrierWave versions
expect(color_difference!(original, version)).to <= 5
Notes
-
compare
writes it's result to STDERR. A lower score is better, I'd test for a threshold like <= 5. - There are different comparison metrics Show archive.org snapshot available
- Link to the profile used in the example Show archive.org snapshot
Data Migration
If you add the color profile conversion to an existing Uploader, don't forget to recreate all versions. You could use a Sidekiq Worker on a low-priority queue if many image records and versions are affected.
References
- sRGB v4 Show archive.org snapshot
- ISO 15076-1 Show archive.org snapshot
- The International Color Consortium Show archive.org snapshot , stating:
The v4 ICC specification is widely used and is referred to in many International and other de-facto standards. It was first approved as an International Standard, ISO 15076-1, in 2005 and revised in 2010.