調色盤和真實世界圖像

来源:百度文库 编辑:神马文学网 时间:2024/05/01 05:47:04
 

調色盤和真實世界圖像
 

當然,儘管我們已經完成了許多有趣的事:連續顯示色彩的網底、做了調色盤動畫,但調色盤管理器的真正目的是允許在8位元顯示模式下顯示真實世界中的圖像。對於本章的其餘部分,我們正好研究一下。正如您所期望的,在使用packed DIB、GDI點陣圖物件和DIB區塊時,必須按照不同的方法來使用調色盤。下面的六個程式闡明了用調色盤來處理點陣圖的各種技術。

調色盤和packed DIB
 

下面三個程式,有助於我們建立處理packed DIB記憶體塊的一系列函式。這些函式都在程式16-12所示的PACKEDIB檔案中。

 程式16-12  PACKEDIB檔案PACKEDIB.H/*-------------------------------------------------------------------------PACKEDIB.H -- Header file for PACKEDIB.C(c) Charles Petzold, 1998--------------------------------------------------------------------------*/#include 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) ;int PackedDibGetColorTableSize (BITMAPINFO * pPackedDib) ;RGBQUAD * PackedDibGetColorTablePtr (BITMAPINFO * pPackedDib) ;RGBQUAD * PackedDibGetColorTableEntry (BITMAPINFO * pPackedDib, int i) ;BYTE * PackedDibGetBitsPtr (BITMAPINFO * pPackedDib) ;int PackedDibGetBitsSize (BITMAPINFO * pPackedDib) ;HPALETTE PackedDibCreatePalette (BITMAPINFO * pPackedDib) ;
PACKEDIB.C/*-------------------------------------------------------------------------PACKEDIB.C -- Routines for using packed DIBs(c) Charles Petzold, 1998---------------------------------------------------------------------------*/#include /*---------------------------------------------------------------------------PackedDibLoad: Load DIB File as Packed-Dib Memory Block----------------------------------------------------------------------------*/BITMAPINFO * PackedDibLoad (PTSTR szFileName){BITMAPFILEHEADER bmfh ;BITMAPINFO     *pbmi ;BOOL             bSuccess ;DWORD            dwPackedDibSize, dwBytesRead ;HANDLE           hFile ;// Open the file: read access, prohibit write accesshFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ;if (hFile == INVALID_HANDLE_VALUE)return NULL ;// Read in the BITMAPFILEHEADERbSuccess = ReadFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER),&dwBytesRead, NULL) ;if (!bSuccess || (dwBytesRead != sizeof (BITMAPFILEHEADER))|| (bmfh.bfType != * (WORD *) "BM")){CloseHandle (hFile) ;return NULL ;}// Allocate memory for the packed DIB & read it indwPackedDibSize = bmfh.bfSize - sizeof (BITMAPFILEHEADER) ;pbmi = malloc (dwPackedDibSize) ;bSuccess = ReadFile (hFile, pbmi, dwPackedDibSize, &dwBytesRead, NULL) ;CloseHandle (hFile) ;if (!bSuccess || (dwBytesRead != dwPackedDibSize)){free (pbmi) ;return NULL ;}return pbmi ;}/*--------------------------------------------------------------------------Functions to get information from packed DIB----------------------------------------------------------------------------*/int PackedDibGetWidth (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return ((PBITMAPCOREINFO)pPackedDib)->bmciHeader.bcWidth ;elsereturn pPackedDib->bmiHeader.biWidth ;}int PackedDibGetHeight (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return ((PBITMAPCOREINFO)pPackedDib)->bmciHeader.bcHeight ;elsereturn abs (pPackedDib->bmiHeader.biHeight) ;}int PackedDibGetBitCount (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return ((PBITMAPCOREINFO)pPackedDib)->bmciHeader.bcBitCount ;elsereturn pPackedDib->bmiHeader.biBitCount ;}int PackedDibGetRowLength (BITMAPINFO * pPackedDib){return ((PackedDibGetWidth (pPackedDib) *PackedDibGetBitCount (pPackedDib) + 31) & ~31) >> 3 ;}/*---------------------------------------------------------------------------PackedDibGetInfoHeaderSize includes possible color masks!----------------------------------------------------------------------------*/int PackedDibGetInfoHeaderSize (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return ((PBITMAPCOREINFO)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 returns value in information header;could be 0 to indicate non-truncated color table!----------------------------------------------------------------------------*/int PackedDibGetColorsUsed (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return 0 ;elsereturn pPackedDib->bmiHeader.biClrUsed ;}/*----------------------------------------------------------------------------PackedDibGetNumColors is actual number of entries in color table-----------------------------------------------------------------------------*/int PackedDibGetNumColors (BITMAPINFO * pPackedDib){int iNumColors ;iNumColors = PackedDibGetColorsUsed (pPackedDib) ;if (iNumColors == 0 && PackedDibGetBitCount (pPackedDib) < 16)iNumColors =1 << PackedDibGetBitCount (pPackedDib) ;return iNumColors ;}int PackedDibGetColorTableSize (BITMAPINFO * pPackedDib){if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return PackedDibGetNumColors (pPackedDib) * sizeof (RGBTRIPLE) ;elsereturn PackedDibGetNumColors (pPackedDib) * sizeof (RGBQUAD) ;}RGBQUAD * PackedDibGetColorTablePtr (BITMAPINFO * pPackedDib){if (PackedDibGetNumColors (pPackedDib) == 0)return 0 ;return (RGBQUAD *) (((BYTE *)pPackedDib) +PackedDibGetInfoHeaderSize (pPackedDib)) ;}RGBQUAD * PackedDibGetColorTableEntry (BITMAPINFO * pPackedDib, int i){if (PackedDibGetNumColors (pPackedDib) == 0)return 0 ;if (pPackedDib->bmiHeader.biSize == sizeof (BITMAPCOREHEADER))return (RGBQUAD *)(((RGBTRIPLE *) PackedDibGetColorTablePtr (pPackedDib)) + i) ;elsereturn PackedDibGetColorTablePtr (pPackedDib) + i ;}/*--------------------------------------------------------------------------PackedDibGetBitsPtr finally!----------------------------------------------------------------------------*/BYTE * PackedDibGetBitsPtr (BITMAPINFO * pPackedDib){return ((BYTE *) pPackedDib)+PackedDibGetInfoHeaderSize (pPackedDib) +PackedDibGetColorTableSize (pPackedDib) ;}/*-----------------------------------------------------------------------------PackedDibGetBitsSize can be calculated from the height and row lengthif it's not explicitly in the biSizeImage field-----------------------------------------------------------------------------*/int PackedDibGetBitsSize (BITMAPINFO * pPackedDib){if ((pPackedDib->bmiHeader.biSize != sizeof (BITMAPCOREHEADER)) &&(pPackedDib->bmiHeader.biSizeImage != 0))return pPackedDib->bmiHeader.biSizeImage ;return PackedDibGetHeight (pPackedDib) *PackedDibGetRowLength (pPackedDib) ;}/*---------------------------------------------------------------------------PackedDibCreatePalette creates logical palette from PackedDib-----------------------------------------------------------------------------*/HPALETTE PackedDibCreatePalette (BITMAPINFO * pPackedDib){HPALETTE   hPalette ;int        i, iNumColors ;LOGPALETTE * plp ;RGBQUAD    * prgb ;if (0 == ( iNumColors = PackedDibGetNumColors (pPackedDib)))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 ;}

