The PODA Blog

News, views and articles from our membership

Archive for October 10th, 2007

Colours in Word 2007, Part 2

Posted by Tony Jollans (Microsoft MVP for Word) on 10th October 2007

Introduction and a Puzzle

In my first post I looked at how new Theme colour references are stored in old Color properties, and how to set and query them but I stopped short of how to translate them into RGB values. Read on! But, first, a puzzle:

Here’s a line of code for VBA in Word 2007; run it against a blank document. It’s very simple; it just adds a coloured square to the top left of the document.


ActiveDocument _
    .Shapes.AddShape(msoShapeRectangle, 1, 1, 100, 100) _
    .Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent2

Here’s a line of code for VBA in Excel 2007; run it against a blank workbook. It’s very simple; it’s just like the one above except that ActiveDocument has been replaced by ActiveSheet


ActiveSheet _
    .Shapes.AddShape(msoShapeRectangle, 1, 1, 100, 100) _
    .Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent2

Here’s a line of code for VBA in PowerPoint 2007; run it against a blank presentation. It’s very simple; it’s just like the ones above except that it’s a little bit more complex to refer to the Active Slide in PowerPoint.


ActiveWindow.Selection.SlideRange(1) _
    .Shapes.AddShape(msoShapeRectangle, 1, 1, 100, 100) _
    .Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent2

If you are using the same Theme in all three applications, you might expect to see the same result in all of them. The fact that you don’t is part of what makes working with the new colour model so difficult. Although I don’t go into much detail about applications other than Word, I hope that, by the end of this post, you will know, if not understand, why this strange effect occurs.

Themes, Schemes, and Enumerations

Word 2000 saw the introduction of a Themes feature. It was poorly documented, poorly understood, and little used. It still exists but, apart from a guest appearance in E-Mail Options, about which probably the less said the better, the User Interface has gone. The Word 2007, really Office 2007, Themes feature, for most practical purposes, replaces it. This, too, is poorly documented, but will, I suspect, be more used. Part of the Word 2007 Themes feature, and the only part of interest here, is the colour scheme.

A Theme Color Scheme consists of 12 base colours, called Theme Colors: four Text and Background colours (Text/Background - Dark 1, Text/Background - Light 1, Text/Background - Dark 2, and Text/Background – Light 2), six Accent colours (Accent 1, Accent 2, Accent 3, Accent 4, Accent 5, Accent 6), and two Hyperlink colours (Hyperlink, Followed Hyperlink).

As far as I can tell, there is no VBA interface to the available Themes, but there is one to the Document Theme. The DocumentTheme object (of type OfficeTheme), not to be confused with the ActiveTheme property (of Type String), which relates to old Themes, has a ThemeColorScheme property, which takes a single argument of type msoThemeColorSchemeIndex; this enumeration has the following values:

Enumeration Constant  Value 
msoThemeDark1 1
msoThemeLight1 2
msoThemeDark2 3
msoThemeLight2 4
msoThemeAccent1 5
msoThemeAccent2 6
msoThemeAccent3 7
msoThemeAccent4 8
msoThemeAccent5 9
msoThemeAccent6 10
msoThemeHyperlink 11
 msoThemeFollowedHyperlink  12

The msoThemeColorSchemeIndex Enumeration

To get a reference to the “Text/Background - Dark 1ThemeColorScheme object, for example, you would use the msoThemeDark1 constant. From this you can query and set some details of the theme colour scheme, but I must stress that not all of the details are exposed through the object model.

The object that explicitly uses theme colours in the object model is the ColorFormat object; in Word, its ObjectThemeColor property (usually) takes values from the wdThemeColorIndex enumeration. You also saw last time that values from this enumeration could be used as part of a hex value representing a theme colour on document elements that did not have a ColorFormat object. This Word enumeration has the following, slightly different, values:

Enumeration Constant  Value 
(wdNotThemeColor) (-1)
wdThemeColorMainDark1 0
wdThemeColorMainLight1 1
wdThemeColorMainDark2 2
wdThemeColorMainLight2 3
wdThemeColorAccent1 4
wdThemeColorAccent2 5
wdThemeColorAccent3 6
wdThemeColorAccent4 7
wdThemeColorAccent5 8
wdThemeColorAccent6 9
wdThemeColorHyperlink 10
 wdThemeColorFollowedHyperlink  11
