# saturation modulation (satMod) • ### Question

• Hi,
I'm trying to calculate the value for satMod (one of the color transformation) and am having no luck in one particular area. Let me tell you what *does* work first though:

With a color of FF99FF (R=255, G=153, B=255) and satMod of 35%:

```<a:srgbClr val="FF99FF">
<a:satMod="35000"/>
</a:srgbClr>```

I can calculate the correct value of DEBADE (R=222, G=186, B=222). This is simply accomplished by
1. using converting the original color to HSL with .NET's color.getHue/getSaturation/getBrightness
2. modifying the saturation by taking the sat mod value / 100000 and multiplying it by the getSaturation value and then
3. converting back to RGB by a standard hsl-to-rgb code routine

So this works well. Now for the problem.

I'm finding that some Office theme's backgrounds modify the color with a percentage greater than 100%. For example, <a:satMod val="350000"/> or 350%. Using:

```<a:srgbClr val="FF99FF">
<a:satMod="350000"/>
</a:srgbClr>```

PowerPoint produces a value of FF19FF (R=255, G=25, B=255).

This is what I can't figure out - using my formula above, and with the fact that the saturation value of FF99FF is already 100%, using 350% would make it 350% and that just doesn't work. The Ecma specs state that the satMod value multipied by the color's sat value will produce the result in the range of 0-100.

Does anyone have any idea what the secret sauce is here to calculate for satMod values that produce sat values above 100%?

十門
Sunday, November 8, 2009 9:44 AM

• Hello,

The problem you are having is that the RGB values must be converted from sRGB to Linear RGB first, then the Linear RGB's are converted to HSL, do the Saturation Modulation, then go from HSL to Linear to sRGB.

See my post here for the algorithm to convert sRGB to Linear and Vis Versa: http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/f6d26f2c-114f-4a0d-8bca-a27442aec4d0

And here's some VBA code to do it:

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

• Proposed as answer by Thursday, April 8, 2010 12:05 AM
• Unproposed as answer by Friday, April 30, 2010 1:32 AM
• Marked as answer by Tuesday, July 26, 2011 7:12 AM
Thursday, April 8, 2010 12:04 AM

### All replies

• Could anyone help out here? This seems to an issue that can't easily be resolved on my own or through any publically available information. It could do well to eventually be included in the Ecma specs as well if answered here. Appreciate any response on this.
十門
Wednesday, November 11, 2009 6:47 AM
• But it seems that your question does not related to Open XML SDK functions. It is just  Open XML issue.

However, we are glad to solve the problem together with you as well, if you could provide us more specific steps to repro the problem. For example, which version of Office you are using, 2007 SP1 or SP2? And what to do in PowerPoint? Better to have some code snippets. And you said "The Ecma spec state that the satMod ...", then which section is this statement in?
Wednesday, November 11, 2009 7:30 AM
• Hi Ethan,
Thanks for offering to help out. Let's take my example above:

<a:srgbClr val="FF99FF">
<a:satMod val="350000"/>
</a:srgbClr>

If I want to determine what the satMod of #FF99FF is, assuming satMod is between 0-100, I would do something like the below:

