Draw transparent image with windows API?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

This don't stop after a while like Fred's did:
I got it from here.

Code: Select all

Procedure DrawTransparentImage(DC, ImageID, x, y, TransparentColor) 
  Protected ImageList, BM.BITMAP 
  
  GetObject_(ImageID, SizeOf(BITMAP), BM.BITMAP) 
  ImageID = CopyImage_(ImageID, #IMAGE_BITMAP, BM\bmWidth, BM\bmHeight, 0) 
  ImageList = ImageList_Create_(BM\bmWidth, BM\bmHeight, #ILC_COLORDDB|#ILC_MASK, 1, 0) 
  ImageList_AddMasked_(ImageList, ImageID, TransparentColor) 
  ImageList_Draw_(ImageList, 0, DC, x, y, #ILD_TRANSPARENT) 
  ImageList_Destroy_(ImageList) 
  DeleteObject_(ImageID) 
EndProcedure 

Enumeration ;Images 
  #Image1 
  #Image2 
EndEnumeration 

CreateImage(#Image1,32,32) 
CreateImage(#Image2,32,32) 

UseImage(#Image1) 
StartDrawing(ImageOutput()) 
  Box(0,0,32,32,RGB(255,0,0)) 
  Box(5,5,22,22,RGB(0,0,0)) 
  StopDrawing() 

UseImage(#Image2) 
StartDrawing(ImageOutput()) 
  Box(0,0,32,32,RGB(0,0,255)) 
  Box(5,5,22,22,RGB(0,0,0)) 
  StopDrawing() 

OpenWindow(0,0,0,200,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"DrawTransparentImage()") 

Repeat 
  Event = WindowEvent() 
  
  X = Random(168) 
  Y = Random(168) 
  Image = Random(#Image2) 
  
  DC = StartDrawing(WindowOutput()) 
    DrawTransparentimage(DC,UseImage(Image),X,Y,RGB(0,0,0)) 
  StopDrawing() 
Until Event = #PB_Event_CloseWindow
Last edited by Joakim Christiansen on Tue Sep 27, 2005 4:15 pm, edited 3 times in total.
I like logic, hence I dislike humans but love computers.
Intrigued
Enthusiast
Enthusiast
Posts: 501
Joined: Thu Jun 02, 2005 3:55 am
Location: U.S.A.

Post by Intrigued »

netmaestro wrote:Beautiful! Thanks Fred! I think programmers would switch to PB in droves if they knew we were being spoiled like this.

@intrigued: Works perfectly here. Did you download the images and make sure they were available to your program when you ran it?
Thanks netmaestro. That was the deal. I flew right over such in the commented out area of the code chunk.
Intrigued - Registered PureBasic, lifetime updates user
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

This don't crash after a while like Fred's did:
OK, that's great. But after a couple hours turning it over in my mind I can't see why Fred's code should have a problem. It is all API calls and he is releasing everything he's creating. So... ??? :?
BERESHEIT
Brice Manuel

Post by Brice Manuel »

OK, that's great. But after a couple hours turning it over in my mind I can't see why Fred's code should have a problem. It is all API calls and he is releasing everything he's creating. So... ???
Fred's worked fine on my nine test systems here when I was testing it yesterday.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

netmaestro wrote:
This don't crash after a while like Fred's did:
OK, that's great. But after a couple hours turning it over in my mind I can't see why Fred's code should have a problem. It is all API calls and he is releasing everything he's creating. So... ??? :?
I don't know why it crash either, it's very weird.
This is the code that make it crash on my computer, does it crash on yours?:
Edit:
When I said crash I actually meant that is stoped working, it dind't crash the program or something like that... Sorry about that.

Code: Select all

Procedure DrawTransparentImage(DC, Bitmap, x, y, Width, Height, TransparentColor) 

    ; First, create some DC's. These are our gateways To associated 
    ; bitmaps in RAM 
    maskDC = CreateCompatibleDC_(DC) 
    tempDC = CreateCompatibleDC_(DC) 
    
    SourceDC = CreateCompatibleDC_(DC) 
    SelectObject_(SourceDC, Bitmap) 
    

    ; Then, we need the bitmaps. Note that we create a monochrome 
    ; bitmap here! 
    ; This is a trick we use For creating a mask fast enough. 
    hMaskBmp = CreateBitmap_(Width, Height, 1, 1, 0) 
    hTempBmp = CreateCompatibleBitmap_(DC, Width, Height) 

    ; Then we can assign the bitmaps to the DCs 
    ; 
    hMaskBmp = SelectObject_(maskDC, hMaskBmp) 
    hTempBmp = SelectObject_(tempDC, hTempBmp) 

    ; Now we can create a mask. First, we set the background color 
    ; To the transparent color; then we copy the image into the 
    ; monochrome bitmap. 
    ; When we are done, we reset the background color of the 
    ; original source. 
    TransparentColor= SetBkColor_(SourceDC, TransparentColor) 
    BitBlt_ (maskDC, 0, 0, Width, Height, SourceDC, 0, 0, #SRCCOPY) 
    SetBkColor_(SourceDC, TransparentColor) 

    ; The first we do with the mask is To MergePaint it into the 
    ; destination. 
    ; This will punch a WHITE hole in the background exactly were 
    ; we want the graphics To be painted in. 
    BitBlt_ (tempDC, 0, 0, Width, Height, maskDC, 0, 0, #SRCCOPY) 
    BitBlt_ (DC, X, Y, Width, Height, tempDC, 0, 0, #MERGEPAINT) 

    ; Now we delete the transparent part of our source image. To do 
    ; this, we must invert the mask And MergePaint it into the 
    ; source image. The transparent area will now appear as WHITE. 
    BitBlt_ (maskDC, 0, 0, Width, Height, maskDC, 0, 0, #NOTSRCCOPY) 
    BitBlt_ (tempDC, 0, 0, Width, Height, SourceDC, 0, 0, #SRCCOPY) 
    BitBlt_ (tempDC, 0, 0, Width, Height, maskDC, 0, 0, #MERGEPAINT) 

    ; Both target And source are clean. All we have To do is To And 
    ; them together! 
    BitBlt_ (DC, X, Y, Width, Height, tempDC, 0, 0, #SRCAND) 

    ; Now all we have To do is To clean up after us And free system 
    ; resources.. 
    DeleteObject_ (hMaskBmp) 
    DeleteObject_ (hTempBmp) 
    DeleteDC_ (maskDC) 
    DeleteDC_ (tempDC) 
    DeleteDC_ (SourceDC) 

EndProcedure

Enumeration ;Images 
  #Image1 
  #Image2 
EndEnumeration 

CreateImage(#Image1,32,32) 
CreateImage(#Image2,32,32) 

UseImage(#Image1) 
StartDrawing(ImageOutput()) 
  Box(0,0,32,32,RGB(255,0,0)) 
  Box(5,5,22,22,RGB(0,0,0)) 
  StopDrawing() 

UseImage(#Image2) 
StartDrawing(ImageOutput()) 
  Box(0,0,32,32,RGB(0,0,255)) 
  Box(5,5,22,22,RGB(0,0,0)) 
  StopDrawing() 

OpenWindow(0,0,0,200,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"DrawTransparentImage() BUG") 

Repeat 
  Event = WindowEvent() 
  
  X = Random(168) 
  Y = Random(168) 
  Image = Random(#Image2) 
  
  DC = StartDrawing(WindowOutput()) 
    DrawTransparentimage(DC,UseImage(Image),X,Y,32,32,RGB(0,0,0)) 
  StopDrawing() 
Until Event = #PB_Event_CloseWindow
Last edited by Joakim Christiansen on Tue Sep 27, 2005 4:32 pm, edited 2 times in total.
I like logic, hence I dislike humans but love computers.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

That doesn't appear to be Fred's code.

Fred's runs fine on my computer.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

It's Fred's code all right. I put it in my personal library when he posted it and in testing I substituted the command from my lib to see if that would make a difference and no dice. It doesn't run on my computer. It doesn't exactly crash either. What it does is stop refreshing the drawing surface after 5000 draws. It keeps running and incrementing the counter I added to it, just no refreshing of the window.
BERESHEIT
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Thanks for removing the "retarded" comment because to me -

OpenWindow(0, 100, 100, 200, 200, #PB_Window_SystemMenu, "FastTransparency")

LoadImage(0, "Test1.bmp") ; Background
LoadImage(1, "Test2.bmp") ; Image to be drawn as transparent

UseImage(0)
DC = StartDrawing(ImageOutput())
If DC
DrawTransparentimage(DC, UseImage(1), 0, 0, 97, 97, RGB(255, 0, 255))
StopDrawing()
EndIf


CreateGadgetList(WindowID())
ImageGadget(0, 10, 10, 100, 100, UseImage(0))

Repeat
Event = WaitWindowEvent()

Until Event = #PB_Event_CloseWindow


Is NOT the same as -

Enumeration ;Images
#Image1
#Image2
EndEnumeration

CreateImage(#Image1,32,32)
CreateImage(#Image2,32,32)

UseImage(#Image1)
StartDrawing(ImageOutput())
Box(0,0,32,32,RGB(255,0,0))
Box(5,5,22,22,RGB(0,0,0))
StopDrawing()

UseImage(#Image2)
StartDrawing(ImageOutput())
Box(0,0,32,32,RGB(0,0,255))
Box(5,5,22,22,RGB(0,0,0))
StopDrawing()

OpenWindow(0,0,0,200,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"DrawTransparentImage() BUG")

Repeat
Event = WindowEvent()

X = Random(168)
Y = Random(168)
Image = Random(#Image2)

DC = StartDrawing(WindowOutput())
DrawTransparentimage(DC,UseImage(Image),X,Y,32,32,RGB(0,0,0))
StopDrawing()
Until Event = #PB_Event_CloseWindow

and what I said was they didn't appear to be the same.

Fred's does run fine for me.

cheers,
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

Fred's example, except that the user doesn't need to know DC stuff...

Code: Select all

Procedure DrawTransparentImage(Bitmap.l, x.l, y.l, Width.l, Height.l, TransparentColor.l)
  Protected hDC.l, maskDC.l, tempDC.l, sourceDC.l, hMaskBmp.l, hTempBmp.l
  
  !extrn _PB_2DDrawing_CurrentDC
  !MOV eax, dword [_PB_2DDrawing_CurrentDC]
  !MOV [esp+24], eax
  
  If hDC
    maskDC = CreateCompatibleDC_(hDC)
    tempDC = CreateCompatibleDC_(hDC)
   
    sourceDC = CreateCompatibleDC_(hDC)
    SelectObject_(sourceDC, Bitmap)
    
    hMaskBmp = CreateBitmap_(Width, Height, 1, 1, #Null)
    hTempBmp = CreateCompatibleBitmap_(hDC, Width, Height)
    
    hMaskBmp = SelectObject_(maskDC, hMaskBmp)
    hTempBmp = SelectObject_(tempDC, hTempBmp)
    
    TransparentColor = SetBkColor_(sourceDC, TransparentColor)
    BitBlt_(maskDC, 0, 0, Width, Height, sourceDC, 0, 0, #SRCCOPY)
    SetBkColor_(sourceDC, TransparentColor)
    
    BitBlt_(tempDC, 0, 0, Width, Height, maskDC, 0, 0, #SRCCOPY)
    BitBlt_(hDC, X, Y, Width, Height, tempDC, 0, 0, #MERGEPAINT)
    
    BitBlt_(maskDC, 0, 0, Width, Height, maskDC, 0, 0, #NOTSRCCOPY)
    BitBlt_(tempDC, 0, 0, Width, Height, SourceDC, 0, 0, #SRCCOPY)
    BitBlt_(tempDC, 0, 0, Width, Height, maskDC, 0, 0, #MERGEPAINT)
    
    BitBlt_(hDC, X, Y, Width, Height, tempDC, 0, 0, #SRCAND)
    
    DeleteObject_ (hMaskBmp)
    DeleteObject_ (hTempBmp)
    DeleteDC_ (maskDC)
    DeleteDC_ (tempDC)
    DeleteDC_ (SourceDC)
    
    ProcedureReturn #True
  EndIf
EndProcedure

OpenWindow(0, 100, 100, 280, 280, #PB_Window_SystemMenu, "FastTransparency")

LoadImage(0, "Test1.bmp") ; Background
LoadImage(1, "Test2.bmp") ; Image to be drawn as transparent

UseImage(0)

If StartDrawing(ImageOutput())
  DrawTransparentimage(UseImage(1), 0, 0, 128, 128, $FF00FF)
  StopDrawing()
EndIf


CreateGadgetList(WindowID())
ImageGadget(0, 10, 10, 100, 100, UseImage(0))

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Dri
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Dr Dri, Fred's code stops drawing to the window after 5000 draws as shown by Joakim Christiansen's example above. Running his example and substituting Fred's procedure for your procedure of the same name, I find yours does the same thing. 5000 draws and then it stops drawing. Nobody so far has been able to figure out why this is happening. Can you?
BERESHEIT
Dr. Dri
Enthusiast
Enthusiast
Posts: 243
Joined: Sat Aug 23, 2003 6:45 pm

Post by Dr. Dri »

i don't know :shock:
i just wanted to have a DrawTransparentImage Similar to DrawImage
and of course i share my code. nothing more, nothing less :?

Dri
User avatar
Mischa
Enthusiast
Enthusiast
Posts: 115
Joined: Fri Aug 15, 2003 7:43 pm

Post by Mischa »

This one works fine:

Code: Select all

Procedure DrawTransparentImage(DC, Bitmap, x, y, Width, Height, TransparentColor)

    ; First, create some DC's. These are our gateways To associated
    ; bitmaps in RAM
    maskDC = CreateCompatibleDC_(DC)
    tempDC = CreateCompatibleDC_(DC)
   
    SourceDC = CreateCompatibleDC_(DC)
    SelectObject_(SourceDC, Bitmap)
   

    ; Then, we need the bitmaps. Note that we create a monochrome
    ; bitmap here!
    ; This is a trick we use For creating a mask fast enough.
    hMaskBmp = CreateBitmap_(Width, Height, 1, 1, 0)
    hTempBmp = CreateCompatibleBitmap_(DC, Width, Height)

    ; Then we can assign the bitmaps to the DCs
    ;
    hMaskBmp2 = SelectObject_(maskDC, hMaskBmp)
    hTempBmp2 = SelectObject_(tempDC, hTempBmp)

    ; Now we can create a mask. First, we set the background color
    ; To the transparent color; then we copy the image into the
    ; monochrome bitmap.
    ; When we are done, we reset the background color of the
    ; original source.
    TransparentColor= SetBkColor_(SourceDC, TransparentColor)
    BitBlt_ (maskDC, 0, 0, Width, Height, SourceDC, 0, 0, #SRCCOPY)
    SetBkColor_(SourceDC, TransparentColor)

    ; The first we do with the mask is To MergePaint it into the
    ; destination.
    ; This will punch a WHITE hole in the background exactly were
    ; we want the graphics To be painted in.
    BitBlt_ (tempDC, 0, 0, Width, Height, maskDC, 0, 0, #SRCCOPY)
    BitBlt_ (DC, X, Y, Width, Height, tempDC, 0, 0, #MERGEPAINT)

    ; Now we delete the transparent part of our source image. To do
    ; this, we must invert the mask And MergePaint it into the
    ; source image. The transparent area will now appear as WHITE.
    BitBlt_ (maskDC, 0, 0, Width, Height, maskDC, 0, 0, #NOTSRCCOPY)
    BitBlt_ (tempDC, 0, 0, Width, Height, SourceDC, 0, 0, #SRCCOPY)
    BitBlt_ (tempDC, 0, 0, Width, Height, maskDC, 0, 0, #MERGEPAINT)

    ; Both target And source are clean. All we have To do is To And
    ; them together!
    BitBlt_ (DC, X, Y, Width, Height, tempDC, 0, 0, #SRCAND)

    ; Now all we have To do is To clean up after us And free system
    ; resources..
    DeleteObject_ (hMaskBmp)
    DeleteObject_ (hTempBmp)
    DeleteObject_ (hMaskBmp2)
    DeleteObject_ (hTempBmp2)
    DeleteDC_ (maskDC)
    DeleteDC_ (tempDC)
    DeleteDC_ (SourceDC)

EndProcedure

Enumeration ;Images
  #Image1
  #Image2
EndEnumeration

CreateImage(#Image1,32,32)
CreateImage(#Image2,32,32)

UseImage(#Image1)
StartDrawing(ImageOutput())
  Box(0,0,32,32,RGB(255,0,0))
  Box(5,5,22,22,RGB(0,0,0))
  StopDrawing()

UseImage(#Image2)
StartDrawing(ImageOutput())
  Box(0,0,32,32,RGB(0,0,255))
  Box(5,5,22,22,RGB(0,0,0))
  StopDrawing()

OpenWindow(0,0,0,200,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"DrawTransparentImage() NO BUG")

Repeat
  Event = WindowEvent()
 
  X = Random(168)
  Y = Random(168)
  Image = Random(#Image2)
 
  DC = StartDrawing(WindowOutput())
    DrawTransparentimage(DC,UseImage(Image),X,Y,32,32,RGB(0,0,0))
    ReleaseDC_(WindowID(0),DC)
  StopDrawing()
Until Event = #PB_Event_CloseWindow
Can you see the difference?

:wink:

You should take a look at PureArea.net, where you can find
sources like this...sometimes this could be helpful.

..and don't forget, the blitting way is much faster (10 times!?) than
ImageList_AddMasked, DIBs, or such things.

Regards,
Mischa
Last edited by Mischa on Wed Oct 05, 2005 9:22 pm, edited 1 time in total.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Good job Mischa. That was confusing a lot of people for quite some time. I see the difference, but I don't see the need to create the 2's and then destroy them after never using them. I replaced the 2='s with just SelectObject_() and took out the DeleteObject_() lines for them and it still works fine, while not creating confusion with names that never get used. Thanks for clearing this up for us. I can stick this proc in my personal lib now and use it.
BERESHEIT
User avatar
Mischa
Enthusiast
Enthusiast
Posts: 115
Joined: Fri Aug 15, 2003 7:43 pm

Post by Mischa »

You are right, makes no sense here.

Cause there are no "old" bitmaps in these DCs.

Code: Select all

oldobject = SelectObject_(anyDC,newobject)
Regards,
Mischa
josku_x
Addict
Addict
Posts: 997
Joined: Sat Sep 24, 2005 2:08 pm

Post by josku_x »

this is very great code, but is it possible to use this in commands like ButtonImageGadget()?? thanks for any help will be very appreciated.
Post Reply