wdThemeColorBackground1 12
wdThemeColorText1 13
wdThemeColorBackground2 14
wdThemeColorText2 15

The wdThemeColorIndex Enumeration

Although there are similarities between the two enumerations, there is no immediately obvious correlation. Not only is the correlation not immediately obvious, it is also not fixed and not made available via the object model. Without comment, further details being beyond the scope of this post, the default mapping is:

Word Theme Colour  (Value)  Theme Colour  (Value) 
wdThemeColorMainDark1 0 msoThemeDark1* 1
wdThemeColorMainLight1 1 msoThemeLight1* 2
wdThemeColorMainDark2 2 msoThemeDark2* 3
wdThemeColorMainLight2 3 msoThemeLight2* 4
wdThemeColorAccent1 4 msoThemeAccent1 5
wdThemeColorAccent2 5 msoThemeAccent2 6
wdThemeColorAccent3 6 msoThemeAccent3 7
wdThemeColorAccent4 7 msoThemeAccent4 8
wdThemeColorAccent5 8 msoThemeAccent5 9
wdThemeColorAccent6 9 msoThemeAccent6 10
wdThemeColorHyperlink 10 msoThemeHyperlink 11
 wdThemeColorFollowedHyperlink  11  msoThemeFollowedHyperlink  12
wdThemeColorBackground1 12 msoThemeLight1 2
wdThemeColorText1 13 msoThemeDark1 1
wdThemeColorBackground2 14 msoThemeLight2 4
wdThemeColorText2 15 msoThemeDark2 3

The default mapping of Word colours to Theme colours

The first four values (marked with asterisks) are not explicitly mapped but, if used, will act as per the simple fixed mapping shown. Also beyond the scope of this article and, again, not addressable via the object model is the fact that the default Dark1 and Light1 colours are Windows system colours for Window Text and Window Background respectively.

Red, Green, and Blue

So far all that you have seen is references to colours, not real colours at all. RGB binary triple values for Theme Colours are made available via the RGB property of the OfficeTheme object. Used in conjunction with the mapping shown above this allows you, at last, to start to translate references into real colours.

If you look back at part 1 you will see a routine, Colours2, which called another routine, QuerySchemeColor, which, in turn, displayed the theme colour in use on the Selection. I intend to continue to leave the interested reader to turn one or both of these routines into Functions and, in that vein, the QuerySchemeColor routine can now be amended to display the RGB colour instead of the scheme name. Instead of translating the Scheme colour to a name, it is now converted to an index into the Theme ColorScheme as per the above table. This can then be used to get, and display, the scheme red, green, and blue values instead of that name.


