Ooops
October 28, 2020, 11:56:26 PM

Author Topic: [bmx] Color space conversion by Pineapple [ 1+ years ago ]  (Read 1980 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] Color space conversion by Pineapple [ 1+ years ago ]
« on: June 29, 2017, 12:28:43 AM »
Title : Color space conversion
Author : Pineapple
Posted : 1+ years ago

Description : Convert colors to and from RGB, CMY, CMYK, HSV, HSL, HCL, YIQ, YUV, CIE XYZ, and CIE L*ab

Code :
Code: BlitzMax
  1. '       --+-----------------------------------------------------------------------------------------+--
  2. '         |   This code was originally written by Sophie Kirschner (sophiek@pineapplemachine.com)   |  
  3. '         | It is released as public domain. Please don't interpret that as liberty to claim credit |  
  4. '         |   that isn't yours, or to sell this code when it could otherwise be obtained for free   |  
  5. '         |                because that would be a really shitty thing of you to do.                |
  6. '       --+-----------------------------------------------------------------------------------------+--
  7.  
  8.  
  9. ' Usage:
  10. '  1:
  11. '   Use FloatRGB:Float[] ( red:Int , green:Int, blue:Int ) to convert your
  12. '   color to a form that the conversion functions can best work with.
  13. '  2:
  14. '   Call your function rgbto___:Float[] ( ___:Float[] ) using that returned
  15. '   value to get it in your desired color space. (Where "___" is the color
  16. '   space you want to convert to)
  17. '  3:
  18. '   Modify the values in that returned array however you like
  19. '  4:
  20. '   Use SetColorRGB ( rgb:Float[] ) to set it as a color, or
  21. '   ___torgb:Float[] to conver it back to the rgb colorspace and then
  22. '   IntRGB:Int[] ( rgb:Float[] ) or ByteRGB:Byte[] ( rgb:Float[] ) or
  23. '   GetR:Int( rgb:Float[] ) and GetG:Int( rgb:Float[] ) and
  24. '   GetB:Int( rgb:Float[] ) to get the new red,green,blue values
  25. '  Ranges:
  26. '   RGB: [0,1]
  27. '   CMY: [0,1]
  28. '   CMYK: [0,1]
  29. '   HSV: [0,1]
  30. '   HSL: [0,1]
  31. '   HCL: [0,1]
  32. '   YIQ: [-1,1]
  33. '   YUV: [-1,1]
  34. '   XYZ: [0,1]
  35. '   L*ab: [0,100] for L*, a and b are theoretically unbounded (I think,
  36. '                 I could very well be interpreting this stuff wrong)
  37.  
  38.  
  39. SuperStrict
  40.  
  41. ' example program
  42. Rem
  43. AppTitle="Color spaces"
  44. Graphics 320,240
  45. Local val#[]=[.5,.5,.5],s#=0.005
  46. Repeat
  47.         setcolorrgb hsvtorgb(val)
  48.         DrawRect 0,0,64,240
  49.         setcolorrgb hsltorgb(val)
  50.         DrawRect 64,0,64,240
  51.         setcolorrgb hcltorgb(val)
  52.         DrawRect 128,0,64,240
  53.         setcolorrgb xyztorgb(val)
  54.         DrawRect 192,0,64,240
  55.         setcolorrgb cmytorgb(val)
  56.         DrawRect 256,0,64,240
  57.        
  58.         DrawText_ "hsv",2,220
  59.         DrawText_ "hsl",66,220
  60.         DrawText_ "hcl",130,220
  61.         DrawText_ "xyz",194,220
  62.         DrawText_ "cmy",258,220
  63.        
  64.         DrawText_ "value: "+Left(val[0],5)+","+Left(val[1],5)+","+Left(val[2],5),2,0
  65.         DrawText_ "a,z,s,x,d,c keys to alter the values",2,16
  66.        
  67.         If KeyDown(key_a) Then val[0]:+s
  68.         If KeyDown(key_z) Then val[0]:-s
  69.         If KeyDown(key_s) Then val[1]:+s
  70.         If KeyDown(key_x) Then val[1]:-s
  71.         If KeyDown(key_d) Then val[2]:+s
  72.         If KeyDown(key_c) Then val[2]:-s
  73.         For Local x%=0 To 2
  74.                 If val[x]>1 val[x]=1
  75.                 If val[x]<0 val[x]=0
  76.         Next
  77.         Flip
  78. Until KeyDown(27) Or AppTerminate()
  79.  
  80. Function DrawText_(str$,x%,y%)
  81.         SetColor 0,0,0
  82.         DrawText str,x,y+1
  83.         DrawText str,x+1,y
  84.         DrawText str,x,y-1
  85.         DrawText str,x-1,y
  86.         DrawText str,x+1,y+1
  87.         DrawText str,x-1,y-1
  88.         DrawText str,x+1,y-1
  89.         DrawText str,x-1,y+1
  90.         SetColor 255,255,255
  91.         DrawText str,x,y
  92. End Function
  93. End Rem
  94.  
  95. ' For your convenience, SetColor for an array containing 3 floats indicating rgb
  96. Function SetColorRGB(rgb#[])
  97.         SetColorRGBv rgb[0],rgb[1],rgb[2]
  98. End Function
  99.  
  100. ' SetColor for 3 floats indicating rgb
  101. Function SetColorRGBv(br#,bg#,bb#)
  102.         Local r%=br*255,g%=bg*255,b%=bb*255
  103.         If r<0 r=0
  104.         If g<0 g=0
  105.         If b<0 b=0
  106.         If r>255 r=255
  107.         If g>255 g=255
  108.         If b>255 b=255
  109.         SetColor r,g,b
  110. End Function
  111.  
  112. ' Turn a float array indicating RGB into a byte array
  113. Function ByteRGB@[](rgb#[])
  114.         Return [Byte(rgb[0]*255),Byte(rgb[1]*255),Byte(rgb[2]*255)]
  115. End Function
  116.  
  117. ' Turn a float array indicating RGB into an int array
  118. Function IntRGB%[](rgb#[])
  119.         Return [Int(rgb[0]*255),Int(rgb[1]*255),Int(rgb[2]*255)]
  120. End Function
  121.  
  122. ' Turn rgb into a float array
  123. Function FloatRGB#[](red%,green%,blue%)
  124.         Return [red/255.0,green/255.0,blue/255.0]
  125. End Function
  126.  
  127. Function FloatARGB#[](argb%)
  128.         Return [((argb Shr 16)&$ff)/255.0,((argb Shr 8)&$ff)/255.0,(argb&$ff)/255.0]
  129. End Function
  130.  
  131. ' Get individual channels from float array
  132. Function GetR%(rgb#[])
  133.         Return rgb[0]*255
  134. End Function
  135. Function GetG%(rgb#[])
  136.         Return rgb[0]*255
  137. End Function
  138. Function GetB%(rgb#[])
  139.         Return rgb[0]*255
  140. End Function
  141.  
  142. ' the following code was adapted from the examples found at:
  143. ' http://easyrgb.com/index.php?X=MATH&H=02#text2
  144.  
  145. ' observer = 2 degrees, illuminant = D65
  146. Const refx#=95.047
  147. Const refy#=100.0
  148. Const refz#=108.883
  149.  
  150. ' assumes rgb in the range [0,1]
  151. ' returns xyz in the range [0,1]
  152. Function rgbtoxyz#[](rgb#[])
  153.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  154.         If(r>0.04045) Then
  155.                 r=((r+0.055)/1.055)^2.4
  156.         Else
  157.                 r:/12.92
  158.         EndIf
  159.         If(g>0.04045) Then
  160.                 g=((g+0.055)/1.055)^2.4
  161.         Else
  162.                 g:/12.92
  163.         EndIf
  164.         If(b>0.04045) Then
  165.                 b=((b+0.055)/1.055)^2.4
  166.         Else
  167.                 b:/12.92
  168.         EndIf
  169.         r:*100
  170.         g:*100
  171.         b:*100
  172.         Return [(r*0.4124+g*0.3576+b*0.1805)/refx,(r*0.2126+g*0.7152+b*0.0722)/refy,(r*0.0193+g*0.1192+b*0.9505)/refz]
  173. End Function
  174. ' assumes xyz in the range [0,1]
  175. ' returns rgb in the range [0,1]
  176. Function xyztorgb#[](xyz#[])
  177.         Local x#=xyz[0]*refx/100.0,y#=xyz[1]*refy/100.0,z#=xyz[2]*refz/100.0
  178.         Local r#=x* 3.2406+y*-1.5372+z*-0.4986
  179.         Local g#=x*-0.9689+y* 1.8758+z* 0.0415
  180.         Local b#=x* 0.0557+y*-0.2040+z* 1.0570
  181.         If r>0.0031308 Then
  182.                 r=1.055*(r^(0.416666667))-.055
  183.         Else
  184.                 r:*12.92
  185.         EndIf
  186.         If g>0.0031308 Then
  187.                 g=1.055*(g^(0.416666667))-.055
  188.         Else
  189.                 g:*12.92
  190.         EndIf
  191.         If b>0.0031308 Then
  192.                 b=1.055*(b^(0.416666667))-.055
  193.         Else
  194.                 b:*12.92
  195.         EndIf
  196.         Return [r,g,b]
  197. End Function
  198. ' assumes xyz in the range [0,1]
  199. ' returns l*ab in a very varying range
  200. Function xyztolab#[](xyz#[])
  201.         Local x#=xyz[0],y#=xyz[1],z#=xyz[2]
  202.         If(x>0.008856) Then
  203.                 x=x^0.333333333
  204.         Else
  205.                 x=(x*7.787)+0.137931034
  206.         EndIf
  207.         If(y>0.008856) Then
  208.                 y=y^0.333333333
  209.         Else
  210.                 y=(y*7.787)+0.137931034
  211.         EndIf
  212.         If(z>0.008856) Then
  213.                 z=z^0.333333333
  214.         Else
  215.                 z=(z*7.787)+0.137931034
  216.         EndIf
  217.         Return [116*y-16,500*(x-y),200*(y-z)]
  218. End Function
  219. ' assumes l*ab in a very varying range
  220. ' assumes xyz in the range [0,1]
  221. Function labtoxyz#[](lab#[])
  222.         Local y#=(lab[0]+16)/116.0
  223.         Local x#=lab[1]/500.0+y
  224.         Local z#=y-lab[2]/200.0
  225.         If x^3>.008856 Then
  226.                 x=x^3
  227.         Else
  228.                 x=(x-0.137931034)/7.787
  229.         EndIf
  230.         If y^3>.008856 Then
  231.                 y=y^3
  232.         Else
  233.                 y=(y-0.137931034)/7.787
  234.         EndIf
  235.         If z^3>.008856 Then
  236.                 z=z^3
  237.         Else
  238.                 z=(z-0.137931034)/7.787
  239.         EndIf
  240.         Return [x,y,z]
  241. End Function
  242. ' assumes rgb in the range [0,1]
  243. ' returns l*ab in a very varying range
  244. Function rgbtolab#[](rgb#[])
  245.         Return xyztolab(rgbtoxyz(rgb))
  246. End Function
  247. ' assumes l*ab in a very varying range
  248. ' returns rgb in the range [0,1]
  249. Function labtorgb#[](lab#[])
  250.         Return xyztorgb(labtoxyz(lab))
  251. End Function
  252. ' assumes rgb in the range [0,1]
  253. ' returns cmy in the range [0,1]
  254. Function rgbtocmy#[](rgb#[])
  255.         Return [1-rgb[0],1-rgb[1],1-rgb[2]]
  256. End Function
  257. ' assumes cmy in the range [0,1]
  258. ' returns rgb in the range [0,1]
  259. Function cmytorgb#[](cmy#[])
  260.         Return [1-cmy[0],1-cmy[1],1-cmy[2]]
  261. End Function
  262. ' assumes cmy in the range [0,1]
  263. ' returns cmyk in the range [0,1]
  264. Function cmytocmyk#[](cmy#[])
  265.         Local c#=cmy[0],m#=cmy[1],y#=cmy[2]
  266.         Local k#=1
  267.         If c<k Then k=c
  268.         If m<k Then k=m
  269.         If y<k Then k=y
  270.         If k=1 Then Return [0.0,0.0,0.0,k]
  271.         Local k1#=1-k
  272.         Return [(c-k)/k1,(m-k)/k1,(y-k)/k1,k]
  273. End Function
  274. ' assumes cmyk in the range [0,1]
  275. ' returns cmy in the range [0,1]
  276. Function cmyktocmy#[](cmyk#[])
  277.         Local k1#=1-cmyk[3]
  278.         Return [cmyk[0]*k1+cmyk[3],cmyk[1]*k1+cmyk[3],cmyk[2]*k1+cmyk[3]]
  279. End Function
  280. ' assumes rgb in the range [0,1]
  281. ' returns cmyk in the range [0,1]
  282. Function rgbtocmyk#[](rgb#[])
  283.         Return cmytocmyk(rgbtocmy(rgb))
  284. End Function
  285. ' assumes cmyk in the range [0,1]
  286. ' returns rgb in the range [0,1]
  287. Function cmyktorgb#[](cmyk#[])
  288.         Return cmytorgb(cmyktocmy(cmyk))
  289. End Function
  290.  
  291. ' the following code was adapted from the examples found at:
  292. ' http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
  293.  
  294. ' assumes rgb in the range [0,1]
  295. ' returns hsl in the range [0,1]
  296. Function rgbtohsl#[](rgb#[])
  297.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  298.         Local hsl#[]=New Float[3]
  299.         Local ax#=Max(Max(r,g),b),in#=Min(Min(r,g),b)
  300.         hsl[2]=(ax+in)/2.0
  301.         If(ax=in) Then Return hsl
  302.         Local d#=ax-in
  303.         If hsl[2]>.5 Then hsl[1]=d/(2.0-ax-in) Else hsl[1]=d/(ax+in)
  304.         Select ax
  305.                 Case r
  306.                         Local gv%=0
  307.                         If g<b Then gv=6
  308.                         hsl[0]=(g-b)/d+gv
  309.                 Case g
  310.                         hsl[0]=(b-r)/d+2
  311.                 Case b
  312.                         hsl[0]=(r-g)/d+4
  313.         End Select
  314.         hsl[0]:/6.0
  315.         Return hsl
  316. End Function
  317. ' assumes hsl in the range [0,1]
  318. ' returns rgb in the range [0,1]
  319. Function hsltorgb#[](hsl#[])
  320.         Local h#=hsl[0],s#=hsl[1],l#=hsl[2]
  321.         If s=0 Then Return [l,l,l]
  322.         Local q#
  323.         If l<.5 Then q=l*(1+s) Else q=(l+s-l*s)
  324.         Local p#=2*l-q
  325.         Return [_huetorgb(p,q,h+0.333333333),_huetorgb(p,q,h),_huetorgb(p,q,h-0.333333333)]
  326. End Function
  327. Function _huetorgb#(p#,q#,t#)
  328.         If t<0 t:+1
  329.         If t>1 t:-1
  330.         If t<0.166666667 Return p+(q-p)*6*t
  331.         If t<0.5 Return q
  332.         If t<0.666666667 Return p+(q-p)*(0.666666667-t)*6
  333.         Return p
  334. End Function
  335. ' assumes rgb in the range [0,1]
  336. ' returns hsv in the range [0,1]
  337. Function rgbtohsv#[](rgb#[])
  338.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  339.         Local hsv#[]=New Float[3]
  340.         Local ax#=Max(Max(r,g),b),in#=Min(Min(r,g),b)
  341.         hsv[2]=ax
  342.         Local d#=ax-in
  343.         hsv[1]=0
  344.         If ax<>0 Then hsv[1]=d/ax
  345.         If(ax=in) Then hsv[0]=0;Return hsv
  346.         Select ax
  347.                 Case r
  348.                         Local gv%=0
  349.                         If g<b Then gv=6
  350.                         hsv[0]=(g-b)/d+gv
  351.                 Case g
  352.                         hsv[0]=(b-r)/d+2
  353.                 Case b
  354.                         hsv[0]=(r-g)/d+4
  355.         End Select
  356.         hsv[0]:/6.0
  357.         Return hsv
  358. End Function
  359. ' assumes hsv in the range [0,1]
  360. ' returns rgb in the range [0,1]
  361. Function hsvtorgb#[](hsv#[])
  362.         Local h#=hsv[0],s#=hsv[1],v#=hsv[2]
  363.         Local h6#=h*6
  364.         Local i%=h6
  365.         Local f#=h6-i
  366.         Local p#=v*(1-s)
  367.         Local q#=v*(1-f*s)
  368.         Local t#=v*(1-(1-f)*s)
  369.         Select i Mod 6
  370.                 Case 0 Return [v,t,p]
  371.                 Case 1 Return [q,v,p]
  372.                 Case 2 Return [p,v,t]
  373.                 Case 3 Return [p,q,v]
  374.                 Case 4 Return [t,p,v]
  375.                 Case 5 Return [v,p,q]
  376.         End Select
  377.         Return [0.0,0.0,0.0]
  378. End Function
  379.  
  380. ' the following code was derived from the information found at:
  381. ' http://en.wikipedia.org/wiki/HSL_and_HSV#From_luma.2Fchroma.2Fhue
  382.  
  383. Const _b_r#=.3,_b_g#=.59,_b_b#=.11
  384.  
  385. ' assumes hcl in the range [0,1]
  386. ' returns rgb in the range [0,1]
  387. Function hcltorgb#[](hcl#[])
  388.         Local h#=hcl[0]*6,c#=hcl[1]
  389.         Local x#=c*(1-Abs((h Mod 2)-1))
  390.         Local rgb#[]
  391.         If 0<=h And h<1
  392.                 rgb=[c,x,0.0]
  393.         ElseIf 1<=h And h<2
  394.                 rgb=[x,c,0.0]
  395.         ElseIf 2<=h And h<3
  396.                 rgb=[0.0,c,x]
  397.         ElseIf 3<=h And h<4
  398.                 rgb=[0.0,x,c]
  399.         ElseIf 4<=h And h<5
  400.                 rgb=[x,0.0,c]
  401.         ElseIf 5<=h And h<=6
  402.                 rgb=[c,0.0,x]
  403.         Else
  404.                 rgb=[0.0,0.0,0.0]
  405.         EndIf
  406.         Local m#=hcl[2]-(_b_r*rgb[0]+_b_g*rgb[1]+_b_b*rgb[2])
  407.         rgb[0]:+m
  408.         rgb[1]:+m
  409.         rgb[2]:+m
  410.         Return rgb
  411. End Function
  412. ' assumes rgb in the range [0,1]
  413. ' returns hcl in the range [0,1]
  414. Function rgbtohcl#[](rgb#[])
  415.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  416.         Local hcl#[]=New Float[3]
  417.         Local m#=Max(Max(r,g),b)
  418.         hcl[1]=m-Min(Min(r,g),b)
  419.         If hcl[1]=0 Then
  420.                 hcl[0]=0
  421.         ElseIf m=r
  422.                 hcl[0]=((g-b)/hcl[1]) Mod 6
  423.         ElseIf m=g
  424.                 hcl[0]=((b-r)/hcl[1])+2
  425.         ElseIf m=b
  426.                 hcl[0]=((r-g)/hcl[1])+4
  427.         EndIf
  428.         hcl[0]:/6.0
  429.         hcl[2]=_b_r*r+_b_g*g+_b_b*b
  430.         Return hcl
  431. End Function
  432.  
  433. ' assumes rgb in the range [0,1]
  434. ' returns yiq in the range [-1,1]
  435. Function rgbtoyiq#[](rgb#[])
  436.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  437.         Local yiq#[]=New Float[3]
  438.         yiq[0]=0.299000*r + 0.587000*g + 0.114000*b
  439.         yiq[1]=0.595716*r - 0.274453*g - 0.321264*b
  440.         yiq[2]=0.211456*r - 0.522591*g + 0.311350*b
  441.         Return yiq
  442. End Function
  443.  
  444. ' assumes yiq in the range [-1,1]
  445. ' returns rgb in the range [0,1]
  446. Function yiqtorgb#[](yiq#[])
  447.         Local y#=yiq[0],i#=yiq[1],q#=yiq[2]
  448.         Local rgb#[]=New Float[3]
  449.         rgb[0]=y + 0.9563*i + 0.6210*q
  450.         rgb[1]=y - 0.2721*i - 0.6474*q
  451.         rgb[2]=y - 1.1070*i + 1.7046*q
  452.         Return rgb
  453. End Function
  454.  
  455. ' assumes rgb in the range [0,1]
  456. ' returns yuv in the range [-1,1]
  457. Const yuv_uconst#=1.0/0.436
  458. Const yuv_vconst#=1.0/0.615
  459. Function rgbtoyuv#[](rgb#[])
  460.         Local r#=rgb[0],g#=rgb[1],b#=rgb[2]
  461.         Local yuv#[]=New Float[3]
  462.         yuv[0]=(0.299*r + 0.587*g + 0.114*b)
  463.         yuv[1]=(0.492*(b-yuv[0]))*yuv_uconst
  464.         yuv[2]=(0.877*(r-yuv[0]))*yuv_vconst
  465.         yuv[0]=yuv[0]*2-1
  466.         Return yuv
  467. End Function
  468.  
  469. ' assumes yuv in the range [-1,1]
  470. ' returns rgb in the range [0,1]
  471. Function yuvtorgb#[](yuv#[])
  472.         Local y#=(yuv[0]+1)/2.0,u#=yuv[1]/yuv_uconst,v#=yuv[2]/yuv_vconst
  473.         Local rgb#[]=New Float[3]
  474.         rgb[0]=y + 1.140*v
  475.         rgb[1]=y - 0.395*u - 0.581*v
  476.         rgb[2]=y + 2.032*u
  477.         Return rgb
  478. End Function


Comments :


Pineapple(Posted 1+ years ago)

 2 July, 2012: Added support for the YIQ and YUV color spaces


Streaksy(Posted 1+ years ago)

 Very good. :D


Midimaster(Posted 1+ years ago)

 It is not as easy as the code will say us...the problem is that it is not only a mathematical formula to change from RGB to CMYK:
Code: [Select]
Function rgbtocmy#[](rgb#[])
Return [1-rgb[0],1-rgb[1],1-rgb[2]]
End Function
There are RGB constellations, which cannot transformed in an valid CMYK color space and this formula will cause problems in the print office. Your picture will change to PURPLE in all DARK BLUE areas.So,... a real good code should warn when leaving the CMYK color space.


Pineapple(Posted 1+ years ago)

 Midimaster: I used <a href="http://easyrgb.com/index.php?X=MATH&H=11#text11" target="_blank">http://easyrgb.com/index.php?X=MATH&H=11#text11[/url] as a reference, assuming that it was a reasonably accurate conversion. Do any better algorithms exist?


Midimaster(Posted 1+ years ago)

 yes and noa simple algo like yours does not respect the limitations of RGB and CMYK color spaces. The conversion will change colors.Read this:<a href="http://www.printingforless.com/rgb-cmyk.html" target="_blank">http://www.printingforless.com/rgb-cmyk.html[/url]there are a lot of advises which show, that the conversion is not that simple."We recommend a CMYK value of 100-65-0-0 to get a nice clean blue"<a href="http://www.colormatch.de/" target="_blank">http://www.colormatch.de/[/url]In theory the "full blue" RGB 0-0-255 would result in CMYK 1-1-0-0. But if you print this color it would be "purple".1-0.6-0-0 is the best "blue" you can get in CMYK. But this is based on experience. So how could a formula look like? There are better algo's: Adobe Photoshop knows how to convert, but they do not tell anything about the formula. [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal