Вариант 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; } |