Sub QuerySchemeColor(HexString As String)

    Dim SchemeColorByte As String
    Dim ZeroByte        As String
    Dim DarknessByte    As String
    Dim LightnessByte   As String

    Dim SchemeColor As Long
    Dim Darkness    As Long
    Dim Lightness   As Long

    Dim SchemeColorName   As String
    Dim TintingAndShading As String

    SchemeColorByte = Mid$(HexString, 1, 2)
    ZeroByte        = Mid$(HexString, 3, 2)
    DarknessByte    = Mid$(HexString, 5, 2)
    LightnessByte   = Mid$(HexString, 7, 2)

    SchemeColor = "&H" & Right$(SchemeColorByte, 1)

    ' New variables
    Dim ThemeColor     As MsoThemeColorSchemeIndex
    Dim ThemeColorRGB  As Long
    Dim ThemeColorHex  As String

    ' Changed translation, now to theme colour scheme index
    Select Case SchemeColor
        Case wdThemeColorMainDark1:     ThemeColor = msoThemeDark1    
        Case wdThemeColorMainLight1:    ThemeColor = msoThemeLight1   
        Case wdThemeColorMainDark2:     ThemeColor = msoThemeDark2    
        Case wdThemeColorMainLight2:    ThemeColor = msoThemeLight2   
        Case wdThemeColorAccent1:       ThemeColor = msoThemeAccent1  
        Case wdThemeColorAccent2:       ThemeColor = msoThemeAccent2  
        Case wdThemeColorAccent3:       ThemeColor = msoThemeAccent3  
        Case wdThemeColorAccent4:       ThemeColor = msoThemeAccent4  
        Case wdThemeColorAccent5:       ThemeColor = msoThemeAccent5  
        Case wdThemeColorAccent6:       ThemeColor = msoThemeAccent6  
        Case wdThemeColorHyperlink:     ThemeColor = msoThemeHyperlink
        Case wdThemeColorHyperlinkFollowed:
                             ThemeColor = msoThemeFollowedHyperlink   
        Case wdThemeColorBackground1:   ThemeColor = msoThemeLight1   
        Case wdThemeColorText1:         ThemeColor = msoThemeDark1    
        Case wdThemeColorBackground2:   ThemeColor = msoThemeLight2   
        Case wdThemeColorText2:         ThemeColor = msoThemeDark2    
        Case Else:           ' This shouldn't really ever happen
    End Select

    ' Pick up the RGB and translate to a hex string
    ThemeColorRGB = _
        ActiveDocument.DocumentTheme.ThemeColorScheme(ThemeColor).RGB
    ThemeColorHex = Right$(String$(7, "0") & Hex$(ThemeColorRGB), 8)

    Lightness = 100 - ("&H" & LightnessByte) / &HFF * 100
    Darkness = 100 - ("&H" & DarknessByte) / &HFF * 100

    If Lightness = 0 Then
        If Darkness = 0 Then
            TintingAndShading = ""
        Else
            TintingAndShading = ", Darker " & Darkness & "%"
        End If
    Else
        TintingAndShading = ", Lighter " & Lightness & "%"
    End If

    ' Display the colour instead of the scheme name
    MsgBox "The colour is: " & _
           "Red: " & CLng("&H" & Mid$(ThemeColorHex, 7, 2)) & _
           ", Green: " & CLng("&H" & Mid$(ThemeColorHex, 5, 2)) & _
           ", Blue: " & CLng("&H" & Mid$(ThemeColorHex, 3, 2)) & _
           TintingAndShading

End Sub

If, when you ran this, your Selection was simply coloured with a scheme colour you would have been told its RGB values; you may even have verified that they were correct. But, if you had had a Selection coloured with a tint (lightness) or shade (darkness) applied you would have only been told the RGB values for the base colour, and that the adjustment was set. To actually apply the tinting or shading requires a journey into colour space.

Hue, Saturation, and Luminance

As an alien in colour space, I don’t want to say too much on the subject, but it can’t altogether be avoided. As I understand it, RGB is a colour model, a way of identifying colours within a colour space, and HSL (Hue, Saturation, Luminance) is a different model that can be used to identify the same colours within the same colour space. Conversion between RGB and HSL is relatively simple, and algorithms for the conversions are widely available.

HSL values are expressed in various ways. Hue is often expressed as an angle between 0° and 360°, with Saturation and Luminance as percentages or as values between 0 and 1. In Word dialogues they are expressed as three values from 0 to 255, and in Windows dialogues as three values from 0 to 240. The routines shown below just express them as three values from 0 to 1, although it doesn’t really matter as they are never presented to any user, nor do the units matter providing there is consistency. To make it easier to just cut and paste, these subroutines are complete as they stand; it would be more normal to have them as functions returning a user-defined type of HSL.


Sub RGBtoHSL(RGB As Long, H As Double, S As Double, L As Double)

    Dim R As Double
    Dim G As Double
    Dim B As Double

    Dim RGB_Max  As Double
    Dim RGB_Min  As Double
    Dim RGB_Diff As Double

    Dim HexString As String

    ' Get R, G, and B from input Long as values between 0 and 1
    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

    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 Sub

An RGB to HSL Conversion Routine


