Colour (mis)management on the web

21st March 2021

Colour management – appropriate rendering of colour information – has a troubled relationship with the web, which is to say few people understand it and many websites commit heinous atrocities to colour.

For websites, it’s very simple: don’t mess with colour information. Leave that colour profile alone and walk away. The website should store graphic elements with any embedded colour profiles or colour-related metadata. When the page is requested from the website it should then supply the graphic element with any embedded profile and colour-related metadata unaltered. Any rendering from one colour space to another should normally be a matter for the browser, not the website.

If your website is concerned only with sRGB images, you can make a case for converting images to sRGB. That’s not always a good idea, and means the website may not be future-proof, but it may make sense if you are targetting a general web audience, who probably have roughly sRGB gamut monitors. Whatever you do, don’t simply remove the profile or colour-related metadata, and if you convert to another colour space, make sure the correct profile for the new colour space is embedded. Unfortunately many web content management systems (CMS) are a bit clueless about colour, and don’t convert images to sRGB, they simply delete the profile! This is like taking a temperature value and crossing off the label that says whether it’s degrees F or degrees C (or even degrees K). When the web page is retrieved, the poor bloody browser has no clue how to render the colour in the image, and has to guess. 

WordPress

This website uses WordPress, and I’ve discovered that WordPress and some plugins do mysterious and inconsistent things to colour profiles. When an image is uploaded to the site, typically it is put in the “Media Library”.  In addition to the original image (with any profile and colour-related metadata intact), WordPress typically creates lower resolution versions with the profile and most medadata stripped out.  The W3C standard says that images without embedded profiles or colour metadata should be in sRGB colour space, but WordPress doesn’t bother to convert or even check the colour space before discarding any relevant information. 

When an image is displayed, what happens depends on whether the original image is displayed or one of the reduced resolution versions.  Code created by the WordPress block editor may choose one of the lower resolution versions, which may then be displayed incorrectly.  This is unpredictable.  It does this for all block types I’ve checked that that incorporate images, including the legacy Classsic blocks. To make matters worse, different browsers make different assumptions if profile and/or metadata is missing. Intriguingly, even different Chrome-based browsers differ in how they render WordPress-delivered images.  Nextgen Gallery and other gallery plugins may take different action. 

The result of all this is that images in colour spaces other than sRGB may be displayed incorrectly, depending on the exact circumstances in which the image is displayed (including the size of the displayed image), which plugins are used to upload or display the images, and depending on assumptions made by the browser for missing profile or metadata. 

This chaotic and arbitrary treatment of colour has been around a long time. Googling about colour errors on WordPress returns many, many hits where people report inaccurate colour on WordPress sites, and the only answer appears to be to upload only sRGB images. It’s a disaster if you want to use other colour spaces. The WordPress developer community is presumably blissfully unaware of the problems they create, as most of the web is unconcerned with colour accuracy and most monitors are roughly sRGB.

This issue will come back to bite WordPress, as increasingly monitors will not be sRGB, but will be wider gamut spaces like UHD Rec 2020, and people will start wondering why colours are all wrong. They may also start wondering why they can’t have the bright, vivid colours that were the reason for buying an HDR monitor.

The only fix I’ve found is to display images by inserting custom html blocks with <img > tags that explicitly reference the original uploaded image, rather than one of the reduced resolution versions (which is what WordPress editor blocks tend to do).

The moral for website developers: if you don’t know what you’re doing, don’t touch profiles or colour metadata, and follow the standards. 

Microsoft browsers and image viewers

Internet Explorer and Edge (up until the new Chromium-based version launched in 2020) had colour management built in, but deliberatly crippled it.  They ignore the monitor profile and convert the image to sRGB.  This guarantees wrong colours except for monitors with an accurate sRGB colour space, and I’ve yet to hear any rational explanation for this behaviour. 

The Windows 7 “Windows Photo Viewer” correctly colour-manages.  But the newer Windows 10 Photos app behaves the same way as IE and the old Edge.  Why?

Firefox

The Firefox developer community don’t get it quite right either.  The W3C (World Wide Web Consortium), who write the web standards, do understand colour, and and specify that if an image or graphic element does not contain an embedded profile it should be rendered as sRGB.  The Firefox developers (probably through ignorance and failure to read the W3C specs) decided that by default Firefox won’t colour-manage elements without a profile.  The means that if an element has no profile, it will be displayed in the right colour only if by coincidence the monitor has exactly the same colour space as the image. 

There is an option to make Firefox obey the W3C standard, by setting option “gfx.color_management.mode” to 1 (from its default of 2).  However in 2020, Firefox made a change to the browser that stopped even this option working.  This was apparently not a bug, but a misunderstanding of colour management.  This made Firefox largely unusable on a wide-gamut monitor. The discussion on the bugzilla threads for this change suggested the developers didn’t really understand the issue (which was fixed after a month or two following a lot of grumbling from users that did understand the issue).