Converting a bitmap to a region

The function BitmapToRegion() below, as its name implies, create a region from a bitmap. It scans the bitmap content (using a memory DC associated to a 32 bit DIB section), find continguous lines of non "transparent" pixels, add these lines to a RGNDATA structure, and finally, create the resulting region by calling ExtCreateRgn(). The function takes three arguments : the bitmap to scan, the base color which indicates the minimum value for the "transparents" pixels, and the tolerance color which, added to the base color, gives the maximum value for theses "transparents" pixels.

The sample Win32 project you can download shows how to use BitmapToRegion() to create a non-rectangular splash screen. The resulting region is equal to the "winnt256.bmp" bitmap, minus the black and "almost black" pixels. This region is then passed as an argument to the SetWindowRgn() function, with a handle to a window we created before. At last, we have only to paint de bitmap into the window to get the non-rectangular splash screen !

BitmapToRegion() is a pure Win32 function. It doesn't make any use of the MFC. Its code is standalone and only need to be compiled in a C++ file (a C compiler implies some minor modifications in the code). The function has been tested successfully on both Window 95, Windows 98 and Windows NT4. On the two formers systems, we only had have to modify the function slightly, because ExtCreateRgn() failed to create regions containing more than 4000 rectangles. The performances are quite good : on a PII-400 under NT4, the function spend only 70 ms to scan a 575x846x8 drawing (from the great artist Luis Royo) and create a corresponding region of more than 21000 rectangles ! / // BitmapToRegion : Create a region from the "non-transparent" pixels of a bitma // Author : Jean-Edouard Lachand-Robert (, June 1998 / // hBmp : Source bitma // cTransparentColor : Color base for the "transparent" pixels (default is black // cTolerance : Color tolerance for the "transparent" pixels / // A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is // greater or equal to the corresponding value in cTransparentColor and is lower or equal to the // corresponding value in cTransparentColor + cTolerance / HRGN BitmapToRegion (HBITMAP hBmp, COLORREF cTransparentColor = 0, COLORREF cTolerance = 0x101010) { HRGN hRgn = NULL; ASSERT(hBmp); if (hBmp) { // Create a memory DC inside which we will scan the bitmap conten HDC hMemDC = CreateCompatibleDC(NULL); ASSERT(hMemDC); if (hMemDC) { // Get bitmap siz BITMAP bm; GetObject(hBmp, sizeof(bm), &bm); // Create a 32 bits depth bitmap and select it into the memory DC BITMAPINFOHEADER RGB32BITSBITMAPINFO = { sizeof(BITMAPINFOHEADER), // biSize bm.bmWidth, // biWidth; bm.bmHeight, // biHeight; 1, // biPlanes; 32, // biBitCount BI_RGB, // biCompression; 0, // biSizeImage; 0, // biXPelsPerMeter; 0, // biYPelsPerMeter; 0, // biClrUsed; 0 // biClrImportant; }; VOID * pbits32; HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0); ASSERT(hbm32); if (hbm32) { HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32); // Create a DC just to copy the bitmap into the memory D HDC hDC = CreateCompatibleDC(hMemDC); ASSERT(hDC); if (hDC) { // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits BITMAP bm32; VERIFY(GetObject(hbm32, sizeof(bm32), &bm32)); while (bm32.bmWidthBytes % 4) bm32.bmWidthBytes++; // Copy the bitmap into the memory D HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp); VERIFY(BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY)); // For better performances, we will use the ExtCreateRegion() function to create th // region. This function take a RGNDATA structure on entry. We will add rectangles b // amount of ALLOC_UNIT number in this structure #define ALLOC_UNIT 100 DWORD maxRects = ALLOC_UNIT; HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects)); RGNDATA *pData = (RGNDATA *)GlobalLock(hData); pData->rdh.dwSize = sizeof(RGNDATAHEADER); pData->rdh.iType = RDH_RECTANGLES; pData->rdh.nCount = pData->rdh.nRgnSize = 0; SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); // Keep on hand highest and lowest values for the "transparent" pixel BYTE lr = GetRValue(cTransparentColor); BYTE lg = GetGValue(cTransparentColor); BYTE lb = GetBValue(cTransparentColor); BYTE hr = min(0xff, lr + GetRValue(cTolerance)); BYTE hg = min(0xff, lg + GetGValue(cTolerance)); BYTE hb = min(0xff, lb + GetBValue(cTolerance)); // Scan each bitmap row from bottom to top (the bitmap is inverted vertically BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes; for (int y = 0; y < bm.bmHeight; y++) { // Scan each bitmap pixel from left to righ for (int x = 0; x < bm.bmWidth; x++) { // Search for a continuous range of "non transparent pixels" int x0 = x; LONG *p = (LONG *)p32 + x; while (x < bm.bmWidth) { BYTE b = GetRValue(*p); if (b >= lr && b <= hr) { b = GetGValue(*p); if (b >= lg && b <= hg) { b = GetBValue(*p); if (b >= lb && b <= hb) // This pixel is "transparent" break; } } p++; x++; } if (x > x0) { // Add the pixels (x0, y) to (x, y+1) as a new rectangle in the regio if (pData->rdh.nCount >= maxRects) { GlobalUnlock(hData); maxRects += ALLOC_UNIT; VERIFY(hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE)); pData = (RGNDATA *)GlobalLock(hData); ASSERT(pData); } RECT *pr = (RECT *)&pData->Buffer; SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1); if (x0 < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0; if (y < pData-> pData-> = y; if (x > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x; if (y+1 > pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y+1; pData->rdh.nCount++; // On Windows98, ExtCreateRegion() may fail if the number of rectangles is to // large (ie: > 4000). Therefore, we have to create the region by multiple steps if (pData->rdh.nCount == 2000) { HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); ASSERT(h); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); DeleteObject(h); } else hRgn = h; pData->rdh.nCount = 0; SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); } } } // Go to next row (remember, the bitmap is inverted vertically p32 -= bm32.bmWidthBytes; } // Create or extend the region with the remaining rectangle HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); ASSERT(h); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); DeleteObject(h); } else hRgn = h; // Clean u SelectObject(hDC, holdBmp); DeleteDC(hDC); } DeleteObject(SelectObject(hMemDC, holdBmp)); } DeleteDC(hMemDC); } } return hRgn; }

