Introduction
You may have seen the TransparencyKey
property of Windows Forms. It is for setting a color which will appear transparent in the output. But, unfortunately, this property will not work when we set a background image for the form and pick a color from the image and set it as the TransparencyKey
. This is a bug in the framework.
- BUG: The
TransparencyKey
property is not effective for Windows Forms if the color depth of the monitor is set to a value that is greater than 24-bit.
But unfortunately, the resolution provided also will not work sometimes: check out this link.
Background
You may have already read my previous post about speeding up Windows Forms drawing when a background image is used. That technique is also used here (see how the form background property is overridden).
Using the Code
See the following function that is used to extract a region from a Bitmap
object:
Region ^ DrawingHelper::ExtractRegion(Bitmap ^bitmap, Color transparencyKey)
{
if (bitmap == nullptr)
return nullptr;
GraphicsUnit unit = GraphicsUnit::Pixel;
System::Drawing::RectangleF boundsF = bitmap->GetBounds(unit);
System::Drawing::Rectangle bounds =
System::Drawing::Rectangle(safe_cast<int>(boundsF.Left),
safe_cast<int>(boundsF.Top), safe_cast<int>(boundsF.Width),
safe_cast<int>(boundsF.Height));
System::UInt32 key =
safe_cast<System::UInt32>((transparencyKey.A << 24) |
(transparencyKey.R << 16) | (transparencyKey.G << 8) |
(transparencyKey.B << 0));
BitmapData ^bitmapData = bitmap->LockBits(bounds,
ImageLockMode::ReadOnly, PixelFormat::Format32bppArgb);
System::UInt32* pixelPtr = (System::UInt32*)bitmapData->Scan0.ToPointer();
int yMax = safe_cast<int>(boundsF.Height);
int xMax = safe_cast<int>(boundsF.Width);
GraphicsPath ^path = gcnew GraphicsPath();
for (int y = 0; y < yMax; y++)
{
System::Byte* basePos = (System::Byte*)pixelPtr;
for (int x = 0; x < xMax; x++, pixelPtr++)
{
if (*pixelPtr == key)
continue;
int x0 = x;
while (x < xMax && *pixelPtr != key)
{
++x;
pixelPtr++;
}
path->AddRectangle(System::Drawing::Rectangle(x0, y, x - x0, 1));
}
pixelPtr = (System::UInt32*)(basePos + bitmapData->Stride);
}
Region ^region = gcnew Region(path);
delete path;
bitmap->UnlockBits(bitmapData);
return region;
}
The extracted region is set as the region of the form so that we can make forms in any shape.
If you need the source code in any other language like C# or VB.NET, please drop me an email.
Happy coding :)