Click here to Skip to main content
16,021,172 members
Articles / Programming Languages / C++/CLI
Article

Skinned Forms Using Images

Rate me:
Please Sign up or sign in to vote.
1.50/5 (2 votes)
26 Jul 2008CDDL1 min read 24.4K   545   18  
An alternate method to when TransparencyKey is not working .

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:

MC++
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));

    //Prepare the trasperant color key

    System::UInt32 key = 
      safe_cast<System::UInt32>((transparencyKey.A << 24) | 
      (transparencyKey.R << 16) | (transparencyKey.G << 8) | 
      (transparencyKey.B << 0));

    //access to the raw bits of the image
    BitmapData ^bitmapData = bitmap->LockBits(bounds, 
           ImageLockMode::ReadOnly, PixelFormat::Format32bppArgb);

    System::UInt32* pixelPtr = (System::UInt32*)bitmapData->Scan0.ToPointer();

    //avoid property accessors in the for better perforance

    int yMax = safe_cast<int>(boundsF.Height);
    int xMax = safe_cast<int>(boundsF.Width);

    //Graphics path to keep extracted area 
    GraphicsPath ^path = gcnew GraphicsPath();

    for (int y = 0; y < yMax; y++)
    {
        //store the pointer so we can jump to next linr from it later
        System::Byte* basePos = (System::Byte*)pixelPtr;

        for (int x = 0; x < xMax; x++, pixelPtr++)
        {
            //is transparent? if yes, just continue the loop
            if (*pixelPtr == key)
                continue;

            //store where the starting position 
            int x0 = x;

            //if not transparent - scan until the next transparent byte
            while (x < xMax && *pixelPtr != key)
            {
                ++x;
                pixelPtr++;

            }

            //add the area we have found to the path
            path->AddRectangle(System::Drawing::Rectangle(x0, y, x - x0, 1));
        }

        //jump to the next line
        pixelPtr = (System::UInt32*)(basePos + bitmapData->Stride);
    }

    //now create the region from the graphic path
    Region ^region = gcnew Region(path);

    //clean up
    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 :)

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --