Сохранение изображения
Многие приложения постоянно сохраняют изображения как файлы. Например, рисующие приложения сохраняют картинки, приложения - электронные таблицы сохраняют диаграммы, приложения автоматизированного проектирования CAD сохраняют чертежи и так далее.
Если Вы пишете приложение, которое сохраняет растровое изображение в файле, вам следует использовать формат файла точечной графики, описанный в статье Сохранение точечного рисунка. Чтобы сохранить точечный рисунок в этом формате, Вы должны использовать структуру BITMAPINFOHEADER, BITMAPV4HEADER или BITMAPV5HEADER и массив структур RGBQUAD, а так же массив индексов палитры.
Код примера ниже определяет функцию, которая использует структуру BITMAPINFO и выделяет память и инициализирует члены внутри структуры BITMAPINFOHEADER.
|
Обратите внимание! на то, что то, что структура BITMAPINFO не может быть использована или со структурой BITMAPV4HEADER или с BITMAPV5HEADER. |
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;
// Извлечем формат цвета, ширину и высоту точечного рисунка.
if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
errhandler("GetObject", hwnd);
// Преобразуем формат для подсчета битов.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if (cClrBits == 1)
cClrBits = 1;
else if (cClrBits <= 4)
cClrBits = 4;
else if (cClrBits <= 8)
cClrBits = 8;
else if (cClrBits <= 16)
cClrBits = 16;
else if (cClrBits <= 24)
cClrBits = 24;
else cClrBits = 32;
// Выделим память для структуры BITMAPINFO. (Эта структура
// содержит структуру BITMAPINFOHEADER и массив структур
// данных RGBQUAD.)
if (cClrBits != 24)
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * (1<< cClrBits));
// Для формата 24 бита на пиксель массива RGBQUAD нет.
else
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER));
// Инициализируем поля структуры BITMAPINFO.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
// Если точечный рисунок не сжат, установим флажок BI_RGB.
pbmi->bmiHeader.biCompression = BI_RGB;
// Сравним число байтов в массиве обозначающем цвет и сохраним
// результат в переменной biSizeImage. Для Windows NT, ширина
// должна выравниваться по DWORD, если точечный рисунок является
// не сжатым RLE. Этот пример показывает это. Для Windows 95/98/Me,
// ширина должна выравниваться по WORD, если точечный рисунок
// является не сжатым RLE.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth *
cClrBits +31)& ~31) /8 * pbmi->bmiHeader.biHeight;
// Установим biClrImportant в 0, обозначая, что все
// устройства цвета являются важными.
pbmi->bmiHeader.biClrImportant = 0;
return pbmi;
}
|
Код примера ниже определяет функцию, которая инициализирует остальные структуры, извлекает массив индексов палитры, открывает файл, копирует данные, и закрывает файл.
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,
HBITMAP hBMP, HDC hDC)
{
HANDLE hf; // дескриптор файла
BITMAPFILEHEADER hdr; // заголовочный файл точечного рисунка
PBITMAPINFOHEADER pbih; // информ. заголовок точечного рисунка
LPBYTE lpBits; // указатель на память
DWORD dwTotal; // общий подсчет байтов
DWORD cb; // нарастающий подсчет байтов
BYTE *hp; // указатель на байты
DWORD dwTmp;
pbih = (PBITMAPINFOHEADER) pbi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if (!lpBits)
errhandler("GlobalAlloc", hwnd);
// Извлекаем таблицу цветов (массив RGBQUAD) и битов
// (массив индикаторов палитры) из DIB.
if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
DIB_RGB_COLORS))
{
errhandler("GetDIBits", hwnd);
}
// Создаем файл с расширением .BMP.
hf = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hf == INVALID_HANDLE_VALUE)
errhandler("CreateFile", hwnd);
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Подсчитываем размер всего файла.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
// Подсчитываем смещение на массив индикаторов цвета.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof (RGBQUAD);
// Копируем BITMAPFILEHEADER в файл .BMP.
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
(LPDWORD) &dwTmp, NULL))
{
errhandler("WriteFile", hwnd);
}
// Копируем BITMAPINFOHEADER и массив RGBQUAD в файл.
if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
+ pbih->biClrUsed * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, ( NULL))
errhandler("WriteFile", hwnd);
// Копируем массив индикаторов цвета в файл .BMP.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
errhandler("WriteFile", hwnd);
// Закрываем файл .BMP.
if (!CloseHandle(hf))
errhandler("CloseHandle", hwnd);
// Освобождаем память.
GlobalFree((HGLOBAL)lpBits);
}
|