Sub HSLtoRGB(RGB As Long, H As Double, S As Double, L As Double)

    Dim R As Double
    Dim G As Double
    Dim B As Double

    Dim HR As Double
    Dim HG As Double
    Dim HB As Double

    Dim X As Double
    Dim Y As Double

    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

        HR = IIf(H > 2 / 3, H - 2 / 3, H + 1 / 3)
        HG = H
        HB = IIf(H < 1 / 3, H + 2 / 3, H - 1 / 3)

        R = H2C(X, Y, HR)
        G = H2C(X, Y, HG)
        B = H2C(X, Y, HB)

    End If

    RGB = CLng("&H00" & _
               Right$("0" & Hex$(Round(B * 255)), 2) & _
               Right$("0" & Hex$(Round(G * 255)), 2) & _
               Right$("0" & Hex$(Round(R * 255)), 2))

End Sub

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

An HSL to RGB Conversion Routine

Before going any further I must say that the above routines, which, as far as I can tell, are correct, do not produce exactly the same values as Word does. Neither Word nor Windows makes HSL values available to code, nor provides any conversion function, nor any documentation on the algorithms they use, so guesswork is all that is open to the user. I’m sorry to say that my guesswork has not (yet) been good enough. The small differences that I have noticed (of 1 in one or more of the components) seem to be due to rounding and, in at least one case, Word does not return consistent results: that is, entering an HSL value given by Word does not return the RGB value that Word used to generate the HSL value in the first place.

Tint and Shade

There is just one more piece needed to hold the jigsaw together: the actual calculation of lightness and darkness – or tinting and shading.

A Tint specifies a lighter version of a colour and is defined such that a 10% tint, say, is 10% of the colour combined with 90% white. Similarly a Shade is a darker version of a colour and is defined such that a 10% shade is 10% of the colour combined with 90% black. When a colour in Word 2007 is defined as, for example, 40% lighter what it means is that it has a 60% tint.

What the definition, paraphrased slightly from Microsoft, doesn’t say is what 10% of a colour means, or what combined with means. In the current context 10% of a colour means 10% of its luminance, and combined with means added to. The luminance scale runs from black at the low end of the scale, to white at the high end; if using a scale from 0 to 1, black is 0, and white, 1. If a colour has a luminance value of 0.2, then a 60% tint (40% lighter) has a luminance value of 0.12 (60% of 0.2) plus 0.4 (40% of white), giving a total of 0.52.

With this knowledge, you can now write code to calculate the actual RGB value of a, possibly adjusted, theme colour. The code below does not, again, produce exactly the results Word does but the differences are, again, small and could, charitably, be put down to rounding.

You will remember from Part 1 that, for example, 40% lighter is held as 60%, and you will now see that it is the Tint rather than the percentage lighter that is actually being held. The following code uses the Tint (and corresponding Shade) figure directly instead of complicating things by calculating a percentage from it first. Other than that it simply builds on what you have so far.


Sub QuerySchemeColor(HexString As String)

    Dim SchemeColorByte As String
    Dim ZeroByte        As String
    Dim DarknessByte    As String
    Dim LightnessByte   As String

    Dim SchemeColor As Long
    ' Dim Darkness    As Long ' no longer used
    ' Dim Lightness   As Long ' no longer used

    ' New variables - Tint and Shade replace Darkness and Lightness
    Dim Tint        As Long
    Dim Shade       As Long

    ' New variables - for the conversion to/from HSL
    Dim Hue         As Double
    Dim Saturation  As Double
    Dim Luminance   As Double

    ' Dim SchemeColorName   As String ' no longer used
    ' Dim TintingAndShading As String ' no longer used

    SchemeColorByte = Mid$(HexString, 1, 2)
    ZeroByte = Mid$(HexString, 3, 2)
    DarknessByte = Mid$(HexString, 5, 2)
    LightnessByte = Mid$(HexString, 7, 2)

    SchemeColor = "&H" & Right$(SchemeColorByte, 1)

    Dim ThemeColor     As MsoThemeColorSchemeIndex
    Dim ThemeColorRGB  As Long
    Dim ThemeColorHex  As String

    Select Case SchemeColor
        Case wdThemeColorMainDark1:     ThemeColor = msoThemeDark1
        Case wdThemeColorMainLight1:    ThemeColor = msoThemeLight1
        Case wdThemeColorMainDark2:     ThemeColor = msoThemeDark2
        Case wdThemeColorMainLight2:    ThemeColor = msoThemeLight2
        Case wdThemeColorAccent1:       ThemeColor = msoThemeAccent1
        Case wdThemeColorAccent2:       ThemeColor = msoThemeAccent2
        Case wdThemeColorAccent3:       ThemeColor = msoThemeAccent3
        Case wdThemeColorAccent4:       ThemeColor = msoThemeAccent4
        Case wdThemeColorAccent5:       ThemeColor = msoThemeAccent5
        Case wdThemeColorAccent6:       ThemeColor = msoThemeAccent6
        Case wdThemeColorHyperlink:     ThemeColor = msoThemeHyperlink
        Case wdThemeColorHyperlinkFollowed:
                             ThemeColor = msoThemeFollowedHyperlink
        Case wdThemeColorBackground1:   ThemeColor = msoThemeLight1
        Case wdThemeColorText1:         ThemeColor = msoThemeDark1
        Case wdThemeColorBackground2:   ThemeColor = msoThemeLight2
        Case wdThemeColorText2:         ThemeColor = msoThemeDark2
        Case Else:           ' This shouldn't really ever happen
    End Select

    ' Pick up the RGB
    ThemeColorRGB = _
        ActiveDocument.DocumentTheme.ThemeColorScheme(ThemeColor).RGB

    Tint = CLng("&H" & LightnessByte)
    Shade = CLng("&H" & DarknessByte)

    If Tint <> 255 Then ' There is a Tint
        RGBtoHSL ThemeColorRGB, Hue, Saturation, Luminance
        Luminance = (Luminance * (Tint / 255)) + ((255 - Tint) / 255)
        HSLtoRGB ThemeColorRGB, Hue, Saturation, Luminance
    Else
        If Shade <> 255 Then ' There is a Shade
            RGBtoHSL ThemeColorRGB, Hue, Saturation, Luminance
            Luminance = (Luminance * (Shade / 255))
            HSLtoRGB ThemeColorRGB, Hue, Saturation, Luminance
        End If
    End If

    ' convert (possibly) adjusted RGB colour to a hex string
    ThemeColorHex = Right$(String$(7, "0") & Hex$(ThemeColorRGB), 8)

    ' Display the actual adjusted colour
    MsgBox "The colour is: " & _
           "Red: " & CLng("&H" & Mid$(ThemeColorHex, 7, 2)) & _
           ", Green: " & CLng("&H" & Mid$(ThemeColorHex, 5, 2)) & _
           ", Blue: " & CLng("&H" & Mid$(ThemeColorHex, 3, 2))

End Sub

Just as a reminder, the Colours2 routine (in Part 1) calls the QuerySchemeColor routine (above), which, in turn, calls the RGBtoHSL and HSLtoRGB routines (also above) to display the colour of the Font of the Selection. They are all designed to be instructive, rather than functional as is. Change any or all of them to suit your own purposes.

ColorFormat Objects

If the new improved Color properties haven’t been exciting enough for you, maybe you’ll find ColorFormat objects more to your liking. Ever since their introduction in Word 97, these objects have been offering scintillating glimpses of their potential to cause absolute confusion. There have always been two ColorFormat objects: a Word.ColorFormat object and a hidden Office.ColorFormat object. As far as I can tell the Office variety has never been returned by any property or method of anything.

In a nutshell, ColorFormat objects are used for colours in drawing objects. Being slightly less than technical, they exist for Fills, Lines, Shadows, and ThreeDs of Shapes. They have had an ever-changing set of properties and methods, some hidden, some not, some functional, some not; they have also had counterparts in Excel that have been different again.

ColorFormat objects have gained a new Property, ObjectThemeColor, to tie them to Theme colours and use an existing property, TintAndShade, to apply adjustments. There are, however, some quite complex interactions between these and other properties of ColorFormat objects.

ObjectThemeColor

The ObjectThemeColor property has a type of wdThemeColorIndex, as you saw earlier. To set the colour of a Shape to the Accent 2 colour, you could code something like:


