Page 1 of 1
General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 9:00 am
by netmaestro
Code: Select all
; Demo: General purpose transparent drawing in 24 bits
; Authors: Lloyd Gallant (netmaestro): original idea
wilbert: improvements for speed and efficiency
DeclareModule filters
Declare SetTransparentColor(color.l)
Declare TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EndDeclareModule
Module filters
Global transcolor.l
Procedure SetTransparentColor(color.l)
transcolor.l = color | $FF<<24
EndProcedure
Procedure TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EnableASM
mov eax, sourcecolor
cmp eax, transcolor
!jne .cont
mov eax, targetcolor
!.cont:
ProcedureReturn
DisableASM
EndProcedure
EndModule
UseModule filters
CreateImage(0, 256,256,24,RGB(255,0,255)) ;Pink is the transparent color
StartDrawing(ImageOutput(0))
Box(96,96,64,64,#Blue)
StopDrawing()
OpenWindow(0,0,0,640,480,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
SetWindowColor(0, #White)
CanvasGadget(0, 180,80,256,256)
StartDrawing(CanvasOutput(0))
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@TransparentFilter())
SetTransparentColor(RGB(255,0,255))
DrawImage(ImageID(0), 0, 0)
StopDrawing()
Repeat : EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
Note that the posted code has been improved by contributors on the forum so some replies may not make quite as much sense as they originally did. But I judge it less confusing to post the latest and best code in the first post. Credit is gratefully given where it is due.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 10:21 am
by wilbert
Is there any advantage to using a Static variable compared to a Global for transcolor ?
Using a Global would probably make the callback procedure faster since you could remove the code to set transcolor from the procedure.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:02 am
by netmaestro
I wrote it this way because I wanted to avoid using a global for the color. As SetTransparentColor() is called only once for each whole image, there should be no speed gain to be had by using a global as you still have to set the global once and then draw rather than set the static once and then draw. I'm just not a fan of global variables and I like to find ways to accomplish goals without using them. Let me say, not "no speed gain" as the static version does involve a test at each pixel drawn. A test is cheap, but is it cheap enough to warrant the avoidance of a global? To me, yes. To the average user, not sure. I haven't done exhaustive tests. Ideally I'd like the team to add an optional lParam parameter to the callback but they probably won't do that so this is my way of doing the next best thing. But I defer to your judgment when it comes to speed. If you say the global is faster I'll take your word.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:11 am
by netmaestro
Btw wilbert does this code produce the desired results in OSX? I ask because when we were working on our Gif decoders in 2013 I originally used this approach but was told by Mac users that a bug in PureBasic caused it to not work properly. So I reluctantly switched over to 32bits and depended on the alpha layer for transparency. Just wondering if that bug is a concern anymore or did they fix it in the meantime.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:20 am
by wilbert
With the 5.60 beta (required to support constants like #Blue), your code seems to work fine on OSX.
On OSX however, the internal format is always 32 bit even if you specify 24.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:23 am
by netmaestro
On OSX however, the internal format is always 32 bit even if you specify 24.
Next time you're talking to Tim Cook, you have my permission to punch him in the face. Be sure to mention my name first so he understands it'll be OK. The Donald will back me up. (if he took his meds)
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:28 am
by walbus
@Netmaestro
I love this simple and efficient methods
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:34 am
by netmaestro
Walbus, hang on for a second or two. Demivec suggested to me this code, which might be faster:
Code: Select all
DeclareModule filters
Declare SetTransparentColor(color)
Declare TransparentFilter(x, y, sourcecolor, targetcolor)
EndDeclareModule
Module filters
Global transcolor
Procedure SetTransparentColor(color)
transcolor = color | $FF<<24
EndProcedure
Procedure TransparentFilter(x, y, sourcecolor, targetcolor)
If sourcecolor = transcolor
ProcedureReturn targetcolor
Else
ProcedureReturn sourcecolor
EndIf
EndProcedure
EndModule
CreateImage(0, 256,256,24,RGB(255,0,255)) ;Pink is the transparent color
StartDrawing(ImageOutput(0))
Box(96,96,64,64,#Blue)
StopDrawing()
OpenWindow(0,0,0,640,480,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
SetWindowColor(0, #White)
CanvasGadget(0, 180,80,256,256)
StartDrawing(CanvasOutput(0))
DrawingMode(#PB_2DDrawing_CustomFilter)
filters::SetTransparentColor(RGB(255,0,255))
CustomFilterCallback(filters::@TransparentFilter())
DrawImage(ImageID(0), 0, 0)
StopDrawing()
Repeat : EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
By encapsulating the code in a module the global var is much less despicable as its scope ends with the module. It's probably better than what I posted as my posted code requires a test at each drawn pixel.
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 11:43 am
by walbus
Yep, i make the same with the globals, in a module and good is
I would firstly use FilterCallback in my BF, but, all over it was not needed
Also it is a next stepp for trying FilterCallback for testing a available speed up
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 12:00 pm
by wilbert
netmaestro wrote:Walbus, hang on for a second or two. Demivec suggested to me this code, which might be faster:
Asm variation (probably slightly faster)
Code: Select all
DeclareModule filters
Declare SetTransparentColor(color.l)
Declare TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EndDeclareModule
Module filters
Global transcolor.l
Procedure SetTransparentColor(color.l)
transcolor.l = color | $FF<<24
EndProcedure
Procedure TransparentFilter(x, y, sourcecolor.l, targetcolor.l)
EnableASM
mov eax, sourcecolor
cmp eax, transcolor
!jne .cont
mov eax, targetcolor
!.cont:
ProcedureReturn
DisableASM
EndProcedure
EndModule
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 12:20 pm
by walbus
@Wilbert
Many thanks for this
Yep, i would ask you for this and also a little asm optimized variant for that
Code: Select all
Macro color_distance
If c1<>c2
Protected r1=Red(c1), g1=Green(c1), b1=Blue(c1)
Protected r2=Red(c2), g2=Green(c2), b2=Blue(c2)
Protected diff_red=Abs(r1-r2), diff_green=Abs(g1-g2), diff_blue=Abs(b1-b2)
Protected r.f=diff_red/255, g.f=diff_green/255, b.f=diff_blue/255
ProcedureReturn (r+g+b)/3*100
Else
ProcedureReturn 0
EndIf
EndMacro
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 12:57 pm
by wilbert
@Walbus,
It's a different question but if SSE2 is no problem, try something like this
Code: Select all
Procedure color_distance(c1, c2); SSE2
!movd xmm0, [p.v_c1]
!movd xmm1, [p.v_c2]
!pslld xmm0, 8
!pslld xmm1, 8
!psadbw xmm0, xmm1
!movd eax, xmm0 ; eax range [0, 765]
!imul eax, 0x2176cc ; div by 7.65
!add eax, 0x800000
!shr eax, 24
ProcedureReturn
EndProcedure
Re: General purpose transparency in 24 bits - all OS
Posted: Mon Feb 13, 2017 1:49 pm
by walbus
@Wilbert
Many thanks wilbert, your kindly help is inexpensive
