MS Office Forum / Word / Programming / May 2008
Word 2007 Font.Color fun
|
|
Thread rating:  |
Max - 13 May 2008 08:21 GMT Can someone please help me understand what gives with Font.Color values in Word 2007?
Recording a macro to see the Font values for Heading 1 style in a new 2007 document, the Color value is:
.Color = -738148353
I don't think this corresponds to an RGB value, even though the 2007 VBA Help says the Font.Color property:
"Returns or sets the 24-bit color for the specified Font object. Can be any valid WdColor constant or a value returned by Visual Basic's RGB function."
If I record a macro where I select Heading 1 style, choose Modify > Format > Font, click OK to close the Font dialog, then OK again to close the Modify Style dialog, the Color value is:
.Color = 9527094
Exact (?) same colour, very different value, which is an RGB colour.
Does anyone know how to get the correct RGB colour value in the first place without having to drill down through dialogs? I need the RGB colour for a VB application.
Many thanks for any help.
Klaus Linke - 13 May 2008 10:22 GMT Hi Max,
Haven't looked into it yet... but Tony Jollans thankfully has: http://www.wordarticles.com/Articles/Colours/2007.htm. http://proofficedev.com/blog/2007/08/21/colours-in-word-2007-part-1/, http://proofficedev.com/blog/2007/10/10/colours-in-word-2007-part-2/ and
As Jay Freedman said: "This stuff makes quantum chromodynamics look easy. :-)"
Regards, Klaus
Max - 14 May 2008 11:06 GMT Hi Klaus
Thanks very much for those links. They're quite helpful. I'd seen part 1 of the proofficedev explanation but not part 2.
Also quite dispiriting. Yikes.
Am I missing something? Why on earth did MS change the ground rules so drastically (and faultily)?
I don't understand the need for all this complexity about font colors. It would be one thing if they decided to upgrade their colour system to proper CMYK instead of RGB. But to base colouring on themes? The themes business seems so OTT and beside the point, especially in a corporate context. It's especially disappointing that MS' Help files on the subject are incomplete and conflict with how the app works (you get one non-RGB colour number value for an RGB property until you open and close a dialog without changing the colour and then you get a different value that's actually RGB???).
Part 2 of Tony's proofficedev article mentions that while his code appears correct it generates slightly different results depending on context, which he suspects is due to a rounding problem in the innards of Word but the algorithms MS uses for colour valuing are not exposed or documented so Tony can't troubleshoot or explain it. Poor guy, bless him for trying but really MS - what's up with that?
Forgive me if I'm rehashing an old thread somewhere but if anyone from MS is listening: Is there rational explanation for why the colour system had to be so drastically changed and yet not documented? (By rational explanation I mean something that delivers significant business benefits to corporate customers, benefits that outweigh the costs of trying to make the new system work properly.) Were font colours so broken that you had to "fix" them this way? Any chance the "fix" will get fixed?
Anyway, thanks again Klaus
> Hi Max, > [quoted text clipped - 8 lines] > Regards, > Klaus Tony Jollans - 14 May 2008 13:39 GMT > Poor guy, bless him for trying but really ... Thank you :-)
The idea for consistent colour schemes across the whole of Office is good - and the basic idea of themes is good, too, but I think not yet understood by many.
The problem is in the inconsistent approach both within and between applications - in the UI, never mind VBA. It looks as though the edict to use themes came down and each application development team did what (dare I say the minimum that) they could to squeeze it into their own little corner of their own application without any kind of consideration of the wider impact.
As a side note, the fact that I can't get the HSL conversions to give the same result as Word really annoys me - Microsoft do not expose anything anywhere to do with HSL yet they use it themselves in all sorts of places - the only reason I can think of for this is that they know they haven't got it right.
 Signature Enjoy, Tony
> Hi Klaus > [quoted text clipped - 55 lines] >> Regards, >> Klaus Max - 15 May 2008 09:36 GMT Hi Tony
You're welcome! I'm sure there's a lot of people who are really grateful for your putting in the time to figure out what MS has done.
I've been trying the code you posted in your two articles and I'm getting odd results - as with the Microsoft code, I get different rgb values when I test the Heading 1 style colour out of the box vs applied through the Font dialog. I'm sure the problem is either with what MS is doing behind the scenes or with my misunderstanding of their new colour modelling. In any case I was hoping you might be able to help.
Out of the box (recorded in a macro) the Heading 1 Font.Color property is:
.Color = -738148353
if I record a second macro and go into the Font Color drop down in the style editing dialog, choose More Colors and click OK (to accept the current selection), the value recorded by the macro is:
.Color = 9527094
In the dialog the RGB values are 54 / 95 / 145.
When I run your Colours2 macro on Heading 1 out of the box, the rgb values are 79 / 129 / 189 with a darkness of .25 (25%).
When I run your Colours2 macro on Heading 1 after I go into the Font Color drop down in the style editing dialog, choose More Colors and click OK (to accept the current selection), your macro retutrns RGB values of 54 / 95 / 145, as it should.
If I run your HSLtoRGB macro using the following values:
HSLtoRGB RGB(79,129,189),0,0,.25
I get the RGB value of 12566463 which isn't either one of the RGB value the Microsoft code produces. That might be because I'm incorrectly passing 0 for both H and S parameters in the HSLtoRGB macro, or the wrong L value. I don't know how to tell what the H and S values would be and the RGB return value is different yet again if I supply .75 instead of .25 as the L argument.
I'm stumped how to convert the out of the box value MS has assigned to the Heading 1 Font.Color property into a proper RGB value programmatically rather than manually going into the style editing dialog and accepting the font color first.
From the above can you see where I'm going wrong?
Again many thanks...
> > Poor guy, bless him for trying but really ... > [quoted text clipped - 76 lines] > >> Regards, > >> Klaus Tony Jollans - 15 May 2008 10:35 GMT I'm not quite sure what you have done. 12566463 is RGB(191,191,191) - the colour with hue 0 (but irrelevant because saturation is zero - the colour is on the central axis of the hsl bicone, has indeterminate hue and is just a shade of grey), saturation 0, and luminance 0.25 - a quarter of the way from white to black.
The HSLtoRGB function is just a conversion routine; it accepts a fully specified HSL colour and returns the RGB equivalent - it does not adjust the colour itself.
If you take the the Colours2 routine from Part 1 of the proofficedev article, and the QuerySchemeColor, RGBtoHSL, RGBtoHSL (and H2C) routines from part 2 of the article - and run Colours2 with the selection in your Heading1 it should tell you 55, 96, 146 - 1 'out' on each of the RGB elements. That code works with the selection.font.color but you could change it to work with a test driver: copy the SchemeColorProperty from part 1, change the beginning of Colours2 to this:
Sub Colours2(TestColour)
Dim HexString As String HexString = Right$(String$(7, "0") & Hex$(TestColour), 8) ' etc. as was
(make it accept an argument and use said argument in the Hex conversion)
and then drive with something like this:
Sub Test() ' This should give the RGB for Accent1, 25% darker (Heading1 default) Colours2 CLng(SchemeColorProperty(wdThemeColorAccent1, -0.25)) End Sub
Does that help?
-----------------------------
I am, at the moment, working on the long-unfinished piece on the WordArticles site and should update it next week (or maybe the week after). I intend to include a downloadable example to make it easier to work with.
 Signature Enjoy, Tony
