본문 바로가기
IT창고/API

bitmap 리전 만들기..

by 창구창고 2007. 1. 22.

📑 목차

    반응형

    #define _WIN32_WINNT 0x0501
    #define WINVER 0x0501

    #include <windows.h>
    #include "resource.h" // <<-- 추가


    // BitmapToRegion : Create a region from the "non-transparent" pixels of a bitma
    // Author :  Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), 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, COLORREF cTolerance)
    {
     HRGN hRgn = NULL;

     if (hBmp)
     {
      // Create a memory DC inside which we will scan the bitmap content
      HDC hMemDC = ::CreateCompatibleDC(NULL);
      if (hMemDC)
      {
       // Get bitmap size
       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);
       if (hbm32)
       {
        HBITMAP holdBmp = (HBITMAP)::SelectObject(hMemDC, hbm32);

        // Create a DC just to copy the bitmap into the memory DC
        HDC hDC = ::CreateCompatibleDC(hMemDC);
        if (hDC)
        {
         // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)
         BITMAP bm32;
         ::GetObject(hbm32, sizeof(bm32), &bm32);
         while (bm32.bmWidthBytes % 4)
          bm32.bmWidthBytes++;

         // Copy the bitmap into the memory DC
         HBITMAP holdBmp = (HBITMAP)::SelectObject(hDC, hBmp);
         ::BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);

         // For better performances, we will use the ExtCreateRegion() function to create the
         // region. This function take a RGNDATA structure on entry. We will add rectangles by
         // 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" pixels
         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 right
          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 region
            if (pData->rdh.nCount >= maxRects)
            {
             ::GlobalUnlock(hData);
             maxRects += ALLOC_UNIT;
             hData = ::GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
             pData = (RGNDATA *)::GlobalLock(hData);
            }
            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->rdh.rcBound.top)
             pData->rdh.rcBound.top = 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 too
            // 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);
             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 rectangles
         HRGN h = ::ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
         if (hRgn)
         {
          ::CombineRgn(hRgn, hRgn, h, RGN_OR);
          ::DeleteObject(h);
         }
         else
          hRgn = h;

         // Clean up
         ::GlobalFree(hData);
         ::SelectObject(hDC, holdBmp);
         ::DeleteDC(hDC);
        }

        ::DeleteObject(::SelectObject(hMemDC, holdBmp));
       }

       ::DeleteDC(hMemDC);
      } 
     }

     return hRgn;
    }


    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
     static HBITMAP hBitmap = (HBITMAP)LoadBitmap( GetModuleHandle(0),
               MAKEINTRESOURCE(IDB_BITMAP1));

     switch(msg)
     {
     case WM_PAINT:
      {
       PAINTSTRUCT ps;
       HDC hdc = BeginPaint(hwnd, &ps);
     
       HDC mem = CreateCompatibleDC(hdc);
       HBITMAP old = (HBITMAP)SelectObject(mem, hBitmap);
       
       BitBlt( hdc, 0, 0, 413, 382, mem, 0, 0, SRCCOPY);
       SelectObject(mem, old);
       DeleteDC(mem);
       EndPaint(hwnd, &ps);
       
      }
      return 0;


     case WM_NCHITTEST : return HTCAPTION;

     case WM_CREATE :
      {
       // 비정형 윈도우는 대부분 캡션바와 size 조절을 때어 낸다.
       UINT style = GetWindowLong( hwnd, GWL_STYLE );

       style = style & ~WS_CAPTION & ~WS_THICKFRAME;

       SetWindowLong( hwnd, GWL_STYLE, style );
       //===============================================



       // 흑백 비트맵을 Load 한다.
       HBITMAP hMask = (HBITMAP)LoadBitmap( GetModuleHandle(0),  // hInstance
               MAKEINTRESOURCE(IDB_BITMAP2));
       // 비트맵으로 리젼을 만들어 낸다.
       HRGN h = BitmapToRegion( hMask, RGB(255,255,255), 0); // 2번째 인자부터, 3번째 인자 사이의 색깔을 투명하게

       SetWindowRgn( hwnd, h, TRUE );

       DeleteObject( h );
       DeleteObject( hMask);
      }
      return 0;

     case WM_DESTROY :
      DeleteObject( hBitmap ); // <<-- 추가 2


      PostQuitMessage(0);
      return 0;
     }
     return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
    {
     WNDCLASS wc;

     wc.cbClsExtra = 0;
     wc.cbWndExtra = 0;
     wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
     wc.hCursor = LoadCursor(0, IDC_ARROW);
     wc.hIcon = LoadIcon(0, IDI_APPLICATION);
     wc.hInstance = hInstance;
     wc.lpfnWndProc = WndProc;
     wc.lpszClassName = "클래스 이름";
     wc.lpszMenuName = 0;
     wc.style = 0;

     ATOM atom = RegisterClass(&wc);

     if(atom == 0)
     {
      MessageBox(0, "클래스 등록에 실패했습니다.", "에러", MB_OK);
      return 0;
     }

     HWND hwnd = CreateWindowEx(0, "클래스 이름", "윈도우창 이름", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, 0, 0, hInstance, 0);

     ShowWindow(hwnd, nShowCmd);
     UpdateWindow(hwnd);

     MSG msg;

     while(GetMessage(&msg, 0, 0, 0))
     {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
     }

     return 0;
    }

    반응형

    "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."