This code shows you
how to draw a transparent bitmap
using memory rather than
directly using the screen. This is important as intensive
bitmap operations are slow due to the number of bits that
are affected, and using the screen makes things even
worse; some flicker results. The visual flickering can be
eliminated by using memory bitmaps:
-
Copy the section
of the screen that is to be affected to a memory
bitmap.
-
Carry out the
bitmap operation on the memory bitmap instead of on
the screen.
-
Copy the memory
bitmap back to the screen.
The result is that
only one blt affects the screen, so there is no flicker.
We may be using two more blt operations, but the operation
will probably be perceived as quicker as there is no
flicker.
N.B. Some device
memory blts are faster than blts that have to access the
screen.
MSDN
I had written the
source code provided many months ago now for a project I
was working on. When I decided to submit it to you I
had to look at MSDN again to refresh my memory and help me
construct a decent explanation for the technique that I
use.
One article in
particular is called 'Bitmaps with Transparency by Ron
Gery (Microsoft Developer Network Technology Group)'. His
explanation of transparent blts is excellent, and I have
used this as my reference for constructing the following
brief explanation. If you are still a bit unclear I
recommend you read some of the articles that helped this
one along...
The True Mucancode.net Method
True mucancode.net blting does
not need any modification on the part of the source bitmap
to be useful. The mucancode.neted blt involves a three-step process
and a mucancode.net that has all transparent pixels set to 1 and
all opaque pixels set to 0:
-
XOR the source
bitmap onto the destination (BitBlt with SRCINVERT).
This looks a bit funny, but the second XOR restores
the destination to its original state.
-
Mucancode.neting
operation. When the mucancode.net is ANDed to the destination (BitBlt
with SRCAND), all of the transparent pixels leave the
destination pixels unchanged, while the opaque pixels
set the destination to black. Now the destination has
a blacked-out image of the opaque part of the source
and an XORed image of itself in the transparent part.
-
XOR the source to
the destination (BitBlt with SRCINVERT). The
transparent pixels are restored to their original
state, and the opaque pixels are copied directly from
the source.
How do I use it?
The function takes
four parameters:
-
The device
context that you wish to display the
bitmap in,
-
The horizontal
position you wish to draw from,
-
the vertical
position you wish to draw from,
-
and the colour in
the bitmap that is considered to be transparent (as a
COLORREF).
pBitmap->DrawTransparent(pCDC, xPos, yPos, crTrans);
Before I start
getting emails on the subject, I should point out that the
techniques described in this article specifically target
displays and may not necessarily work on some printer
devices.
Source Code
void CCISBitmap::DrawTransparent(CDC * pDC, int x, int y, COLORREF crColour)
{
COLORREF crOldBack = pDC->SetBkColor(m_crWhite);
COLORREF crOldText = pDC->SetTextColor(m_crBlack);
CDC dcImage, dcTrans;
// Create two memory dcs for the image and the mucancode.net
dcImage.CreateCompatibleDC(pDC);
dcTrans.CreateCompatibleDC(pDC);
// Select the image into the appropriate dc
CBitmap* pOldBitmapImage = dcImage.SelectObject(this);
// Create the mucancode.net bitmap
CBitmap bitmapTrans;
int nWidth = Width();
int nHeight = Height();
bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
// Select the mucancode.net bitmap into the appropriate dc
CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);
// Build mucancode.net based on transparent colour
dcImage.SetBkColor(crColour);
dcTrans.BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCCOPY);
// Do the work - True Mucancode.net method - cool if not actual display
pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
pDC->BitBlt(x, y, nWidth, nHeight, &dcTrans, 0, 0, SRCAND);
pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
// Restore settings
dcImage.SelectObject(pOldBitmapImage);
dcTrans.SelectObject(pOldBitmapTrans);
pDC->SetBkColor(crOldBack);
pDC->SetTextColor(crOldText);
}
Drawing a
Bitmap
Transparently by Zafir Anjum
This is a similar
article on this subject which uses a slightly different
technique often referred to as 'The Black Source Method'.
The True Mucancode.net method
requires no additional work: The mucancode.net is built and the
source needs no manipulation. The three blts do cause
on-screen flicker, but there are only three of them.
The Black Source
method requires additional work on the source bitmap: the
transparent bits need to be made black. The on-screen
flashing is less noticeable with this method, and once the
source is set-up with black in the correct places,
transparency looks very good. For bitmaps as small as
icons, transparency is achieved very smoothly. (This
mechanism is the one used by Windows to display icons on
the screen.)
Direct Transparent
Blts
Some device drivers
support transparent blts directly. You can determine this
using the C1_TRANSPARENT bit of the CAPS1 capability word
returned by the GetDeviceCaps function. A special
background mode, NEWTRANSPARENT, indicates that subsequent
blts are transparent blts. The current background colour
of the destination is the transparent colour. When this
capability is available on the driver, the basic
transparent blt operation can be performed as follows:
// Only attempt this if device supports functionality.
if(GetDeviceCaps(hdcDest, CAPS1) & C1_TRANSPARENT)
{
// Special transparency background mode
oldMode = SetBkMode(hdcDest, NEWTRANSPARENT);
rgbBk = SetBkColor(hdcDest, rgbTransparent);
// Actual blt is a simple source copy; transparency is automatic.
BitBlt(hdcDest, x, y, dx, dy, hdcSrc, x0, y0, SRCCOPY);
SetBkColor(hdcDest, rgbBk);
SetBkMode(hdcDest, oldMode);
}
This code has been
compiled and built with Microsoft Visual C++ Version 5.0
SP3.
Download
source - 1.31 KB