Page 1 of 3

Draw transparent image with windows API?

Posted: Wed Oct 20, 2004 7:39 am
by TheBeck
Hi, I am making a 2d game and I do not want it to require directx. If i draw the images using DrawImage() I can not set any transparency. I have to use DisplayTransparentSprite() witch requires directx. If there was a command DrawTransparentImage() then all would be right with the world. Well for me at least.

I found in MSDN an api that will act like DrawTransparentImage(), I think. Only problem is I don't have the required synaptic pathways connecting the neurons in my head to make use of this. If anyone would be so kind as to let me know if this would work with other 2d drawing commands such as StartDrawing() I would be very grateful. Maybe even an example? The best thing would be to wrap this into a procedure called DrawTransparentImage() and everyone could use this until Fred has time to incorporate it into the language.

Link to MSDN api:
http://msdn.microsoft.com/library/defau ... s_2y9g.asp

Posted: Wed Oct 20, 2004 9:35 am
by TheBeck
Here is some code to draw draw a transparent image without using directx or windows API. The zip file contains required image files so you don't have to make your own. There has got to be a better way to do this, this method is very dirty and can't be the fastest, although I was surprised at how fast it is, PureBasic rocks! This code is of course free ;) If you do use it, it is the same as DrawImage() except for the last argument witch is what color to make transparent. You have to make sure to change all the WindowOutput() inside the DrawTransparentImage() procedure to whatever you are drawing on if it is different, I don't know how to fix this.

http://www.thebeck.com/DrawTransparentImage.zip

Here is the code in case you just want to see it:

Code: Select all

#background = 1
#foreground = 2

Procedure DrawTransparentImage(image_id.l,x.l,y.l,rgb.l)
  UseImage(image_id)
  Debug ImageHeight()
  Debug ImageWidth()
  For row = 0 To ImageHeight() - 1
    For col = 0 To ImageWidth() - 1
      StopDrawing()
      StartDrawing(ImageOutput())
      color = Point(col,row)
      If color <> rgb
        StopDrawing()
        StartDrawing(WindowOutput())
        Plot(col + x,row + y,color)
      EndIf
    Next col
  Next row
  StopDrawing()
  StartDrawing(WindowOutput())
EndProcedure

If OpenWindow(1,0,0,400,400,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"DrawTransparentImage")
Else
  End
