HSVA to RGBA function

I decided I wanted to be able to adjust color with a single slider like you would on the “hue” bar in GIMP ( or Photoshop or whatever ). The colors are created with a combination of Hue, Saturation, and Value. Instead of Red, Blue, Green.

So just in case somebody wants to do this too here is your function - h = hue , s = saturation, v = value, a = alpha


Function HSVAtoRGBA(h%,s%,v%,a%) As Integer
   ' Romans_I_XVI port (w/ a few tweaks) of:
   ' http://schinckel.net/2012/01/10/hsv-to-rgb-in-javascript/
   
   h% = h% MOD 360
   
   rgb = [ 0, 0, 0 ]
   if s% = 0 then
      rgb = [v%/100, v%/100, v%/100]
   else
      s = s%/100 : v = v%/100 : h = h%/60 : i = int(h)

      data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))]
      
      if i = 0 then
         rgb = [v, data[2], data[0]]
      else if i = 1 then
         rgb = [data[1], v, data[0]]   
      else if i = 2 then
         rgb = [data[0], v, data[2]]
      else if i = 3 then
         rgb = [data[0], data[1], v]
      else if i = 4 then
         rgb = [data[2], data[0], v]
      else
         rgb = [v, data[0], data[1]]
      end if
   end if

   for c = 0 to rgb.count()-1 : rgb[c] = int(rgb[c] * 255) : end for
   color% = (rgb[0] << 24) + (rgb[1] << 16) + (rgb[2] <<  :smiling_face_with_sunglasses:  + a%

   return color%
End Function

I converted a Javascript function that I found to work for BrightScript.

Cheers.

Edit: I’ve changed the code to use dev42’s code which solves the problem with the color getting clipped off at a baby blue and not continuing all the way back to red. Thank you very much Dev42!

That looks useful - maybe i could be Cint(h) to be a bit more accurate

Thanks for posting this I’m totally stealing it.

Glad I could help.

And Komag - the original javascript function was using a floor function. Here is what I based it on.
http://schinckel.net/2012/01/10/hsv-to- … avascript/

oooh oooh oooh! I wanna steal it too! I wanna steal it too!

OK, but a question… why not return hex value in the first place?
It’s not that I didn’t read THIS, I just didn’t catch it at first.
… and I wanted to do bit shifting and keep things hexy.

Glad you like it dev42 . How were you planning on implementing it though? I’m currently jumping through about 3 hoops. But it doesn’t matter too much because I’m not running these functions often.

I start with that original HSVAtoRGBA function, which gives me a decimal. Then I have to pass it through this function.


function decToHex (dec) as string
   hexTab = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
   hex = ""
   while dec > 0
      hex = hexTab [dec mod 16] + hex
      dec = dec / 16
   end while
   if hex = "" return "0" else return hex
end function

Then I’m left with a string that I finally turn back into hex like so.

val(hexstring,16)

In my Brightscript I’m doing it like this.

 some_hex_color = val(decTohex(HSVAtoRGBA(hue,sat,100,255)),16)

“Romans_I_XVI” wrote:
How were you planning on implementing it though?
Pardon my ignorance, and I’m not as nimble as others here, but why do you need the hex codes? I thought TheEndless’ comment was that you could just use the color as an Integer/roInteger?

It’s hard to say how I’d do it… :laughing: Warning! Continue at your own peril.

Options include, but are not limited to:

  • using roByteArray.toHexString()

  • convert each color channel into a Hex String and concatenate them together

  • make a Look Up table… Just a spectrum bitmap & a percentage …

  • can colors be read from screen?

The huge numbers that you are multiplying by work. So why change it? But I’d prefer, “R << 24 + G << 16 + B << 8 + a” or whatever they are supposed to be.

edit: Supposedly they should be: “(R << 24) + (G << 16) + (B << 8 ) + a”
I don’t know order of operations apparently. ( extra space lest I get a smiley instead of an 8 )

Ic. For me the integers only worked up to a certain number, then the color stopped changing. I have no idea why, all I know is I got it to work by doing what’s in my previous post.

[spoiler=tiny updates to HSVAtoRGBA v3:2n1w1e57]

Function HSVAtoRGBA(h%,s%,v%,a%) As Integer
	' Romans_I_XVI port (w/ a few tweaks) of:
	' http://schinckel.net/2012/01/10/hsv-to-rgb-in-javascript/
	h% = h% MOD 360
   
	rgb = [ 0, 0, 0 ]
	if s% = 0 then
		rgb = [v, v, v]
	else
		s = s%/100 : v = v%/100 : h = h%/60 : i = int(h)

		data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))]
	   
		if i = 0 then
			rgb = [v, data[2], data[0]]
		else if i = 1 then
			rgb = [data[1], v, data[0]]   
		else if i = 2 then
			rgb = [data[0], v, data[2]]
		else if i = 3 then
			rgb = [data[0], data[1], v]
		else if i = 4 then
			rgb = [data[2], data[0], v]
		else
			rgb = [v, data[0], data[1]]
		end if
	end if

	for c = 0 to rgb.count()-1 : rgb[c] = int(rgb[c] * 255) : end for
	color% = (rgb[0] << 24) + (rgb[1] << 16) + (rgb[2] <<  :smiling_face_with_sunglasses:  + a%

	return color%
End Function

[/spoiler:2n1w1e57]
And my incredibly detailed/painstakingly laborious testing:

for hue = 0 to 360
  scr.DrawLine(100,100+hue,200,100+hue, HSVAtoRGBA(hue,100,100,255))
end for

TO DO: maybe add some bounds checking on the h, s, v, a params?

@dev42

Take a look at the second to last post on this thread.
viewtopic.php?f=34&t=84652&p=484454

Probably should have mentioned the earlier but couldn’t remember where it was, plus I’m posting from my phone which is difficult (not home right now). RokuKC explains in depth the difference between a hex value and an integer.

Cheers

@Romans -

Thanks for that link! Awesome stuff there.

Now, is there still a problem? Because, to me at least, once the signed/unsigned issue is understood, it should become clear that, when talking about signed integers:
&hFFFFFFFF != 4294967295

&hFFFFFFFF == -1

still working on how the 64 bit Double gets clipped to the 32 bit Signed Integer.

Edit: Double is to Float as int is to char!
4294967295 == 0x41EFFFFFFFE00000 ==
01000001 11101111 11111111 11111111
11111111 11100000 00000000 00000000

but it is getting clipped… possibly taking the least significant 32 bits. ( chime in any time gurus! )


Wikipedia: 2’s Complement

“EnTerr” wrote:
Maybe calling it always with V=100, A=255 has saved your bacon so far, IDK. But check for colors with strong R, they should all be washing to cyan (?).
Thats what I found, passing it pure red returned a really pale cyan. I already had another solution so i didnt pursue it though.

I haven’t yet tried this with DrawObject and I’m not understanding the point of converting 2^32 to “decimal” and then use that as a color IF the HSVAtoRGBA() func is working as it should …

The main tweak’s to HSVAtoRGBA() are that it now uses Integers, Integer bit shifting which supposedly avoids the Double to Integer conversion issue, and returns an Integer. The function (latest ver) returned negative values and a spectrum from Red through all the hues back to Red… so, I was pleasantly content.

I did call out how fully I tested this. :wink:

I’ll dig deeper later.


“squirreltown” wrote:
Thats what I found, passing it pure red returned a really pale cyan. I already had another solution so i didn’t pursue it though.
I did make mention of the “baby blue” :roll: … and again, my changes to the HSV…() fixed it. No more “pale cyan”. Could some kind soul test it out?

Sorry, the dectohex function I posted earlier is not the same as what I’m using, I forgot I removed that “As Integer” so it is not getting chopped off and I’m getting back the correct hex as a string, I just now tested it.

Ok finally tested your version of the function dev42 and it works perfect! Thank you for your magic!

I think I will replace the one in the original function with yours.

“dev42” wrote:

I did make mention of the “baby blue” :roll: … and again, my changes to the HSV…() fixed it. No more “pale cyan”. Could some kind soul test it out?
Yep it works, thank you.

It’s throwing a type mismatch if I give it a saturation of 0 though. I’ve tried 0 with everything else and it works.


Type Mismatch. (runtime error &h18) in pkg:/source/generalUtils.brs(77)
077:    for c = 0 to rgb.count()-1 : rgb[c] = int(rgb[c] * 255) : end for

I think I found the problem.

This


   if s% = 0 then
      rgb = [v, v, v]
   else

Needed to change to this

   if s% = 0 then
      rgb = [v%/100, v%/100, v%/100]
   else

Good catch. Glad to be helpful.

Out of curiosity, why are you using HSV instead of RGB in the first place?