Загрузка независимых от устройства битмапов
Формат заголовка файла одинаков для всех версий битмапов; он описывается структурой BITMAPFILEHEADER: typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; Поле bfType, должно быть содержать две буквы "BM" (значение 0x4D42). Поле bfSize указывает полный размер файла, включая этот заголовок. Обратите внимание на то, что размер задается двойным словом, так как может существенно превышать 64K. Например битмап 1280x1024, 24 бита/пиксель имеет размер более 3M. Вообще говоря, это поле может быть не заполнено; хотя и крайне редко, но может даже оказаться, что там указана некорректная величина, вместо правильного размера или 0. По крайней мере для битмапов OS/2 в поле bfSize может оказаться величина, равная размеру заголовка файла плюс заголовок битмапа (26). Во всех случаях лучше исходить не из этой величины, а из реального размера файла. Поля bfReserved1 и bfReserved2 оба содержат 0. По крайней мере так считает Microsoft. В битмапах OS/2 часто эти поля содержат ненулевые данные. Поле bfOffBits указывает адрес, с которого в данном файле размещаются собственно данные изображения. Этим полем удобно пользоваться для получения размера заголовка битмапа и данных о его цветах, а заодно для вычисления адреса начала данных изображения. Так, благодаря наличию поля bfOffBits, можно сформулировать универсальный алгоритм загрузки битмапа в память, не зависящий от версии битмапа и его характеристик. В этом примере мы будем ориентироваться на работу с функциями Windows API, что позволяет сделать более компактный, переносимый код, помимо этого введем дополнительную структуру, описывающую DIB. Она будет удобна по двум причинам — во–первых, после загрузки DIB удобно возвращать два указателя, которые могут понадобиться в дальнейшем, плюс хендл блока памяти, содержащего битмап; все это проще хранить в одной структуре. Во–вторых, эту же структуру мы сможем использовать еще раз, когда рассмотрим загрузку битмапов из ресурсов приложения. Подробнее обо всех указателях и их типах — см. в разделе “Заголовок независимого от устройства битмапа”.
#define STRICT #include <windows.h> #include <windowsx.h> // описываем структуру, содержащую информацию о битмапе typedef struct _DIB { HGLOBAL hglbDib; // хендл блока памяти или ресурса LPBITMAPINFOHEADER lpDibHdr; // указатель на заголовок битмапа LPSTR lpImage; // указатель на изображение UINT uDibFlags; // флаг 1-загружен из файла, 2-из ресурса } FAR* LP_DIB; #define DIB_FILE 1 #define DIB_RESOURCE 2 #define DIB_SIGNATURE 0x4D42 #ifdef __NT__ #define _memcpy_ (to,from,sz) CopyMemory ((LPVOID) (to), (LPVOID) (from), (sz)) #else #define _memcpy_ (to,from,sz) hmemcpy ((void huge*) (to), (void huge*) (from), (sz)) #endif BOOL LoadDIBfromFile (LP_DIB lpDib, LPSTR lpszFileName) {HFILE hFile; DWORD dwSize; BITMAPFILEHEADER bmfh; // инициализируем возвращаемые данные: lpDib->hglbDib = NULL; lpDib->lpDibHdr = (LPBITMAPINFOHEADER)NULL; lpDib->lpImage = (LPSTR)NULL; lpDib->uDibFlags = 0; // открываем файл с битмапом для чтения hFile = _lopen (lpszFileName, READ); if (hFile == HFILE_ERROR) return FALSE; // определяем размер упакованного битмапа dwSize = _llseek (hFile, 0L, 2); _llseek (hFile, 0L, 0); if (dwSize >= sizeof (bmhf)) dwSize -= sizeof (bmhf); // выделяем блок для хранения упакованного битмапа lpDib->lpDibHdr = (LPBITMAPINFOHEADER)GlobalAllocPtr (GHND, dwSize); if (lpDib->lpDibHdr!= (LPBITMAPINFOHEADER)NULL) { // считываем заголовок файла if ((_lread (hFile, &bmhf, sizeof (bmhf)) == sizeof (bmhf)) && (bmhf.bfType == DIB_SIGNATURE)) { // если заголовок успешно считан, считываем сам битмап if (_hread (hFile, lpDib->lpDibHdr, dwSize) == dwSize) { // и устанавливаем нужные поля структуры _DIB: lpDib->hglbDib = GlobalPtrHandle (lpDib->lpDibHdr); lpDib->lpImage = (LPSTR) ( (char huge*) (lpDib->lpDibHdr) + bmhf.bfOffBits - sizeof (bmhf)); lpDib->uDibFlags = DIB_FILE;}} // если где-то возникла ошибка - освобождаем память if (lpDib->uDibFlags == 0) { GlobalFreePtr (lpDib->lpDibHdr); lpDib->lpDibHdr = (LPBITMAPINFOHEADER)NULL;}} _lclose (hFile); return lpDib->uDibFlags? TRUE: FALSE;} Следует обратить внимание на то, что в этой процедуре основная часть кода выполняет проверки или связана с несколько избыточным описанием структуры _DIB; в частных случаях вся процедура может свестись к выполнению 3х–4х функций.
По сути близкий к этому случай может быть связан с загрузкой независимых от устройства битмапов из ресурсов приложения. При рассмотрении зависимых от устройства битмапов было отмечено, что функция LoadBitmap, загружающая битмап из ресурсов приложения, возвращает зависимый от устройства битмап, предназначенный для воспроизведения на дисплее. Это может быть неудобно, если битмап должен отображаться, скажем, на принтере. По счастью в ресурсы приложения включается непосредственно независимый от устройства битмап, что позволяет получить к нему доступ с помощью функций FindResource и LoadResource. В результате вы получите указатель на блок памяти, содержащий целиком образ файла битмапа, включая структуру BITMAPFILEHEADER. Останется только вычислить адрес начала данных изображения и адрес информации о битмапе: // включаемые заголовки и описание структуры _DIB - см. в предыдущем примере BOOL LoadDIBfromResources (LP_DIB lpDib, HINSTANCE hInstance, LPSTR lpszResName) {LPBITMAPFILEHEADER lpbmfh; HRSRC hresDib; // инициализируем возвращаемые данные: lpDib->hglbDib = NULL; lpDib->lpDibHdr = (LPBITMAPINFOHEADER)NULL; lpDib->lpImage = (LPSTR)NULL; lpDib->uDibFlags = 0; // ищем нужный ресурс hresDib = FindResource (hInstance, lpszResName, RT_BITMAP); if (!hresDib) return FALSE; // ресурс найден, получаем его хендл lpDib->hglbDib = LoadResource (hInstance, hresDib); if (! (lpDib->hglbDib)) return FALSE; // получаем указатель на загруженный ресурс lpbmfh = (LPBITMAPFILEHEADER)LockResource (lpDib->hglbDib); if (lpbmfh!= (LPBITMAPFILEHEADER)NULL) { // заполняем остальные поля структуры _DIB: lpDib->lpDibHdr = (LPBITMAPINFOHEADER) (lpbmfh + 1); lpDib->lpImage = (char FAR*) (lpbmfh) + bmhf.bfOffBits; lpDib->uDibFlags = DIB_RESOURCE;} if (lpDib->uDibFlags == 0) { #ifndef __NT__ FreeResource (lpDib->hglbDib); #endif lpDib->hglbDib = NULL;} return lpDib->uDibFlags? TRUE: FALSE;} Заканчивая рассмотрение функций для загрузки независимых от устройства битмапов из файла или из ресурса приложения, приведем еще одну функцию, освобождающую выделенные ресурсы. Необходимость в этой функции возникает, как только вводится собственная структура _DIB, в которой содержатся хендлы и указатели на выделяемые ресурсы разного типа (блок памяти или ресурс приложения). BOOL FreeDIB (LP_DIB lpDib) {BOOL fResult = FALSE; switch (lpDib->uDibFlags) {
case DIB_FILE: if (lpDib->lpDibHdr) GlobalFreePtr (lpDib->lpDibHdr); fResult = TRUE; break; case DIB_RESOURCE: #ifndef __NT__ if (lpDib->hglbDib) { UnlockResource (lpDib->hglbDib); // для NT не требуется FreeResource (lpDib->hglbDib); // для NT не требуется} #endif fResult = TRUE; break; default: break;} // инициализируем структуру _DIB: lpDib->hglbDib = NULL; lpDib->lpDibHdr = (LPBITMAPINFOHEADER)NULL; lpDib->lpImage = (LPSTR)NULL; lpDib->uDibFlags = 0; return fResult;}
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|