Как вырезать окно по картинке

Вариант 1. 

В связи с появлением всяких разных программ, в которых окна нестандартной формы, почему-то всех тянет сделать свое окно таким же... Для многих окон используются маски... Т.е. точки, цвет которых совпадает или не совпадает, удаляются, а то что останется и будет нашей формой.

Вот и я решил сделать функцию, чтобы это можно было делать за о-о-очень короткое время. Вот она:

HRGN CreateRgnFromBitmap(LPTSTR szFileName = NULL, UINT Num = NULL, LPPOINT pPoint = NULL, BOOL bEqaul = 1)
// szFileName - путь к файлу *.bmp, из которого грузим битмапу
// Num - номер битмапы в ресурсах
// pPoint - указатель на координаты точки, цвет который нас интересует в качестве маски
// bEqual - Если 1, то оставляются все точки, цвет которой задан в маске. Если 0, то наоборот, все точки с заданным цветом "удалятся"
{
    
HBITMAP hBmp;

    
if (strlen(szFileName))  // Если предали путь к файлу *.bmp, то
    
{
        
hBmp = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  // грузим битмапу из файла
        
if (!hBmp)  // если не получилось загрузить битмапу, то показываем мессагу
        
{
            
MessageBox(hWND, "There is not bitmap", "Error", MB_OK | MB_ICONEXCLAMATION);
            
hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(Num));
            
strcpy(szFileName, "");
        }
    }
    
else if (Num)  // если передали номер ресурсы
    
{
        
hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(Num));
    }
    
else  // иначе выход...
        
return 0;

    
if (!hBmp)  // если битмапы нету...
    
{
        
MessageBox(hWND, "Can't load bitmap", "Error", MB_OK | MB_ICONSTOP);
        
CloseWindow(hWND);  // выход... можно еще "return 0;"
    
}

    
BITMAP bi;
    
GetObject(hBmp, sizeof(BITMAP), &bi);  // получаем размеры битмапы...
    
int iScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    
int iScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    
RECT R;
    
GetWindowRect(hWND, &R);

    
MoveWindow(hWND,
                    
R.left,
                    
R.top,
                    
bi.bmWidth,
                    
bi.bmHeight,
                    1);  
// меняем размеры окна

    
BYTE bpp;
    
DWORD e;
    
DWORD f, t;
    
INT x, y;
    
bool b = false;
    
HRGN Rgn, ResRgn = CreateRectRgn( 0, 0, 0, 0 );  // создаем пустой регион
    
    
GetObject( hBmp, sizeof( BITMAP ), &bi );  // получаем опять размеры (хотя зачем еще раззз)
    
bpp = bi.bmBitsPixel >> 3;
    
    
BYTE *pBits = new BYTE[ bi.bmWidth * bi.bmHeight * bpp ];  // выделяем буфер на биты
    
int p = GetBitmapBits( hBmp, bi.bmWidth * bi.bmHeight * bpp, pBits );  // получаем биты
    
     // далее получаем цвет точки, которые выкалывать/оставлять
    
if ( pPoint == NULL || pPoint->x >= bi.bmWidth || pPoint->y >= bi.bmHeight )
        
e = *(DWORD*)pBits;
    
else
        
e = *(DWORD*)(pBits + (pPoint->y * bi.bmWidth + pPoint->x) * bpp );
    
    
if (bEqaul)  // если 1, то оставлять точки только данного цвета
    
{
        
for ( y = 0; y < bi.bmHeight; y++ )
            
for ( x = 0; x < bi.bmWidth; x++ )
            {
                
// далее получаем цвета каждой точки + некоторые навороты...
                
t = *(DWORD*)(pBits + (y * bi.bmWidth + x) * bpp)
                    
if ( t == e )
                    {
                        
if ( !b )
                        {
                            
f = x;
                            
b = true;
                        }
                        
else if ( x == (bi.bmWidth - 1) )
                        {
                            
Rgn = CreateRectRgn( f, y, x, y + 1 );
                            
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
                            
b = false;
                        }
                    }
                    
else if ( b )
                    {
                        
Rgn = CreateRectRgn( f, y, x, y + 1 );
                        
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
                        
b = false;
                    }
            }
    }
    
else  // в противном случае выкалываем все точки, цвет которой совпадает с цветом заданной точки
    
{
        
for ( y = 0; y < bi.bmHeight; y++ )
            
for ( x = 0; x < bi.bmWidth; x++ )
            {
                
t = *(DWORD*)(pBits + (y * bi.bmWidth + x) * bpp)
                    
if ( t != e )
                    {
                        
if ( !b )
                        {
                            
f = x;
                            
b = true;
                        }
                        
else if ( x == (bi.bmWidth - 1) )
                        {
                            
Rgn = CreateRectRgn( f, y, x, y + 1 );
                            
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
                            
b = false;
                        }
                    }
                    
else if ( b )
                    {
                        
Rgn = CreateRectRgn( f, y, x, y + 1 );
                        
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
                        
b = false;
                    }
            }
    }
    
delete pBits;  // удаляем биты
    
return ResRgn;  // и возвращаем указатель на регион
}
А теперь где-нибудь в программе делаем так:
POINT pt;
pt.x = 0; pt.y = 0; // координаты точки, цвет которой будет считаться за маску

HRGN hRgn = CreateRgnFromBitmap(szFileNameBuf, IDB_BITMAP, &pt, 0);
// szFileNameBuf - путь к файлу с битмапой (в качестве маски)
// IDB_BITMAP - идентификатор битмапы в ресурсах

