Приложение BMPINFO
После всего сказанного выше у вас могло сложиться впечатление, что процедура рисования изображений DIB значительно труднее, чем процедура рисования файлов DDB. В самом деле, для отображения содержимого bmp-файла вы должны считать его в память, проверить формат всех структур, при необходимости создать палитру и следить за ее изменениями со стороны других приложений. В момент рисования вам нужно подготовить значительное количество структур, указателей и параметров. Увы, для рисования изображений DIB в программном интерфейсе GDI операционной системы Windows версии 3.1 нет ничего более удобного, чем описанные нами функции.
Большинство приложений, тем не менее, нуждается в рисовании изображений DIB. Для иллюстрации методов работы с такими изображениями мы подготовили приложение BMPINFO. Это приложение умеет загружать bmp-файлы любых "легальных" форматов Windows и Presentation Manager версии 1.x, и выводит соответствующую информацию из заголовков этих файлов, однако оно способно рисовать только некомпрессованные изображения в формате Windows. Как мы уже говорили, в большинстве случаев это как раз именно то, что нужно.
В меню "File" есть строки "Open", "Info..." и, конечно, "Exit". С помощью строки "Open" вы можете выбрать bmp-файл. Если это некомпрессованный файл в формате Windows, он рисуется в окне приложения (рис. 4.7).
Рис. 4.7. Главное окно приложения BMPINFO
Выбрав из меню "File" строку "Info...", вы можете просмотреть информацию о файле, такую, как размер файла и заголовка, формат файла, размер изображения в пикселах и т. д. (рис. 4.8).
Рис. 4.8. Информация о bmp-файле
Если выбранный bmp-файл имеет формат Presentation Manager, на экране появится диалоговая панель, аналогичная изображенной на рис. 4.8.
Основной файл исходных текстов приложения BMPINFO приведен в листинге 4.6.
Листинг 4.6. Файл bmpinfo/bmpinfo.cpp
// ---------------------------------------- // Приложение BMPINFO // Просмотр и анализ bmp-файлов в формате DIB // ----------------------------------------
#define STRICT #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <mem.h> #pragma hdrstop
#include "dib.hpp" #include "bmpinfo.hpp"
// Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
// Имя класса окна char const szClassName[] = "BmpInfoClass";
// Заголовок окна char const szWindowTitle[] = "Bitmap Information";
// Размеры внутренней области окна short cxClient, cyClient;
// ===================================== // Функция WinMain // ===================================== #pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения
// Инициализируем приложение if(!InitApp(hInstance)) return FALSE;
// После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);
// Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE;
// Рисуем главное окно ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
// Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; }
// ===================================== // Функция InitApp // Выполняет регистрацию класса окна // =====================================
BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc));
// Подключаем меню wc.lpszMenuName = "APP_MENU";
wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszClassName = (LPSTR)szClassName;
// Регистрация класса aWndClass = RegisterClass(&wc);
return (aWndClass != 0); }
// ===================================== // Функция WndProc // =====================================
LRESULT CALLBACK _export WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps;
static HFILE hfDIBFile; static HDIB hDib; static HPALETTE hPal, hOldPal;
// Размер файла static DWORD dwFileSize;
switch (msg) { case WM_CREATE: { hfDIBFile = NULL; hDib = NULL; hPal = NULL; return 0; }
// При изменении размеров окна сохраняем // новые значения для ширины и высоты case WM_SIZE: { cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; }
// Рисование в окне case WM_PAINT: { // Получаем контекст отображения для // рисования во внутренней области окна hdc = BeginPaint(hwnd, &ps);
// Если DIB был загружен, и он в формате // некомпрессованного bmp-файла для Windows, // рисуем его if((hDib != NULL) && (DIBType(hDib) == WINRGB_DIB)) { // Если при загрузке была создана палитра, // выбираем ее if(hPal) { hOldPal = SelectPalette(hdc, hPal, FALSE); RealizePalette(hdc); }
// Рисуем DIB DIBPaint(hdc, 0, 0, hDib);
// Выбираем старую палитру if(hPal) { SelectPalette(hdc, hOldPal, FALSE); } }
// Для других форматов bmp-файлов выводим // информацию из заголовка файла else { if(hDib) DIBInfo(hDib, dwFileSize); }
// Освобождаем контекст отображения EndPaint(hwnd, &ps); return 0; }
// Обработка сообщений от меню case WM_COMMAND: { switch (wParam) { case CM_HELPABOUT: { MessageBox(hwnd, "Bitmap Information, v.1.0\n" "(C) Frolov A.V., 1994", "About BMPINFO", MB_OK | MB_ICONINFORMATION); return 0; }
// Загрузка bmp-файла case CM_FILEOPEN: { // Выбираем файл hfDIBFile = DIBSelectFile();
if(hfDIBFile != NULL) { // Читаем файл в память hDib = DIBReadFile(hfDIBFile, &dwFileSize);
// Если файл прочитан, создаем палитру на // базе таблицы цветов. Если таблицы цветов нет, // палитра не создается if((hDib != NULL) && (DIBType(hDib) == WINRGB_DIB)) { hPal = DIBCreatePalette(hDib); }
// Перерисовываем окно InvalidateRect(hwnd, NULL, TRUE); } return 0; }
// Выводим диалоговую панель с информацией из // заголовка bmp-файла case CM_FILEINFO: { if(hDib != NULL) DIBInfo(hDib, dwFileSize);
return 0; }
// Завершаем работу приложения case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; }
default: return 0; } }
// Это сообщение приходит при изменении // системной палитры. Наше приложение в ответ // на это сообщение заново реализует свою логическую // палитру и при необходимости перерисовывает окно case WM_PALETTECHANGED: { // Если это не наше окно, передаем управление // обработчику сообщения WM_QUERYNEWPALETTE if (hwnd == (HWND) wParam) break; }
// В ответ на это сообщение приложение должно // реализовать свою логическую палитру и // обновить окно case WM_QUERYNEWPALETTE: { HDC hdc; HPALETTE hOldPal; int nChanged;
// Выбираем логическую палитру в // контекст отображения hdc = GetDC(hwnd);
// При обработке сообщения WM_QUERYNEWPALETTE // палитра выбирается для активного окна, // а при обработке сообщения WM_PALETTECHANGED - // для фонового hOldPal = SelectPalette(hdc, hPal, (msg == WM_QUERYNEWPALETTE) ? FALSE : TRUE);
// Реализуем логическую палитру и выбираем // ее в контекст отображения nChanged = RealizePalette(hdc); SelectPalette(hdc, hOldPal, TRUE);
// Освобождаем контекст отображения ReleaseDC(hwnd, hdc);
// Если были изменения палитры, // перерисовываем окно if(nChanged) InvalidateRect(hwnd, NULL, TRUE);
return nChanged; }
case WM_DESTROY: {
// Удаляем логическую палитру
if(hPal)
DeletePalette(hPal);
PostQuitMessage(0); return 0; }
default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); }
Обработчик сообщения WM_CREATE сбрасывает содержимое переменных, в которых находятся идентификатор открытого bmp-файла, идентификатор загруженного изображения DIB, а также идентификатор палитры:
hfDIBFile = NULL; hDib = NULL; hPal = NULL;
Обработчик сообщения WM_PAINT, рисующий изображение DIB, достаточно прост:
hdc = BeginPaint(hwnd, &ps); if((hDib != NULL) && (DIBType(hDib) == WINRGB_DIB)) { if(hPal) { hOldPal = SelectPalette(hdc, hPal, FALSE); RealizePalette(hdc); } DIBPaint(hdc, 0, 0, hDib); if(hPal) { SelectPalette(hdc, hOldPal, FALSE); } } else { if(hDib) DIBInfo(hDib, dwFileSize); } EndPaint(hwnd, &ps); return 0;
Если загружено изображение DIB, его идентификатор отличен от NULL. В этом случае вызывается функция DIBType, определенная в нашем приложении в файле dib.cpp (листинг 4.8). Эта функция выполняет все необходимые проверки полей структуры заголовка изображения и возвращает тип изображения. Для некомпрессованных изображений DIB в формате Windows возвращается значение WINRGB_DIB.
Если при загрузке bmp-файла выяснилось, что он содержит таблицу цветов, создается палитра, идентификатор которой записывается в переменную hPal. Если содержимое этой переменной отлично от NULL, перед рисованием обработчик сообщения WM_PAINT выбирает палитру в контекст отображения и реализует ее, вызывая функции SelectPalette и RealizePalette.
Далее вызывается функция DIBPaint, определенная в файле dib.cpp, которая рисует изображение DIB. В качестве параметров этой функции передается идентификатор контекста отображения, координаты (x,y) левого верхнего угла прямоугольной области, в которой нужно нарисовать изображение, и идентификатор загруженного изображения DIB.
После этого восстанавливается старая палитра (если были изменения палитры).
Если же было загружено изображение DIB в формате Presentation Manager, вызывается функция DIBInfo, которая выводит на экран диалоговую панель с параметрами этого изображения.
При выборе в меню "File" строки "Open" получает управление обработчик сообщения WM_COMMAND. Этот обработчик вызывает функцию DIBSelectFile, определенную в файле dib.cpp. Функция DIBSelectFile выводит на экран стандартную диалоговую панель "Open" и позволяет вам выбрать для загрузки любой файл. Идентификатор открытого файла записывается в переменную hfDIBFile.
Далее файл читается в память, для чего вызывается функция DIBReadFile, определенная в файле dib.cpp. Функция читает весь файл в заказанный ей глобальный блок памяти, причем перед возвратом управления отмечает этот блок как перемещаемый и возвращает идентификатор блока памяти. Дополнительно она записывает размер файла в байтах в переменную, адрес которой указан ей в качестве второго параметра.
После удачного чтения с помощью функции DIBType определяется тип файла. Если это некомпрессованный файл в формате Windows, вызывается функция DIBCreatePalette, которая проверяет наличие таблицы цветов и при необходимости создает логическую палитру, записывая ее идентификатор в переменную hPal.
Затем для перерисовки окна и отображения загруженного изображения вызывается функция InvalidateRect.
Обработчики сообщений об изменении системной палитры WM_PALETTECHANGED и WM_QUERYNEWPALETTE аналогичны использованным в приложении PALETTE, поэтому мы не будем их описывать еще раз.
Перед завершением работы приложения функция окна удаляет логическую палитру, если она была создана, вызывая макрокоманду DeletePalette.
Идентификаторы строк меню описаны в файле bmpihfo.hpp (листинг 4.7).
Листинг 4.7. Файл bmpinfo/bmpinfo.hpp
#define CM_HELPABOUT 301 #define CM_FILEOPEN 302 #define CM_FILEINFO 303 #define CM_FILEEXIT 304
Все функции, предназначенные для работы с bmp-файлами и изображениями DIB, загруженными в оперативную память, мы вынесли в отдельный файл dib.cpp (листинг4.8).
Листинг 4.8. Файл bmpinfo/dib.cpp
// ----------------------------------------------------- // Функции для работы с файлами в формате DIB // -----------------------------------------------------
#define STRICT #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <mem.h> #pragma hdrstop
#include "dib.hpp"
// ------------------------------- // Функция DIBSelectFile // Выбор DIB-файла // -------------------------------
HFILE DIBSelectFile(void) { // Структура для выбора файла OPENFILENAME ofn;
// Буфер для записи пути к выбранному файлу char szFile[256];
// Буфер для записи имени выбранного файла char szFileTitle[256];
// Фильтр расширений имени файлов char szFilter[256] = "Bitmap Files\0*.bmp;*.dib;*.rle\0Any Files\0*.*\0";
// Идентификатор открываемого файла HFILE hf;
// Инициализация имени выбираемого файла // не нужна, поэтому создаем пустую строку szFile[0] = '\0';
// Записываем нулевые значения во все поля // структуры, которая будет использована для // выбора файла memset(&ofn, 0, sizeof(OPENFILENAME));
// Инициализируем нужные нам поля
// Размер структуры ofn.lStructSize = sizeof(OPENFILENAME);
// Идентификатор окна ofn.hwndOwner = NULL;
// Адрес строки фильтра ofn.lpstrFilter = szFilter;
// Номер позиции выбора ofn.nFilterIndex = 1;
// Адрес буфера для записи пути // выбранного файла ofn.lpstrFile = szFile;
// Размер буфера для записи пути // выбранного файла ofn.nMaxFile = sizeof(szFile);
// Адрес буфера для записи имени // выбранного файла ofn.lpstrFileTitle = szFileTitle;
// Размер буфера для записи имени // выбранного файла ofn.nMaxFileTitle = sizeof(szFileTitle);
// В качестве начального каталога для // поиска выбираем текущий каталог ofn.lpstrInitialDir = NULL;
// Определяем режимы выбора файла ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Выбираем входной файл if (GetOpenFileName(&ofn)) {
// Открываем выбранный файл hf = _lopen(ofn.lpstrFile, OF_READ);
// Возвращаем идентификатор файла return hf; } // При отказе от выбора возвращаем // нулевое значение else return 0; }
// ------------------------------- // Функция DIBReadFile // Чтение DIB-файла // -------------------------------
HDIB DIBReadFile(HFILE hfDIBFile, DWORD *dwFileSize) { // Идентификатор глобального блока // памяти, который будет использован для // чтения файла HDIB hDib;
HCURSOR hCursor; // идентификатор курсора
// Указатель на глобальный блок памяти LPDIB lpBuf;
// Курсор в виде песочных часов hCursor = SetCursor (LoadCursor(NULL, IDC_WAIT));
// Определяем размер файла. Для этого // устанавливаем текущую позицию на // конец файла *dwFileSize = _llseek(hfDIBFile, 0l, 2);
// Устанавливаем текущую позицию // на начало файла _llseek(hfDIBFile, 0l, 0);
// Заказываем глобальный блок памяти, // размер которого равен длине файла hDib = (HDIB)GlobalAlloc(GMEM_FIXED, *dwFileSize); lpBuf = (unsigned char huge *)GlobalLock(hDib);
// Если мало свободной памяти, // возвращаем признак ошибки if(lpBuf == NULL) return(NULL);
// Читаем файл в полученный блок памяти _hread(hfDIBFile, lpBuf, *dwFileSize);
// Восстанавливаем курсор SetCursor (hCursor);
// Расфиксируем память GlobalUnlock(hDib);
// Закрываем файл _lclose(hfDIBFile);
return hDib; }
// ------------------------------- // Функция DIBInfo // Вывод диалоговой панели с информацией // о DIB-файле // -------------------------------
BOOL DIBInfo(HDIB hDib, DWORD dwFileSize) { char szBuf[256], szBuf1[256]; DWORD biSize; LPBITMAPFILEHEADER lpDIBFileHeader; LPBITMAPINFOHEADER lpDIBInfoHeader; LPBITMAPCOREHEADER lpDIBCoreHeader; DWORD bfOffset; BOOL bWDIB; LPDIB lpDIBPtr; int nDIBType; WORD wNumColors;
// Определяем тип битового изображения nDIBType = DIBType(hDib);
if(!nDIBType) // если ошибка, выдаем сообщение { MessageBox(NULL, "Ошибка в формате DIB-файла", "Bitmap Info", MB_OK | MB_ICONHAND); return FALSE; }
// Фиксируем область памяти, в которую загружен DIB lpDIBPtr = (unsigned char huge *)GlobalLock(hDib); if(lpDIBPtr == NULL) return(FALSE);
lpDIBFileHeader = (LPBITMAPFILEHEADER)lpDIBPtr;
// Определяем смещение бит изображения // и размер заголовка bfOffset = lpDIBFileHeader->bfOffBits; biSize = (DWORD)(lpDIBPtr[sizeof(BITMAPFILEHEADER)]);
// Готовим текстовую строку для вывода wsprintf(szBuf, "Размер заголовка, байт:\t%ld\n", biSize); wsprintf(szBuf1, "Размер файла, байт: \t%ld\n", dwFileSize); lstrcat(szBuf, szBuf1); wsprintf(szBuf1, "Смещение изображения, байт:\t%ld\n", bfOffset); lstrcat(szBuf, szBuf1);
// В зависимости от формата DIB (PM или Windows) // выводим различную информацию из заголовка файла if((nDIBType == WINRGB_DIB) (nDIBType == WINRLE4_DIB) (nDIBType == WINRLE8_DIB)) { wsprintf(szBuf1, "\nBMP для Windows\n", biSize); lstrcat(szBuf, szBuf1); lpDIBInfoHeader = (LPBITMAPINFOHEADER)(lpDIBPtr + sizeof(BITMAPFILEHEADER));
wsprintf(szBuf1, "Размер:\t%ldx%ld\n", lpDIBInfoHeader->biWidth, lpDIBInfoHeader->biHeight); lstrcat(szBuf, szBuf1);
wsprintf(szBuf1, "Бит на пиксел:\t%d\n", lpDIBInfoHeader->biBitCount); lstrcat(szBuf, szBuf1);
wNumColors = DIBNumColors(lpDIBPtr); wsprintf(szBuf1, "Таблица цветов:\t%d\n", wNumColors); lstrcat(szBuf, szBuf1);
if(lpDIBInfoHeader->biCompression == BI_RGB) { lstrcat(szBuf, "Без компрессии\n"); } else if(lpDIBInfoHeader->biCompression == BI_RLE4) { lstrcat(szBuf, "Компрессия RLE4\n"); } else if(lpDIBInfoHeader->biCompression == BI_RLE8) { lstrcat(szBuf, "Компрессия RLE8\n"); } }
// Для файлов DIB в формате PM else { wsprintf(szBuf1, "\nBMP для Presentation Manager\n", biSize); lstrcat(szBuf, szBuf1); lpDIBCoreHeader = (LPBITMAPCOREHEADER)(lpDIBPtr + sizeof(BITMAPFILEHEADER));
wsprintf(szBuf1, "Размер:\t%dx%d\n", lpDIBCoreHeader->bcWidth, lpDIBCoreHeader->bcHeight); lstrcat(szBuf, szBuf1);
wsprintf(szBuf1, "Бит на пиксел:\t%d\n", lpDIBCoreHeader->bcBitCount); lstrcat(szBuf, szBuf1); }
MessageBox(NULL, (LPSTR)szBuf, "Bitmap Info", MB_OK | MB_ICONINFORMATION);
GlobalUnlock(hDib); return TRUE; }
// ------------------------------- // Функция DIBType // Определение и проверка формата DIB // -------------------------------
int DIBType(HDIB hDib) { LPBITMAPFILEHEADER lpDIBFileHeader; LPBITMAPINFOHEADER lpih; LPBITMAPCOREHEADER lpch;
DWORD biSize; LPDIB hDIBPtr; int nDIBType;
if(hDib == NULL) // Неправильный идентификатор DIB return(-2);
// Фиксируем память, в которой находится DIB hDIBPtr = (LPDIB)GlobalLock(hDib); if(hDIBPtr == NULL) return(-1);
lpDIBFileHeader = (LPBITMAPFILEHEADER)hDIBPtr;
// Проверяем тип файла if(lpDIBFileHeader->bfType != 0x4d42) { GlobalUnlock(hDib); return 0; }
// Проверяем размер заголовка biSize = (DWORD)(hDIBPtr[sizeof(BITMAPFILEHEADER)]);
if(biSize == sizeof(BITMAPINFOHEADER)) // 40 байт { // Это заголовок DIB в формате Windows lpih = (LPBITMAPINFOHEADER)(hDIBPtr + sizeof(BITMAPFILEHEADER));
// Проверяем основные поля заголовка DIB if((lpih->biPlanes == 1) && ((lpih->biBitCount == 1) (lpih->biBitCount == 4) (lpih->biBitCount == 8) (lpih->biBitCount == 24)) && ((lpih->biCompression == BI_RGB) (lpih->biCompression == BI_RLE4 && lpih->biBitCount == 4) (lpih->biCompression == BI_RLE8 && lpih->biBitCount == 8))) { // Определяем метод компрессии файла if(lpih->biCompression == BI_RGB) nDIBType = WINRGB_DIB; else if(lpih->biCompression == BI_RLE4) nDIBType = WINRLE4_DIB; else if(lpih->biCompression == BI_RLE8) nDIBType = WINRLE8_DIB; else nDIBType = 0; } else nDIBType = 0; }
else if(biSize == sizeof(BITMAPCOREHEADER)) // 12 байт { // Это заголовок DIB в формате Presentation Manager lpch = (LPBITMAPCOREHEADER)(hDIBPtr + sizeof(BITMAPFILEHEADER));
// Проверяем основные поля заголовка DIB if((lpch->bcPlanes == 1) && (lpch->bcBitCount == 1 lpch->bcBitCount == 4 lpch->bcBitCount == 8 lpch->bcBitCount == 24)) { nDIBType = PM_DIB; } else nDIBType = 0; }
else nDIBType = 0;
GlobalUnlock(hDib);
// Возвращаем тип файла или признак ошибки return nDIBType; }
// ------------------------------- // Функция DIBNumColors // Определение размера палитры // -------------------------------
WORD DIBNumColors(LPDIB lpDib) { DWORD dwColorUsed; LPBITMAPINFOHEADER lpih;
lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER));
// Количество цветов dwColorUsed = lpih->biClrUsed;
// Если используется палитра уменьшенного размера, // возвращаем нужный размер if(dwColorUsed) return((WORD)dwColorUsed);
// Если количество использованных цветов не указано, // вычисляем стандартный размер палитры исходя из // количества бит, определяющих цвет пиксела switch(lpih->biBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; // палитра не используется } }
// ------------------------------- // Функция DIBHeight // Определение высоты DIB в пикселах // -------------------------------
WORD DIBHeight(LPDIB lpDib) { LPBITMAPINFOHEADER lpih;
lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER)); return lpih->biHeight; }
// ------------------------------- // Функция DIBWidth // Определение ширины DIB в пикселах // -------------------------------
WORD DIBWidth(LPDIB lpDib) { LPBITMAPINFOHEADER lpih;
lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER)); return lpih->biWidth; }
// ------------------------------- // Функция DIBFindBits // Определение адреса массива бит изображения // -------------------------------
LPSTR DIBFindBits(LPDIB lpDib) { LPBITMAPFILEHEADER lpfh; LPBITMAPINFOHEADER lpih;
lpfh = (LPBITMAPFILEHEADER)lpDib;
// Используем значение, указанное в заголовке // файла ( если оно не равно нулю) if(lpfh->bfOffBits) return((LPSTR)lpfh + lpfh->bfOffBits);
// Вычисляем адрес исходя из размеров заголовков и // таблицы цветов lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER));
return((LPSTR)lpih + lpih->biSize + (DWORD)(DIBNumColors(lpDib) * sizeof(RGBQUAD))); }
// ------------------------------- // Функция DIBPaint // Рисование DIB при помощи функции StretchDIBits // -------------------------------
BOOL DIBPaint(HDC hdc, int x, int y, HDIB hDib) { HBITMAP hbmp; HDC hMemDC; WORD wHeight, wWidth; LPDIB lpDib; LPBITMAPINFOHEADER lpih;
lpDib = (LPDIB)GlobalLock(hDib); if(lpDib == NULL) return(-1);
lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER));
// Определяем размеры DIB wHeight = lpih->biHeight; wWidth = lpih->biWidth;
// Рисуем DIB без масштабирования StretchDIBits(hdc, x, y, wWidth, wHeight, 0, 0, wWidth, wHeight, DIBFindBits(lpDib), (LPBITMAPINFO)lpih, DIB_RGB_COLORS, SRCCOPY);
GlobalUnlock(hDib);
return TRUE; }
// ------------------------------- // Функция DIBPaintBlt // Рисование DIB при помощи функции BitBlt // -------------------------------
BOOL DIBPaintBlt(HDC hdc, int x, int y, HDIB hDib) { HBITMAP hbmp; HDC hMemDC; WORD wHeight, wWidth; LPDIB lpDib; LPBITMAPINFOHEADER lpih;
lpDib = (LPDIB)GlobalLock(hDib); if(lpDib == NULL) return(-1);
lpih = (LPBITMAPINFOHEADER)(lpDib + sizeof(BITMAPFILEHEADER));
wHeight = lpih->biHeight; wWidth = lpih->biWidth;
// Создаем совместимое битовое изображение hbmp = CreateCompatibleBitmap(hdc, wWidth, wHeight);
// Создаем совместимый контекст памяти hMemDC = CreateCompatibleDC(hdc);
// Преобразуем DIB в DDB SetDIBits(hdc, hbmp, 0, wHeight, DIBFindBits(lpDib), (LPBITMAPINFO)lpih, DIB_RGB_COLORS);
// Выбираем DDB в контекст отображения hbmp = (HBITMAP)SelectObject(hMemDC, hbmp);
// Рисуем DDB BitBlt(hdc, x, y, wWidth, wHeight, hMemDC, 0, 0, SRCCOPY);
// Удаляем контекст памяти DeleteObject(SelectObject(hMemDC, hbmp)); DeleteDC(hMemDC);
GlobalUnlock(hDib); return TRUE; }
// ------------------------------- // Функция DIBCreatePalette // Создаем палитру на базе таблицы цветов DIB // -------------------------------
HPALETTE DIBCreatePalette(HDIB hDib) { LPLOGPALETTE lpPal; HPALETTE hPal = NULL; HANDLE hLogPal; int i, wNumColors; LPSTR lpbi; LPBITMAPINFO lpbmi;
if (!hDib) return NULL;
lpbi = (LPSTR)GlobalLock(hDib); lpbmi = (LPBITMAPINFO)(lpbi + sizeof(BITMAPFILEHEADER));
// Определяем размер таблицы цветов wNumColors = DIBNumColors(lpbi);
// Если в DIB есть таблица цветов, создаем палитру if (wNumColors) { // Заказываем память для палитры hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * wNumColors);
if (!hLogPal) { GlobalUnlock(hDib); return NULL; }
// Получаем указатель на палитру lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
// Заполняем заголовок lpPal->palVersion = 0x300; lpPal->palNumEntries = wNumColors;
// Заполняем палитру for (i = 0; i < wNumColors; i++) { lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0; }
// Создаем палитру hPal = CreatePalette(lpPal); if (!hPal) { GlobalUnlock(hLogPal); GlobalFree(hLogPal); return NULL; }
GlobalUnlock(hLogPal); GlobalFree(hLogPal); }
GlobalUnlock(hDib);
// Возвращаем идентификатор созданной палитры return hPal; }
Опишем функции, определенные в файле dib.cpp.