Download source and demo project - 175KB


  • Some questions confused me.

    Posted by Rudy Xiong on 06/03/2015 05:09am

    1.while (bm32.bmWidthBytes % 4) bm32.bmWidthBytes++; Since you have set 'biBitCount' to be 32 when you create the 'BITMAPINFOHEADER', so 'bm32.bmWidthBytes' will always be exactly division by 4, right? 2.pData-rdh.rcBound? when I removed all code about this member, it seems nothing was affected. 3.The pData was not released, won't it cause memory leak?

  • idyqww

    Posted by Mandyujn on 03/30/2013 09:16am

    ray ban sunglasses,Sure enough, the rest of the five Fallen panic agents just quickly disappeared immediately, and quickly fled in all directions, it seems ray ban wayfarer sunglasses wisdom is not the Xiao Feng imagined so bad. Xiao Feng could not help but chuckle after seeing a bit, I thought it really was timid family! Two gold coins and a ring, then your mind a move, five Fallen have stiff body fall also broke one of the body, in fact, if not also the floor of the ring like games issued bites is heard, Xiao Feng really did not notice. ray ban caravan then still watching the changes in his body inside the original Xiao Feng to kill those Fallen sensitive after a few road capability found wafting from the corpses of those monster into the body of oakley sunglasses outlet very weak, but it does melt into the ability of the body of the oakley sunglasses cheap, but for Xiao Feng's strength now is simply a drop in the ocean.

  • You Will cherish Nike jordan Footwear and relish the Knowledge

    Posted by NopFrufFElurl on 02/28/2013 06:06pm

    Low cost nike air jordan footwear within wintertime,we've! If you're chased for the airport terminal month possibly even,cheap jordan should you like baseball otherwise you just about all got message on the baseball Globe Festival. The actual much more your with that function experienced dispersed it had the other boot, in order that we can think about your refreshing memory. This is no declare of our facet on almost all assaulting footwear in which were established cost-free about this plot of land were just about all really good. Today all of us get a new facade in the Brand-new AJ The year of 2010 construction within this Increase Combined We all Version. This need to end up being mentioned in which Jordani? This year provides one particular from the greatest many years within the fresh previous itemising involving fresh variations of the Nike Air Jordan 4 series. A lot of of the males had currently frosty Jordan shoes that you are advertise so far this kind of yr and also involves the diagram of our very republican timeless classics that individuals tends to make mucky on their own arms.Put on forget occur close up six or 7 years, had been following anyone needed to perform with the sign on the phrase Melo anyplace close to your which means in a abuse as well as Jordani? Athletic shoes inside the racket regarding unmanageable approach straight away occupants acquired? Effectively, item are generally relatively a lot more as extremely rousing, nevertheless there you have an excellent couple of skate footwear Melo to attract close off, but now he or she has been in the identity for the Jordani? Hearth extended, a style associated with composed came into being a little. Naturally, the merchandise that bulk of AJ Shoes comes in yellow neglects sky-blue and more material respected color ways. The Nike AJ Fireplace originated air Jordan 2010 to rate the actual heritage of Michael Jordan throughout golf ball, where the particular short-term on the interpersonal of the wearing routines for the aceded Group The nike jordan players. Mid-air Jordans The year of 2010 Fashion gleaming Jordans Consider Airfare commemoration remembers Overall performance Parts and also pinnacle Black/Yellow leather to be able to include to the close up no-sew specialized information for a easy motivate story. [url=]air jordan max[/url]|

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date