Page 1 of 1
Recoloring an icon
Posted: Thu Apr 02, 2015 2:38 pm
by Joubarbe
Hello,
As you can (barely) see in this image, the inside of this icon is green, and I would like to be able to redraw it in whatever color the user choose. So I can use FillArea() you would say, but no, because if you look closely, there's an inner shadow in this, meaning that I need to keep this effect when changing color. Thus, keeping the Brightness value, and FillArea won't do that.
1/ So, I guess my question is : how to recolor a sprite without affecting the default Brightness values ?
2/ And a bonus question : how to manage the glowing color behind the unit ? I guess it's not the same answer.
Thanks

Re: Recoloring an icon
Posted: Thu Apr 02, 2015 4:53 pm
by kenmo
Here is a very simple example to get you started...
Code: Select all
InFile.s = OpenFileRequester("Open Image", GetCurrentDirectory(), "Images|*.png;*.bmp", 0) ; "test.png"
NewColor.i = ColorRequester() ; RGB(255, 255, 0)
Procedure.i _Max(x.i, y.i)
If (x > y)
ProcedureReturn x
Else
ProcedureReturn y
EndIf
EndProcedure
Procedure ColorizeImage(Image.i, Color.i)
If IsImage(Image)
If StartDrawing(ImageOutput(0))
For x = 0 To ImageWidth(Image) - 1
For y = 0 To ImageHeight(Image) - 1
; This is a very simple version!
OldColor.i = Point(x, y)
Brightness.f = _Max(_Max(Red(OldColor), Green(OldColor)), Blue(OldColor)) / 255.0
NewColor.i = RGB(Brightness * Red(Color), Brightness * Green(Color), Brightness * Blue(Color))
Plot(x, y, NewColor)
Next y
Next x
StopDrawing()
EndIf
EndIf
EndProcedure
UsePNGImageDecoder()
UsePNGImageEncoder()
If LoadImage(0, InFile)
ColorizeImage(0, NewColor)
OutFile.s = InFile + ".png"
SaveImage(0, OutFile, #PB_ImagePlugin_PNG)
RunProgram(OutFile)
EndIf
Now a more advanced version might preserve the pixels' gamma, saturation, only colorize selective hues, etc...

Re: Recoloring an icon
Posted: Thu Apr 02, 2015 5:41 pm
by Joubarbe
Oh... That was so easy I'm ashamed of having asked that question
And uh... Is it also that simple to obtain hue and saturation ?
Hey man, you could have said "just take the higher RGB value of your old color to get the brightness, then multiply your new RGB values with this brightness", but no, you wrote a nice working example ! Thanks a lot for that
(The simple version will do, because it's working perfectly)
Re: Recoloring an icon
Posted: Thu Apr 02, 2015 10:17 pm
by BasicallyPure
Joubarbe wrote:And uh... Is it also that simple to obtain hue and saturation ?
Hi Joubarbe,
I just worked this out the other day.
Here are procedures that will convert BGR to HSV color space and back to BGR.
Code: Select all
; BGR to HSV to BGR floating point example
Structure HSV_color_Type
Hue.f
Saturation.f
Value.f
EndStructure
EnableExplicit
Procedure BGR_To_HSV(BGRcolor, *output.HSV_color_Type)
; this procedure uses floating point math
; input standard PureBasic BGRcolor value : 0<= BGRcolor <= $FFFFFF
; *output.HSV_color_Type
; \Hue.f : 0<= Hue < 360
; \Saturation.f : 0<= Saturation <= 1
; \Value.f : 0<= Value <= 1
Protected.i delta, BGR_min, BGR_max, R, G, B
R = BGRcolor & $FF : BGRcolor >> 8
G = BGRcolor & $FF : BGRcolor >> 8
B = BGRcolor & $FF
; find the smallest of R, G, B
If g<=b:If r<=g:BGR_min=r:Else:BGR_min=g:EndIf:ElseIf r<=b:BGR_min=r:Else:BGR_min=b:EndIf
; find the largest of R, G, B
If g>=b:If r>=g:BGR_max=r:Else:BGR_max=g:EndIf:ElseIf r>=b:BGR_max=r:Else:BGR_max=b:EndIf
With *output
\Value = BGR_max / 255.0
If \Value = 0
\Hue = 0
\Saturation = 0
ProcedureReturn
EndIf
delta = BGR_max - BGR_min
\Saturation = delta / BGR_max
If \Saturation = 0 Or delta = 0
\Hue = 0
ProcedureReturn
EndIf
If BGR_max = R
\Hue = 60 * (G - B) / delta
ElseIf BGR_max = G
\Hue = 120 + 60 *(B - R) / delta
Else
\Hue = 240 + 60 *(R - G) / delta
EndIf
If \Hue < 0 : \Hue + 360 : EndIf
EndWith
EndProcedure
Procedure HSV_to_BGR(*input.HSV_color_Type)
; this procedure uses floating point math
; input HSV_color_Type
; *input\Hue.f : 0<= Hue < 360
; *input\Saturation.f : 0<= Saturation <= 1
; *input\Value.f : 0<= Value <= 1
; returns the standard PureBasic BGR color value : 0 <= BGRcolor <= $FFFFFF
Protected.f C, X, M
Protected.i R, G, B
With *input
If \Saturation = 0
R = \Value * 255
ProcedureReturn ( R<<16 | R<<8 | R )
EndIf
C = \Value * \Saturation
X = C * (1 - Abs(Mod(\Hue / 60, 2) - 1))
M = (\Value - C) * 255
C * 255
X * 255
If \Hue < 60
R = C+M : G = X+M : B = M
ElseIf \Hue < 120
R = X+M : G = C+M : B = M
ElseIf \Hue < 180
R = M : G = C+M : B = X+M
ElseIf \Hue < 240
R = M : G = X+M : B = C+M
ElseIf \Hue < 300
R = X+M : G = M : B = C+M
Else
R = C+M : G = M : B = X+M
EndIf
EndWith
ProcedureReturn ( B<<16 | G<<8 | R )
EndProcedure
Define HSVcolor.HSV_color_Type
Define BGRcolor = Random($FFFFFF)
Debug "------ original BGR ------"
Debug "Blue = " + Blue(BGRcolor)
Debug "Green = " + Green(BGRcolor)
Debug "Red = " + Red(BGRcolor)
Debug ""
Debug "----- convert to HSV -----"
BGR_To_HSV(BGRcolor, @HSVcolor)
Debug "Hue = " + HSVcolor\Hue
Debug "Sat = " + HSVcolor\Saturation
Debug "Val = " + HSVcolor\Value
Debug ""
Debug "------ back to BGR -------"
BGRcolor = HSV_to_BGR(@HSVcolor)
Debug "Blue = " + Blue(BGRcolor)
Debug "Green = " + Green(BGRcolor)
Debug "Red = " + Red(BGRcolor)
Re: Recoloring an icon
Posted: Thu Apr 02, 2015 10:26 pm
by Joubarbe
Hmm... Thanks, hue seems harder to define !
Re: Recoloring an icon
Posted: Sun Apr 05, 2015 7:36 am
by Blue
Hello kenmo
I'm curious...
In the following code you provide
kenmo wrote:
Code: Select all
...
Procedure.i _Max(x.i, y.i)
If (x > y)
ProcedureReturn x
Else
ProcedureReturn y
EndIf
EndProcedure
....
why do you start the Max() function with an underscore ?
Any compelling reason, besides a style preference ?
Re: Recoloring an icon
Posted: Sun Apr 05, 2015 3:58 pm
by kenmo
No important reason.
Just in case Joubarbe wanted to drop some of that example into his project. Didn't want to cause any name conflicts... maybe he already has Max() defined as a procedure for floats, or an array, or something

Re: Recoloring an icon
Posted: Sun Apr 05, 2015 10:26 pm
by Blue
kenmo wrote:No important reason.
Just in case Joubarbe wanted to drop some of that example into his project. Didn't want to cause any name conflicts... maybe he already has Max() defined as a procedure for floats, or an array, or something

OK.
So, just good forward thinking on your part.
Nice.
Thanks kenmo.