Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Due to spam on this forum, all posts now need moderator approval.
Entire forum
➜ MUSHclient
➜ Bug reports
➜ Mush Color functions are inconsistent and sometimes flip RGB to BGR
Mush Color functions are inconsistent and sometimes flip RGB to BGR
|
It is now over 60 days since the last post. This thread is closed.
Refresh page
Posted by
| Kahenraz
(75 posts) Bio
|
Date
| Fri 07 Jun 2019 11:47 AM (UTC) Amended on Fri 07 Jun 2019 12:19 PM (UTC) by Kahenraz
|
Message
| print("orange : #" .. string.format("%06X", ColourNameToRGB("orange")) .. " : " .. RGBColourToName(0x00A5FF))
print("orange : #" .. string.format("%06X", ColourNameToRGB("#00A5FF")) .. " : " .. RGBColourToName(ColourNameToRGB("#00A5FF")))
Output is:
orange : #00A5FF : orange
orange : #FFA500 : #00A5FF
Expected output:
orange : #FFA500 : orange
orange : #FFA500 : orange
The color "orange" should be 0xFFA500. But the red and blue bytes get reversed when passed as "word" to ColourNameToRGB(). 0xFFA500 becomes 0x00A5FF.
ColourTell() already correctly reads hex colors:
ColourTell("#FF0000", "", "Some text : red")
print("")
ColourTell("#00FF00", "", "Some text : green")
print("")
ColourTell("#0000FF", "", "Some text : blue")
print("")
The issue is with ColourNameToRGB() and RGBColourToName() flipping the R and B bytes. The bigger problem is that RGBColourToName() expects these bytes to be flipped. So both functions exhibit symptoms of the same bug. | Top |
|
Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Date
| Reply #1 on Fri 07 Jun 2019 10:59 PM (UTC) Amended on Fri 07 Jun 2019 11:04 PM (UTC) by Nick Gammon
|
Message
| This is intentional.
RGBColourToName(0x00A5FF) is not the same as RGBColourToName(ColourNameToRGB("#00A5FF")).
The HTML representation of colours puts red first (as in red, green, blue). However MUSHclient internally stores colours as a COLORREF data type, which has the order reversed.
See COLORREF - Windows documentation.
Quote:
The low-order byte contains a value for the relative intensity of red; the second byte contains a value for green; and the third byte contains a value for blue.
Here is another reference.
It is surprisingly difficult to find web pages that talk about this. Almost every page I find just mentions that HTML colour codes are in the form #rrggbb without specifying how that ends up in a (unsigned long) variable in a computer language like C. I suppose you "assume" that you just slap "0x" there instead of "#" and you are done, but apparently not.
Technical point: It is probably an endianness thing.
Quote:
print("orange : #" .. string.format("%06X", ColourNameToRGB("#00A5FF")) .. " : " .. RGBColourToName(ColourNameToRGB("#00A5FF")))
...
Expected output:
orange : #FFA500 : orange
No, that is not the expected output. See HTML Color Names. Orange is #FFA500 in HTML so you have not supplied a valid "orange" colour string, and thus "orange" is not printed.
Internally MUSHclient is consistent, and it would be far too late to change this behaviour now. There would be many plugins that expect the colours to be returned the way they are. Perhaps the documentation for the client could be changed to make it absolutely clear.
For now, though, if you want to use hex codes directly (eg. 0x0000FF) then 0x0000FF is red and not blue. In other words: 0xbbggrr. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Date
| Reply #2 on Fri 07 Jun 2019 11:11 PM (UTC) |
Message
| I have amended the documentation to make this clear.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Date
| Reply #3 on Fri 07 Jun 2019 11:37 PM (UTC) Amended on Sat 08 Jun 2019 12:17 AM (UTC) by Nick Gammon
|
Message
| If you type in an Immediate scripting window:
Then you see the codes and it is clear (for most colours) that the "hex" code is reversed. That is, the code shown with 0x in front of it, compared to the code with # in front of it.
black R= 0 G= 0 B= 0 #000000 &h000000 0x000000 00000000
dimgray R=105 G=105 B=105 #696969 &h696969 0x696969 06908265
gray R=128 G=128 B=128 #808080 &h808080 0x808080 08421504
darkgray R=169 G=169 B=169 #A9A9A9 &hA9A9A9 0xA9A9A9 11119017
silver R=192 G=192 B=192 #C0C0C0 &hC0C0C0 0xC0C0C0 12632256
lightgrey R=211 G=211 B=211 #D3D3D3 &hD3D3D3 0xD3D3D3 13882323
lightgray R=211 G=211 B=211 #D3D3D3 &hD3D3D3 0xD3D3D3 13882323
gainsboro R=220 G=220 B=220 #DCDCDC &hDCDCDC 0xDCDCDC 14474460
whitesmoke R=245 G=245 B=245 #F5F5F5 &hF5F5F5 0xF5F5F5 16119285
white R=255 G=255 B=255 #FFFFFF &hFFFFFF 0xFFFFFF 16777215
rosybrown R=188 G=143 B=143 #BC8F8F &h8F8FBC 0x8F8FBC 09408444
indianred R=205 G= 92 B= 92 #CD5C5C &h5C5CCD 0x5C5CCD 06053069
brown R=165 G= 42 B= 42 #A52A2A &h2A2AA5 0x2A2AA5 02763429
firebrick R=178 G= 34 B= 34 #B22222 &h2222B2 0x2222B2 02237106
lightcoral R=240 G=128 B=128 #F08080 &h8080F0 0x8080F0 08421616
maroon R=128 G= 0 B= 0 #800000 &h000080 0x000080 00000128
darkred R=139 G= 0 B= 0 #8B0000 &h00008B 0x00008B 00000139
red R=255 G= 0 B= 0 #FF0000 &h0000FF 0x0000FF 00000255
snow R=255 G=250 B=250 #FFFAFA &hFAFAFF 0xFAFAFF 16448255
mistyrose R=255 G=228 B=225 #FFE4E1 &hE1E4FF 0xE1E4FF 14804223
salmon R=250 G=128 B=114 #FA8072 &h7280FA 0x7280FA 07504122
tomato R=255 G= 99 B= 71 #FF6347 &h4763FF 0x4763FF 04678655
darksalmon R=233 G=150 B=122 #E9967A &h7A96E9 0x7A96E9 08034025
coral R=255 G=127 B= 80 #FF7F50 &h507FFF 0x507FFF 05275647
orangered R=255 G= 69 B= 0 #FF4500 &h0045FF 0x0045FF 00017919
lightsalmon R=255 G=160 B=122 #FFA07A &h7AA0FF 0x7AA0FF 08036607
sienna R=160 G= 82 B= 45 #A0522D &h2D52A0 0x2D52A0 02970272
seashell R=255 G=245 B=238 #FFF5EE &hEEF5FF 0xEEF5FF 15660543
chocolate R=210 G=105 B= 30 #D2691E &h1E69D2 0x1E69D2 01993170
saddlebrown R=139 G= 69 B= 19 #8B4513 &h13458B 0x13458B 01262987
sandybrown R=244 G=164 B= 96 #F4A460 &h60A4F4 0x60A4F4 06333684
peachpuff R=255 G=218 B=185 #FFDAB9 &hB9DAFF 0xB9DAFF 12180223
peru R=205 G=133 B= 63 #CD853F &h3F85CD 0x3F85CD 04163021
linen R=250 G=240 B=230 #FAF0E6 &hE6F0FA 0xE6F0FA 15134970
bisque R=255 G=228 B=196 #FFE4C4 &hC4E4FF 0xC4E4FF 12903679
darkorange R=255 G=140 B= 0 #FF8C00 &h008CFF 0x008CFF 00036095
burlywood R=222 G=184 B=135 #DEB887 &h87B8DE 0x87B8DE 08894686
tan R=210 G=180 B=140 #D2B48C &h8CB4D2 0x8CB4D2 09221330
antiquewhite R=250 G=235 B=215 #FAEBD7 &hD7EBFA 0xD7EBFA 14150650
navajowhite R=255 G=222 B=173 #FFDEAD &hADDEFF 0xADDEFF 11394815
blanchedalmond R=255 G=235 B=205 #FFEBCD &hCDEBFF 0xCDEBFF 13495295
papayawhip R=255 G=239 B=213 #FFEFD5 &hD5EFFF 0xD5EFFF 14020607
moccasin R=255 G=228 B=181 #FFE4B5 &hB5E4FF 0xB5E4FF 11920639
orange R=255 G=165 B= 0 #FFA500 &h00A5FF 0x00A5FF 00042495
wheat R=245 G=222 B=179 #F5DEB3 &hB3DEF5 0xB3DEF5 11788021
oldlace R=253 G=245 B=230 #FDF5E6 &hE6F5FD 0xE6F5FD 15136253
floralwhite R=255 G=250 B=240 #FFFAF0 &hF0FAFF 0xF0FAFF 15792895
darkgoldenrod R=184 G=134 B= 11 #B8860B &h0B86B8 0x0B86B8 00755384
goldenrod R=218 G=165 B= 32 #DAA520 &h20A5DA 0x20A5DA 02139610
cornsilk R=255 G=248 B=220 #FFF8DC &hDCF8FF 0xDCF8FF 14481663
gold R=255 G=215 B= 0 #FFD700 &h00D7FF 0x00D7FF 00055295
khaki R=240 G=230 B=140 #F0E68C &h8CE6F0 0x8CE6F0 09234160
lemonchiffon R=255 G=250 B=205 #FFFACD &hCDFAFF 0xCDFAFF 13499135
palegoldenrod R=238 G=232 B=170 #EEE8AA &hAAE8EE 0xAAE8EE 11200750
darkkhaki R=189 G=183 B=107 #BDB76B &h6BB7BD 0x6BB7BD 07059389
beige R=245 G=245 B=220 #F5F5DC &hDCF5F5 0xDCF5F5 14480885
lightgoldenrodyellow R=250 G=250 B=210 #FAFAD2 &hD2FAFA 0xD2FAFA 13826810
olive R=128 G=128 B= 0 #808000 &h008080 0x008080 00032896
yellow R=255 G=255 B= 0 #FFFF00 &h00FFFF 0x00FFFF 00065535
lightyellow R=255 G=255 B=224 #FFFFE0 &hE0FFFF 0xE0FFFF 14745599
ivory R=255 G=255 B=240 #FFFFF0 &hF0FFFF 0xF0FFFF 15794175
olivedrab R=107 G=142 B= 35 #6B8E23 &h238E6B 0x238E6B 02330219
yellowgreen R=154 G=205 B= 50 #9ACD32 &h32CD9A 0x32CD9A 03329434
darkolivegreen R= 85 G=107 B= 47 #556B2F &h2F6B55 0x2F6B55 03107669
greenyellow R=173 G=255 B= 47 #ADFF2F &h2FFFAD 0x2FFFAD 03145645
chartreuse R=127 G=255 B= 0 #7FFF00 &h00FF7F 0x00FF7F 00065407
lawngreen R=124 G=252 B= 0 #7CFC00 &h00FC7C 0x00FC7C 00064636
forestgreen R= 34 G=139 B= 34 #228B22 &h228B22 0x228B22 02263842
limegreen R= 50 G=205 B= 50 #32CD32 &h32CD32 0x32CD32 03329330
lightgreen R=144 G=238 B=144 #90EE90 &h90EE90 0x90EE90 09498256
palegreen R=152 G=251 B=152 #98FB98 &h98FB98 0x98FB98 10025880
darkgreen R= 0 G=100 B= 0 #006400 &h006400 0x006400 00025600
green R= 0 G=128 B= 0 #008000 &h008000 0x008000 00032768
lime R= 0 G=255 B= 0 #00FF00 &h00FF00 0x00FF00 00065280
honeydew R=240 G=255 B=240 #F0FFF0 &hF0FFF0 0xF0FFF0 15794160
darkseagreen R=141 G=188 B=143 #8DBC8F &h8FBC8D 0x8FBC8D 09419917
seagreen R= 46 G=139 B= 87 #2E8B57 &h578B2E 0x578B2E 05737262
mediumseagreen R= 60 G=179 B=113 #3CB371 &h71B33C 0x71B33C 07451452
springgreen R= 0 G=255 B=127 #00FF7F &h7FFF00 0x7FFF00 08388352
mintcream R=245 G=255 B=250 #F5FFFA &hFAFFF5 0xFAFFF5 16449525
mediumspringgreen R= 0 G=250 B=154 #00FA9A &h9AFA00 0x9AFA00 10156544
mediumaquamarine R=102 G=205 B=170 #66CDAA &hAACD66 0xAACD66 11193702
aquamarine R=127 G=255 B=212 #7FFFD4 &hD4FF7F 0xD4FF7F 13959039
turquoise R= 64 G=224 B=208 #40E0D0 &hD0E040 0xD0E040 13688896
darkturquoise R= 0 G=222 B=209 #00DED1 &hD1DE00 0xD1DE00 13753856
lightseagreen R= 32 G=178 B=170 #20B2AA &hAAB220 0xAAB220 11186720
mediumturquoise R= 72 G=209 B=204 #48D1CC &hCCD148 0xCCD148 13422920
darkslategray R= 47 G= 79 B= 79 #2F4F4F &h4F4F2F 0x4F4F2F 05197615
paleturquoise R=175 G=238 B=238 #AFEEEE &hEEEEAF 0xEEEEAF 15658671
teal R= 0 G=128 B=128 #008080 &h808000 0x808000 08421376
darkcyan R= 0 G=139 B=139 #008B8B &h8B8B00 0x8B8B00 09145088
cyan R= 0 G=255 B=255 #00FFFF &hFFFF00 0xFFFF00 16776960
aqua R= 0 G=255 B=255 #00FFFF &hFFFF00 0xFFFF00 16776960
lightcyan R=224 G=255 B=255 #E0FFFF &hFFFFE0 0xFFFFE0 16777184
azure R=240 G=255 B=255 #F0FFFF &hFFFFF0 0xFFFFF0 16777200
cadetblue R= 95 G=158 B=160 #5F9EA0 &hA09E5F 0xA09E5F 10526303
powderblue R=176 G=224 B=230 #B0E0E6 &hE6E0B0 0xE6E0B0 15130800
lightblue R=173 G=216 B=230 #ADD8E6 &hE6D8AD 0xE6D8AD 15128749
deepskyblue R= 0 G=191 B=255 #00BFFF &hFFBF00 0xFFBF00 16760576
skyblue R=135 G=206 B=235 #87CEEB &hEBCE87 0xEBCE87 15453831
lightskyblue R=135 G=206 B=250 #87CEFA &hFACE87 0xFACE87 16436871
steelblue R= 70 G=130 B=180 #4682B4 &hB48246 0xB48246 11829830
aliceblue R=240 G=248 B=255 #F0F8FF &hFFF8F0 0xFFF8F0 16775408
dodgerblue R= 30 G=144 B=255 #1E90FF &hFF901E 0xFF901E 16748574
slategray R=112 G=128 B=144 #708090 &h908070 0x908070 09470064
lightslategray R=119 G=136 B=153 #778899 &h998877 0x998877 10061943
lightsteelblue R=176 G=196 B=222 #B0C4DE &hDEC4B0 0xDEC4B0 14599344
cornflowerblue R=100 G=149 B=237 #6495ED &hED9564 0xED9564 15570276
royalblue R= 65 G=105 B=225 #4169E1 &hE16941 0xE16941 14772545
midnightblue R= 25 G= 25 B=112 #191970 &h701919 0x701919 07346457
lavender R=230 G=230 B=250 #E6E6FA &hFAE6E6 0xFAE6E6 16443110
navy R= 0 G= 0 B=128 #000080 &h800000 0x800000 08388608
darkblue R= 0 G= 0 B=139 #00008B &h8B0000 0x8B0000 09109504
mediumblue R= 0 G= 0 B=205 #0000CD &hCD0000 0xCD0000 13434880
blue R= 0 G= 0 B=255 #0000FF &hFF0000 0xFF0000 16711680
ghostwhite R=248 G=248 B=255 #F8F8FF &hFFF8F8 0xFFF8F8 16775416
slateblue R=106 G= 90 B=205 #6A5ACD &hCD5A6A 0xCD5A6A 13458026
darkslateblue R= 72 G= 61 B=139 #483D8B &h8B3D48 0x8B3D48 09125192
mediumslateblue R=123 G=104 B=238 #7B68EE &hEE687B 0xEE687B 15624315
mediumpurple R=147 G=112 B=219 #9370DB &hDB7093 0xDB7093 14381203
rebeccapurple R=102 G= 51 B=153 #663399 &h993366 0x993366 10040166
blueviolet R=138 G= 43 B=226 #8A2BE2 &hE22B8A 0xE22B8A 14822282
indigo R= 75 G= 0 B=130 #4B0082 &h82004B 0x82004B 08519755
darkorchid R=153 G= 50 B=204 #9932CC &hCC3299 0xCC3299 13382297
darkviolet R=148 G= 0 B=211 #9400D3 &hD30094 0xD30094 13828244
mediumorchid R=186 G= 85 B=211 #BA55D3 &hD355BA 0xD355BA 13850042
thistle R=216 G=191 B=216 #D8BFD8 &hD8BFD8 0xD8BFD8 14204888
plum R=221 G=160 B=221 #DDA0DD &hDDA0DD 0xDDA0DD 14524637
violet R=238 G=130 B=238 #EE82EE &hEE82EE 0xEE82EE 15631086
purple R=128 G= 0 B=128 #800080 &h800080 0x800080 08388736
darkmagenta R=139 G= 0 B=139 #8B008B &h8B008B 0x8B008B 09109643
magenta R=255 G= 0 B=255 #FF00FF &hFF00FF 0xFF00FF 16711935
fuchsia R=255 G= 0 B=255 #FF00FF &hFF00FF 0xFF00FF 16711935
orchid R=218 G=112 B=214 #DA70D6 &hD670DA 0xD670DA 14053594
mediumvioletred R=199 G= 21 B=133 #C71585 &h8515C7 0x8515C7 08721863
deeppink R=255 G= 20 B=147 #FF1493 &h9314FF 0x9314FF 09639167
hotpink R=255 G=105 B=180 #FF69B4 &hB469FF 0xB469FF 11823615
lavenderblush R=255 G=240 B=245 #FFF0F5 &hF5F0FF 0xF5F0FF 16118015
palevioletred R=219 G=112 B=147 #DB7093 &h9370DB 0x9370DB 09662683
crimson R=220 G= 20 B= 60 #DC143C &h3C14DC 0x3C14DC 03937500
lightpink R=255 G=182 B=193 #FFB6C1 &hC1B6FF 0xC1B6FF 12695295
pink R=255 G=200 B=203 #FFC8CB &hCBC8FF 0xCBC8FF 13355263
142 colours.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Kahenraz
(75 posts) Bio
|
Date
| Reply #4 on Sun 09 Jun 2019 08:11 PM (UTC) |
Message
| The assumption came from the expectation of a consistent input<->output relationship.
I did expect the output of ColourNameToRGB() to return the same name when passed to RGBColourToName().
I understand that you're using COLORREF internally but that should be completely opaque to the public API. I shouldn't have to care about the internal representation.
It was a surprise to me that I had to swap bytes around on my end to add this consistency.
Thank you for adding this to the documentation. | Top |
|
Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Date
| Reply #5 on Sun 09 Jun 2019 09:15 PM (UTC) Amended on Sun 09 Jun 2019 09:29 PM (UTC) by Nick Gammon
|
Message
|
Quote:
I did expect the output of ColourNameToRGB() to return the same name when passed to RGBColourToName().
But it does do that! Try running this script in the immediate window:
for k, v in pairs (colour_names) do
local value = ColourNameToRGB(k) -- turn into a number
if v ~= value then
print ("Incorrect conversion for colour", k)
end
local name = RGBColourToName (value) -- turn back into a name
if name ~= k then
print (string.format ("Colour value 0x%06x converted to %s rather than %s", value, name, k))
end -- if
end -- for
Output:
Colour value 0xd3d3d3 converted to lightgrey rather than lightgray
Colour value 0xffff00 converted to cyan rather than aqua
Colour value 0xff00ff converted to magenta rather than fuchsia
There are two tests there: First is that every colour name, after converting to a number, is converted to the same value as is stored internally in the colour_names table. Every single one passes!
The second is that every colour number, after converting to a name, converts back to the same name as originally. There are three failures there, because those three colours listed have the same codes (ie. lightgrey is the same as lightgray). Thus it has to choose one or the other. All the other pass.
Your confusion is that you think that #123456 is the same as 0x123456 when it just isn't. One is an HTML code for a colour, the other is the way numbers are stored in C. Because of endianness, they are not equivalent.
Here's a post on Stack Overflow by someone who is getting the "wrong" colours because he tries to use actual numbers rather than the HTML colours.
Here's another post about colours and endianness.
MUSHclient isn't wrong, it is just not storing colours the way you are expecting it to. Hence when you use the 0xRRGGBB notation you are getting the wrong results.
Its conversion to and from numbers to names is consistent, as the example above shows.
Here is another example showing converting to and from HTML codes:
for i = 1, 5000 do
local HTMLname = string.format ("#%06X", i)
local value = ColourNameToRGB(HTMLname) -- convert to number
local name = RGBColourToName (value) -- convert back to name
if name ~= HTMLname then
print (string.format ("Colour value 0x%06x converted to %s rather than %s", value, name, HTMLname))
end -- if
end -- for
print "done"
Output:
Colour value 0x800000 converted to navy rather than #000080
Colour value 0x8b0000 converted to darkblue rather than #00008B
Colour value 0xcd0000 converted to mediumblue rather than #0000CD
Colour value 0xff0000 converted to blue rather than #0000FF
done
Of the 5000 colours tested (ie. #000001, #000002 and so on) all but four convert exactly back to what they started. Those four (listed above) "fail" because an equivalent name was found so that was used instead.
You will notice above that the actual RGB codes are reversed, as expected. One is done by doing a string.format in hex of the underlying code. The other is the HTML code, so the byte order is different. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Date
| Reply #6 on Sun 09 Jun 2019 09:38 PM (UTC) |
Message
|
Kahenraz said:
I understand that you're using COLORREF internally but that should be completely opaque to the public API. I shouldn't have to care about the internal representation.
You may have a point about that, but it is too late to change it. There will be plugins where people check for blue text, and they will have worked out how the blue byte is stored, by trial and error if nothing else. To change the way it is represented now would break things for thousands of users.
Internally in the Windows API there are macros for getting the red, green and blue components, like this:
#define GetRValue(rgb) ((BYTE)(rgb))
#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
#define GetBValue(rgb) ((BYTE)((rgb)>>16))
You could easily make something equivalent in Lua to hide the internals of where each colour is, eg.
function getRed (rgb)
return bit.band (rgb, 0xFF)
end -- getRed
function getGreen (rgb)
return bit.band (bit.shr (rgb, 8), 0xFF)
end -- getGreen
function getBlue (rgb)
return bit.band (bit.shr (rgb, 16), 0xFF)
end -- getBlue
orange = ColourNameToRGB("orange")
print (string.format ("Orange is %02X %02X %02X", getRed (orange), getGreen (orange), getBlue (orange)))
Output:
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
20,946 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top