> Hi Tony > [quoted text clipped - 149 lines] >> >> Regards, >> >> Klaus Max - 15 May 2008 19:35 GMT Thanks for the suggested code. I tried new code you suggested and I got the same results as I posted previously. The out of the box RGB values for Heading 1 default are 79 / 129 / 189 darkness of 25%. If I go into the style dialog and just open the font color dialog then immediately close it (without changing anything) and then run your code again your code message box says it's an RGB color with values of 54 / 95 / 145.
It looks like the problem isn't with your code or with anything I'm doing, the problem is that the default value for theme colours isn't strictly RGB even though MS says it's supposed to be.
Would you have any ideas about how to programmatically convert that non-RGB default value (79 / 129 / 189 darkness of 25%) to plain old RGB? Would I use HSLtoRGB for that? I tried doing that ("HSLtoRGB RGB(79,129,189),0,0,.25") but seem to have used the wrong parameters because I got 12566463 which is RGB(191,191,191). QuerySchemeColor gave me the same 79 / 129 / 189 darkness of 25% that I got using Colours2.
And really thank you for your patience!
> I'm not quite sure what you have done. 12566463 is RGB(191,191,191) - the > colour with hue 0 (but irrelevant because saturation is zero - the colour is [quoted text clipped - 191 lines] > >> >> Regards, > >> >> Klaus Tony Jollans - 15 May 2008 23:35 GMT How are you using HSLtoGRB? It takes 4 arguments - an output RGB and three inputs: H, S, and L. Called like this: "HSLtoRGB RGB(79,129,189),0,0,.25", as you state, it looks at the input HSL (0,0,0.25) and converts that to RGB, overwriting whatever was in the RGB variable passed to it.
When you copy the code from proofficedev make sure you take QuerySchemeColor from Part 2 (the version in Part 1 is but a step on the way and will indeed return what you say).
 Signature Enjoy, Tony
> Thanks for the suggested code. I tried new code you suggested and I got > the [quoted text clipped - 261 lines] >> >> >> Regards, >> >> >> Klaus Max - 16 May 2008 10:29 GMT I'm using the correct code (there's no actual code in part 1's QuerySchemeColor).
I thnk I'm calling HSLtoRGB correctly, with 4 arguments:
HSLtoRGB RGB(79,129,189),0,0,.25
Why would "RGB(79,129,189)" return 0? Shouldn't RGB(79,129,189) return the long RGB value of "R79, G129, B189"?
In any case below is a copy of the code I'm using. The only modifications I've made to your posted code are as follows:
In Colours2 I added "Call QuerySchemeColor(HexString)" to Case FF and commented out the messagebox line in that case. That added line is a copy and paste of your code at Case D4 To DF.
In QuerySchemeColour I added the following lines at the end. I only did this because it seems that HSLtoRGB isn't recognising the function RGB as a valid first argument - I figured I'd try passing a long value as the first argument to see if I got any different results.
Dim lngr As Long Dim lngg As Long Dim lngb As Long Dim lngrgb As Long
lngr = CLng("&H" & Mid$(ThemeColorHex, 7, 2)) lngg = CLng("&H" & Mid$(ThemeColorHex, 5, 2)) lngb = CLng("&H" & Mid$(ThemeColorHex, 3, 2)) lngrgb = RGB(lngr, lngg, lngb)
HSLtoRGB lngrgb, 0, 0, 0.25 <<
In HSLtoRGB I added "MsgBox RGB" to the end to display the RGB value that that macro ends up with. (Can I make a suggestion? Isn't RGB the name of a VB function? You might want to change the name of that variable.)
No matter what selection I run Colours2 from, HSLtoRGB returns "4210752".
From the following code can you see what I'm doing wrong?
Thanks again, code follows...
Sub Colours2()
Dim HexString As String HexString = Right$(String$(7, "0") & Hex$(Selection.Font.Color), 8)
Select Case Left$(HexString, 2)
Case "00" If HexString = "00C8C67F" Then MsgBox "The colour of the Selection is not all the same" Else MsgBox "The colour is an RGB value:" & vbCr & _ "Red: " & _ CLng("&H" & Mid$(HexString, 7, 2)) & vbCr & _ "Green: " & _ CLng("&H" & Mid$(HexString, 5, 2)) & vbCr & _ "Blue: " & _ CLng("&H" & Mid$(HexString, 3, 2)) End If
Case "FF" 'ADDED CODE Call QuerySchemeColor(HexString) 'END ADDED CODE 'MsgBox "The colour is set to the default of 'Automatic'"
Case "80" MsgBox "The colour is an OLE Color"
Case "D4" To "DF" Call QuerySchemeColor(HexString)
Case Else MsgBox "The colour is of an unknown type." & vbCr & _ "The code is: 0x" & HexString
End Select End Sub
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 'ADDED CODE Dim lngr As Long Dim lngg As Long Dim lngb As Long Dim lngrgb As Long
lngr = CLng("&H" & Mid$(ThemeColorHex, 7, 2)) lngg = CLng("&H" & Mid$(ThemeColorHex, 5, 2)) lngb = CLng("&H" & Mid$(ThemeColorHex, 3, 2)) lngrgb = RGB(lngr, lngg, lngb)
HSLtoRGB lngrgb, 0, 0, 0.25 'END ADDED CODE
' 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
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))
'ADDED CODE MsgBox RGB 'returns 4210752
End Sub
> How are you using HSLtoGRB? It takes 4 arguments - an output RGB and three > inputs: H, S, and L. Called like this: "HSLtoRGB RGB(79,129,189),0,0,.25", [quoted text clipped - 4 lines] > from Part 2 (the version in Part 1 is but a step on the way and will indeed > return what you say). Tony Jollans - 16 May 2008 12:16 GMT The way I wrote the articles is perhaps slightly confusing and Part 1 does include an empty QuerySchemeColor, and then, later, a version with some code; then in Part 2 I provide yet another version of it.
You are using the (second) version from Part 1, not the version from Part 2.
Again, the RGB parameter is output from (not input to) the HSLtoRGB routine.
 Signature Enjoy, Tony
