Search code examples
excelms-officeopenxmldrawingml

Office Open XML satMod results in more than 100% saturation


I'm trying to calculate the satMod (saturation modulation) for something like the following:

<a:srgbClr val="58CAFF">
    <a:satMod="300000"/>
</a:srgbClr>

Section 20.1.2.3.27 of the EMCA-376 spec says of the <satMod> element: "This element specifies the input color with its saturation modulated by the given percentage. A 50% saturation modulate reduces the saturation by half. A 200% saturation modulate doubles the saturation."

The problem I'm having is that many colors are already saturated enough that increasing the saturation by 300% (the 300000 in there corresponds to 300%) puts it way out of the 0-100% range. I have been simply capping the saturation at 100% but my results are pretty different from what Excel does.

It seems there is some special magic happening here in cases where the saturation should overflow. Anyone know what Office/Excel does in this case?

I found essentially the same question here: http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/040e0a1f-dbfe-4ce5-826b-38b4b6f6d3f7

The answer indicated that the srgb color should be converted to linear rgb first and then to hsl before the saturation is modified. For me that hasn't solved the problem.


Solution

  • That was me that asked that original question. I have since figured it out. With ever single color transformations (satMod, redMod, lumMod, etc.), you have to clamp the value to within sRGB 0,0,0 or 255,255,255 (or 1.0,1.0,1.0). Meaning if your satMod modifies your color by 300% and the result is a color value above 255, clamp it to 255 (or 1.0). With that resulting color, you can then apply other color transforms if they are in your color srgbClr or other color spaces.

    This is what I do in an example like yours.

    1. Convert color to HSL space (these kinds of RGB->HSL routines are common on Bing/Google in a look up).

    2. Send in that color and the satMod to a routine like this:

      Public Sub modulateHSL(ByVal c As HSL, ByVal val As System.Double)
          Select Case c
              Case HSL.Hue
                  Hue = Hue * val
                  If Hue = 0.0 Then
                      If val >= 1.0 Then
                          Hue = val - Fix(val)
                      End If
                  Else
                      Hue = Hue - Fix(Hue)
                  End If
              Case HSL.Saturation
                  Saturation = Saturation * val
              Case HSL.Luminance
                  Luminance = Luminance * val
          End Select
          HSL_To_sRGB(Hue, Saturation, Luminance)
          Clamp_sARGB() 
      End Sub
      
    3. At the end of this routine, you'll notice two calls 1) HSL_To_sRGB(Hue, Saturation, Luminance) and 2) Clamp_sARGB(). The first one converts back to sRGB space and the second one clamps the RGB values, like this:

      Public Sub Clamp_sARGB()
          If Red <= 0.0 Then Red = 0.0 Else If Red >= 1.0 Then Red = 1.0
          If Green <= 0.0 Then Green = 0.0 Else If Green >= 1.0 Then Green = 1.0
          If Blue <= 0.0 Then Blue = 0.0 Else If Blue >= 1.0 Then Blue = 1.0
          If Alpha <= 0.0 Then Alpha = 0.0 Else If Alpha >= 1.0 Then Alpha = 1.0
          sRGB_To_HSL(Red, Green, Blue)
      End Sub
      

    Note there is no need to use Linear RGB in the case where you're only modifying the saturation. I maintain both RBG and HSL spaces in class level fields (RGB in 0-1 space), so that's why you see sRGB_To_HSL(Red, Green, Blue) at the end of that routine.

    Now this is for DrawingML as it appears in PowerPoint. Excel may be different (there is a long drawn out thread here that deals with charts that may also have your answer). Keep in mind that modifying saturation can also modify luminance depending on how you coded your routine. If that's the case, you'll want to use the original luminance when converting back from HSL to RGB.

    If none of this is working for you, can you put an example XLSX on a DropBox point somewhere with what is going on, what you're expecting, etc.?