Search code examples
c#openxmldrawingml

OpenXML scheme color transformations - applying <a:gamma> and <a:invgamma>


When processing an open xml document, colors can have various transformations applied to a base color to generate a relative color. For instance <a:satMod value="25000"> would modify the base colors saturation by 25%. There are two transforms I have been able to find very little information on and they are:

<a:gamma> 

The docs say "This element specifies that the output color rendered by the generating application should be the sRGB gamma shift of the input color."

and

<a:invGamma>

The docs say "This element specifies that the output color rendered by the generating application should be the inverse sRGB gamma shift of the input color."

I would like to understand what calculation I would have to do on the base color to transform it using either of these transformations. Has anybody figured this out?


Solution

  • Yeah. Simply put,

    • <a:gamma> simply means to take the sRGB value (0-1 scale) and linearize it (convert to linear RGB). Take those linear RGB values and save them as sRGB (and convert to 0-255 range if you want).
    • <a:invGamma> is the opposite - take the linear RGB value (0-1 scale) and delinearize it (convert to sRGB). Take those delinearized RGB values and save them as sRGB (and convert to 0-255 range if you want).

    So what is linear RGB? The calculation is here on Wikipedia's sRGB page.

    Here's also a VBA version:

    Public Function sRGB_to_linearRGB(value As Double) 
       If value < 0# Then 
          sRGB_to_linearRGB = 0# 
          Exit Function 
       End If 
       If value <= 0.04045 Then 
          sRGB_to_linearRGB = value / 12.92 
          Exit Function 
       End If 
       If value <= 1# Then 
          sRGB_to_linearRGB = ((value + 0.055) / 1.055) ^ 2.4 
          Exit Function 
       End If 
       sRGB_to_linearRGB = 1# 
    End Function 
    
    Public Function linearRGB_to_sRGB(value As Double) 
       If value < 0# Then 
          linearRGB_to_sRGB = 0# 
          Exit Function 
       End If 
       If value <= 0.0031308 Then 
          linearRGB_to_sRGB = value * 12.92 
          Exit Function 
       End If 
       If value < 1# Then 
          linearRGB_to_sRGB = 1.055 * (value ^ (1# / 2.4)) - 0.055 
          Exit Function 
       End If 
       linearRGB_to_sRGB = 1# 
    End Function 
    

    The value that you pass in is the R, G, B component in 0-1 range, either sRGB or linear RGB. You'll receive the same range back, 0-1, and depending on your needs, you can then convert to 0-255 range to construct your color.