Page 1 of 1
Quickly replace image colors?
Posted: Mon Oct 01, 2018 6:53 am
by Dude
I have a PNG image in my app, that I need to quickly replace specific colors with another. In the example image below, I want to replace all the pink with one specific color, and all the blue text with another specific color, based on what the user selects. Is there a quick way of doing this instantly, or do I really have to loop through all pixels and change them one by one? Thanks.
Here's what I'm doing at the moment, but there must be a more efficient way, especially if the image is huge?
Code: Select all
If StartDrawing(ImageOutput(i))
w=ImageWidth(i)-1
h=ImageHeight(i)-1
back=[whatever]
text=[whatever]
For x=0 To w
For y=0 To h
Select Point(x,y)
Case #Magenta : Plot(x,y,back)
Case #Blue : Plot(x,y,text)
EndSelect
Next
Next
StopDrawing()
EndIf
Re: Quickly replace image colors?
Posted: Mon Oct 01, 2018 8:03 am
by RASHAD
Hi Dude
Code: Select all
Procedure FilterCallback(x, y, SourceColor, TargetColor)
If SourceColor = $FF181FFE
ProcedureReturn $FF76F6F1
ElseIf SourceColor = $FF32FE18
ProcedureReturn $FFFE3718
Else
ProcedureReturn SourceColor
EndIf
EndProcedure
CreateImage(1,400,200,32,$FF181FFE)
StartDrawing(ImageOutput(1))
Circle(200,100,100,$FF32FE18)
Circle(200,100,50,$FF2A18FE)
StopDrawing()
If OpenWindow(0, 0, 0, 800, 200, "2DDrawing Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If CreateImage(0, 800, 200) And StartDrawing(ImageOutput(0))
DrawImage(ImageID(1), 0, 0, 400, 200)
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@FilterCallback())
DrawImage(ImageID(1), 400, 0, 400, 200)
StopDrawing()
ImageGadget(0, 0, 0, 800, 200, ImageID(0))
EndIf
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 4:32 am
by Dude
Thanks Rashad (as always!).
Quick question: I haven't speed-tested this, but the manual for CustomFilterCallback() says:
"This callback will be called many times (for every pixel to draw) so it should be very small and fast to not have a too big impact on the drawing performance."
I'm guessing this means the callback is repeatedly called for every pixel, which could end up being no faster than my For/next loop?
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 5:08 am
by RASHAD
Hi Dude
The callback is faster by about 30 to 45 %
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 6:10 am
by Dude
Cool, thanks. I'll switch to using it.

Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 6:53 am
by Fig
If you want to avoid double loop (hidden or not), you can only create a new colored sprite before your main loop.
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 1:34 pm
by kenmo
Is this any faster? Try it in a StartDrawing() block.
Code: Select all
Procedure.i ReplaceColor(OldColor.i, NewColor.i)
Protected Result.i = #False
OldColor & $00FFFFFF
NewColor & $00FFFFFF
If (NewColor = OldColor)
ProcedureReturn (#True)
EndIf
Protected Format.i = DrawingBufferPixelFormat() & (~#PB_PixelFormat_ReversedY)
If ((Format = #PB_PixelFormat_24Bits_BGR) Or (Format = #PB_PixelFormat_32Bits_BGR))
OldColor = RGB(Blue(OldColor), Green(OldColor), Red(OldColor))
NewColor = RGB(Blue(NewColor), Green(NewColor), Red(NewColor))
EndIf
If ((Format = #PB_PixelFormat_32Bits_BGR) Or (Format = #PB_PixelFormat_32Bits_RGB))
Protected *Ptr.LONG = DrawingBuffer()
Protected *End = *Ptr + OutputHeight() * DrawingBufferPitch()
While (*Ptr < *End)
If (*Ptr\l & $00FFFFFF = OldColor)
*Ptr\l = (*Ptr\l & $FF000000) | NewColor
EndIf
*Ptr + 4
Wend
Result = #True
ElseIf ((Format = #PB_PixelFormat_24Bits_BGR) Or (Format = #PB_PixelFormat_24Bits_RGB))
*Ptr = DrawingBuffer()
*End = *Ptr + OutputHeight() * DrawingBufferPitch()
While (*Ptr < *End)
If (CompareMemory(*Ptr, @OldColor, 3))
CopyMemory(@NewColor, *Ptr, 3)
EndIf
*Ptr + 3
Wend
Result = #True
EndIf
ProcedureReturn (Result)
EndProcedure
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 1:47 pm
by firace
It's actually possible to just update the PNG palette in-place, which should give pretty much instant results regardless of image size.
Here's an example in Python:
https://stackoverflow.com/a/1214765/
Re: Quickly replace image colors?
Posted: Tue Oct 02, 2018 7:41 pm
by RASHAD
- Debugger Disabled
- Iteration = 500
- Changing 2 colors
Dude 1100 ms
Callback 820 ms
kenmo 1350 ms
Re: Quickly replace image colors?
Posted: Wed Oct 03, 2018 2:10 am
by Dude
Thanks for the speed test, Rashad.
Firace, thanks for the info on PNG palette changing, but I'll skip that one (it looks too hard, especially because I'm not changing the colors from a file, but from a PNG already loaded in memory).
