16.3.1 调色板和紧凑DIB
(1)对于16、24、32位的DIB,没有颜色表,就不必创建调色板。但在8位视频模式下,只会用标准的20种保留色来显示。由DIB颜色表创建的调色板被称为“原生调色板”
(2)dwPixel =PackedDibGetPixel(pPackedDib,x,y),当这类函数多次调用时会使程序变慢。
(3)很多函数,需要对OS/2兼容DIB作不同处理。
【ShowDib3程序】——原生(Native)调色板
效果图
//PackedDIB.h文件
/*------------------------------------------------------------------ PACKEDDIB.H -- Header file for PACKDIB.C (c) Charles Petzold,1998 ------------------------------------------------------------------*/ #pragma once #include <windows.h> BITMAPINFO* PackedDibLoad(PTSTR szFileName); int PackedDibGetWidth(BITMAPINFO* pPackedDib); int PackedDibGetHeight(BITMAPINFO* pPackedDib); int PackedDibGetBitCount(BITMAPINFO* pPackedDib); int PackedDibGetRowLength(BITMAPINFO* pPackedDib); int PackedDibGetInfoHeaderSize(BITMAPINFO* pPackedDib); int PackedDibGetColorsUsed(BITMAPINFO* pPackedDib); int PackedDibGetNumColors(BITMAPINFO* pPackedDib); RGBQUAD* PackedDibGetColorTableSize(BITMAPINFO* pPackedDib); RGBQUAD* PackedDibGetColorTableEntry(BITMAPINFO*, int i); BYTE* PackedDibGetBitsPtr(BITMAPINFO* pPackedDib); int PackedDibGetBitsSize(BITMAPINFO* pPackedDib); HPALETTE PackedDibCreatePalette(BITMAPINFO* pPackedDib);
//PackedDIB.c文件
/*----------------------------------------------------------------- PACKEDDIB.C -- Routines for using packed DIBs (c) Charles Petzold,1998 -----------------------------------------------------------------*/ #include <windows.h> /*--------------------------------------------------------- PackedDibLoad:将DIB文件作以紧缩型格式加载进内存中 ---------------------------------------------------------*/ BITMAPINFO* PackedDibLoad(PTSTR szFileName) { BITMAPFILEHEADER bmfh; BITMAPINFO* pbmi; HANDLE hFile; BOOL bSuccess; DWORD dwBytesRead, dwPackedDibSize; //打开文件,指定读和写属性 hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) return NULL; //读取文件头 bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL); if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER)) || (bmfh.bfType != *(WORD*)"BM")) { CloseHandle(hFile); return NULL; } //计算紧缩型DIB的大小 dwPackedDibSize = bmfh.bfSize - sizeof(BITMAPFILEHEADER); //文件大小减小文件头的大小 //分配内存,并读入信息(含信息头与像素数据) pbmi = malloc(dwPackedDibSize); bSuccess = ReadFile(hFile, pbmi, dwPackedDibSize, &dwBytesRead, NULL); CloseHandle(hFile); if (!bSuccess || (dwPackedDibSize != dwBytesRead)) { free(pbmi); return NULL; } return pbmi; } /*---------------------------------------------- 获取紧缩型DIB信息的函数 ----------------------------------------------*/ int PackedDibGetWidth(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcWidth; else return pPackedDib->bmiHeader.biWidth; } int PackedDibGetHeight(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcHeight; else return abs(pPackedDib->bmiHeader.biHeight); //取绝对值 } int PackedDibGetBitCount(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcBitCount; else return pPackedDib->bmiHeader.biBitCount; } int PackedDibGetRowLength(BITMAPINFO* pPackedDib) { return ((PackedDibGetWidth(pPackedDib)*PackedDibGetBitCount(pPackedDib) + 31) & ~31) >> 3; } /*----------------------------------------------------------- 获取DIB信息头大小(含可能的颜色遮罩)——单位:字节 -----------------------------------------------------------*/ int PackedDibGetInfoHeaderSize(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcSize; else if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) return pPackedDib->bmiHeader.biSize + (pPackedDib->bmiHeader.biCompression == BI_BITFIELDS ? 12 : 0); //颜色遮罩 else return pPackedDib->bmiHeader.biSize; } /*------------------------------------------------------------- PackedDibGetColorsUsed:返回信息头中的bClrUse字段,表示用到的颜色数 如果没有颜色表,则该值为0 -------------------------------------------------------------*/ int PackedDibGetColorsUsed(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return 0; else return pPackedDib->bmiHeader.biClrUsed; } /*------------------------------------------------------------------ PackedDibGetNumColors:颜色表中实际的条目数 ------------------------------------------------------------------*/ int PackedDibGetNumColors(BITMAPINFO* pPackedDib) { int iNumColors; iNumColors = PackedDibGetColorsUsed(pPackedDib); //iNumColor等于0时,说明实际使用的颜色由biBitCount计算出来 //16、24、32位时获得的iNumColors的一般为0 if (iNumColors == 0 && (PackedDibGetBitCount(pPackedDib) < 16)) iNumColors = 1 << (PackedDibGetBitCount(pPackedDib)); //2^biBitCount个 return iNumColors; } int PackedDibGetColorTableSize(BITMAPINFO* pPackedDib) { if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return PackedDibGetNumColors(pPackedDib)*sizeof(RGBTRIPLE); else return PackedDibGetNumColors(pPackedDib)*sizeof(RGBQUAD); } RGBQUAD* PackedDibGetColorTablePtr(BITMAPINFO* pPackedDib) { if (PackedDibGetNumColors(pPackedDib) == 0) return NULL; return (RGBQUAD*)(((BYTE*)pPackedDib) + PackedDibGetInfoHeaderSize(pPackedDib)); } RGBQUAD* PackedDibGetColorTableEntry(BITMAPINFO* pPackedDib, int i) { if (PackedDibGetNumColors(pPackedDib) == 0) return NULL; if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) return (RGBQUAD*)((RGBTRIPLE*)PackedDibGetColorTablePtr(pPackedDib) + i); else return PackedDibGetColorTablePtr(pPackedDib) + i; } /*---------------------------------- PackedDibGetBitsPtr:获取像素数据的指针 ----------------------------------*/ BYTE* PackedDibGetBitsPtr(BITMAPINFO* pPackedDib) { return (BYTE*)(pPackedDib)+PackedDibGetInfoHeaderSize(pPackedDib) + PackedDibGetColorTableSize(pPackedDib); } /*----------------------------------------------------------------------- PackedDibGetBitsSize: 自动计算像素数据的空间大小(即使biSizeImage字段没有显式的指定) -----------------------------------------------------------------------*/ int PackedDibGetBitsSize(BITMAPINFO* pPackedDib) { if ((pPackedDib->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) && (pPackedDib->bmiHeader.biSizeImage != 0)) return pPackedDib->bmiHeader.biSizeImage; return PackedDibGetHeight(pPackedDib)* PackedDibGetRowLength(pPackedDib); } /*---------------------------------------------------------------- PackedDibCreatePalette:从紧缩型DIB中创建逻辑调色板 ----------------------------------------------------------------*/ HPALETTE PackedDibCreatePalette(BITMAPINFO* pPackedDib) { HPALETTE hPalette; int i, iNumColors; LOGPALETTE* plp; RGBQUAD* prgb; iNumColors = PackedDibGetNumColors(pPackedDib); if (0 == iNumColors) //16、24、32位时获得的iNumColors的一般为0 return NULL; plp = malloc(sizeof(LOGPALETTE)*(iNumColors - 1)*sizeof(PALETTEENTRY)); plp->palVersion = 0x0300; plp->palNumEntries = iNumColors; for (i = 0; i < iNumColors; i++) { prgb = PackedDibGetColorTableEntry(pPackedDib, i); plp->palPalEntry[i].peRed = prgb->rgbRed; plp->palPalEntry[i].peGreen = prgb->rgbGreen; plp->palPalEntry[i].peBlue = prgb->rgbBlue; plp->palPalEntry[i].peFlags = 0; } hPalette = CreatePalette(plp); free(plp); return hPalette; }
//ShowDib3.c
/*------------------------------------------------------------ SHOWDIB3.C -- Displays DIB with native palette (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #include "PackedDIB.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static TCHAR szAppName[] = TEXT("ShowDib3"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASSEX wndclass; HACCEL hAccel; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Show DIB #3:Native Palette"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BITMAPINFO* pPackedDib; static HPALETTE hPalette; HDC hdc; PAINTSTRUCT ps; static OPENFILENAME ofn; static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP) *.bmp ") TEXT("All Files(*.*) *.* "); static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static int cxClient, cyClient; switch (message) { case WM_CREATE: memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = szTitleName; ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = TEXT("bmp"); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: //显示打开文件对话框 if (!GetOpenFileName(&ofn)) return 0; //如果图像己经存在,则释放内存 if (pPackedDib) { free(pPackedDib); pPackedDib = NULL; } //如果逻辑调色板己经存在,则删除 if (hPalette) { DeleteObject(hPalette); hPalette = NULL; } //加载紧缩型DIB到内存中 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); pPackedDib = PackedDibLoad(szFileName); ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); if (pPackedDib) { //创建逻辑调色板 hPalette = PackedDibCreatePalette(pPackedDib); } else { MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0); } InvalidateRect(hwnd, NULL, TRUE); return 0; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if (hPalette) //16、24、32位的DIB没有颜色表,在8位视频模式下,只显示20种保留色 { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } if (pPackedDib) { SetDIBitsToDevice(hdc, 0, 0, PackedDibGetWidth(pPackedDib), PackedDibGetHeight(pPackedDib), 0, 0, 0, PackedDibGetHeight(pPackedDib), PackedDibGetBitsPtr(pPackedDib), pPackedDib, DIB_RGB_COLORS); } EndPaint(hwnd, &ps); return 0; case WM_QUERYNEWPALETTE: if (!hPalette) return FALSE; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); InvalidateRect(hwnd, NULL, TRUE); ReleaseDC(hwnd, hdc); return TRUE; case WM_PALETTECHANGED: if (!hPalette || (HWND)wParam == hwnd) break; hdc = GetDC(hwnd); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); UpdateColors(hdc); ReleaseDC(hwnd, hdc); break; case WM_DESTROY: if (pPackedDib) free(pPackedDib); if (hPalette) DeleteObject(hPalette); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.c
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 ShowDIB3.rc 使用 // #define IDM_FILE_OPEN 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//ShowDib3.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "