How to get the RGB/Long values from PowerPoint color palette

后端 未结 3 1022
礼貌的吻别
礼貌的吻别 2021-01-19 15:18

I am trying (mostly successfully) to \"read\" the colors from the active ThemeColorScheme.

The subroutine below will obtain 12 colors from the theme,

相关标签:
3条回答
  • 2021-01-19 16:09

    At first sight Floris' solution seems to work, but if you're concerned with accuracy you'll soon realize that the previous solution matches the office color calculations for just a minor part of the color space.

    A Proper solution - Using HSL color space

    Office seems to use HSL color mode while calculating tinting and shading, and using this technique gives us almost 100% accurate color calculations (tested on Office 2013).

    The methodology for calculating the values correctly seems to be:

    1. Convert the base RGB color to HSL
    2. Find the tint and shade values to use for the five sub-colors
    3. Apply tint/shade values
    4. Convert back from HSL to RGB color space

    To find the tint/shade values (step #3), you look at the Luminosity-value of the HSL color and uses this table (found by trial & error):

    | [0.0] | <0.0 - 0.2> | [0.2 - 0.8] | <0.8 - 1.0> | [1.0] |
    |:-----:|:-----------:|:-----------:|:-----------:|:-----:|
    | + .50 |    + .90    |    + .80    |    - .10    | - .05 |
    | + .35 |    + .75    |    + .60    |    - .25    | - .15 |
    | + .25 |    + .50    |    + .40    |    - .50    | - .25 |
    | + .10 |    + .25    |    - .25    |    - .75    | - .35 |
    | + .05 |    + .10    |    - .50    |    - .90    | - .50 |
    

    Positive values are tinting the color (making it lighter), and negative values are shading the color (making it darker). There are five groups; 1 group for completely black and 1 group for completely white. These will just match these specific values (and not e.g. RGB = {255, 255, _254_}). Then there are two small ranges of very dark and very light colors that are treated separately, and finally a big range for all of the rest colors.

    Note: A value of +0.40 means that the value will get 40% lighter, not that it is a 40% tint of the original color (which actually means that it is 60% lighter). This might be confusing to someone, but this is the way Office uses these values internally (i.e. in Excel through the TintAndShade property of the Cell.Interior).

    PowerPoint VBA code to implement the solution

    [Disclaimer]: I've built upon Floris' solution to create this VBA. A lot of the HSL translation code is also copied from a Word article mentioned in the comments already.

    The output from the code below is the following color variations:

    Program output, calculated color variations

    At first glance, this looks very similar to Floris' solution, but on closer inspection you can clearly see the difference in many situations. Office theme colors (and thus this solution) is generally more saturated the the plain RGB lighten/darken technique.

    Comparison of the different solutions. This matches office very well!

    Option Explicit
    
    Public Type HSL
        h As Double ' Range 0 - 1
        S As Double ' Range 0 - 1
        L As Double ' Range 0 - 1
    End Type
    
    Public Type RGB
        R As Byte
        G As Byte
        B As Byte
    End Type
    
    Sub CalcColor()
        Dim ii As Integer, jj As Integer
        Dim pres As Presentation
        Dim schemeColors As ThemeColorScheme
        Dim ts As Double
        Dim c, c2 As Long
        Dim hc As HSL, hc2 As HSL
    
        Set pres = ActivePresentation
        Set schemeColors = pres.Designs(1).SlideMaster.Theme.ThemeColorScheme
    
        ' For all colors
        For ii = 0 To 11
          c = schemeColors(ii + 1).RGB
    
          ' Generate all the color variations
          For jj = 0 To 5
            hc = RGBtoHSL(c)
            ts = SelectTintOrShade(hc, jj)
            hc2 = ApplyTintAndShade(hc, ts)
            c2 = HSLtoRGB(hc2)
            Call CreateShape(pres.Slides(1), ii, jj, c2)
          Next jj
        Next ii
    
    End Sub
    
    ' The tint and shade value is a value between -1.0 and 1.0, where
    ' -1.0 means fully shading (black), and 1.0 means fully tinting (white)
    ' A tint/shade value of 0.0 will not change the color
    Public Function SelectTintOrShade(hc As HSL, variationIndex As Integer) As Double
    
        Dim shades(5) As Variant
        shades(0) = Array(0#, 0.5, 0.35, 0.25, 0.15, 0.05)
        shades(1) = Array(0#, 0.9, 0.75, 0.5, 0.25, 0.1)
        shades(2) = Array(0#, 0.8, 0.6, 0.4, -0.25, -0.5)
        shades(3) = Array(0#, -0.1, -0.25, -0.5, -0.75, -0.9)
        shades(4) = Array(0#, -0.05, -0.15, -0.25, -0.35, -0.5)
    
        Select Case hc.L
            Case Is < 0.001: SelectTintOrShade = shades(0)(variationIndex)
            Case Is < 0.2:   SelectTintOrShade = shades(1)(variationIndex)
            Case Is < 0.8:   SelectTintOrShade = shades(2)(variationIndex)
            Case Is < 0.999: SelectTintOrShade = shades(3)(variationIndex)
            Case Else:       SelectTintOrShade = shades(4)(variationIndex)
        End Select
    End Function
    
    Public Function ApplyTintAndShade(hc As HSL, TintAndShade As Double) As HSL
    
        If TintAndShade > 0 Then
            hc.L = hc.L + (1 - hc.L) * TintAndShade
        Else
            hc.L = hc.L + hc.L * TintAndShade
        End If
    
        ApplyTintAndShade = hc
    
    End Function
    
    Sub CreateShape(slide As slide, xIndex As Integer, yIndex As Integer, color As Long)
    
        Dim newShape As Shape
        Dim xStart As Integer, yStart As Integer
        Dim xOffset As Integer, yOffset As Integer
        Dim xSize As Integer, ySize As Integer
        xStart = 100
        yStart = 100
        xOffset = 30
        yOffset = 30
        xSize = 25
        ySize = 25
    
        Set newShape = slide.Shapes.AddShape(msoShapeRectangle, xStart + xOffset * xIndex, yStart + yOffset * yIndex, xSize, ySize)
        newShape.Fill.BackColor.RGB = color
        newShape.Fill.ForeColor.RGB = color
        newShape.Line.ForeColor.RGB = 0
        newShape.Line.BackColor.RGB = 0
    
    End Sub
    
    ' From RGB to HSL
    
    Function RGBtoHSL(ByVal RGB As Long) As HSL
    
        Dim R As Double ' Range 0 - 1
        Dim G As Double ' Range 0 - 1
        Dim B As Double ' Range 0 - 1
    
        Dim RGB_Max  As Double
        Dim RGB_Min  As Double
        Dim RGB_Diff As Double
    
        Dim HexString As String
    
        HexString = Right$(String$(7, "0") & Hex$(RGB), 8)
        R = CDbl("&H" & Mid$(HexString, 7, 2)) / 255
        G = CDbl("&H" & Mid$(HexString, 5, 2)) / 255
        B = CDbl("&H" & Mid$(HexString, 3, 2)) / 255
    
        RGB_Max = R
        If G > RGB_Max Then RGB_Max = G
        If B > RGB_Max Then RGB_Max = B
    
        RGB_Min = R
        If G < RGB_Min Then RGB_Min = G
        If B < RGB_Min Then RGB_Min = B
    
        RGB_Diff = RGB_Max - RGB_Min
    
        With RGBtoHSL
    
            .L = (RGB_Max + RGB_Min) / 2
    
            If RGB_Diff = 0 Then
    
                .S = 0
                .h = 0
    
            Else
    
                Select Case RGB_Max
                    Case R: .h = (1 / 6) * (G - B) / RGB_Diff - (B > G)
                    Case G: .h = (1 / 6) * (B - R) / RGB_Diff + (1 / 3)
                    Case B: .h = (1 / 6) * (R - G) / RGB_Diff + (2 / 3)
                End Select
    
                Select Case .L
                    Case Is < 0.5: .S = RGB_Diff / (2 * .L)
                    Case Else:     .S = RGB_Diff / (2 - (2 * .L))
                End Select
    
            End If
    
        End With
    
    End Function
    
    ' .. and back again
    
    Function HSLtoRGB(ByRef HSL As HSL) As Long
    
        Dim R As Double
        Dim G As Double
        Dim B As Double
    
        Dim X As Double
        Dim Y As Double
    
        With HSL
    
            If .S = 0 Then
    
                R = .L
                G = .L
                B = .L
    
            Else
    
                Select Case .L
                    Case Is < 0.5: X = .L * (1 + .S)
                    Case Else:     X = .L + .S - (.L * .S)
                End Select
    
                Y = 2 * .L - X
    
                R = H2C(X, Y, IIf(.h > 2 / 3, .h - 2 / 3, .h + 1 / 3))
                G = H2C(X, Y, .h)
                B = H2C(X, Y, IIf(.h < 1 / 3, .h + 2 / 3, .h - 1 / 3))
    
            End If
    
        End With
    
        HSLtoRGB = CLng("&H00" & _
                        Right$("0" & Hex$(Round(B * 255)), 2) & _
                        Right$("0" & Hex$(Round(G * 255)), 2) & _
                        Right$("0" & Hex$(Round(R * 255)), 2))
    
    End Function
    
    Function H2C(X As Double, Y As Double, hc As Double) As Double
    
        Select Case hc
            Case Is < 1 / 6: H2C = Y + ((X - Y) * 6 * hc)
            Case Is < 1 / 2: H2C = X
            Case Is < 2 / 3: H2C = Y + ((X - Y) * ((2 / 3) - hc) * 6)
            Case Else:       H2C = Y
        End Select
    
    End Function
    
    0 讨论(0)
  • 2021-01-19 16:10

    Based on the above solution with HSL values adding here a demo that works in Excel. Works in conjunction with the above listed HSL solution.

    Sub DemoExcelThemecolorsHSL()
       Dim rng As Range
       Dim n As Integer, m As Integer
       Dim arrNames
       Dim arrDescriptions
       Dim arrValues
       Dim schemeColors As ThemeColorScheme
       Dim dblTintShade As Double
       Dim lngColorRGB As Long, lngColorRGBshaded As Long
       Dim ColorHSL As HSL, ColorHSLshaded As HSL
    
       Set schemeColors = ActiveWorkbook.Theme.ThemeColorScheme
    
       arrNames = Array("xlThemeColorDark1", "xlThemeColorLight1", "xlThemeColorDark2", "xlThemeColorLight2", "xlThemeColorAccent1", "xlThemeColorAccent2", _
                        "xlThemeColorAccent3", "xlThemeColorAccent4", "xlThemeColorAccent5", "xlThemeColorAccent6", "xlThemeColorHyperlink", "xlThemeColorFollowedHyperlink")
       arrDescriptions = Array("Dark1", "Light1", "Dark2", "Light2", "Accent1", "Accent2", "Accent3", "Accent4", "Accent5", "Accent6", "Hyperlink", "Followed hyperlink")
       arrValues = Array(2, 1, 4, 3, 5, 6, 7, 8, 9, 10, 11, 12)
    
       ' New sheet, title row
       ActiveWorkbook.Worksheets.Add
       Set rng = Cells(1, 2)
       rng(1, 1).Value2 = "ThemeColor Name"
       rng(1, 2).Value2 = "Value"
       rng(1, 3).Value2 = "Description"
       rng(1, 4).Value2 = "TintAndShade"
       rng.Resize(1, 4).Font.Bold = True
    
       Set rng = rng(3, 1)
       ' color matrix
       For n = 0 To 11
          rng(n * 2, 1).Value = arrNames(n)
          rng(n * 2, 2).Value = arrValues(n)
          rng(n * 2, 3).Value = arrDescriptions(n)
    
          lngColorRGB = schemeColors(n + 1).RGB
          For m = 0 To 5
             ColorHSL = RGBtoHSL(lngColorRGB)
             dblTintShade = SelectTintOrShade(ColorHSL, m)
             ColorHSLshaded = ApplyTintAndShade(ColorHSL, dblTintShade)
             lngColorRGBshaded = HSLtoRGB(ColorHSLshaded)
    
             With rng(n * 2, m + 4)
                .Value = dblTintShade
                If ColorHSLshaded.L < 0.5 Then .Font.ColorIndex = 2
    
                ' fixed color, not changing when a new Color scheme is being selected
                .Interior.color = lngColorRGBshaded
    
                ' cell color dependent on selected color palette
                .Offset(1, 0).Interior.ThemeColor = arrValues(n)
                .Offset(1, 0).Interior.TintAndShade = dblTintShade
    
             End With
          Next m
       Next n
       rng.Resize(1, 3).EntireColumn.AutoFit
    
    End Sub
    
    0 讨论(0)
  • 2021-01-19 16:12

    If you use VBA for excel, you can record your keystrokes. Selecting another color (from below the theme) shows:

        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .ThemeColor = xlThemeColorLight2
        .TintAndShade = 0.599993896298105
        .PatternTintAndShade = 0
    

    The .TintAndShade factor modifies the defined color. Different colors in the theme use different values for .TintAndShade - sometimes the numbers are negative (to make light colors darker).

    Incomplete table of .TintAndShade (for the theme I happened to have in Excel, first two colors):

     0.00  0.00
    -0.05  0.50
    -0.15  0.35
    -0.25  0.25
    -0.35  0.15
    -0.50  0.05
    

    EDIT some code that "more or less" does the conversion - you need to make sure that you have the right values in your shades, but otherwise the conversion of colors seems to work

    updated to be pure PowerPoint code, with output shown at the end

    Option Explicit
    
    Sub calcColor()
    Dim ii As Integer, jj As Integer
    Dim pres As Presentation
    Dim thm As OfficeTheme
    Dim themeColor As themeColor
    Dim schemeColors As ThemeColorScheme
    Dim shade
    Dim shades(12) As Variant
    Dim c, c2 As Long
    Dim newShape As Shape
    
    Set pres = ActivePresentation
    Set schemeColors = pres.Designs(1).SlideMaster.Theme.ThemeColorScheme
    shades(0) = Array(0, -0.05, -0.15, -0.25, -0.35, -0.5)
    shades(1) = Array(0, 0.05, 0.15, 0.25, 0.35, 0.5)
    shades(2) = Array(-0.1, -0.25, -0.5, -0.75, -0.9)
    For ii = 3 To 11
      shades(ii) = Array(-0.8, -0.6, -0.4, 0.25, 0.5)
    Next
    
    For ii = 0 To 11
      c = schemeColors(ii + 1).RGB
      For jj = 0 To 4
        c2 = fadeRGB(c, shades(ii)(jj))
        Set newShape = pres.Slides(1).Shapes.AddShape(msoShapeRectangle, 200 + 30 * ii, 200 + 30 * jj, 25, 25)
        newShape.Fill.BackColor.RGB = c2
        newShape.Fill.ForeColor.RGB = c2
        newShape.Line.ForeColor.RGB = 0
        newShape.Line.BackColor.RGB = 0
      Next jj
    Next ii
    
    End Sub
    
    Function fadeRGB(ByVal c, s) As Long
    Dim r, ii
    r = toRGB(c)
    For ii = 0 To 2
      If s < 0 Then
        r(ii) = Int((r(ii) - 255) * s + r(ii))
      Else
        r(ii) = Int(r(ii) * (1 - s))
      End If
    Next ii
    fadeRGB = r(0) + 256& * (r(1) + 256& * r(2))
    
    End Function
    
    Function toRGB(c)
    Dim retval(3), ii
    
    For ii = 0 To 2
      retval(ii) = c Mod 256
      c = (c - retval(ii)) / 256
    Next
    
    toRGB = retval
    
    End Function
    

    enter image description here

    0 讨论(0)
提交回复
热议问题