EndIf
LoadImage(#background,"background.bmp")
LoadImage(#foreground,"foreground.bmp")
Repeat
  StartDrawing(WindowOutput())
  DrawImage(UseImage(#background),0,0)
  DrawTransparentImage(#foreground,WindowMouseX(),WindowMouseY(),RGB(0,0,0))
  StopDrawing()
Until WaitWindowEvent() = #PB_Event_CloseWindow
End

Posted: Wed Oct 20, 2004 10:09 am
by Fred
Here is an example which should work on any Windows version. I will probably add this code as native command. Just follow the URL to get the tests pictures. If someone knows a faster way to achieve the same goal, just tell us ;)

Code: Select all

;
; Conversion for PB of a Vegard Fiksdal Technologies code
; http://www.codeguru.com/vb/gen/vb_graphics/transparency/article.php/c5329/
;
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



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


Posted: Wed Oct 20, 2004 12:16 pm
by TheBeck
Thanks Fred, that works perfect! 8)

Posted: Sun Sep 25, 2005 1:30 am
by Joakim Christiansen
Nice, just what I needed!
Did you forget to add this Fred? :P

Posted: Sun Sep 25, 2005 5:27 pm
by Intrigued
This is something I was looking for before as well;however, upon Previewing (F5)... an error dialog popups up and then the Preview crashes.

The error doc (XML) is below (I click on View Details and then it had the info. below list in the temp (error) file):

<?xml version="1.0" encoding="UTF-16"?>
<DATABASE>
<EXE NAME="PureBasic392104750.exe" FILTER="GRABMI_FILTER_PRIVACY">
<MATCHING_FILE NAME="Atl.dll" SIZE="73785" CHECKSUM="0xB17C9B2B" BIN_FILE_VERSION="3.0.8449.0" BIN_PRODUCT_VERSION="6.0.0.8449" PRODUCT_VERSION="6.00.8449" FILE_DESCRIPTION="ATL Module for Windows (ANSI)" COMPANY_NAME="Microsoft Corporation" PRODUCT_NAME="Microsoft (R) Visual C++" FILE_VERSION="3.00.8449" ORIGINAL_FILENAME="ATL.DLL" INTERNAL_NAME="ATL" LEGAL_COPYRIGHT="Copyright © Microsoft Corp. 1996-1998" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x4" VERFILETYPE="0x2" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x20000" UPTO_BIN_FILE_VERSION="3.0.8449.0" UPTO_BIN_PRODUCT_VERSION="6.0.0.8449" LINK_DATE="03/25/1999 14:42:10" UPTO_LINK_DATE="03/25/1999 14:42:10" VER_LANGUAGE="English (United States) [0x409]" />
<MATCHING_FILE NAME="Engine3D.dll" SIZE="612352" CHECKSUM="0xAE1A1BD6" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" LINK_DATE="04/03/2004 22:23:26" UPTO_LINK_DATE="04/03/2004 22:23:26" />
<MATCHING_FILE NAME="FAsm.exe" SIZE="65536" CHECKSUM="0x4311C044" MODULE_TYPE="WIN32" PE_CHECKSUM="0x123E5" LINKER_VERSION="0x0" LINK_DATE="02/10/2005 13:04:26" UPTO_LINK_DATE="02/10/2005 13:04:26" />
<MATCHING_FILE NAME="folink.exe" SIZE="18944" CHECKSUM="0xA7CED0" MODULE_TYPE="WIN32" PE_CHECKSUM="0x1043D" LINKER_VERSION="0x0" LINK_DATE="09/24/2004 15:59:49" UPTO_LINK_DATE="09/24/2004 15:59:49" />
<MATCHING_FILE NAME="PBCompiler-jaPBe.exe" SIZE="134176" CHECKSUM="0x96662F7C" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" LINK_DATE="03/01/2005 11:52:16" UPTO_LINK_DATE="03/01/2005 11:52:16" />
<MATCHING_FILE NAME="PBCompiler.exe" SIZE="134176" CHECKSUM="0x96662F7C" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" LINK_DATE="03/01/2005 11:52:16" UPTO_LINK_DATE="03/01/2005 11:52:16" />
<MATCHING_FILE NAME="polib.exe" SIZE="74240" CHECKSUM="0x83E44FD3" BIN_FILE_VERSION="2.80.1.0" BIN_PRODUCT_VERSION="2.80.0.0" PRODUCT_VERSION="2.80" FILE_DESCRIPTION="Pelles Library Manager" COMPANY_NAME="Pelle Orinius" PRODUCT_NAME="Pelles C for Windows" FILE_VERSION="2.80.1" ORIGINAL_FILENAME="POLIB.EXE" INTERNAL_NAME="POLIB" LEGAL_COPYRIGHT="Copyright © Pelle Orinius 1997-2004" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x10004" VERFILETYPE="0x1" MODULE_TYPE="WIN32" PE_CHECKSUM="0x19245" LINKER_VERSION="0x0" UPTO_BIN_FILE_VERSION="2.80.1.0" UPTO_BIN_PRODUCT_VERSION="2.80.0.0" LINK_DATE="06/10/2004 18:18:57" UPTO_LINK_DATE="06/10/2004 18:18:57" />
<MATCHING_FILE NAME="polink.exe" SIZE="142336" CHECKSUM="0x39A2A7B0" BIN_FILE_VERSION="3.0.0.0" BIN_PRODUCT_VERSION="3.0.0.0" PRODUCT_VERSION="3.00" FILE_DESCRIPTION="Pelles Linker" COMPANY_NAME="Pelle Orinius" PRODUCT_NAME="Pelles C for Windows" FILE_VERSION="3.00.0" ORIGINAL_FILENAME="POLINK.EXE" INTERNAL_NAME="POLINK" LEGAL_COPYRIGHT="Copyright © Pelle Orinius 1998-2005" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x10004" VERFILETYPE="0x1" MODULE_TYPE="WIN32" PE_CHECKSUM="0x273DB" LINKER_VERSION="0x0" UPTO_BIN_FILE_VERSION="3.0.0.0" UPTO_BIN_PRODUCT_VERSION="3.0.0.0" LINK_DATE="01/14/2005 20:34:01" UPTO_LINK_DATE="01/14/2005 20:34:01" />
<MATCHING_FILE NAME="porc.dll" SIZE="114688" CHECKSUM="0xC434015B" BIN_FILE_VERSION="2.80.3.0" BIN_PRODUCT_VERSION="2.80.0.0" PRODUCT_VERSION="2.80" FILE_DESCRIPTION="Pelles Resource Compiler DLL" COMPANY_NAME="Pelle Orinius" PRODUCT_NAME="Pelles C for Windows" FILE_VERSION="2.80.3" ORIGINAL_FILENAME="PORC.DLL" INTERNAL_NAME="PORC" LEGAL_COPYRIGHT="Copyright © Pelle Orinius 2001-2004" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x10004" VERFILETYPE="0x1" MODULE_TYPE="WIN32" PE_CHECKSUM="0x1C899" LINKER_VERSION="0x0" UPTO_BIN_FILE_VERSION="2.80.3.0" UPTO_BIN_PRODUCT_VERSION="2.80.0.0" LINK_DATE="06/11/2004 18:49:05" UPTO_LINK_DATE="06/11/2004 18:49:05" />
<MATCHING_FILE NAME="porc.exe" SIZE="32256" CHECKSUM="0x64CA77FD" BIN_FILE_VERSION="2.80.3.0" BIN_PRODUCT_VERSION="2.80.0.0" PRODUCT_VERSION="2.80" FILE_DESCRIPTION="Pelles Resource Compiler Driver" COMPANY_NAME="Pelle Orinius" PRODUCT_NAME="Pelles C for Windows" FILE_VERSION="2.80.3" ORIGINAL_FILENAME="PORC.DLL" INTERNAL_NAME="PORC" LEGAL_COPYRIGHT="Copyright © Pelle Orinius 1997-2004" VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x10004" VERFILETYPE="0x1" MODULE_TYPE="WIN32" PE_CHECKSUM="0x14E9E" LINKER_VERSION="0x0" UPTO_BIN_FILE_VERSION="2.80.3.0" UPTO_BIN_PRODUCT_VERSION="2.80.0.0" LINK_DATE="06/11/2004 18:32:39" UPTO_LINK_DATE="06/11/2004 18:32:39" />
<MATCHING_FILE NAME="PureBasic392104750.exe" SIZE="15872" CHECKSUM="0xC1D25DD9" MODULE_TYPE="WIN32" PE_CHECKSUM="0x0" LINKER_VERSION="0x0" LINK_DATE="09/25/2005 16:21:18" UPTO_LINK_DATE="09/25/2005 16:21:18" />
</EXE>
<EXE NAME="kernel32.dll" FILTER="GRABMI_FILTER_THISFILEONLY">
<MATCHING_FILE NAME="kernel32.dll" SIZE="983552" CHECKSUM="0x4CE79457" BIN_FILE_VERSION="5.1.2600.2180" BIN_PRODUCT_VERSION="5.1.2600.2180" PRODUCT_VERSION="5.1.2600.2180" FILE_DESCRIPTION="Windows NT BASE API Client DLL" COMPANY_NAME="Microsoft Corporation" PRODUCT_NAME="Microsoft® Windows® Operating System" FILE_VERSION="5.1.2600.2180 (xpsp_sp2_rtm.040803-2158)" ORIGINAL_FILENAME="kernel32" INTERNAL_NAME="kernel32" LEGAL_COPYRIGHT="© Microsoft Corporation. All rights reserved." VERFILEDATEHI="0x0" VERFILEDATELO="0x0" VERFILEOS="0x40004" VERFILETYPE="0x2" MODULE_TYPE="WIN32" PE_CHECKSUM="0xFF848" LINKER_VERSION="0x50001" UPTO_BIN_FILE_VERSION="5.1.2600.2180" UPTO_BIN_PRODUCT_VERSION="5.1.2600.2180" LINK_DATE="08/04/2004 07:56:36" UPTO_LINK_DATE="08/04/2004 07:56:36" VER_LANGUAGE="English (United States) [0x409]" />
</EXE>
</DATABASE>

Posted: Sun Sep 25, 2005 6:24 pm
by netmaestro
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?

Posted: Sun Sep 25, 2005 6:57 pm
by einander
Another way
Updated

Code: Select all

Procedure TransparentRGB(IMG,x,y,RGB) 
    HLC=ImageList_Create_(ImageWidth(),ImageHeight(),#ILC_COLOR32|#ILC_MASK,1,0) 
    ImageList_AddMasked_(HLC,IMG,RGB) 
    DC=BeginPaint_(WindowID(),@PaintStruct.PAINTSTRUCT)
    ImageList_Draw_(HLC,0,DC,x,y,#ILD_TRANSPARENT) 
    ImageList_Destroy_(HLC) 
    EndPaint_(WindowID(),@PaintStruct)
    ImageList_Destroy_(HLC)
EndProcedure 

hWnd = OpenWindow(0, 0, 0,0,0 , #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE,"Transparent Color") 
IMG=LoadImage(0,  "c:\test2.bmp")  ;************************* 
If IMG 
TransparentRGB(IMG,100,100,#White)  ; here the color to be converted in transparent 
    Repeat 
    Until WaitWindowEvent()=#PB_EventCloseWindow 
EndIf 
End

Posted: Sun Sep 25, 2005 7:04 pm
by josku_x
hey, I tried that code, but it doesn't work :( I get just white image.

Posted: Sun Sep 25, 2005 7:05 pm
by einander
Also there is TransparentBlt_() API, but PB don't recognize it.

Posted: Sun Sep 25, 2005 7:06 pm
by josku_x
your code messes my image, but duh, atleast Fred's code work :)

Posted: Mon Sep 26, 2005 3:20 pm
by einander
This one works with WinXP. Not tested with ME - 9x

Code: Select all

#IMG=1
 Procedure CreateTranspBMP(IMG,RGB) 
    IMG=UseImage(IMG)
    ImgList=ImageList_Create_(ImageWidth(),ImageHeight(),#ILC_COLOR16|#ILC_MASK,1,0) 
    ImageList_AddMasked_(ImgList,IMG,RGB) 
    ProcedureReturn ImgList
EndProcedure 


OpenWindow(0,0,0,0,0 , #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE,"Transparent BMP") 
hDC=GetDC_(WindowID()) 
LoadImage(#IMG,"c:\test1.bmp") ;*************** your image here*************
; ResizeImage(#IMG,80,80)  ; uncomment to resize
Halfw=ImageWidth()/2:Halfh=ImageHeight()/2 ; to center mouse on BMP

TransparentRGB=#White   ; select RGB for transparency ********************
ImgList=CreateTranspBMP(#IMG,TransparentRGB)
MASK=#ILD_TRANSPARENT ; see API ImageList_Draw Function to change Masks
        
Repeat 
    EV=WaitWindowEvent()
    If GetAsyncKeyState_(#VK_LBUTTON)
        If EV=#WM_MOUSEMOVE
            ImageList_Draw_(ImgList,0,hDC,WindowMouseX()-Halfw,WindowMouseY()-Halfh,MASK) 
        EndIf
    EndIf 
Until EV= #PB_Event_CloseWindow 
    
ImageList_Destroy_(ImgList) 
End

Posted: Mon Sep 26, 2005 5:17 pm
by Brice Manuel
WooHoo!!!! Fred's example is just what I needed for something I am working on. Thanks to whoever bumped this :wink:

Posted: Mon Sep 26, 2005 5:27 pm
by Henrik
@einander
If White should be the transparent color, then both works on 98
just that, in the first example you use "test2.bmp" (Freds link) and it do not contain any
white color, test1.bmp does use that and the clouds is transparent.
On 98 that is..

Posted: Mon Sep 26, 2005 6:08 pm
by einander
@Henrik:Thanx for your reply.

On my examples you can choose any BMP, and must choose the RGB color that you want to be transparent.

The file c:\test1:bmp is on my HD, and is supposed to be replaced with your own Bmp. (No related with the file test.bmp on Fred's great example.)

I think my 2nd example is less buggy. Both works better with small or medium sized BMPs, 100*200 or less.