vba - 如何从 PowerPoint 调色板中获取 RGB/Long 值

标签 vba powerpoint

我正在尝试(大部分成功)从事件 ThemeColorScheme 中“读取”颜色.

下面的子程序将从主题中获取 12 种颜色,例如这是 myAccent1 :

http://i.imgur.com/ZwBRgQO.png

我还需要从调色板中获得另外 4 种颜色。我需要的四种颜色将是上面指示的颜色正下方的一种,然后是从左到右接下来的 3 种颜色。

因为ThemeColorScheme对象只有 12 个项目我得到 The specified value is out of range错误,正如预期的那样,如果我尝试为 myAccent9 赋值这边走。我了解此错误及其发生原因。我不知道如何从调色板访问其他 40 多种颜色,这些颜色不属于 ThemeColorScheme目的?

Private Sub ColorOverride()

Dim pres As Presentation
Dim thm As OfficeTheme
Dim themeColor As themeColor
Dim schemeColors As ThemeColorScheme

Set pres = ActivePresentation

Set schemeColors = pres.Designs(1).SlideMaster.Theme.ThemeColorScheme

    myDark1 = schemeColors(1).RGB         'msoThemeColorDark1
    myLight1 = schemeColors(2).RGB        'msoThemeColorLight
    myDark2 = schemeColors(3).RGB         'msoThemeColorDark2
    myLight2 = schemeColors(4).RGB        'msoThemeColorLight2
    myAccent1 = schemeColors(5).RGB       'msoThemeColorAccent1
    myAccent2 = schemeColors(6).RGB       'msoThemeColorAccent2
    myAccent3 = schemeColors(7).RGB       'msoThemeColorAccent3
    myAccent4 = schemeColors(8).RGB       'msoThemeColorAccent4
    myAccent5 = schemeColors(9).RGB       'msoThemeColorAccent5
    myAccent6 = schemeColors(10).RGB      'msoThemeColorAccent6
    myAccent7 = schemeColors(11).RGB      'msoThemeColorThemeHyperlink
    myAccent8 = schemeColors(12).RGB      'msoThemeColorFollowedHyperlink

    '## THESE LINES RAISE AN ERROR, AS EXPECTED:

    'myAccent9 = schemeColors(13).RGB     
    'myAccent10 = schemeColors(14).RGB
    'myAccent11 = schemeColors(15).RGB
    'myAccent12 = schemeColors(16).RGB

End Sub

所以我的问题是,如何从调色板/主题中获取这些颜色的 RGB 值?

最佳答案

第一眼Floris' solution似乎可行,但如果您关心准确性,您很快就会意识到先前的解决方案仅与色彩空间的一小部分的办公室颜色计算相匹配。

正确的解决方案 - 使用 HSL 色彩空间

办公室好像用HSL color模式,同时计算着色和阴影,并使用此技术为我们提供了几乎 100% 准确的颜色计算(在 Office 2013 上测试)。

正确计算值的方法似乎是:

  • 将基本 RGB 颜色转换为 HSL
  • 找到用于五种子颜色的色调和阴影值
  • 应用色调/阴影值
  • 从 HSL 转换回 RGB 色彩空间

  • 要找到色调/阴影值(第 3 步),您可以查看 HSL 颜色的亮度值并使用此表(通过反复试验找到):
    | [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 |
    

    正值使颜色着色(使其更亮),负值使颜色着色(使其更暗)。有五个组; 1 组为全黑,1 组为全白。这些将只匹配这些特定值(而不是例如 RGB = {255, 255, _254_} )。然后是两个小范围的非常深和非常浅的颜色,分别处理,最后是所有其余颜色的大范围。

    注意:+0.40 的值意味着该值将变亮 40%,而不是原始颜色的 40%(这实际上意味着它变亮 60%)。这可能会让某些人感到困惑,但这是 Office 在内部使用这些值的方式(即在 Excel 中通过 TintAndShadeCell.Interior 属性)。

    PowerPoint VBA代码实现解决方案

    【免责声明】:我已经建立在 Floris 的解决方案上来创建这个 VBA。很多HSL翻译代码也是从Word article mentioned in the comments复制过来的已经。

    下面代码的输出是以下颜色变化:

    Program output, calculated color variations

    乍一看,这与 Floris 的解决方案非常相似,但仔细观察后,您可以清楚地看到许多情况下的差异。办公室主题颜色(以及此解决方案)通常比普通的 RGB 变亮/变暗技术更饱和。

    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
    

    关于vba - 如何从 PowerPoint 调色板中获取 RGB/Long 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21142732/

    相关文章:

    excel - 在打开的Word文档中找到未知的姓名和姓氏,将其复制并使用excel VBA粘贴到excel .activesheet中的单元格A12中

    java - Android PowerPoint 远程

    vba - VBA 中 msoTextOrientationHorizo​​ntal 的常量值是多少?

    vba - 当我在 vba powerpoint 中按下一个键时调用一个 Sub

    vba - 将单元格地址的位置存储到 VBA 中的变量中

    python - 如何将值从 VBA 传递到 python

    vba - McAfee 从 VBA 模块中删除代码

    c# - 如何使用 Interop 和 C# 将 *.ppt、*.pptx 文件保存为 *.wmv?

    java - 如何在 OpenXML 中为 java 中的 powerpoint 生成 DataXML

    vba - 执行 URLDownloadToFile 函数返回 E_ACCESSDENIED 公司网络上的一般访问被拒绝错误 0x80070005