SetWindowRgn(hWnd, hRgn, TRUE);

 Вариант 2. 

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !                                                                                                                   
// !    For Win9x image width MUST BE dword aligned!!!                            !
// !                                                                                                                   
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
HRGN CFileRgnDlg::CreateRgnFromFile( HBITMAP hBmp, COLORREF color )
{
    
// get image properties
    
BITMAP bmp = { 0 };
    
GetObject( hBmp, sizeof(BITMAP), &bmp );

    
// allocate memory for extended image information
    
LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 8 ];

    
memset( bi, 0, sizeof(BITMAPINFO) + 8 );
    
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    
// set window size
    
m_dwWidth       = bmp.bmWidth;      // bitmap width
    
m_dwHeight      = bmp.bmHeight;     // bitmap height

    // create temporary dc
    
HDC dc = CreateDC( "DISPLAY",NULL,NULL,NULL );

    
// get extended information about image (length, compression, length of color table if exist, ...)
    
DWORD res = GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS );

    
// allocate memory for image data (colors)
    
LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 4 ];

    
// allocate memory for color table
    
if ( bi->bmiHeader.biBitCount == 8 )
    {
        
// actually color table should be appended to this header(BITMAPINFO),
        // so we have to reallocate and copy it
        
LPBITMAPINFO old_bi = bi;

        
// 255 - because there is one in BITMAPINFOHEADER
        
bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ];

        
memcpy( bi, old_bi, sizeof(BITMAPINFO) );

        
// release old header
        
delete old_bi;
    }
    
// get bitmap info header
    
BITMAPINFOHEADER& bih = bi->bmiHeader;

    
// get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD))
    
LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors;

    
// fill bits buffer
    
res = GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS );

    
DeleteDC( dc );

    
// shift bits and byte per pixel (for comparing colors)
    
LPBYTE pClr = (LPBYTE)&color;

    
// swap red and blue components
    
BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;

    
// convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5)
    
if ( bih.biBitCount == 16 )
    {
        
color = ((DWORD)(pClr[0] & 0xf8) >> 3) |            // 3
                
((DWORD)(pClr[1] & 0xf8) << 3) |            // 2
                
((DWORD)(pClr[2] & 0xf8) << 8);             // 7
    
}

    
const DWORD RGNDATAHEADER_SIZE  = sizeof(RGNDATAHEADER);
    
const DWORD ADD_RECTS_COUNT         = 40;           // number of rects to be appended
                                                    // to region data buffer

    
BYTE    Bpp = bih.biBitCount >> 3;                  // bytes per pixel

    // DIB image is flipped that's why we scan it from the last line
    
LPBYTE  pColor = pBits + (bih.biHeight - 1) * (bih.biWidth * Bpp);
    
DWORD   dwLineBackLen = 2 * bih.biWidth * Bpp;  // offset of previous scan line
                                                    // (after processing of current)
    
DWORD   dwRectsCount = bih.biHeight;            // number of rects in allocated buffer
    
INT         i, j;                                   // current position in mask image
    
INT         first = 0;                                  // left position of current scan line
                                                    // where mask was found
    
bool    wasfirst = false;                           // set when mask has been found in current scan line
    
bool    ismask;                                 // set when current color is mask color

    // allocate memory for region data
    // region data here is set of regions that are rectangles with height 1 pixel (scan line)
    // that's why first allocation is <bm.biHeight> RECTs - number of scan lines in image
    
RGNDATAHEADER* pRgnData =
        (
RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];

    
// get pointer to RECT table
    
LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);

    
// zero region data header memory (header  part only)
    
memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );

    
// fill it by default
    
pRgnData->dwSize    = RGNDATAHEADER_SIZE;
    
pRgnData->iType     = RDH_RECTANGLES;

    
for ( i = 0; i < bih.biHeight; i++ )
    {
        
for ( j = 0; j < bih.biWidth; j++ )
        {
            
// get color
            
switch ( bih.biBitCount )
            {
            
case 8:
                
ismask = (clr_tbl[ *pColor ] != color);
                
break;

            
case 16:
                
ismask = (*(LPWORD)pColor != (WORD)color);
                
break;

            
case 24:
                
ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color);
                
break;

            
case 32:
                
ismask = (*(LPDWORD)pColor != color);
            }
            
// shift pointer to next color
            
pColor += Bpp;

            
// place part of scan line as RECT region if transparent color found after mask color or
            // mask color found at the end of mask image
            
if ( wasfirst && (ismask ^ (j < bih.biWidth - 1)) )
            {
                
// save current RECT
                
pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 );

                
// if buffer full reallocate it with more room
                
if ( pRgnData->nCount >= dwRectsCount )
                {
                    
dwRectsCount += ADD_RECTS_COUNT;
                    
// allocate new buffer
                    
LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT)];

                    
// copy current region data to it
                    
memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );

                    
// delte old region data buffer
                    
delete pRgnData;

                    
// set pointer to new regiondata buffer to current
                    
pRgnData = (RGNDATAHEADER*)pRgnDataNew;

                    
// correct pointer to RECT table
                    
pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
                }
                
wasfirst = false;
            }
            
else if ( !wasfirst && ismask )     // set wasfirst when mask is found
            
{
                
first = j;
                
wasfirst = true;
            }
        }

        
pColor -= dwLineBackLen;
    }
    
// release image data
    
delete pBits;
    
delete bi;

    
// create region
    
HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
    
// release region data
    
delete pRgnData;

    
return hRgn;
}
 
« Предыдущая статья