第一個函式是PackedDibLoad,它將唯一的參數作為檔案名,並傳回指向記憶體中packed DIB的指標。其他所有函式都將這個packed DIB指標作為它們的第一個參數並傳回有關DIB的資訊。這些函式按「由下而上」順序排列到檔案中。每個函式都使用從前面函式獲得的資訊。

我不傾向於說這是在處理packed DIB時有用的「完整」函式集。而且,我也不想彙編一個真正的擴展集,因為我不認為這是處理packed DIB的一個好方法。在寫類似下面的函式時,您會很明顯地發現這一點:

dwPixel = PackedDibGetPixel (pPackedDib, x, y) ;

這種函式包括太多的巢狀函式呼叫,以致於效率非常低而且很慢。本章的後面將討論一種我認為更好的方法。

另外,您將注意到,其中許多函式都需要對OS/2相容的DIB採取不同的處理程序;這樣,函式將頻繁地檢查BITMAPINFO結構的第一個欄位是否與BITMAPCOREHEADER結構的大小相同。

特別注意最後一個函式PackedDibCreatePalette。這個函式用DIB中的顏色表來建立調色盤。如果DIB中沒有顏色表(這意味著DIB的每圖素有16、24或32位元),那麼就不建立調色盤。我們有時會將從DIB顏色表建立的調色盤稱為DIB 自己的 調色盤。

