Запись изображения окна в BMP файл

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

Чтобы сохранить изображение окна в BMP файл, необходимо нарисовать картинку на контексте устройства, преобразовать битмап, связанный с DC в памяти в устройство-независимый битмап, а затем записать DIB в файл. Ниже преведена функция WriteWindowToDIB(), в которой для решения нашей задачи используются функции DDBToDIB() и WriteDIB().

Давайте разберёмся, как создаётся изображение окна на контексте устройства в памяти и как создаётся логическая палитра, которая отвечает за изображение. Для начала создадим DC в памяти, совместимый с оконным DC. Далее создадим совместимый битмап, который имеет такой же размер как и окно. Затем воспользуемся BitBlt(), чтобы передать изображение в DC в памяти, получив тем самым битмап.

Однако, это только половина работы; другая половина заключается в том, чтобы получить логическую палитру, которая будет использоваться с битмапом. Если битмапу требуется логическая палитра, и она не будет доступна, то битмап не захочет правильно отображаться. Воспользуемся функцией GetDeviceCaps(), чтобы определить, поддерживает ли дисплей манипуляции с палитрой. Далее выделяем достаточное количество памяти для структуры LOGPALETTE, а затем используем GetSystemPaletteEntries() чтобы заполнить таблицу цветов. Теперь мы можем спокойно создать логическую палитру.

В заключение используются функции DDBToDIB() и WriteDIB(). Обратите внимание, что если окно частично перекрывается другими окнами, то в сохранённом битмапе будут содержаться части этих окон.

BOOL WriteWindowToDIB( LPTSTR szFile, CWnd *pWnd )
{
CBitmap bitmap;
CWindowDC dc(pWnd);
CDC memDC;
CRect rect;

memDC.CreateCompatibleDC(&dc);

pWnd->GetWindowRect(rect);

bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height() );

CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);

//
Если устройство поддерживает палитру, то создаём логическую палитру
CPalette pal;
if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;

pLP->palNumEntries =
GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry );

//
Создаём палитру
pal.CreatePalette( pLP );

delete[] pLP;
}

memDC.SelectObject(pOldBitmap);

//
Преобразуем битмап в DIB
HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, &pal );

if( hDIB == NULL )
return FALSE;

//
Записываем в файл
WriteDIB( szFile, hDIB );

//
Освобождаем память выделенную DDBToDIB для DIB
GlobalFree( hDIB );
return TRUE;
}