Drawing+a+Transparent+Bitmap

//Introduction by Richard Russell//

The commands built into //BBC BASIC for Windows// for displaying a bitmap image (*DISPLAY and *MDISPLAY) can only display an **opaque** image, i.e. anything 'underneath' the image will be obliterated. You may sometimes want to display a **transparent** image, that is one which has some regions in which you can see 'through' it to what lies beneath; you can do that using Windows GDI (Graphics Device Interface) **API functions** or BB4W **library functions**.

There are a number of different ways in which you can create and display a 'transparent' image:


 * Create the image as an **icon** (e.g. in the form of a .ICO file). An icon consists of two parts: a bitmap image and a **mask**; the mask is a one-bit-per-pixel bitmap determining which pixels of the image are //opaque// and which are //transparent//.  You can create an icon in memory (e.g. **CreateIcon** API) or load it from a file (e.g. **LoadIcon** or **LoadImage**) and then display it using (e.g.) the Windows **DrawIcon** API or the SPRITELIB library.
 * Use a separate mask. As with the icon method, the mask consists of a one-bit-per-pixel monochrome bitmap (having the same dimensions as the image), determining which pixels of the image are //opaque// and which are //transparent//.  You can display the resulting transparent bitmap using the **MaskBlt** API.
 * Define one of the colours in the bitmap image as 'transparent'; for example you could define all the 'black' pixels as being transparent. You can achieve that using the **TransparentBlt** function described in the main article below, or by means of the GFXLIB library.
 * Create the image as a 32-bits-per-pixel ARGB bitmap, in which each pixel consists of a 24-bit **RGB** value (8 bits red, 8 bits green, 8 bits blue) plus an 8-bit **alpha** value. The alpha value defines a 'per-pixel' opacity which can be anything from 0 (fully transparent) to 255 (fully opaque).  You can display such a bitmap using the **AlphaBlend** API, by using the **GDIplus** or **Direct3D** subsystems, or by means of the GFXLIB library.
 * Create the image as a **Transparent GIF** or **PNG** and display it using, for example, the code listed here.

//by Michael Hutton, July 2009//

How do you make a part of a bitmap transparent? One way is to use the "TransparentBlt" function supplied in MSIMG32.DLL.

A complete example is here.

And an example bitmap you can use is here.

Explanation:
First select a MODE and define some constants: code format="bb4w" MODE 8

REM!WC IMAGE_BITMAP = 0 LR_LOADFROMFILE = &10

DIM rect{l%,t%,r%,b%}

cx% = 64 : REM width cy% = 64 : REM height code Next, we have to load the MSIMG32.DLL into memory and get the address of the "TransparentBlt" function. code format="bb4w" SYS "LoadLibrary", "MSIMG32.DLL" TO msimg32% SYS "GetProcAddress", msimg32%, "TransparentBlt" TO `TransparentBlt` code Next, load the image we want (we will assume it's in the same directory and is called star.bmp). code format="bb4w" bmpfile$ = @dir$ + "star.bmp" SYS "LoadImage", 0, bmpfile$, IMAGE_BITMAP, cx%, cy%, LR_LOADFROMFILE TO hbitmap% IF hbitmap% = 0 THEN ERROR 100,"Cannot Load Image." code Now, because we are using GDI and we only have a handle to the bitmap we have to create a new Device Context and select our bitmap into it. (A bitmap can only be selected into one DC at a time). code format="bb4w" SYS "CreateCompatibleDC", @memhdc% TO hdc% SYS "SelectObject", hdc%, hbitmap% TO old% code

Now, we can ask GDI to transfer that bitmap into our main window. When using "TransparentBlt" we can select an RGB (COLOURREF) value to make transparent when it is drawing. It is the last parameter in "TranparentBlt". Here I have selected 0 which is all the black bits (Red = 0, Green = 0, Blue = 0) but you can make it any colour you want. We also update a RECT{} so that we only update the region of the screen which has changed. It is much quicker to do this than update the whole window. code format="bb4w" FOR I% = 0 TO 50 xpos% = RND(640) ypos% = RND(500) rect.l% = xpos% rect.r% = xpos% + cx% rect.t% = ypos% rect.b% = ypos% + cy% SYS `TransparentBlt`, @memhdc%, xpos%, ypos%, cx%, cy%, hdc%, 0, 0, cx%, cy%, 0 SYS "InvalidateRect", @hwnd%, rect{}, 0 WAIT 1 NEXT code

Now we must remember to cleanup all the GDI objects we have created otherwise we will end up with a leak. code format="bb4w" SYS "SelectObject", hdc%, old% SYS "DeleteDC", hdc% SYS "DeleteObject", hbitmap% SYS "FreeLibrary", msimg32% END code

The example to copy and paste: code format="bb4w" MODE 8

REM!WC IMAGE_BITMAP = 0 LR_LOADFROMFILE = &10

DIM rect{l%,t%,r%,b%}

SYS "LoadLibrary", "MSIMG32.DLL" TO msimg32% SYS "GetProcAddress", msimg32%, "TransparentBlt" TO `TransparentBlt`

cx% = 64 cy% = 64

bmpfile$ = @dir$ + "star.bmp"

SYS "LoadImage", 0, bmpfile$, IMAGE_BITMAP, cx%, cy%, LR_LOADFROMFILE TO hbitmap% IF hbitmap% = 0 THEN ERROR 100,"Cannot Load Image."

SYS "CreateCompatibleDC", @memhdc% TO hdc% SYS "SelectObject", hdc%, hbitmap% TO old%

FOR I% = 0 TO 50 xpos% = RND(640) ypos% = RND(500) rect.l% = xpos% rect.r% = xpos% + cx% rect.t% = ypos% rect.b% = ypos% + cy% SYS `TransparentBlt`, @memhdc%, xpos%, ypos%, cx%, cy%, hdc%, 0, 0, cx%, cy%, 0 SYS "InvalidateRect", @hwnd%, rect{}, 0 WAIT 1 NEXT

SYS "SelectObject", hdc%, old% SYS "DeleteDC", hdc% SYS "DeleteObject", hbitmap% SYS "FreeLibrary", msimg32%

END code

And there we are! Enjoy.

Michael Hutton