Recoloring an icon

Just starting out? Need help? Post your questions and find answers here.
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Recoloring an icon

Post by Joubarbe »

Hello,

Image

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 :)
User avatar
kenmo
Addict
Addict
Posts: 2033
Joined: Tue Dec 23, 2003 3:54 am

Re: Recoloring an icon

Post 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... :)
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Recoloring an icon

Post 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)
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Recoloring an icon

Post 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)

BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Recoloring an icon

Post by Joubarbe »

Hmm... Thanks, hue seems harder to define !
User avatar
Blue
Addict
Addict
Posts: 964
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Recoloring an icon

Post 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 ?



  
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
kenmo
Addict
Addict
Posts: 2033
Joined: Tue Dec 23, 2003 3:54 am

Re: Recoloring an icon

Post 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 :)
User avatar
Blue
Addict
Addict
Posts: 964
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Recoloring an icon

Post 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.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
Post Reply