ActiveDocument.Shapes(1).Fill.ForeColor _
    .ObjectThemeColor = wdThemeColorAccent2

If you run the above (on a document with at least one shape!), the shape will take on whatever colour you have set for Accent 2. If you look, you will also see that the RGB property is set to whatever the current Accent 2 colour is.

If you look more closely you will also see that the SchemeColor property has been set to 3205. SchemeColor has been around a long time and has nothing directly to do with colour schemes in Word 2007 Themes. The values that are applied are consistent and do, in a sense, have meaning but they are derivable and, at least for the moment, serve no purpose; perhaps that’s why the property is hidden.

TintAndShade

The TintAndShade property is not new. It worked on whatever colour an object may have had. In Word 2003 (and still, in Word 2007) you can code ..


With ActiveDocument.Shapes(1).Fill.ForeColor
    .RGB = wdColorRed
    .TintAndShade = 0.5
End With

.. and your shape will go a sort of pink. I trust that you understand, from having read this far, that a TintAndShade value of 0.5 means a 50% tint, or 50% lighter than the original colour.

If you look at the values of the properties after running the above code you will see that the RGB value is no longer wdColorRed (255), it has been changed by the tinting and reflects the actual colour. You will also see that the TintAndShade value is not exactly as supplied either: if you care to do the calculation you will find that it has been ’rounded’ to 128/255ths.

If you later change the TintAndShade value, you will find that your new colour is based, not on the RGB as held, but on the original red. Word has the information, it knows what the original colour was; if you want to find out for yourself what it was, you must determine it by taking the two properties together (in practice the easiest thing to do is to set the tint to zero, check the RGB, and set the tint back again). In order that the two properties always remain aligned, if you change the RGB value directly, the TintAndShade will be automatically set back to zero.

ObjectThemeColor and TintAndShade together

These two properties, taken together, are all that is required to determine the actual colour applied via a ColorFormat object. As with the other settings described above, when you set both of these, the RGB property (and the SchemeColor property) will be set to reflect the colour you are applying. If you run this code ..


With ActiveDocument.Shapes(1).Fill.ForeColor
    .ObjectThemeColor = wdThemeColorAccent2
    .TintAndShade = 128 / 255
End With

.. your shape will again go a shade of pink (or it will if you are using the default Office colour scheme).

Note that, instead of using a value of 0.5 to set a 50% tint, I coded 128/255, the value to which 0.5 had previously been rounded. If you check the TintAndShade value after running the code you will see that, this time, 128/255 has been rounded to exactly 0.5. When tints (and shades) are applied to Theme colours, the values are rounded to 100ths (that is, whole percentage points) instead of 255ths. I must just say that this is not rounding as you or I understand it, 1/255, for example, is rounded to 1/100; I leave it to the interested reader to determine an algorithm that produces the same results as Word (it isn’t too hard to do!).

What you probably won’t notice is that the algorithms used for tinting and shading when you apply them to Theme colours are not the same as those used when you apply tinting and shading to non-Theme RGB colours. It rather looks like Word had a fairly crude algorithm in the past and that it is still used on pre-existing properties, perhaps for compatibility reasons.

RGB Conversions

ColorFormat objects have another little trick up their sleeves with, as you might now expect, a slight twist. You can set the RGB property of a ColorFormat object to a value in the format used for Theme colours in Fonts, Borders, etc. It will be immediately transformed: the ObjectThemeColor will be set to the encoded Theme; the TintAndShade will be also set to the encoded value, but it will be rounded, as above, to the nearest percentage point.

Excel and PowerPoint

This post is about colours in Word but I cannot finish without a mention of colours in other applications. Briefly, as I am no PowerPoint expert, it appears as though all colours in PowerPoint, with the exception of pre-2007 colour schemes, are specified via ColorFormat objects. Equally briefly, as I am also no Excel expert, the same is not true of Excel, which has RGB values in several places and, in some places seems to offer conflicting old and new properties on the same object, but I am only going to mention the use of ColorFormat objects here.

Excel and PowerPoint have had ColorFormat objects as long as Word and, for all that time they have differed from the Word ones, and from each other. 2007 is no exception; superficially the Word object, the Excel object, and the PowerPoint object all appear similar, but superficially is as far as it goes.