```Imports <xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">

Sub Main()
Dim baseColorStructure As XElement = <a:srgbClr val="FF99FF">
<a:satMod val="350000"/>
</a:srgbClr>
Dim baseColor As String = baseColorStructure.@val
Dim cc As New System.Drawing.ColorConverter
Dim tempColor As System.Drawing.Color = cc.ConvertFromString(baseColor)
Dim hue As Single = tempColor.GetHue

Dim saturation As Single = tempColor.GetSaturation
Dim luminance As Single = tempColor.GetBrightness
Dim saturationModulation As Single = baseColorStructure...<a:satMod>.@val / 100000
Dim newSaturation As Single = saturation * saturationModulation
Dim modifedColor As System.Drawing.Color = hslToRgb(hue, newSaturation, luminance)
Console.WriteLine("#" & UCase(modifedColor.Name.ToString))
Console.WriteLine("R: " & modifedColor.R & ", G: ", modifedColor.G & ", B:" & modifedColor.B
End Sub

Private Function hslToRgb(ByVal H As Double, ByVal S As Double, ByVal L As Double) As System.Drawing.Color
Dim p1 As Double = 0
Dim p2 As Double = 0
Dim R
Dim G
Dim B
If L <= 0.5 Then
p2 = L * (1 + S)
Else
p2 = L + S - (L * S)
End If

p1 = 2 * L - p2

If S = 0 Then
R = L
G = L
B = L
Else
R = toRgb(p1, p2, H + 120)
G = toRgb(p1, p2, H)
B = toRgb(p1, p2, H - 120)
End If
R *= 255
G *= 255
B *= 255
Return System.Drawing.Color.FromArgb(R, G, B)
End Function

Private Function toRgb(ByVal q1 As Double, ByVal q2 As Double, ByVal hue As Double) As Double
If hue > 360 Then
hue = hue - 360
End If
If hue < 0 Then
hue = hue + 360
End If
If hue < 60 Then
Return (q1 + (q2 - q1) * hue / 60)
ElseIf hue < 180 Then
Return (q2)
ElseIf hue < 240 Then
Return (q1 + (q2 - q1) * (240 - hue) / 60)
End If
Return (q1)
End Function```

You'll notice this kicks an error. However, if you use "35000" (thirty five thousand) for the satMod value instead of "350000" (three hundred fifty thousand) it works just fine producing #DEBADE (R=222, G=186, B=222). Having satMod and lumMod above 100% seems to be fairly common in DrawingML (especially with themes), but it doesn't conform to normal HSL modifications of between 0-100%. Setting a maximum return value of "1" in case satMod is above 1 doesn't produce the same color as PowerPoint produces.

Is there a different way to calculate satMod and other modifications?

十門
Monday, November 16, 2009 12:05 AM
• Ethan, have you had a chance to look at this?
十門
Saturday, November 21, 2009 1:18 AM
• Bump.

Anyone?
十門
Wednesday, December 2, 2009 12:55 AM
• I tried on my machine and found out that for color FF99FF, its hsl presentation is (300, 1.0, 0.8). Considering satMod is 3.5, the value of saturation is now 3.5, which is out of valid range of saturation. This could be the cause of the problem, as saturation is supposed to be in the range [0,1]. But how to treat this "overflow" case, i don't know either.

Monday, December 7, 2009 6:51 AM
• Hello,

The problem you are having is that the RGB values must be converted from sRGB to Linear RGB first, then the Linear RGB's are converted to HSL, do the Saturation Modulation, then go from HSL to Linear to sRGB.

See my post here for the algorithm to convert sRGB to Linear and Vis Versa: http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/f6d26f2c-114f-4a0d-8bca-a27442aec4d0

And here's some VBA code to do it:

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

• Proposed as answer by Thursday, April 8, 2010 12:05 AM
• Unproposed as answer by Friday, April 30, 2010 1:32 AM
• Marked as answer by Tuesday, July 26, 2011 7:12 AM
Thursday, April 8, 2010 12:04 AM
• Thanks much Tom. Do you know if the linearRGB->HSL conversion algorithm is the same as the sRGB->HSL one (as posted above)?
十門
Thursday, April 8, 2010 2:14 PM
• Hi Tom,

I've spent days and days searching to see what a "linear RGB to HSL" algorithm may be - there doesn't seem to be a single reference to this on all of the internet. Maybe I'm just not understanding what I'm supposed to be looking for here, but I've spent at least 16 hours searching for every thing possible related to this and have come up completely emtpy as far as any possible algorithm.

Could satMod be calculated differently from your suggestion above as it just doesn't seem possible to perform this task at all?

Cheers,

Todd

十門
Wednesday, April 14, 2010 10:08 AM
• I'm having the same issue with Excel. It seems these very high saturation modulation values are common in themes. I'm not able to reproduce the same colors as Excel in those cases. I tried converting to linear rgb, but that seems to have very little effect on the output. The saturation of the resulting hsl color is still being converted to well over 100%, after all.

Tom, I read the post you are referring to. In my case, for tints and shades I get the wrong colors when converting to linear rgb first, and the right colors when I do not. Is this specific to PowerPoint?

Okatu, did you ever find a solution?

Tuesday, July 19, 2011 9:21 PM