Сохранение изображения
Многие приложения постоянно сохраняют изображения как файлы. Например, рисующие приложения сохраняют картинки, приложения - электронные таблицы сохраняют диаграммы, приложения автоматизированного проектирования 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); } |