The SchemeColor property in Excel is not hidden and takes completely different values that relate to a built in colour scheme of 81 colours: 8 basic ones, 56 palette ones, and 17 system ones, unless you’re working with charts in which case there are only 60 (the palette colours and four system ones). The SchemeColor property in PowerPoint, likewise, is not hidden, but takes different values again, which appear to relate to old-style, PowerPoint Themes.

The TintAndShade property doesn’t round to 255ths, or 100ths, or anything; it is just a value (sometimes a Single data type, sometimes a Double) although, clearly, rounding will occur in the calculations of adjusted RGB values.

It is the ObjectThemeColor, however, that will catch out the unwary. In the Excel and PowerPoint versions this takes values from the msoColorThemeIndex enumeration, and this has different values from the wdColorThemeIndex enumeration used by the Word object.

Office Enumeration Constant  (Value)  Word Enumeration Constant
(msoThemeColorMixed) (-2)  
  (-1) (wdNotThemeColor)
(msoNotThemeColor) 0 wdThemeColorMainDark1
msoThemeColorDark1 1 wdThemeColorMainLight1
msoThemeColorLight1 2 wdThemeColorMainDark2
msoThemeColorDark2 3 wdThemeColorMainLight2
msoThemeColorLight2 4 wdThemeColorAccent1
msoThemeColorAccent1 5 wdThemeColorAccent2
msoThemeColorAccent2 6 wdThemeColorAccent3
msoThemeColorAccent3 7 wdThemeColorAccent4
msoThemeColorAccent4 8 wdThemeColorAccent5
msoThemeColorAccent5 9 wdThemeColorAccent6
msoThemeColorAccent6 10 wdThemeColorHyperlink
msoThemeColorHyperlink 11  wdThemeColorFollowedHyperlink 
 msoThemeColorFollowedHyperlink  12 wdThemeColorBackground1
msoThemeColorText1 13 wdThemeColorText1
msoThemeColorBackground1 14 wdThemeColorBackground2
msoThemeColorText2 15 wdThemeColorText2
msoThemeColorBackground2 16  

A comparison of the msoThemeColorIndex and wdThemeColorIndex Enumerations

The table above compares the two enumerations. Although the actual values are academic you can see that if, for example, you assign a value of msoThemeColorAccent4 to a property expecting a value from the Word enumeration you will actually get wdThemeColorAccent5. Users of Excel and PowerPoint will simply use the Office enumeration and probably think no more of it. Users of Word, on the other hand, have both enumerations available to them and could easily use the wrong one.

You might also note that the Office enumeration has a constant of msoThemeColorMixed. There is no equivalent in Word which has a completely different mechanism for telling you that the colours you are querying are not all the same.

Glow Colours

All I have said so far about ColorFormat objects in Word has been about (changes to) existing objects. There are, also, some new ColorFormat objects, for example, the one returned by the Color Property of the new GlowFormat object, which represents the new glow effect that can be added to pictures. This appears to work reasonably in Excel, although, in common with other ColorFormat objects, it does seem to have an identity crisis, not knowing if it is an Excel or an Office object.

The GlowFormat.Color ColorFormat object in Word reports as being of type Word.ColorFormat in Word, and its ObjectThemeColor property reports as being of type wdThemeColorIndex; it does, however, take values from the msoThemeColorIndex enumeration. There are some other peculiarities of this object, which I am not going to go into at the moment, and I suggest you study it very carefully if you intend to work with it.

Finally

I hope you have enjoyed this brief excursion into colours in Word. I did promise you that the world of ColorFormat objects was wonderful and I hope the glimpse of it that I have given you lived up to the promise; if not, please let me know on a postcard, providing your full address, including planet. More seriously, these things need attention, which I assume they’ll get in due course; I shall be watching and waiting.

I am currently working on providing fuller details of colours on my still-new (and painfully slowly progressing) website at www.wordarticles.com. Please drop in from time to time to follow my journey of discovery around Word and, occasionally, other Office applications.

Tony Jollans, October 2007

Posted in VBA, Word | No Comments »