(edited by Killer Rhino.6794)
[How To] Colors API
Ok, i’ve thrown together an example in php:
https://gist.github.com/codemasher/fb407de5587fdbd3e7c5
conversion functions:
https://gist.github.com/codemasher/741f30e68c6e9c7921c7
I’ve set this up in my Perl module, and I’m running into cases where the saturation transform results in a value greater than 1, which in turn results in negative RGB values. I know that hue can just wrap-around (i.e. if hue > 360 {hue = hue – 360} ), but what do you do for saturation?
Awesome, thanks so much.
A working Java implementation can be seen in my GitHub project:
https://github.com/Goddchen/GuildWars2-API-Explorer/blob/master/GuildWars2APIExplorer/src/main/java/de/goddchen/android/gw2/api/data/Color.java
I’ve set this up in my Perl module, and I’m running into cases where the saturation transform results in a value greater than 1, which in turn results in negative RGB values. I know that hue can just wrap-around (i.e. if hue > 360 {hue = hue – 360} ), but what do you do for saturation?
Do you have some specific examples so i can check that?
I’ve set this up in my Perl module, and I’m running into cases where the saturation transform results in a value greater than 1, which in turn results in negative RGB values. I know that hue can just wrap-around (i.e. if hue > 360 {hue = hue – 360} ), but what do you do for saturation?
Do you have some specific examples so i can check that?
Try (144, Umber) or (341, Patina). There’s some more that have saturation > 1.
EDIT: (947, White) has lightness > 1 instead of saturation.
I’m making use of the PHP examples provided by smiley to change the colour of individual pixels of each image (background, emblem part 1, emblem part 2.)
Some of these seem to be working okay (e.g. Hot Pink) however White and Abyss seem to be somewhat hit or miss.
Code: http://pastebin.com/PiFs0Tje
Using the above code, the example below should have the background coloured Abyss, and the octopus White. However the colour seems quite off. Anyone have any ideas?
Visko Bludhaven – Level 80 Human Elementalist
Gunnar’s Hold Server Forum
Not sure how much help this is, but:
I normalize my base color’s values, and my hue value, between 0 – 1. Part of the reason is that the iOS libraries expect that range. The base color can be represented in HSL as either (0 deg, 66%, 30%), or (360 deg, 66%, 30%). I rely on the later, so that when it comes to my hue shift calculation becomes (360 deg * hue / 360), or rather just hue.
Also, I observed that most (perhaps all) colors that have cloth, leather and metal material values represent dyes. For instance, there are many “Black” colors, but only one “Abyss” color. Furthermore, only one of the “Black” colors has material values for cloth, leather, and metal. I suspect that is our “Black” dye.
(edited by Killer Rhino.6794)
Thats where the error in my example is. I assumed that the S/L values are already normalized to 0-1, i didn’t check that before. (Hot pink has already a l>1, so i should have noticed, but it was like 4am when i wrote that…)
(edited by smiley.1438)
Thanks!
I used it to create simple color sheer, here is code:
https://code.google.com/p/gw2api/source/browse/trunk/src/cz/zweistein/gw2/app/color/ColorSheet.java
And here is result:
https://gw2api.googlecode.com/svn/trunk/colorsheet.html
(you might want to save it as html file on local drive and then open in broswer)
Thats where the error in my example is. I assumed that the S/L values are already normalized to 0-1, i didn’t check that before. (Hot pink has already a l>1, so i should have noticed, but it was like 4am when i wrote that…)
Darn it, I’m not doing a very good job explaining this (and it’s 8AM, what’s my excuse
I had it wrong when I said S & L are between 0 – 1. And for that matter, brightness is not a value between 0 – 255. Use the values that come in S & L as-is in our HSL shifts. I’ll correct the guide now.
(edited by Killer Rhino.6794)
Thanks!
I used it to create simple color sheer, here is code:
https://code.google.com/p/gw2api/source/browse/trunk/src/cz/zweistein/gw2/app/color/ColorSheet.java
And here is result:
https://gw2api.googlecode.com/svn/trunk/colorsheet.html
(you might want to save it as html file on local drive and then open in broswer)
Zwei, in your color shift code, try changing:
hsl0 = (float) (hsl0 * 360 + color.getHue()) / 360;
to:
hsl0 = (float) (color.getHue() / 360);
I took a screenshot of your output and mine. Notice the “Celestial” and “Starry Night”, in particular. The colors on the right should be what to expect.
(edited by Killer Rhino.6794)
I had it wrong when I said S & L are between 0 – 1 (saturation is; lightness is not).
Actually, they seem both to be between 0 and 2 (or at least >1) :
7: {
name: "Ocean",
cloth: {
brightness: -21,
contrast: 1,
hue: 188,
saturation: 1.32813, <--
lightness: 0.976563
},
leather: {
brightness: -18,
contrast: 1,
hue: 188,
saturation: 1.13281, <--
lightness: 1.05469
},
metal: {
brightness: -18,
contrast: 1,
hue: 188,
saturation: 0.78125,
lightness: 1.01563
}
}
Ah, yes. Cliff even specifically pointed that out to me in our conversations. I’ll update it again. Thanks, smiley!
It’s not that the API’s saturation/lightness shift values are > 1, most of the time that’s okay because the calculated S/L that they get applied to are small enough that the result is still < 1. Also, I only see this problem on S, never on L (i.e. L * lightness is always < 1).
Color 592 “Cherry” has “saturation”=1.17188, however, the cloth and leather materials are okay; only on metal does this output an S > 1.
I had it wrong when I said S & L are between 0 – 1 (saturation is; lightness is not).
Actually, they seem both to be between 0 and 2 (or at least >1) :
7: { name: "Ocean", cloth: { brightness: -21, contrast: 1, hue: 188, saturation: 1.32813, <-- lightness: 0.976563 }, leather: { brightness: -18, contrast: 1, hue: 188, saturation: 1.13281, <-- lightness: 1.05469 }, metal: { brightness: -18, contrast: 1, hue: 188, saturation: 0.78125, lightness: 1.01563 } }
Just to make that clear, they’re not raw values you take but factors you multiply the current values with.
How much bigger than 1 is the product? If it’s not much I’d just cut it off.
I’ve seen this happening up to a resulting RGB value of 111,-32,-8 on #122 (Ruby, metal).
Changing it up to 111,0,0 doesn’t completely kill the color, but it’s still something to consider.
You might also want to take a look at colors #144, 145, 146, they have these negative values on all materials.
Saturation & Lightness values are ranged between 0 – 2. A value of 1 means “no change”.
So sorry for the confusion, but the feedback is super helpful.
Edit: I’ve updated the guide to be clearer.
(edited by Killer Rhino.6794)
Doh, sorry, I’ve tracked my issue backwards now – it’s when I apply the contrast transform, and it gives me negative values for G and B.
Color 482 “Midnight Fire” for material “cloth” has “brightness”=-38;“contrast”=1. Applying that to the base 128,26,26 produces 90,-12,-12. I’m obviously missing something here, but I’m not sure what it is.
Dr Ishmael, Let’s take a look at an example:
name: "Midnight Fire"
cloth: {
brightness: -38
contrast: 1
hue: 25
saturation: 0.273438
lightness: 1.01563
}
We start with our baseColor: (R:128, G:26, B:26).
Dealing with just “cloth”, for now, apply the brightness:
(128-38, 26-38, 26-38) = (90, -12, -12).
Now apply the contrast:
(90 – 128) * 1 + 128 = 90
(-12 – 128) * 1 + 128 = -12
(-12 – 128) * 1 + 128 = -12
Now convert RGB to HSL
(Not shown: I will normalize the RGB values between 0 – 1. Also, the conversion function I use will output HSL normalized values between 0 – 1)
R:90 -> H:1 (or 360 deg, if you so prefer)
G:-12 -> S:1 (or 100%, if you so prefer)
B:-12 -> L:0.176471 (or 17.6471%, if you so prefer)
Apply the HSL shifts from the response with the “RGB converted-to- HSL” values:
Hue = 1 * (25 / 360)
Saturation = 1 * 0.273438
Lightness = 0.176471 * 1.01563
So at this point the HSL values I have are:
hsl_Hue 0.0694444
hsl_Sat 0.273438
hsl_Light 0.179229
Finally converting back to RGB should produce:
R:0.228237
G:0.171061
B:0.130221
(edited by Killer Rhino.6794)
What are you normalizing? The RGB input? The calculation results? And how are you doing the normalization considering the fact that RGB is only defined on positive values.
Converting RGB 90, -12, -12 results in HSL 1 / 1.30 / 0.15 (rounded) for me.
What are you normalizing? The RGB input? The calculation results? And how are you doing the normalization considering the fact that RGB is only defined on positive values.
Converting RGB 90, -12, -12 results in HSL 1 / 1.30 / 0.15 (rounded) for me.
Look here: http://www.workwithcolor.com/color-converter-01.htm
Notice that
R:90
G:0
B:0
(as you pointed out, -12 clamps to 0 in RGB)
converts to
H:360 deg (0 deg & 360 deg are the same)
S:100%
L:18%
If we normalize the HSL values to be within 0 – 1:
H: 1 (from 360 deg / 360 deg)
S: 1 (from 100% / 100%)
L: 0.18 (from 18%)
Now look at the values in my example:
Now convert RGB to HSL (The library I use normalizes the values between 0 – 1)
R:90 -> H:1 (or 360 deg, if you so prefer)
G:-12 -> S:1 (or 100%, if you so prefer)
B:-12 -> L:0.176471
They’re pretty close. Did that answer your question?
Rhino, basically what you’re saying is that I should “correct” any negative RGB value to 0 before converting to HSL? Just want clear confirmation of this before I go put it in my code.
Rhino, basically what you’re saying is that I should “correct” any negative RGB value to 0 before converting to HSL? Just want clear confirmation of this before I go put it in my code.
Yes, you should clamp RGB values to the range of 0 – 255. What language are you writing in, btw?
Thanks!
I used it to create simple color sheer, here is code:
https://code.google.com/p/gw2api/source/browse/trunk/src/cz/zweistein/gw2/app/color/ColorSheet.java
And here is result:
https://gw2api.googlecode.com/svn/trunk/colorsheet.html
(you might want to save it as html file on local drive and then open in broswer)
Zwei, in your color shift code, try changing:
hsl0 = (float) (hsl0 * 360 + color.getHue()) / 360;
to:
hsl0 = (float) (color.getHue() / 360);
I took a screenshot of your output and mine. Notice the “Celestial” and “Starry Night”, in particular. The colors on the right should be what to expect.
Fixed, thanks :-)
I’m writing in Perl. My module is on GitHub.
Hmm… Correcting up to 0 solves Midnight Fire, but I’m still getting problems with S * saturation > 1. Let’s go back to color 592 Cherry on metal that I mentioned before.
name: "Cherry"
metal: {
brightness: -5
contrast: 1.13281
hue: 356
saturation: 1.17188
lightness: 1.05469
}
Base color: (R:128, G:26, B:26)
Apply brightness: (R:123, G:21, B:21)
Apply contrast: (R:122.33595, G:6.78933, B:6.78933) <— completely sane, no negative values
Convert to HSL: (H:0, S:0.89484, L:0.25319) <— matches the workwithcolor.com converter
Apply HSL transform: (H:0.98889, S:1.04865, L:0.26703) <— S > 1 ???
(edited by Dr Ishmael.9685)
I’m still unsure if these are right, but: https://chillerlan.net/gw2color.php
I’m still unsure if these are right, but: https://chillerlan.net/gw2color.php
Nailed it!
Edit: added the link to the How-To guide for reference
(edited by Killer Rhino.6794)
I’m still unsure if these are right, but: https://chillerlan.net/gw2color.php
Nailed it!
Really? Hot Purple, #526
→ rgb(308,-11,308)
Same problem as Ish mentioned above, even with clamping, the HSL shift will create values outside of HSL, and subsequently RGB.
I’m still unsure if these are right, but: https://chillerlan.net/gw2color.php
Nailed it!
Really? Hot Purple, #526
-> rgb(308,-11,308)Same problem as Ish mentioned above, even with clamping, the HSL shift will create values outside of HSL, and subsequently RGB.
Have you tried carrying this through the whole algorithm? What do you get?
I’m still unsure if these are right, but: https://chillerlan.net/gw2color.php
Nailed it!
Edit: added the link to the How-To guide for reference
I’ve updated my gist to reflect the changes: https://gist.github.com/codemasher/fb407de5587fdbd3e7c5
€: i’ve forgot to “correct” the final RGB values earlier.
(edited by smiley.1438)
I get the same colors that are already visible, because Opera will silently clamp negative or excessive RGB values to [0..255], but is this really the way to go?
I get the same colors that are already visible, because Opera will silently clamp negative or excessive RGB values to [0..255], but is this really the way to go?
Sure. The easiest way to know if you’re doing it right: Does #947 White result in R:255 G:255 B:255?
Yeah, it does. The colors look like they’re calculated correctly, but I was wondering if clamping to the RGB space is really the way this is intended to be done.
947 White actually gives L > 1. I’m not sure how I didn’t notice this before.
name: "White"
default: {
brightness: 52
contrast: 1.85938
hue: 185
saturation: 0
lightness: 1.99219
}
Base color: (R:128, G:26, B:26)
Apply brightness: (R:180, G:78, B:78)
Apply contrast: (R:224.68776, G:35.031, B:35.031) <— completely sane, no negative values
Convert to HSL: (H:0, S:0.75777, L:0.50925) <— matches the workwithcolor.com converter
Apply HSL transform: (H:0, S:0.51389, L:1.01453) <— L > 1 ???
I posted that earlier up there but the solution should work the same. At least for me it does.
It still seems weird to me to “clamp” results to a given range “just because”, but I have very little experience with colorspace transforms like this.
So it’s perfectly alright to correct the result of a transformation (like applying contrast to RGB or a saturation-shift to HSL) if said result is outside the allowed range? If G < 0, just kick it up to 0? If S > 1, just smack it back down to 1?
This is exactly my concern, too ^^
It still seems weird to me to “clamp” results to a given range “just because”, but I have very little experience with colorspace transforms like this.
So it’s perfectly alright to correct the result of a transformation (like applying contrast to RGB or a saturation-shift to HSL) if said result is outside the allowed range? If G < 0, just kick it up to 0? If S > 1, just smack it back down to 1?
Assuming “0.0 is 0” & “1.0 is 255”, an excerpt from Apple’s official iOS color documentation reads:
Discussion
Values below 0.0 are interpreted as 0.0, and values above 1.0 are interpreted as 1.0.
This is a restriction for any color library. There’s no way to represent an RGB color outside the range of 0 to 255. It’s not that strange.
Yep, that’s probably it. Colors only have a defined range. in RGB you simply cannot go beyond 255 and below zero. So any values above or below the max/min part should be interpreted as their respective max/min values.
I think that the values above or below the normed values come from mathematical conversion. WE don’t know if ANet uses the same way to storage the color values in the game as they give us via the api.
I build a php script to get all colors, but I’m not sure if I did everything right.
Maybe we can compare some RGB values (cloth)?
#2: 70, 69, 71
#129: 95, 115, 48
#443: 187, 186, 185
#629: 95, 10, 15
#1154: 252, 161, 15
I’ve already posted an example, have a look over here: https://chillerlan.net/gw2color.php
(i’ve added title-attributes, so that you can see the RGB values when you hover over a color)
Ah yes, I saw the link in OPs post too late. I compared the values and they are identical, fine.
I stumbled across those CSS3 filters:
-webkit-filter: brightness(1.5) contrast(1.5) hue-rotate(180deg) saturate(2);
Now if only there was a lightness filter :P
Okay, final question (I think). Looking at Smiley’s Gist code (post #2 in this thread), he’s not correcting the S/L values before converting HSL back to RGB, and instead just correcting the final RGB values. If I follow that method, I can produce an exact match of his HTML page.
However, that doesn’t make sense. If S > 1 is outside the HSL colorspace, wouldn’t that result in an invalid conversion back to RGB? Shouldn’t we be correcting S and L to 1 before the final RGB conversion?
Example: color 1220 Shamrock (default). Smiley’s result is (0, 255, 0), but if I correct S/L first, I get (0, 220, 37).
(edited by Dr Ishmael.9685)
*Notice: i don’t claim that these results are correct, they only match Killer Rhino’s results. I’m still waiting for Cliff to clear things up and tell us if we’re on the right track.
Yeah, some official confirmation would be nice at this point.
From the looks of Rhino’s code, and the documentation he quoted, it looks like iOS handles all of these corrections internally and silently. I’m going to go with correcting S/L before the final RGB conversion.
Yeah, some official confirmation would be nice at this point.
From the looks of Rhino’s code, and the documentation he quoted, it looks like iOS handles all of these corrections internally and silently. I’m going to go with correcting S/L before the final RGB conversion.
Not just iOS, the color functions are defined universally. I would check some source material out on the net if you need more affirmative confirmation. Regardless, you shouldn’t need to change any of the values returned by the APis
Edit: take a look again at the detailed example I posted a few responses up.
(edited by Killer Rhino.6794)
Lead Programmer
The colors you were seeing invalid saturation values for were colors that had a different base_rgb than 128,26,26 (skin, hair, eye, etc. colors).
I just updated the API to show the base_rgb of colors. I also removed the non-dye colors to make it more uniform and reduce confusion (multiple “black” dyes, etc.).
I also created a javascript version of our internal color shifting algorithm here: http://jsfiddle.net/cliff/jQ8ga/ . This example code uses the sylvester javascript matrix library for math.
The way it works is pretty different than the processes previously described — it calculates a transformation matrix which is then applied to the color in one pass.
I also added pre-calculated RGB values to the color API for those who don’t need to deal with HSL transformations and just want an RGB value. It can also be used to test your color shifting algorithm against ours for correctness.
(edited by Cliff Spradlin.3512)
The colors you were seeing invalid saturation values for were colors that had a different base_rgb than 128,26,26 (skin, hair, eye, etc. colors).
I just updated the API to show the base_rgb of colors. I also removed the non-dye colors to make it more uniform and reduce confusion (multiple “black” dyes, etc.).
I also created a javascript version of our internal color shifting algorithm here: http://jsfiddle.net/cliff/jQ8ga/ . This example code uses the sylvester javascript matrix library for math.
The way it works is pretty different than the processes previously described — it calculates a transformation matrix which is then applied to the color in one pass.
I also added pre-calculated RGB values to the color API for those who don’t need to deal with HSL transformations and just want an RGB value. It can also be used to test your color shifting algorithm against ours for correctness.
Thanks, Cliff. I updated my library with the new response fields and pushed them up. I’ll update the How-To.