PACKEDIB檔案都放在SHOWDIB3,如程式16-13所示。

 程式16-13  SHOWDIB3SHOWDIB3.C/*--------------------------------------------------------------------------SHOWDIB3.C -- Displays DIB with native palette(c) Charles Petzold, 1998----------------------------------------------------------------------------*/#include #include "PackeDib.h"#include "resource.h"LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;TCHAR szAppName[] = TEXT ("ShowDib3") ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){HWND     hwnd ;MSG      msg ;WNDCLASS wndclass ;wndclass.style         = CS_HREDRAW | CS_VREDRAW ;wndclass.lpfnWndProc   = WndProc ;wndclass.cbClsExtra    = 0 ;wndclass.cbWndExtra    = 0 ;wndclass.hInstance     = hInstance ;wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;wndclass.lpszMenuName  = szAppName ;wndclass.lpszClassName = szAppName ;if (!RegisterClass (&wndclass)){MessageBox (NULL, TEXT ("This program requires Windows NT!"),szAppName, MB_ICONERROR) ;return 0 ;}hwnd = CreateWindow (szAppName, TEXT ("Show DIB #3: Native Palette"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL) ;ShowWindow (hwnd, iCmdShow) ;UpdateWindow (hwnd) ;while (GetMessage (&msg, NULL, 0, 0)){TranslateMessage (&msg) ;DispatchMessage (&msg) ;}return msg.wParam ;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam){static BITMAPINFO *pPackedDib ;static HPALETTE     hPalette ;static int          cxClient, cyClient ;static OPENFILENAME ofn ;static TCHAR        szFileName [MAX_PATH], szTitleName [MAX_PATH] ;static TCHAR        szFilter[] = TEXT ("Bitmap Files (*.BMP)\0*.bmp\0")TEXT ("All Files (*.*)\0*.*\0\0") ;HDC                 hdc ;PAINTSTRUCT         ps ;switch (message){case WM_CREATE:ofn.lStructSize       = sizeof (OPENFILENAME) ;ofn.hwndOwner         = hwnd ;ofn.hInstance         = NULL ;ofn.lpstrFilter      = szFilter ;ofn.lpstrCustomFilter = NULL ;ofn.nMaxCustFilter    = 0 ;ofn.nFilterIndex      = 0 ;ofn.lpstrFile         = szFileName ;ofn.nMaxFile          = MAX_PATH ;ofn.lpstrFileTitle    = szTitleName ;ofn.nMaxFileTitle     = MAX_PATH ;ofn.lpstrInitialDir   = NULL ;ofn.lpstrTitle        = NULL ;ofn.Flags             = 0 ;ofn.nFileOffset       = 0 ;ofn.nFileExtension    = 0 ;ofn.lpstrDefExt       = TEXT ("bmp") ;ofn.lCustData         = 0 ;ofn.lpfnHook          = NULL ;ofn.lpTemplateName    = NULL ;return 0 ;case WM_SIZE:cxClient = LOWORD (lParam) ;cyClient = HIWORD (lParam) ;return 0 ;case WM_COMMAND:switch (LOWORD (wParam)){case IDM_FILE_OPEN:// Show the File Open dialog boxif (!GetOpenFileName (&ofn))return 0 ;// If there's an existing packed DIB, free the memoryif (pPackedDib){free (pPackedDib) ;pPackedDib = NULL ;}// If there's an existing logical palette, delete itif (hPalette){DeleteObject (hPalette) ;hPalette = NULL ;}// Load the packed DIB into memorySetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;pPackedDib = PackedDibLoad (szFileName) ;ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;if (pPackedDib){// Create the palette from the DIB color tablehPalette = 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){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) ;}
 SHOWDIB3.RC (摘錄)//Microsoft Developer Studio generated resource script.#include "resource.h"#include "afxres.h"/////////////////////////////////////////////////////////////////////////////// MenuSHOWDIB3 MENU DISCARDABLEBEGINPOPUP "&File"BEGINMENUITEM "&Open",  IDM_FILE_OPENENDEND
 RESOURCE.H (摘錄)// Microsoft Developer Studio generated include file.// Used by ShowDib3.rc#define IDM_FILE_OPEN         40001

SHOWDIB3中的視窗訊息處理程式將packed DIB指標作為靜態變數來維護,視窗訊息處理程式在「File Open」命令期間呼叫PACKEDIB.C中的PackedDibLoad函式時獲得了此指標。在處理此命令的過程中,SHOWDIB3也呼叫PackedDibCreatePalette來獲得可能用於DIB的調色盤。注意,無論SHOWDIB3什麼時候準備載入新的DIB,都應先釋放前一個DIB的記憶體,並刪除前一個DIB的調色盤。在處理WM_DESTROY訊息的程序中,最後的DIB最後釋放,最後的調色盤最後刪除。

處理WM_PAINT訊息很簡單:如果存在調色盤,則SHOWDIB3將它選進裝置內容並顯現它。然後它呼叫SetDIBitsToDevice,並傳遞有關DIB的函式資訊(例如寬、高和指向DIB圖素位元的指標 ),這些資訊從PACKEDIB中的函式獲得。

另外,請記住SHOWDIB3依據DIB中的顏色表建立了調色盤。如果在DIB中沒有顏色表-通常是16位元、24位元和32位元DIB的情況-就不建立調色盤。在8位元顯示模式下顯示DIB時,它只能用標準保留的20種顏色顯示。

對這個問題有兩種解決方法:第一種是簡單地使用「通用」調色盤,這種調色盤適用於許多圖形。您也可以自己建立調色盤。第二種解決方法是分析DIB的圖素位元,並決定要顯示圖像的最佳顏色。很明顯,第二種方法將涉及更多的工作(對於程式寫作者和處理器都是如此),但是我將在本章結束之前告訴您如何使用第二種方法。