GSK: Linearize sRGB color values prior to performing compositing (Gamma corrected alpha blending)
Goals
Gtk defines colors in the sRGB color space, which makes sense due to (SDR) screens also using this color space. Images are most commonly stored with sRGB colors, designers use sRGB colors for specifying the look of (gtk) applications and finally screens expect an input with sRGB colors. This is all fine and fits perfectly together until you take transparency into consideration.
sRGB color values are non-linearly related to light intensity levels where gamma is the exponent in the power law describing the relationship. However, commonly used blending functions are only correct and physically interpretible when you apply them to light intensities. Applying them to sRGB color values without prior linearization yields errors. Therefore sRGB colors have to be linearized prior to performing alpha blending or filtering. Note: The alpha channel is linear in either case, only colors need to be linearized.
Prior Art
Gamma corrected alpha blending is performed both on windows and mac os. Mac os does it everywhere, whereas on windows it kind of depends on how old the windows toolkit used by a specific application is. Though, gamma correction is definitely done for modern Windows 10 UI. Qt also enables it where possible (e.g. otf fonts rendered by freetype). Chrome and Edge (Chromium) perform gamma correction on windows and mac, while firefox only does it on mac os. Safari does it as well. Gamma correction implementations are different among these platforms and applications with gamma exponents varying between ~1.4 and 2.2.
While the "correct" choice of gamma is debatable, some kind of gamma correction is always desirable. One approach is to apply the proper sRGB transfer function with a gamma of about 2.2. AFAIK this is how it is done on mac os. Caveat: Fonts appear lighter and stem darkening needs to be applied to enhance contrast which e.g. mac os heavily relies on. Also, white text on black background looks bolder when compared to black on white.
Another approach is to use "slight" gamma correction with a gamma of about 1.4 to 1.5. With this, stem-darkening is not required. This is still technically incorrect but there is a pragmatic reason for doing it: Black text on white background and white text on black background appear perceptually inverted. This makes dark and light themes appear perceptually uniform while font weight is preserved regardless of foreground and background brightness. Also, I read that windows does it like this but I dont know the actual gamma value currently used by Windows 10 system applications.
Potential Implementation in GSK
Currently the compositing pipeline in GSK looks like this:
sRGB colored UI nodes -> compositing/blending -> final image
This leads to errors due to ignoring the non-linearity of sRGB color values. In order to get correct and physically interpretible alpha blending results, color space transformations would have to be added like this:
sRGB colored UI nodes -> [sRGB to linear RGB] -> compositing/blending -> [linear RGB to sRGB] -> final image
As a proof of concept, I implemented sRGB <--> linear
transformations in GSK by using OpenGL fragment shaders. OpenGL also provides sRGB framebuffer and texture extensions which made the implementation pretty straight forward. I'm not a professional software developer and it is a bit of a hack but it works. In case there is interest, I can post the patches here.
For a potential implementation in all GSK backends, it may be wise to not hardcode the gamma correction value. With Freetype not yet supporting stem darkening for the native truetype hinter, full gamma correction is not yet feasible. But for starters, "slight" gamma correction could be used due to not having to rely on stem darkening. Once freetype implements stem darkening as a generic feature, gtk would be in a good position to switch to full gamma correction. Furthermore, making the gamma correction value configurable would give users the option to roll back to the old behaviour simply by setting gamma to 1.
Links and further reading
OpenGL
Gamma Correction & Alpha Blending
- Long standing cairo issue regarding gamma corrected alpha blending
- Check if your browser does gamma corrected alpha blending
- Charles Poynton's Gamma FAQ
- Wikipedia: Composing alpha blending with gamma correction
- Short youtube video showing the problems caused by incorrect blending