建立和轉換

来源:百度文库 编辑:神马文学网 时间:2024/04/28 23:10:33

建立和轉換
 

程式16-21所示的DIBHELP第三部分和最後部分展示了如何建立DIB區塊,以及如何將DIB區塊與packed DIB相互轉換。

 程式16-21  DIBHELP.C檔案的第三部分和最後部分DIBHELP.C (第三部分)/*--------------------------------------------------------------------------Calculating shift values from color masks is required by theDibCreateFromInfo function.----------------------------------------------------------------------------*/static int MaskToRShift (DWORD dwMask){int iShift ;if (dwMask == 0)return 0 ;for (iShift = 0 ; !(dwMask & 1) ; iShift++)dwMask >>= 1 ;return iShift ;}static int MaskToLShift (DWORD dwMask){int iShift ;if (dwMask == 0)return 0 ;while (!(dwMask & 1))dwMask >>= 1 ;for (iShift = 0 ; dwMask & 1 ; iShift++)dwMask >>= 1 ;return 8 - iShift ;}/*----------------------------------------------------------------------------DibCreateFromInfo: All DIB creation functions ultimately call this one.This function is responsible for calling CreateDIBSection, allocatingmemory for DIBSTRUCT, and setting up the row pointer.-----------------------------------------------------------------------------*/HDIB DibCreateFromInfo (BITMAPINFO * pbmi){BYTE      * pBits ;DIBSTRUCT * pdib ;HBITMAP     hBitmap ;int         i, iRowLength, cy, y ;hBitmap = CreateDIBSection (NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0) ;if (hBitmap == NULL)return NULL ;if (NULL == (pdib = malloc (sizeof (DIBSTRUCT)))){DeleteObject (hBitmap) ;return NULL ;}pdib->iSignature = HDIB_SIGNATURE ;pdib->hBitmap = hBitmap ;pdib->pBits      = pBits ;GetObject (hBitmap, sizeof (DIBSECTION), &pdib->ds) ;// Notice that we can now use the DIB information functions//   defined above.// If the compression is BI_BITFIELDS, calculate shifts from masksif (DibCompression (pdib) == BI_BITFIELDS){for (i = 0 ; i < 3 ; i++){pdib->iLShift[i] = MaskToLShift (pdib->ds.dsBitfields[i]) ;pdib->iRShift[i] = MaskToRShift (pdib->ds.dsBitfields[i]) ;}}// If the compression is BI_RGB, but bit-count is 16 or 32,//   set the bitfields and the maskselse if (DibCompression (pdib) == BI_RGB){if (DibBitCount (pdib) == 16){pdib->ds.dsBitfields[0] = 0x00007C00 ;pdib->ds.dsBitfields[1] = 0x000003E0 ;pdib->ds.dsBitfields[2] = 0x0000001F ;pdib->iRShift[0]= 10 ;pdib->iRShift[1]=  5 ;pdib->iRShift[2]=  0 ;pdib->iLShift[0]=  3 ;pdib->iLShift[1]=  3 ;pdib->iLShift[2]=  3 ;}else if (DibBitCount (pdib) == 24 || DibBitCount (pdib) == 32){pdib->ds.dsBitfields[0] = 0x00FF0000 ;pdib->ds.dsBitfields[1] = 0x0000FF00 ;pdib->ds.dsBitfields[2] = 0x000000FF ;pdib->iRShift[0] = 16 ;pdib->iRShift[1] =  8 ;pdib->iRShift[2] =  0 ;pdib->iLShift[0] =  0 ;pdib->iLShift[1] =  0 ;pdib->iLShift[2] =  0;}}// Allocate an array of pointers to each row in the DIBcy = DibHeight (pdib) ;if (NULL == (pdib->ppRow = malloc (cy * sizeof (BYTE *)))){free (pdib) ;DeleteObject (hBitmap) ;return NULL ;}// Initialize them.iRowLength = DibRowLength (pdib) ;if (pbmi->bmiHeader.biHeight > 0)       // ie, bottom up{for (y = 0 ; y < cy ; y++)pdib->ppRow[y] = pBits + (cy - y - 1) * iRowLength ;}else// top down{for (y = 0 ; y < cy ; y++)pdib->ppRow[y] = pBits + y * iRowLength ;}return pdib ;}/*--------------------------------------------------------------------------DibDelete:  Frees all memory for the DIB section----------------------------------------------------------------------------*/BOOL DibDelete (HDIB hdib){DIBSTRUCT * pdib = hdib ;if (!DibIsValid (hdib))return FALSE ;free (pdib->ppRow) ;DeleteObject (pdib->hBitmap) ;free (pdib) ;return TRUE ;}/*----------------------------------------------------------------------------DibCreate: Creates an HDIB from explicit arguments-----------------------------------------------------------------------------*/HDIB DibCreate (int cx, int cy, int cBits, int cColors){BITMAPINFO * pbmi ;DWORD        dwInfoSize ;HDIB         hDib ;int          cEntries ;if (cx <= 0 || cy <= 0 ||((cBits !=  1) && (cBits !=  4) && (cBits !=8) &&(cBits != 16) && (cBits != 24) && (cBits != 32))){return NULL ;}if (cColors != 0)cEntries = cColors ;elseif (cBits <= 8)cEntries = 1 << cBits ;dwInfoSize = sizeof (BITMAPINFOHEADER) + (cEntries - 1) * sizeof (RGBQUAD);if (NULL == (pbmi = malloc (dwInfoSize))){return NULL ;}ZeroMemory (pbmi, dwInfoSize) ;pbmi->bmiHeader.biSize          = sizeof (BITMAPINFOHEADER) ;pbmi->bmiHeader.biWidth         = cx ;pbmi->bmiHeader.biHeight        = cy ;pbmi->bmiHeader.biPlanes        = 1 ;pbmi->bmiHeader.biBitCount      = cBits ;pbmi->bmiHeader.biCompression   = BI_RGB ;pbmi->bmiHeader.biSizeImage     = 0 ;pbmi->bmiHeader.biXPelsPerMeter = 0 ;pbmi->bmiHeader.biYPelsPerMeter = 0 ;pbmi->bmiHeader.biClrUsed       = cColors ;pbmi->bmiHeader.biClrImportant  = 0 ;hDib = DibCreateFromInfo (pbmi) ;free (pbmi) ;return hDib ;}/*----------------------------------------------------------------------------DibCopyToInfo:  Builds BITMAPINFO structure.Used by DibCopy and DibCopyToDdb-----------------------------------------------------------------------------*/static BITMAPINFO * DibCopyToInfo (HDIB hdib){BITMAPINFO *pbmi ;int          i, iNumColors ;RGBQUAD    * prgb ;if (!DibIsValid (hdib))return NULL ;// Allocate the memoryif (NULL == (pbmi = malloc (DibInfoSize (hdib))))return NULL ;// Copy the information headerCopyMemory (pbmi, DibInfoHeaderPtr(hdib), sizeof (BITMAPINFOHEADER));// Copy the possible color masksprgb = (RGBQUAD *) ((BYTE *) pbmi + sizeof (BITMAPINFOHEADER)) ;if (DibMaskSize (hdib)){CopyMemory (prgb, DibMaskPtr (hdib), 3 * sizeof (DWORD)) ;prgb = (RGBQUAD *) ((BYTE *) prgb + 3 * sizeof (DWORD)) ;}// Copy the color tableiNumColors = DibNumColors (hdib) ;for (i = 0 ; i < iNumColors ; i++)DibGetColor (hdib, i, prgb + i) ;return pbmi ;}/*--------------------------------------------------------------------------DibCopy:  Creates a new DIB section from an existing DIB section,possibly swapping the DIB width and height.---------------------------------------------------------------------------*/HDIB DibCopy (HDIB hdibSrc, BOOL fRotate){BITMAPINFO * pbmi ;BYTE       * pBitsSrc, * pBitsDst ;HDIB         hdibDst ;if (!DibIsValid (hdibSrc))return NULL ;if (NULL == (pbmi = DibCopyToInfo (hdibSrc)))return NULL ;if (fRotate){pbmi->bmiHeader.biWidth = DibHeight (hdibSrc) ;pbmi->bmiHeader.biHeight = DibWidth (hdibSrc) ;}hdibDst = DibCreateFromInfo (pbmi) ;free (pbmi) ;if (hdibDst == NULL)return NULL ;// Copy the bitsif (!fRotate){pBitsSrc = DibBitsPtr (hdibSrc) ;pBitsDst = DibBitsPtr (hdibDst) ;CopyMemory (pBitsDst, pBitsSrc, DibBitsSize (hdibSrc)) ;}return hdibDst ;}/*----------------------------------------------------------------------------DibCopyToPackedDib is generally used for saving DIBs and fortransferring DIBs to the clipboard. In the second case, the secondargument should be set to TRUE so that the memory is allocatedwith the GMEM_SHARE flag.-----------------------------------------------------------------------------*/BITMAPINFO * DibCopyToPackedDib (HDIB hdib, BOOL fUseGlobal){BITMAPINFO * pPackedDib ;BYTE       * pBits ;DWORD        dwDibSize ;HDC          hdcMem ;HGLOBAL      hGlobal ;int          iNumColors ;PDIBSTRUCT   pdib = hdib ;RGBQUAD    * prgb ;if (!DibIsValid (hdib))return NULL ;// Allocate memory for packed DIBdwDibSize = DibTotalSize (hdib) ;if (fUseGlobal){hGlobal = GlobalAlloc (GHND | GMEM_SHARE, dwDibSize) ;pPackedDib = GlobalLock (hGlobal) ;}else{pPackedDib = malloc (dwDibSize) ;}if (pPackedDib == NULL)return NULL ;// Copy the information headerCopyMemory (pPackedDib, &pdib->ds.dsBmih, sizeof (BITMAPINFOHEADER)) ;prgb = (RGBQUAD *) ((BYTE *) pPackedDib + sizeof (BITMAPINFOHEADER)) ;// Copy the possible color masksif (pdib->ds.dsBmih.biCompression == BI_BITFIELDS){CopyMemory (prgb, pdib->ds.dsBitfields, 3 * sizeof (DWORD)) ;prgb = (RGBQUAD *) ((BYTE *) prgb + 3 * sizeof (DWORD)) ;}// Copy the color tableif (iNumColors = DibNumColors (hdib)){hdcMem = CreateCompatibleDC (NULL) ;SelectObject (hdcMem, pdib->hBitmap) ;GetDIBColorTable (hdcMem, 0, iNumColors, prgb) ;DeleteDC (hdcMem) ;}pBits = (BYTE *) (prgb + iNumColors) ;// Copy the bitsCopyMemory (pBits, pdib->pBits, DibBitsSize (pdib)) ;// If last argument is TRUE, unlock global memory block and//   cast it to pointer in preparation for returnif (fUseGlobal){GlobalUnlock (hGlobal) ;pPackedDib = (BITMAPINFO *) hGlobal ;}return pPackedDib ;}/*--------------------------------------------------------------------------DibCopyFromPackedDib is generally used for pasting DIBs from theclipboard.------------------------------------------------------------------------*/HDIB DibCopyFromPackedDib (BITMAPINFO * pPackedDib){BYTE     * pBits ;DWORD      dwInfoSize, dwMaskSize, dwColorSize ;int        iBitCount ;PDIBSTRUCT pdib ;// Get the size of the information header and do validity checkdwInfoSize = pPackedDib->bmiHeader.biSize ;if (dwInfoSize != sizeof (BITMAPCOREHEADER) &&dwInfoSize != sizeof (BITMAPINFOHEADER) &&dwInfoSize != sizeof (BITMAPV4HEADER) &&dwInfoSize != sizeof (BITMAPV5HEADER)){return NULL ;}// Get the possible size of the color masksif (dwInfoSize == sizeof (BITMAPINFOHEADER) &&pPackedDib->bmiHeader.biCompression == BI_BITFIELDS){dwMaskSize = 3 * sizeof (DWORD) ;}else{dwMaskSize = 0 ;}// Get the size of the color tableif (dwInfoSize == sizeof (BITMAPCOREHEADER)){iBitCount = ((BITMAPCOREHEADER *) pPackedDib)->bcBitCount ;if (iBitCount <= 8){dwColorSize = (1 << iBitCount) * sizeof (RGBTRIPLE) ;}elsedwColorSize = 0 ;}else           // all non-OS/2 compatible DIBs{if (pPackedDib->bmiHeader.biClrUsed > 0){dwColorSize = pPackedDib->bmiHeader.biClrUsed * sizeof (RGBQUAD);}else if (pPackedDib->bmiHeader.biBitCount <= 8){dwColorSize = (1 << pPackedDib->bmiHeader.biBitCount) * sizeof (RGBQUAD) ;}else{dwColorSize = 0 ;}}// Finally, get the pointer to the bits in the packed DIBpBits = (BYTE *) pPackedDib + dwInfoSize + dwMaskSize + dwColorSize ;// Create the HDIB from the packed-DIB pointerpdib = DibCreateFromInfo (pPackedDib) ;// Copy the pixel bitsCopyMemory (pdib->pBits, pBits, DibBitsSize (pdib)) ;return pdib ;}/*----------------------------------------------------------------------------DibFileLoad:  Creates a DIB section from a DIB file-----------------------------------------------------------------------------*/HDIB DibFileLoad (const TCHAR * szFileName){BITMAPFILEHEADER bmfh ;BITMAPINFO     * pbmi ;BOOL             bSuccess ;DWORD            dwInfoSize, dwBitsSize, dwBytesRead ;HANDLE           hFile ;HDIB             hDib ;// 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 information structure & read it indwInfoSize = bmfh.bfOffBits - sizeof (BITMAPFILEHEADER) ;if (NULL == (pbmi = malloc (dwInfoSize))){CloseHandle (hFile) ;return NULL ;}bSuccess = ReadFile (hFile, pbmi, dwInfoSize, &dwBytesRead, NULL) ;if (!bSuccess || (dwBytesRead != dwInfoSize)){CloseHandle (hFile) ;free (pbmi) ;return NULL ;}// Create the DIBhDib = DibCreateFromInfo (pbmi) ;free (pbmi) ;if (hDib == NULL){CloseHandle (hFile) ;return NULL ;}// Read in the bitsdwBitsSize = bmfh.bfSize - bmfh.bfOffBits ;bSuccess = ReadFile (hFile, ((PDIBSTRUCT) hDib)->pBits,dwBitsSize, &dwBytesRead, NULL) ;CloseHandle (hFile) ;if (!bSuccess || (dwBytesRead != dwBitsSize)){DibDelete (hDib) ;return NULL ;}return hDib ;}/*--------------------------------------------------------------------------DibFileSave:  Saves a DIB section to a file----------------------------------------------------------------------------*/BOOL DibFileSave (HDIB hdib, const TCHAR * szFileName){BITMAPFILEHEADER bmfh ;BITMAPINFO     * pbmi ;BOOL             bSuccess ;DWORD            dwTotalSize, dwBytesWritten ;HANDLE           hFile ;hFile = CreateFile (szFileName, GENERIC_WRITE, 0, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ;if (hFile == INVALID_HANDLE_VALUE)return FALSE ;dwTotalSize  = DibTotalSize (hdib) ;bmfh.bfType      = * (WORD *) "BM" ;bmfh.bfSize      = sizeof (BITMAPFILEHEADER) + dwTotalSize ;bmfh.bfReserved1 = 0 ;bmfh.bfReserved2 = 0 ;bmfh.bfOffBits   = bmfh.bfSize - DibBitsSize (hdib) ;// Write the BITMAPFILEHEADERbSuccess = WriteFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER),&dwBytesWritten, NULL) ;if (!bSuccess || (dwBytesWritten != sizeof (BITMAPFILEHEADER))){CloseHandle (hFile) ;DeleteFile (szFileName) ;return FALSE ;}// Get entire DIB in packed-DIB formatif (NULL == (pbmi = DibCopyToPackedDib (hdib, FALSE))){CloseHandle (hFile) ;DeleteFile (szFileName) ;return FALSE ;}// Write out the packed DIBbSuccess = WriteFile (hFile, pbmi, dwTotalSize, &dwBytesWritten, NULL) ;CloseHandle (hFile) ;free (pbmi) ;if (!bSuccess || (dwBytesWritten != dwTotalSize)){DeleteFile (szFileName) ;return FALSE ;}return TRUE ;}/*---------------------------------------------------------------------------DibCopyToDdb:  For more efficient screen displays---------------------------------------------------------------------------*/HBITMAP DibCopyToDdb (HDIB hdib, HWND hwnd, HPALETTE hPalette){BITMAPINFO * pbmi ;HBITMAP      hBitmap ;HDC          hdc ;if (!DibIsValid (hdib))return NULL ;if (NULL == (pbmi = DibCopyToInfo (hdib)))return NULL ;hdc = GetDC (hwnd) ;if (hPalette){SelectPalette (hdc, hPalette, FALSE) ;RealizePalette (hdc) ;}hBitmap = CreateDIBitmap (hdc, DibInfoHeaderPtr (hdib), CBM_INIT,DibBitsPtr (hdib), pbmi, DIB_RGB_COLORS) ;ReleaseDC (hwnd, hdc) ;free (pbmi) ;return hBitmap ;}

這部分的DIBHELP.C檔案從兩個小函式開始,這兩個函式根據16位元和32位元DIB的顏色遮罩得到左、右移位值。這些函式在 第十五章「顏色遮罩」 一節說明。

DibCreateFromInfo函式是DIBHELP中唯一呼叫CreateDIBSection並為DIBSTRUCT結構配置記憶體的函式。其他所有建立和複製函式都重複此函式。DibCreateFromInfo唯一的參數是指向BITMAPINFO結構的指標。此結構的顏色表必須存在,但是它不必用有效的值填充。呼叫CreateDIBSection之後,該函式將初始化DIBSTRUCT結構的所有欄位。注意,在設定DIBSTRUCT結構的ppRow欄位的值時(指向DIB行位址的指標),DIB有由下而上和由上而下的不同儲存方式。ppRow開頭的元素就是DIB的頂行。

DibDelete刪除DibCreateFromInfo中建立的點陣圖,同時釋放在該函式中配置的記憶體。

DibCreate可能比DibCreateFromInfo更像一個從應用程式呼叫的函式。前三個參數提供圖素的寬度、高度和每圖素的位數。最後一個參數可以設定為0(用於顏色表的內定尺寸),或者設定為非0(表示比每圖素位元數所需要的顏色表更小的顏色表)。

DibCopy函式根據現存的DIB區塊建立新的DIB區塊,並用DibCreateInfo函式為BITMAPINFO結構配置了記憶體,還填了所有的資料。DibCopy函式的一個BOOL參數指出是否在建立新的DIB時交換了DIB的寬度和高度。我們將在後面看到此函式的用法。

DibCopyToPackedDib和DibCopyFromPackedDib函式的使用通常與透過剪貼簿傳遞DIB相關。DibFileLoad函式從DIB檔案建立DIB區塊;DibFileSave函式將資料儲存到DIB檔案。

最後,DibCopyToDdb函式根據DIB建立GDI點陣圖物件。注意,該函式需要目前調色盤的代號和程式視窗的代號。程式視窗代號用於獲得選進並顯現調色盤的裝置內容。只有這樣,函式才可以呼叫CreateDIBitmap。這曾在本章前面的SHOWDIB7中展示。

DIBHELP表頭檔案和巨集
 

DIBHELP.H表頭檔案如程式16-22所示。

 程式16-22  DIBHELP.H檔案DIBHELP.H/*--------------------------------------------------------------------------DIBHELP.H header file for DIBHELP.C----------------------------------------------------------------------------*/typedef void * HDIB ;// Functions in DIBHELP.CBOOL DibIsValid (HDIB hdib) ;HBITMAP DibBitmapHandle (HDIB hdib) ;int DibWidth (HDIB hdib) ;int DibHeight (HDIB hdib) ;int DibBitCount (HDIB hdib) ;int DibRowLength (HDIB hdib) ;int DibNumColors (HDIB hdib) ;DWORD DibMask (HDIB hdib, int i) ;int DibRShift (HDIB hdib, int i) ;int DibLShift (HDIB hdib, int i) ;int DibCompression (HDIB hdib) ;BOOL DibIsAddressable (HDIB hdib) ;DWORD DibInfoHeaderSize (HDIB hdib) ;DWORD DibMaskSize (HDIB hdib) ;DWORD DibColorSize (HDIB hdib) ;DWORD DibInfoSize (HDIB hdib) ;DWORD DibBitsSize (HDIB hdib) ;DWORD DibTotalSize (HDIB hdib) ;BITMAPINFOHEADER * DibInfoHeaderPtr (HDIB hdib) ;DWORD * DibMaskPtr (HDIB hdib) ;void * DibBitsPtr (HDIB hdib) ;BOOL DibGetColor (HDIB hdib, int index, RGBQUAD * prgb) ;BOOL DibSetColor (HDIB hdib, int index, RGBQUAD * prgb) ;BYTE * DibPixelPtr (HDIB hdib, int x, int y) ;DWORD DibGetPixel (HDIB hdib, int x, int y) ;BOOL DibSetPixel (HDIB hdib, int x, int y, DWORD dwPixel) ;BOOL DibGetPixelColor (HDIB hdib, int x, int y, RGBQUAD * prgb) ;BOOL DibSetPixelColor (HDIB hdib, int x, int y, RGBQUAD * prgb) ;HDIB DibCreateFromInfo (BITMAPINFO * pbmi) ;BOOL DibDelete (HDIB hdib) ;HDIB DibCreate (int cx, int cy, int cBits, int cColors) ;HDIB DibCopy (HDIB hdibSrc, BOOL fRotate) ;BITMAPINFO * DibCopyToPackedDib (HDIB hdib, BOOL fUseGlobal) ;HDIB DibCopyFromPackedDib (BITMAPINFO * pPackedDib) ;HDIB DibFileLoad (const TCHAR * szFileName) ;BOOL DibFileSave (HDIB hdib, const TCHAR * szFileName) ;HBITMAP DibCopyToDdb (HDIB hdib, HWND hwnd, HPALETTE hPalette) ;HDIB DibCreateFromDdb (HBITMAP hBitmap) ;/*---------------------------------------------------------------------------Quickie no-bounds-checked pixel gets and sets-----------------------------------------------------------------------------*/#define DibPixelPtr1(hdib, x, y)(((* (PBYTE **) hdib) [y]) + ((x) >> 3))#define DibPixelPtr4(hdib, x, y)(((* (PBYTE **) hdib) [y]) + ((x) >> 1))#define DibPixelPtr8(hdib, x, y)(((* (PBYTE **) hdib) [y]) +  (x)  )#define DibPixelPtr16(hdib, x, y)  ((WORD *) (((* (PBYTE **) hdib) [y]) +  (x) *  2))#define DibPixelPtr24(hdib, x, y)  ((RGBTRIPLE *) (((* (PBYTE **) hdib) [y]) +  (x) *  3))#define DibPixelPtr32(hdib, x, y)  ((DWORD *) (((* (PBYTE **) hdib) [y]) +  (x) *  4))#define DibGetPixel1(hdib, x, y)   (0x01 & (* DibPixelPtr1 (hdib, x, y) >> (7 - ((x) & 7))))#define DibGetPixel4(hdib, x, y)   (0x0F & (* DibPixelPtr4 (hdib, x, y) >> ((x) & 1 ? 0 : 4)))#define DibGetPixel8(hdib, x, y)     (* DibPixelPtr8  (hdib, x, y))#define DibGetPixel16(hdib, x, y)  (* DibPixelPtr16 (hdib, x, y))#define DibGetPixel24(hdib, x, y)    (* DibPixelPtr24 (hdib, x, y))#define DibGetPixel32(hdib, x, y)    (* DibPixelPtr32(hdib, x, y))#define DibSetPixel1(hdib, x, y, p)((* DibPixelPtr1 (hdib, x, y) &= ~( 1<< (7 - ((x) & 7)))), (* DibPixelPtr1 (hdib, x, y) |=((p) << (7 - ((x) & 7)))))#define DibSetPixel4(hdib, x, y, p)((* DibPixelPtr4 (hdib, x, y) &= (0x0F <<((x) & 1 ? 4 : 0))),(* DibPixelPtr4 (hdib, x, y) |= ((p)<<((x) & 1 ? 0 : 4))))#define DibSetPixel8(hdib, x, y, p)  (* DibPixelPtr8 (hdib, x, y) = p)#define DibSetPixel16(hdib, x, y, p) (* DibPixelPtr16 (hdib, x, y) = p)#define DibSetPixel24(hdib, x, y, p) (* DibPixelPtr24 (hdib, x, y) = p)#define DibSetPixel32(hdib, x, y, p) (* DibPixelPtr32 (hdib, x, y) = p)

這個表頭檔案將HDIB定義為空指標(void* )。應用程式的確不需要瞭解HDIB所指結構的內部結構。此表頭檔案還包括DIBHELP.C中所有函式的說明,還有一些巨集-非常特殊的巨集。

如果再看一看DIBHELP.C中的DibPixelPtr、DibGetPixel和DibSetPixel函式,並試圖提高它們的執行速度表現,那麼您將看到兩種可能的解決方法。第一種,可以刪除所有的檢查保護,並相信應用程式不會使用無效參數呼叫函式。還可以刪除一些函式呼叫,例如DibBitCount,並使用指向DIBSTRUCT結構內部的指標來直接獲得資訊。

提高執行速度表現另一項較不明顯的方法是刪除所有對每圖素位元數的處理方式,同時分離出處理不同DIB函式-例如DibGetPixel1、DibGetPixel4、DibGetPixel8等等。下一個最佳化步驟是刪除整個函式呼叫,將其處理動作透過inline function或巨集中進行合併。

DIBHELP.H採用巨集的方法。它依據DibPixelPtr、DibGetPixel和DibSetPixel函式提出了三套巨集。這些巨集都明確對應於特殊的圖素位元數。

DIBBLE程式
 

DIBBLE程式,如程式16-23所示,使用DIBHELP函式和巨集工作。儘管DIBBLE是本書中最長的程式,它確實只是一些作業的粗略範例,這些作業可以在簡單的數位影像處理程式中找到。對DIBBLE的明顯改進是轉換成了多重文件介面(MDI:multiple document interface),我們將在 第十九章 學習有關多重文件介面的知識。

 程式16-23  DIBBLEDIBBLE.C/*---------------------------------------------------------------------------DIBBLE.C -- Bitmap and Palette Program(c) Charles Petzold, 1998-----------------------------------------------------------------------------*/#include #include "dibhelp.h"#include "dibpal.h"#include "dibconv.h"#include "resource.h"#define WM_USER_SETSCROLLS    (WM_USER + 1)#define WM_USER_DELETEDIB     (WM_USER + 2)#define WM_USER_DELETEPAL     (WM_USER + 3)#define WM_USER_CREATEPAL     (WM_USER + 4)LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;TCHAR szAppName[] = TEXT ("Dibble") ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){HACCEL   hAccel ;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, szAppName,WS_OVERLAPPEDWINDOW | WM_VSCROLL | WM_HSCROLL,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL) ;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 ;}/*----------------------------------------------------------------------------DisplayDib: Displays or prints DIB actual size or stretcheddepending on menu selection-----------------------------------------------------------------------------*/int DisplayDib (HDC hdc, HBITMAP hBitmap, int x, int y,int cxClient, int cyClient,WORD wShow, BOOL fHalftonePalette){BITMAP bitmap ;HDC    hdcMem ;int    cxBitmap, cyBitmap, iReturn ;GetObject(hBitmap, sizeof (BITMAP), &bitmap) ;cxBitmap =bitmap.bmWidth ;cyBitmap =bitmap.bmHeight ;SaveDC (hdc) ;if (fHalftonePalette)SetStretchBltMode (hdc, HALFTONE) ;elseSetStretchBltMode (hdc, COLORONCOLOR) ;hdcMem = CreateCompatibleDC (hdc) ;SelectObject (hdcMem, hBitmap) ;switch (wShow){case IDM_SHOW_NORMAL:if (fHalftonePalette)iReturn = StretchBlt (hdc,0, 0, min (cxClient, cxBitmap - x),min (cyClient, cyBitmap - y),hdcMem, x, y, min (cxClient, cxBitmap - x),min (cyClient, cyBitmap - y),SRCCOPY);elseiReturn = BitBlt (hdc,0, 0, min (cxClient, cxBitmap - x),min (cyClient, cyBitmap - y),hdcMem, x, y, SRCCOPY) ;break ;case IDM_SHOW_CENTER:if (fHalftonePalette)iReturn = StretchBlt (hdc, (cxClient - cxBitmap) / 2,(cyClient - cyBitmap) / 2,cxBitmap, cyBitmap,hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY);elseiReturn = BitBlt (hdc, (cxClient - cxBitmap) / 2,cyClient - cyBitmap) / 2,cxBitmap, cyBitmap,hdcMem, 0, 0, SRCCOPY) ;break ;case IDM_SHOW_STRETCH:iReturn = StretchBlt (hdc,0, 0, cxClient, cyClient,hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;break ;case IDM_SHOW_ISOSTRETCH:SetMapMode (hdc, MM_ISOTROPIC) ;SetWindowExtEx (hdc, cxBitmap, cyBitmap, NULL) ;SetViewportExtEx (hdc, cxClient, cyClient, NULL) ;SetWindowOrgEx (hdc, cxBitmap / 2, cyBitmap / 2, NULL) ;SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;iReturn = StretchBlt (hdc,0, 0, cxBitmap, cyBitmap,hdcMem,0, 0, cxBitmap, cyBitmap, SRCCOPY) ;break ;}DeleteDC (hdcMem) ;RestoreDC (hdc, -1) ;return iReturn ;}/*---------------------------------------------------------------------------DibFlipHorizontal: Calls non-optimized DibSetPixel and DibGetPixel----------------------------------------------------------------------------*/HDIB DibFlipHorizontal (HDIB hdibSrc){HDIB hdibDst ;int  cx, cy, x, y ;if (!DibIsAddressable (hdibSrc))return NULL ;if (NULL == (hdibDst = DibCopy (hdibSrc, FALSE)))return NULL ;cx = DibWidth  (hdibSrc) ;cy = DibHeight (hdibSrc) ;for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++){DibSetPixel (hdibDst, x, cy - 1 - y, DibGetPixel (hdibSrc, x, y)) ;}return hdibDst ;}/*---------------------------------------------------------------------------DibRotateRight: Calls optimized DibSetPixelx and DibGetPixelx-----------------------------------------------------------------------------*/HDIB DibRotateRight (HDIB hdibSrc){HDIB hdibDst ;int cx, cy, x, y ;if (!DibIsAddressable (hdibSrc))return NULL ;if (NULL == (hdibDst = DibCopy (hdibSrc, TRUE)))return NULL ;cx = DibWidth (hdibSrc) ;cy = DibHeight (hdibSrc) ;switch (DibBitCount (hdibSrc)){case  1:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel1 (hdibDst, cy - y - 1, x,DibGetPixel1 (hdibSrc, x, y)) ;break ;case  4:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel4 (hdibDst, cy - y - 1, x,DibGetPixel4 (hdibSrc, x, y)) ;break ;case  8:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel8 (hdibDst, cy - y - 1, x,DibGetPixel8 (hdibSrc, x, y)) ;break ;case 16:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel16 (hdibDst, cy - y - 1, x,DibGetPixel16 (hdibSrc, x, y)) ;break ;case 24:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel24 (hdibDst, cy - y - 1, x,DibGetPixel24 (hdibSrc, x, y)) ;break ;case 32:for (x = 0 ; x < cx ; x++)for (y = 0 ; y < cy ; y++)DibSetPixel32 (hdibDst, cy - y - 1, x,DibGetPixel32 (hdibSrc, x, y)) ;break ;}return hdibDst ;}/*------------------------------------------------------------------------PaletteMenu: Uncheck and check menu item on palette menu--------------------------------------------------------------------------*/void PaletteMenu (HMENU hMenu, WORD wItemNew){static WORD wItem = IDM_PAL_NONE ;CheckMenuItem (hMenu, wItem, MF_UNCHECKED) ;wItem = wItemNew ;CheckMenuItem (hMenu, wItem, MF_CHECKED) ;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam){static BOOL      fHalftonePalette ;static DOCINFO  di = {sizeof(DOCINFO),TEXT("Dibble:Printing")} ;static HBITMAPhBitmap ;static HDIB        hdib ;static HMENU        hMenu ;static HPALETTEhPalette ;static int          cxClient, cyClient, iVscroll, iHscroll ;static OPENFILENAME ofn ;static PRINTDLG     printdlg = { sizeof (PRINTDLG) } ;static TCHAR        szFileName [MAX_PATH], szTitleName [MAX_PATH] ;static TCHAR        szFilter[]=TEXT ("Bitmap Files (*.BMP)\0*.bmp\0")TEXT ("All Files (*.*)\0*.*\0\0") ;static TCHAR      * szCompression[] = {TEXT("BI_RGB"),TEXT("BI_RLE8"),TEXT("BI_RLE4"),TEXT("BI_BITFIELDS"),TEXT("Unknown")} ;static WORD         wShow = IDM_SHOW_NORMAL ;BOOL                fSuccess ;BYTE              *pGlobal ;HDC                 hdc, hdcPrn ;HGLOBAL             hGlobal ;HDIB                hdibNew ;int                 iEnable, cxPage, cyPage, iConvert ;PAINTSTRUCT         ps ;SCROLLINFO          si ;TCHAR               szBuffer [256] ;switch (message){case WM_CREATE:// Save the menu handle in a static variablehMenu = GetMenu (hwnd) ;// Initialize the OPENFILENAME structure for the File Open//   and File Save dialog boxes.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             = OFN_OVERWRITEPROMPT ;ofn.nFileOffset       = 0 ;ofn.nFileExtension    = 0 ;ofn.lpstrDefExt       = TEXT ("bmp") ;ofn.lCustData         = 0 ;ofn.lpfnHook          = NULL ;ofn.lpTemplateName    = NULL ;return 0 ;case WM_DISPLAYCHANGE:SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;return 0 ;case WM_SIZE:// Save the client area width and height in static variables.cxClient = LOWORD (lParam) ;cyClient = HIWORD (lParam) ;wParam = FALSE ;// fall through// WM_USER_SETSCROLLS:  Programmer-defined Message!// Set the scroll bars. If the display mode is not normal,//   make them invisible. If wParam is TRUE, reset the//   scroll bar position.case WM_USER_SETSCROLLS:if (hdib == NULL || wShow != IDM_SHOW_NORMAL){si.cbSize = sizeof (SCROLLINFO) ;si.fMask  = SIF_RANGE ;si.nMin   = 0 ;si.nMax   = 0 ;SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;}else{// First the vertical scrollsi.cbSize = sizeof (SCROLLINFO) ;si.fMask  = SIF_ALL ;GetScrollInfo (hwnd, SB_VERT, &si) ;si.nMin  = 0 ;si.nMax  = DibHeight (hdib) ;si.nPage = cyClient ;if ((BOOL) wParam)si.nPos = 0 ;SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;GetScrollInfo (hwnd, SB_VERT, &si) ;iVscroll = si.nPos ;// Then the horizontal scrollGetScrollInfo (hwnd, SB_HORZ, &si) ;si.nMin  = 0 ;si.nMax  = DibWidth (hdib) ;si.nPage = cxClient ;if ((BOOL) wParam)si.nPos = 0 ;SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;GetScrollInfo (hwnd, SB_HORZ, &si) ;iHscroll = si.nPos ;}return 0 ;// WM_VSCROLL: Vertically scroll the DIBcase WM_VSCROLL:si.cbSize = sizeof (SCROLLINFO) ;si.fMask  = SIF_ALL ;GetScrollInfo (hwnd, SB_VERT, &si) ;iVscroll = si.nPos ;switch (LOWORD (wParam)){case SB_LINEUP:    si.nPos -= 1 ; break ;case SB_LINEDOWN:  si.nPos += 1 ;break ;case SB_PAGEUP:    si.nPos -= si.nPage ;break ;case SB_PAGEDOWN:  si.nPos += si.nPage ;break ;case SB_THUMBTRACK:si.nPos= si.nTrackPos ;break ;default:   break ;}si.fMask = SIF_POS ;SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ;GetScrollInfo (hwnd, SB_VERT, &si) ;if (si.nPos != iVscroll){ScrollWindow (hwnd, 0, iVscroll - si.nPos, NULL, NULL) ;iVscroll = si.nPos ;UpdateWindow (hwnd) ;}return 0 ;// WM_HSCROLL: Horizontally scroll the DIBcase WM_HSCROLL:si.cbSize = sizeof (SCROLLINFO) ;si.fMask  = SIF_ALL ;GetScrollInfo (hwnd, SB_HORZ, &si) ;iHscroll = si.nPos ;switch (LOWORD (wParam)){case SB_LINELEFT:  si.nPos -=1 ;break ;case SB_LINERIGHT: si.nPos +=1 ;break ;case SB_PAGELEFT:  si.nPos -=si.nPage ;break ;case SB_PAGERIGHT: si.nPos +=si.nPage ;break ;case SB_THUMBTRACK:si.nPos  =si.nTrackPos ;break ;default:     break ;}si.fMask = SIF_POS ;SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;GetScrollInfo (hwnd, SB_HORZ, &si) ;if (si.nPos != iHscroll){ScrollWindow (hwnd, iHscroll - si.nPos, 0, NULL, NULL) ;iHscroll = si.nPos ;UpdateWindow (hwnd) ;}return 0 ;// WM_INITMENUPOPUP:  Enable or Gray menu itemscase WM_INITMENUPOPUP:if (hdib)iEnable = MF_ENABLED ;elseiEnable = MF_GRAYED ;EnableMenuItem (hMenu, IDM_FILE_SAVE,       iEnable) ;EnableMenuItem (hMenu, IDM_FILE_PRINT,      iEnable) ;EnableMenuItem (hMenu, IDM_FILE_PROPERTIES, iEnable) ;EnableMenuItem (hMenu, IDM_EDIT_CUT,        iEnable) ;EnableMenuItem (hMenu, IDM_EDIT_COPY,       iEnable) ;EnableMenuItem (hMenu, IDM_EDIT_DELETE,     iEnable) ;if (DibIsAddressable (hdib))iEnable = MF_ENABLED ;elseiEnable = MF_GRAYED ;EnableMenuItem (hMenu, IDM_EDIT_ROTATE,    iEnable) ;EnableMenuItem (hMenu, IDM_EDIT_FLIP,      iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_01,     iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_04,     iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_08,     iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_16,     iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_24,     iEnable) ;EnableMenuItem (hMenu, IDM_CONVERT_32,     iEnable) ;switch (DibBitCount (hdib)){case  1: EnableMenuItem (hMenu, IDM_CONVERT_01, MF_GRAYED) ; break ;case  4: EnableMenuItem (hMenu, IDM_CONVERT_04, MF_GRAYED) ; break ;case  8: EnableMenuItem (hMenu, IDM_CONVERT_08, MF_GRAYED) ; break ;case 16: EnableMenuItem (hMenu, IDM_CONVERT_16, MF_GRAYED) ; break ;case 24: EnableMenuItem (hMenu, IDM_CONVERT_24, MF_GRAYED) ; break ;case 32: EnableMenuItem (hMenu, IDM_CONVERT_32, MF_GRAYED) ; break ;}if (hdib && DibColorSize (hdib) > 0)iEnable = MF_ENABLED ;elseiEnable = MF_GRAYED ;EnableMenuItem (hMenu, IDM_PAL_DIBTABLE,    iEnable) ;if (DibIsAddressable (hdib) && DibBitCount (hdib) > 8)iEnable = MF_ENABLED ;elseiEnable = MF_GRAYED ;EnableMenuItem (hMenu, IDM_PAL_OPT_POP4,   iEnable) ;EnableMenuItem (hMenu, IDM_PAL_OPT_POP5,   iEnable) ;EnableMenuItem (hMenu, IDM_PAL_OPT_POP6,   iEnable) ;EnableMenuItem (hMenu, IDM_PAL_OPT_MEDCUT, iEnable) ;EnableMenuItem (hMenu, IDM_EDIT_PASTE,IsClipboardFormatAvailable (CF_DIB) ? MF_ENABLED : MF_GRAYED) ;return 0 ;// WM_COMMAND:  Process all menu commands.case WM_COMMAND:iConvert = 0 ;switch (LOWORD (wParam)){case IDM_FILE_OPEN:// Show the File Open dialog boxif (!GetOpenFileName (&ofn))return 0 ;// If there's an existing DIB and palette, delete themSendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;// Load the DIB into memorySetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;hdib = DibFileLoad (szFileName) ;ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;// Reset the scroll barsSendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;// Create the palette and DDBSendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;if (!hdib){MessageBox (hwnd, TEXT ("Cannot load DIB file!"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;}InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;caseIDM_FILE_SAVE:// Show the File Save dialog boxif (!GetSaveFileName (&ofn))return 0 ;// Save the DIB to memorySetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;fSuccess = DibFileSave (hdib, szFileName) ;ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;if (!fSuccess)MessageBox (hwnd, TEXT ("Cannot save DIB file!"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;return 0 ;case IDM_FILE_PRINT:if (!hdib)return 0 ;// Get printer DCprintdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;if (!PrintDlg (&printdlg))return 0 ;if (NULL == (hdcPrn = printdlg.hDC)){MessageBox(hwnd, TEXT ("Cannot obtain Printer DC"),szAppName, MB_ICONEXCLAMATION | MB_OK) ;return 0 ;}// Check if the printer can print bitmapsif (!(RC_BITBLT & GetDeviceCaps (hdcPrn, RASTERCAPS))){DeleteDC (hdcPrn) ;MessageBox (hwnd, TEXT ("Printer cannot print bitmaps"),szAppName, MB_ICONEXCLAMATION | MB_OK) ;return 0 ;}// Get size of printable area of pagecxPage = GetDeviceCaps (hdcPrn, HORZRES) ;cyPage = GetDeviceCaps (hdcPrn, VERTRES) ;fSuccess = FALSE ;// Send the DIB to the printerSetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0)){DisplayDib (hdcPrn, DibBitmapHandle (hdib), 0, 0,cxPage, cyPage, wShow, FALSE) ;if (EndPage (hdcPrn) > 0){fSuccess = TRUE ;EndDoc (hdcPrn) ;}}ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;DeleteDC (hdcPrn) ;if (!fSuccess)MessageBox (hwnd, TEXT ("Could not print bitmap"),szAppName, MB_ICONEXCLAMATION | MB_OK) ;return 0 ;caseIDM_FILE_PROPERTIES:if (!hdib)return 0 ;wsprintf (szBuffer, TEXT ("Pixel width:\t%i\n")TEXT ("Pixel height:\t%i\n")TEXT ("Bits per pixel:\t%i\n")TEXT ("Number of colors:\t%i\n")TEXT ("Compression:\t%s\n"),DibWidth (hdib), DibHeight (hdib),DibBitCount (hdib), DibNumColors (hdib),szCompression [min (3, DibCompression (hdib))]) ;MessageBox (hwnd, szBuffer, szAppName,MB_ICONEXCLAMATION | MB_OK) ;return 0 ;case IDM_APP_EXIT:SendMessage (hwnd, WM_CLOSE, 0, 0) ;return 0 ;case IDM_EDIT_COPY:case IDM_EDIT_CUT:if (!(hGlobal = DibCopyToPackedDib (hdib, TRUE)))return 0 ;OpenClipboard (hwnd) ;EmptyClipboard () ;SetClipboardData (CF_DIB, hGlobal) ;CloseClipboard () ;if (LOWORD (wParam) == IDM_EDIT_COPY)return 0 ;// fall through for IDM_EDIT_CUTcase IDM_EDIT_DELETE:SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;case IDM_EDIT_PASTE:OpenClipboard (hwnd) ;hGlobal = GetClipboardData (CF_DIB) ;pGlobal = GlobalLock (hGlobal) ;// If there's an existing DIB and palette,delete them.// Then convert the packed DIB to an HDIB.if (pGlobal){SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;hdib = DibCopyFromPackedDib ((BITMAPINFO *) pGlobal) ;SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;}GlobalUnlock (hGlobal) ;CloseClipboard () ;// Reset the scroll barsSendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;case IDM_EDIT_ROTATE:if (hdibNew = DibRotateRight (hdib)){DibDelete (hdib) ;DeleteObject (hBitmap) ;hdib = hdibNew ;hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;SendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;InvalidateRect (hwnd, NULL, TRUE) ;}else{MessageBox (hwnd, TEXT ("Not enough memory"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;}return 0 ;case IDM_EDIT_FLIP:if (hdibNew = DibFlipHorizontal (hdib)){DibDelete (hdib) ;DeleteObject (hBitmap) ;hdib = hdibNew ;hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;InvalidateRect (hwnd, NULL, TRUE) ;}else{MessageBox (hwnd, TEXT ("Not enough memory"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;}return 0 ;case IDM_SHOW_NORMAL:case IDM_SHOW_CENTER:case IDM_SHOW_STRETCH:case IDM_SHOW_ISOSTRETCH:CheckMenuItem (hMenu, wShow, MF_UNCHECKED) ;wShow = LOWORD (wParam) ;CheckMenuItem (hMenu, wShow, MF_CHECKED) ;SendMessage (hwnd, WM_USER_SETSCROLLS, FALSE, 0) ;InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;case IDM_CONVERT_32:  iConvert += 8 ;case IDM_CONVERT_24:  iConvert += 8 ;case IDM_CONVERT_16:  iConvert += 8 ;case IDM_CONVERT_08:  iConvert += 4 ;caseIDM_CONVERT_04:  iConvert += 3 ;case IDM_CONVERT_01:  iConvert += 1 ;SetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;hdibNew = DibConvert (hdib, iConvert) ;ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;if (hdibNew){SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;hdib = hdibNew ;SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;InvalidateRect (hwnd, NULL, TRUE) ;}else{MessageBox (hwnd, TEXT ("Not enough memory"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;}return 0 ;case IDM_APP_ABOUT:MessageBox (hwnd, TEXT ("Dibble (c) Charles Petzold, 1998"),szAppName, MB_OK | MB_ICONEXCLAMATION) ;return 0 ;}// All the other WM_COMMAND messages are from the palette// items. Any existing palette is deleted, and the cursor// is set to the hourglass.SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;SetCursor (LoadCursor (NULL, IDC_WAIT)) ;ShowCursor (TRUE) ;// Notice that all messages for palette items are ended// with break rather than return. This is to allow// additional processing later on.switch (LOWORD (wParam)){case IDM_PAL_DIBTABLE:hPalette = DibPalDibTable (hdib) ;break ;case IDM_PAL_HALFTONE:hdc = GetDC (hwnd) ;if (hPalette = CreateHalftonePalette (hdc))fHalftonePalette = TRUE ;ReleaseDC (hwnd, hdc) ;break ;case IDM_PAL_ALLPURPOSE:hPalette = DibPalAllPurpose () ;break ;case IDM_PAL_GRAY2:hPalette    = DibPalUniformGrays   (2);break;case IDM_PAL_GRAY3:hPalette     = DibPalUniformGrays   (3);  break;case IDM_PAL_GRAY4:hPalette     = DibPalUniformGrays   (4); break;case IDM_PAL_GRAY8:hPalette     = DibPalUniformGrays   (8); break;caseIDM_PAL_GRAY16:hPalette = DibPalUniformGrays  (16); break;case IDM_PAL_GRAY32:hPalette = DibPalUniformGrays  (32); break;case IDM_PAL_GRAY64:hPalette = DibPalUniformGrays  (64); break;case IDM_PAL_GRAY128:hPalette = DibPalUniformGrays (128); break;case IDM_PAL_GRAY256:hPalette = DibPalUniformGrays (256);break;case IDM_PAL_RGB222:hPalette = DibPalUniformColors (2,2,2); break;case IDM_PAL_RGB333:hPalette = DibPalUniformColors (3,3,3); break;case IDM_PAL_RGB444:hPalette = DibPalUniformColors (4,4,4); break;case IDM_PAL_RGB555:hPalette = DibPalUniformColors (5,5,5); break;case IDM_PAL_RGB666:hPalette = DibPalUniformColors (6,6,6); break;case IDM_PAL_RGB775:hPalette = DibPalUniformColors (7,7,5); break;case IDM_PAL_RGB757:hPalette = DibPalUniformColors (7,5,7); break;case IDM_PAL_RGB577:hPalette = DibPalUniformColors (5,7,7); break;case IDM_PAL_RGB884:hPalette = DibPalUniformColors (8,8,4); break;case IDM_PAL_RGB848:hPalette = DibPalUniformColors (8,4,8); break;case IDM_PAL_RGB488:hPalette = DibPalUniformColors (4,8,8); break;case IDM_PAL_OPT_POP4:hPalette   = DibPalPopularity (hdib, 4) ;  break ;case IDM_PAL_OPT_POP5:hPalette   = DibPalPopularity (hdib, 5) ;  break ;case IDM_PAL_OPT_POP6:hPalette   = DibPalPopularity (hdib, 6) ;  break ;case IDM_PAL_OPT_MEDCUT:hPalette = DibPalMedianCut  (hdib, 6) ;  break ;}// After processing Palette items from the menu, the cursor// is restored to an arrow, the menu item is checked, and//the window is invalidated.hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;ShowCursor (FALSE) ;SetCursor (LoadCursor (NULL, IDC_ARROW)) ;if (hPalette)PaletteMenu (hMenu, (LOWORD (wParam))) ;InvalidateRect (hwnd, NULL, TRUE) ;return 0 ;// This programmer-defined message deletes an existing DIB//   in preparation for getting a new one.  Invoked during//   File Open command, Edit Paste command, and others.caseWM_USER_DELETEDIB:if (hdib){DibDelete (hdib) ;hdib = NULL ;}SendMessage (hwnd, WM_USER_DELETEPAL, 0, 0) ;return 0 ;// This programmer-defined message deletes an existing palette//in preparation for defining a new one.case WM_USER_DELETEPAL:if (hPalette){DeleteObject (hPalette) ;hPalette = NULL ;fHalftonePalette = FALSE ;PaletteMenu (hMenu, IDM_PAL_NONE) ;}if (hBitmap)DeleteObject (hBitmap) ;return 0 ;// Programmer-defined message to create a new palette based on//a new DIB.  If wParam == TRUE, create a DDB as well.case WM_USER_CREATEPAL:if (hdib){hdc = GetDC (hwnd) ;if (!(RC_PALETTE & GetDeviceCaps (hdc, RASTERCAPS))){PaletteMenu (hMenu, IDM_PAL_NONE) ;}else if (hPalette = DibPalDibTable (hdib)){PaletteMenu (hMenu, IDM_PAL_DIBTABLE) ;}else if (hPalette = CreateHalftonePalette (hdc)){fHalftonePalette = TRUE ;PaletteMenu (hMenu, IDM_PAL_HALFTONE) ;}ReleaseDC (hwnd, hdc) ;if ((BOOL) wParam)hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;}return 0 ;case WM_PAINT:hdc = BeginPaint (hwnd, &ps) ;if (hPalette){SelectPalette (hdc, hPalette, FALSE) ;RealizePalette (hdc) ;}if (hBitmap){DisplayDib (hdc,fHalftonePalette ? DibBitmapHandle (hdib) : hBitmap,iHscroll, iVscroll,cxClient, cyClient,wShow, fHalftonePalette) ;}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 (hdib)DibDelete (hdib) ;if (hBitmap)DeleteObject (hBitmap) ;if (hPalette)DeleteObject (hPalette) ;PostQuitMessage (0) ;return 0 ;}return DefWindowProc (hwnd, message, wParam, lParam) ;}
 DIBBLE.RC (摘錄)//Microsoft Developer Studio generated resource script.#include "resource.h"#include "afxres.h"/////////////////////////////////////////////////////////////////////////////// MenuDIBBLE MENU DISCARDABLE BEGIN POPUP "&File"BEGINMENUITEM "&Open...\tCtrl+O",        IDM_FILE_OPENMENUITEM "&Save...\tCtrl+S",        IDM_FILE_SAVEMENUITEM SEPARATORMENUITEM "&Print...\tCtrl+P",       IDM_FILE_PRINTMENUITEM SEPARATORMENUITEM "Propert&ies...",          IDM_FILE_PROPERTIESMENUITEM SEPARATORMENUITEM "E&xit",      IDM_APP_EXITENDPOPUP "&Edit"BEGINMENUITEM "Cu&t\tCtrl+X",    IDM_EDIT_CUTMENUITEM "&Copy\tCtrl+C",       IDM_EDIT_COPYMENUITEM "&Paste\tCtrl+V",   IDM_EDIT_PASTEMENUITEM "&Delete\tDelete",   IDM_EDIT_DELETEMENUITEM SEPARATORMENUITEM "&Flip",      IDM_EDIT_FLIPMENUITEM "&Rotate",     IDM_EDIT_ROTATEENDPOPUP "&Show"BEGINMENUITEM "&Actual Size", IDM_SHOW_NORMAL, CHECKEDMENUITEM "&Center",   IDM_SHOW_CENTERMENUITEM "&Stretch to Window",  IDM_SHOW_STRETCHMENUITEM "Stretch &Isotropically",IDM_SHOW_ISOSTRETCHENDPOPUP "&Palette"BEGINMENUITEM "&None",IDM_PAL_NONE, CHECKEDMENUITEM "&Dib ColorTable", IDM_PAL_DIBTABLEMENUITEM "&Halftone",     IDM_PAL_HALFTONEMENUITEM "&All-Purpose",    IDM_PAL_ALLPURPOSEPOPUP "&Gray Shades"BEGINMENUITEM "&1. 2 Grays",  IDM_PAL_GRAY2MENUITEM "&2. 3 Grays",       IDM_PAL_GRAY3MENUITEM "&3. 4 Grays",       IDM_PAL_GRAY4MENUITEM "&4. 8 Grays",       IDM_PAL_GRAY8MENUITEM "&5. 16 Grays",      IDM_PAL_GRAY16MENUITEM "&6. 32 Grays",      IDM_PAL_GRAY32MENUITEM "&7. 64 Grays",    IDM_PAL_GRAY64MENUITEM "&8. 128 Grays",    IDM_PAL_GRAY128MENUITEM "&9. 256 Grays",    IDM_PAL_GRAY256ENDPOPUP "&Uniform Colors"BEGINMENUITEM "&1. 2R x 2G x 2B (8)",IDM_PAL_RGB222MENUITEM "&2. 3R x 3G x 3B (27)", IDM_PAL_RGB333MENUITEM "&3. 4R x 4G x 4B (64)",    IDM_PAL_RGB444MENUITEM "&4. 5R x 5G x 5B (125)",      IDM_PAL_RGB555MENUITEM "&5. 6R x 6G x 6B (216)",      IDM_PAL_RGB666MENUITEM "&6. 7R x 7G x 5B (245)",      IDM_PAL_RGB775MENUITEM "&7. 7R x 5B x 7B (245)",      IDM_PAL_RGB757MENUITEM "&8. 5R x 7G x 7B (245)",      IDM_PAL_RGB577MENUITEM "&9. 8R x 8G x 4B (256)",      IDM_PAL_RGB884MENUITEM "&A. 8R x 4G x 8B (256)",      IDM_PAL_RGB848MENUITEM "&B. 4R x 8G x 8B (256)",        IDM_PAL_RGB488ENDPOPUP "&Optimized"BEGINMENUITEM "&1. Popularity Algorithm (4 bits)"IDM_PAL_OPT_POP4MENUITEM "&2. Popularity Algorithm (5 bits)"IDM_PAL_OPT_POP5MENUITEM "&3. Popularity Algorithm (6 bits)"IDM_PAL_OPT_POP6MENUITEM "&4. Median Cut Algorithm ", IDM_PAL_OPT_MEDCUTENDENDPOPUP "Con&vert"BEGINMENUITEM "&1. to 1 bit per pixel",      IDM_CONVERT_01MENUITEM "&2. to 4 bits per pixel",     IDM_CONVERT_04MENUITEM "&3. to 8 bits per pixel",     IDM_CONVERT_08MENUITEM "&4. to 16 bits per pixel",    IDM_CONVERT_16MENUITEM "&5. to 24 bits per pixel",    IDM_CONVERT_24MENUITEM "&6. to 32 bits per pixel",    IDM_CONVERT_32ENDPOPUP "&Help"BEGINMENUITEM "&About",IDM_APP_ABOUTENDEND/////////////////////////////////////////////////////////////////////////////// AcceleratorDIBBLE ACCELERATORS DISCARDABLEBEGIN"C",          IDM_EDIT_COPY,          VIRTKEY, CONTROL, NOINVERT"O",      IDM_FILE_OPEN,          VIRTKEY, CONTROL, NOINVERT"P",      IDM_FILE_PRINT,         VIRTKEY, CONTROL, NOINVERT"S",      IDM_FILE_SAVE,          VIRTKEY, CONTROL, NOINVERT"V",      IDM_EDIT_PASTE,         VIRTKEY, CONTROL, NOINVERTVK_DELETE,      IDM_EDIT_DELETE,        VIRTKEY, NOINVERT"X",      IDM_EDIT_CUT,           VIRTKEY, CONTROL, NOINVERTEND
 RESOURCE.H (摘錄)// Microsoft Developer Studio generated include file.// Used by Dibble.rc#define IDM_FILE_OPEN                40001#define IDM_FILE_SAVE                40002#define IDM_FILE_PRINT               40003#define IDM_FILE_PROPERTIES          40004#define IDM_APP_EXIT                 40005#define IDM_EDIT_CUT                 40006#define IDM_EDIT_COPY                40007#define IDM_EDIT_PASTE               40008#define IDM_EDIT_DELETE              40009#define IDM_EDIT_FLIP                40010#define IDM_EDIT_ROTATE              40011#define IDM_SHOW_NORMAL              40012#define IDM_SHOW_CENTER              40013#define IDM_SHOW_STRETCH             40014#define IDM_SHOW_ISOSTRETCH          40015#define IDM_PAL_NONE                 40016#define IDM_PAL_DIBTABLE             40017#define IDM_PAL_HALFTONE             40018#define IDM_PAL_ALLPURPOSE           40019#define IDM_PAL_GRAY2                40020#define IDM_PAL_GRAY3                40021#define IDM_PAL_GRAY4                40022#define IDM_PAL_GRAY8                40023#define IDM_PAL_GRAY16               40024#define IDM_PAL_GRAY32               40025#define IDM_PAL_GRAY64               40026#define IDM_PAL_GRAY128              40027#define IDM_PAL_GRAY256              40028#define IDM_PAL_RGB222               40029#define IDM_PAL_RGB333               40030#define IDM_PAL_RGB444               40031#define IDM_PAL_RGB555               40032#define IDM_PAL_RGB666               40033#define IDM_PAL_RGB775               40034#define IDM_PAL_RGB757               40035#define IDM_PAL_RGB577               40036#define IDM_PAL_RGB884               40037#define IDM_PAL_RGB848               40038#define IDM_PAL_RGB488               40039#define IDM_PAL_OPT_POP4             40040#define IDM_PAL_OPT_POP5             40041#define IDM_PAL_OPT_POP6             40042#define IDM_PAL_OPT_MEDCUT           40043#define IDM_CONVERT_01               40044#define IDM_CONVERT_04               40045#define IDM_CONVERT_08               40046#define IDM_CONVERT_16               40047#define IDM_CONVERT_24               40048#define IDM_CONVERT_32               40049#define IDM_APP_ABOUT                40050

DIBBLE使用了兩個其他檔案,我將簡要地說明它們。DIBCONV檔案(DIBCONV.C和DIBCONV.H)在兩種不同格式之間轉換-例如,從每圖素24位元轉換成每圖素8位元。DIBPAL檔案(DIBPAL.C和DIBPAL.H)建立調色盤。

DIBBLE維護WndProc中的三個重要的靜態變數。這些是呼叫hdib的HDIB代號、呼叫hPalette的HPALETTE代號和呼叫hBitmap的HBITMAP代號。HDIB來自DIBHELP中的不同函式;HPALETTE來自DIBPAL中的不同函式或CreateHalftonePalette函式;而HBITMAP代號來自DIBHELP.C中的DibCopyToDdb函式並幫助加速螢幕顯示,特別是在256色顯示模式下。不過,無論在程式建立新的「DIB Section」(顯而易見地)或在程式建立不同的調色盤(不很明顯)時,這個代號都必須重新建立。

讓我們從功能上而非循序漸進地來介紹一下DIBBLE。

檔案載入和儲存
 

DIBBLE可以在回應IDM_FILE_LOAD和IDM_FILE_SAVE的WM_COMMAND訊息處理過程中載入DIB檔案並儲存這些檔案。在處理這些訊息處理期間,DIBBLE通過分別呼叫GetOpenFileName和GetSaveFileName來啟動公用檔案對話方塊。

對於「File」、「Save」功能表命令,DIBBLE只需要呼叫DibFileSave。對於「File」、「Open」功能表命令,DIBBLE必須首先刪除前面的HDIB、調色盤和點陣圖物件。它透過發送一個WM_USER_DELETEDIB訊息來完成這件事,此訊息通過呼叫DibDelete和DeleteObject來處理。然後DIBBLE呼叫DIBHELP中的DibFileLoad函式,發送WM_USER_SETSCROLLS和WM_USER_CREATEPAL訊息來重新設定捲動列並建立調色盤。WM_USER_CREATEPAL訊息也位於程式從DIB區塊建立的新的DDB位置。