> I'm using the correct code (there's no actual code in part 1's > QuerySchemeColor). [quoted text clipped - 234 lines] >> indeed >> return what you say). Max - 17 May 2008 11:37 GMT Sorry Tony there are two versions of QuerySchemeColor in Part 2. I didn't realise that, because they look similar.
I used the second version and got the RGB results you mentioned, 55, 96, 146. Close enough, so that's great, EUREKA!
Thanks so much for your patience, I hope you understand my confusion.
While I'm on the subject of my confusion (I'm obviously a bit dim), I'm confused when you say
> Again, the RGB parameter is output from (not input to) the HSLtoRGB routine. Since HSLtoRGB is a sub not a function how does it output (return) something to Colours2? Yet when I commented out HSLtoRGB from QuerySchemeColor the results changed so obviously it's outputting somehow, changing some value for QuerySchemeColor.
I'm also confused when you say that the RGB parameter is not input to HSLtoRGB. The RGB parameter is the first parameter required to be supplied to HSLtoRGB:
> Sub HSLtoRGB(RGB As Long, H As Double, S As Double, L As Double) HSLtoRGB generates an error "Argument not optional" when you leave out that RGB parameter, so it has to be supplied (input) to that sub, yes?
I assumed that since your code requires a parameter called RGB and it's long, when you call it from QuerySchemeColour you can pass any valid long RGB value. That's why I passed it the value returned by the built in VB function RGB, which is supposed to return a long RGB value.
Thanks again!
> The way I wrote the articles is perhaps slightly confusing and Part 1 does > include an empty QuerySchemeColor, and then, later, a version with some [quoted text clipped - 242 lines] > >> indeed > >> return what you say). Tony Jollans - 21 May 2008 13:12 GMT Glad you're sorted.
I was trying to keep things simple (or as simple as I could) - and clearly failed - and wanted to avoid defining (and describing) a user-defined type for the HSL values.
There are different ways to pass parameters but by reference (ByRef) is the default. This means that you pass references to variables in the calling routine which the called routine can access, and change.
In this case the caller passes references to four variables - an RGB variable, an H variable, an S variable and an L variable. The called HSLtoRGB sub reads the values from the H, S, and L variables, calculates the equivalent RGB value and puts it in the caller's (passed) RGB variable. When the sub has finished the caller can then look at its own RGB variable to find the result.
It wasn't particularly designed for stand-alone use, just being part of the whole presented solution. The version that will (shortly) be on my own web page will (a) have a user defined type and (b) a function that, I hope will be easier.
It is easy to assume everybody understands something that is obvious to me, and it is helpful to me to see other people's sticking points so that I can (try to) improve my presentation. Thank you.
 Signature Enjoy, Tony
> Sorry Tony there are two versions of QuerySchemeColor in Part 2. I didn't > realise that, because they look similar. [quoted text clipped - 295 lines] >> >> indeed >> >> return what you say).
|
|
|