Создаём регион из файла

Это очень простая функция, создающая регион из bitmap (.bmp) файла. Так же в примере представлен усовершенствованный вариант этой функции, позволяющий задавать маску изображения.

Компилятор: Visual C++ 4-6

Функция называется CreateRgn и имеет два параметра:
szFileName - имя файла, содержащего картинку.
pPoint - указатель на структуру POINT , которая содержит координаты цвета, который используется для конструирования региона, если параметр NULL, то будет использоваться цвет в координате (0, 0).

HRGN CreateRgn(LPTSTR szFileName, LPPOINT pPoint)
{
HBITMAP hBmp = (HBITMAP)LoadImage( NULL, szFileName,
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
if ( !hBmp ) return NULL;

BITMAP bi;
BYTE bpp;
DWORD e;
DWORD f, t;
INT i, j;
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 );

e <<= 32 - bi.bmBitsPixel;

for ( i = 0; i < bi.bmHeight; i++ )
for ( j = 0; j < bi.bmWidth; j++ )
{
t = *(DWORD*)(pBits + (i * bi.bmWidth +
j) * bpp) << (32 - bi.bmBitsPixel);

if ( t == e )
{
if ( !b )
{
f = j;
b = true;
} else if ( j == (bi.bmWidth - 1) )
{
Rgn = CreateRectRgn( f, i, j, i + 1 );
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
b = false;
}
} else if ( b )
{
Rgn = CreateRectRgn( f, i, j, i + 1 );
CombineRgn( ResRgn, ResRgn, Rgn, RGN_OR );
b = false;
}
}

delete pBits;

return ResRgn;
}

Update: Ниже представлена улучшенная версия функции, которая требует маску битмапа для TrueColor. В Win9x ширина маски битмапа  должна быть DWORD.

HRGN CreateRgnFromFile(HBITMAP hBmp, COLORREF color)
{
// получаем размер маски
BITMAP bm = { 0 };
GetObject( hBmp, sizeof(BITMAP), &bm );

m_dwWidth= bm.bmWidth;// ширина bitmap
m_dwHeight= bm.bmHeight;// высота bitmap

// Распределяем буфер для маски
LPBYTE pBits = new BYTE[ bm.bmWidthBytes * bm.bmHeight ];
// заполняем буфер свойствами
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize= sizeof( BITMAPINFOHEADER );
bi.bmiHeader.biBitCount= bm.bmBitsPixel;
bi.bmiHeader.biHeight= bm.bmHeight;
bi.bmiHeader.biWidth= bm.bmWidth;
bi.bmiHeader.biPlanes= bm.bmPlanes;
// заполняем биты буфера
HDC hdc = ::GetDC( NULL );
GetDIBits( hdc, hBmp, 0, bm.bmHeight, pBits, &bi, DIB_RGB_COLORS );
::ReleaseDC( NULL, hdc );

if ( bi.bmiHeader.biBitCount < 16 ) return NULL;

// сдвигаем биты и байт на пиксель (для сравнения цветов)
BYTE sb = 32 - bi.bmiHeader.biBitCount;
BYTE bpp = bi.bmiHeader.biBitCount >> 3;

LPBYTE pClr = (LPBYTE)&color;
// переставляем красный и синий компоненты
BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;
// convert color if curent DC is 16-bit (5:5:5)
if ( bpp == 2 )color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
((DWORD)(pClr[1] & 0xf8) << 2) |
((DWORD)(pClr[2] & 0xf8) << 7);
// выравниваем цвет для сравнения
color <<= sb;

const DWORD RDHDR = sizeof(RGNDATAHEADER);
const DWORD MAXBUF = 40;// размер одного блока в RECT-ах
// (т.e. MAXBUF*sizeof(RECT)
// в байтах)

LPBYTEpColor = pBits;
LPRECTpRects;
DWORDcBlocks = 0;// кол-во распределённых блоков

INTi, j;// текущая позиция в маске картинки
INTfirst = 0;// левая координата текущей линии,
// в которой была найдена маска
boolwasfirst = false;// устанавливается, если маска была
// найдена в текущей линии

boolismask;// устанавливается, если текущий
// цвет является маской


// распределяем память для данных региона
RGNDATAHEADER* pRgnData = (RGNDATAHEADER*)new BYTE[ RDHDR +
++cBlocks * MAXBUF * sizeof(RECT) ];
memset( pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT) );
// заполняем его по умолчанию
pRgnData->dwSize= RDHDR;
pRgnData->iType= RDH_RECTANGLES;
pRgnData->nCount= 0;

for ( i = 0; i < bm.bmHeight; i++ )
for ( j = 0; j < bm.bmWidth; j++ )
{
// получаем цвет
ismask = *(DWORD*)pColor << sb != color;
// сдвиг указателя на следующий цвет
pColor += bpp;
// помещаем часть сканируемой линии как регион RECT,
// если прозрачный цвет найден после цвета маски либо
// цвет маски найден в конце маски изображения
if ( wasfirst && (ismask ^ (j < bm.bmWidth - 1)) )
{
// получаем смещение в массиве RECT
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
// сохраняем текущий RECT
pRects[ pRgnData->nCount++ ] = CRect( first,
bm.bmHeight - i - 1, j, bm.bmHeight - i );
// если буфер полон, то перераспределяем его
if ( pRgnData->nCount >= cBlocks * MAXBUF )
{
LPBYTE pRgnDataNew = new BYTE[ RDHDR +
++cBlocks * MAXBUF * sizeof(RECT) ];
memcpy( pRgnDataNew, pRgnData, RDHDR +
(cBlocks - 1) * MAXBUF * sizeof(RECT));

delete pRgnData;
pRgnData = (RGNDATAHEADER*)pRgnDataNew;
}
wasfirst = false;
}
else if ( !wasfirst && ismask ) // устанавливаем
// wasfirst когда
// маска найдена

{
first = j;
wasfirst = true;
}
}

delete pBits;

// создаём регион
HRGN hRgn = ExtCreateRegion( NULL, RDHDR +
pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );

delete pRgnData;

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