DIB函数注释
《數(shù)字圖像處理》老師非要用MFC做實(shí)驗(yàn),所以我被迫接觸了一些window api 。一開始看的很辛苦,不過(guò)本著不會(huì)就查,再不會(huì)再查的遞歸解決思想,我也解決了一些問(wèn)題,
不過(guò)MFC的機(jī)制我還是一無(wú)所知,我的本心也不想知道,只能是要用多少就學(xué)多少吧。在這里我給DIB函數(shù)寫了一些注釋,或許能給那些和我一樣剛剛接觸Windows編程的人,
或是湊巧要做圖像處理作業(yè)的人一些幫助。// ************************************************************************
// 文件名:dibapi.cpp
//
// DIB(Independent Bitmap) API函數(shù)庫(kù):
//
// PaintDIB() - 繪制DIB對(duì)象
// CreateDIBPalette() - 創(chuàng)建DIB對(duì)象調(diào)色板
// FindDIBBits() - 返回DIB圖像象素起始位置
// DIBWidth() - 返回DIB寬度
// DIBHeight() - 返回DIB高度
// PaletteSize() - 返回DIB調(diào)色板大小
// DIBNumColors() - 計(jì)算DIB調(diào)色板顏色數(shù)目
// CopyHandle() - 拷貝內(nèi)存塊
//
// SaveDIB() - 將DIB保存到指定文件中
// ReadDIBFile() - 重指定文件中讀取DIB對(duì)象
//
// DIBToPCX256() - 將指定的256色DIB對(duì)象保存為256色PCX文件
// ReadPCX256() - 讀取256色PCX文件
//
// ************************************************************************#include "stdafx.h"
#include "dibapi.h"
#include <io.h>
#include <errno.h>#include <math.h>
#include <direct.h>//目錄/** Dib文件頭標(biāo)志(字符串"BM",寫DIB時(shí)用到該常數(shù))*/
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')//這是在構(gòu)造“BM”在內(nèi)存中的表示,
‘M’的ascii碼是77,它的二進(jìn)制是01001101,左移八位為 0100 1101 0000 0000
‘B’的ascii碼是66,它的二進(jìn)制是01000010,0100 1101 0000 0000|0000 0000 0100 0010=0100 1101 0100 0010
結(jié)果就是BM在內(nèi)存中的表示/*************************************************************************** 函數(shù)名稱:* PaintDIB()** 參數(shù):* HDC hDC - 輸出設(shè)備DC//HDC是一個(gè)結(jié)構(gòu)體指針,結(jié)構(gòu)體內(nèi)只有一個(gè)名為unused的int變量* LPRECT lpDCRect - 繪制矩形區(qū)域//LPRECT是一個(gè)指向tagRECT結(jié)構(gòu)體的指針,//struct tagRECT// {//LONG left;//LONG top;//LONG right;//LONG bottom;//}
//LONG是long的別名,為什么它要取一個(gè)這么沒(méi)有用的別名??????* HDIB hDIB - 指向DIB對(duì)象的指針//HDIB的類型同HDC,但是它不是//Windows內(nèi)置的別名,要自己用DECLARE_HANDLE()宏定義* LPRECT lpDIBRect - 要輸出的DIB區(qū)域//同上* CPalette* pPal - 指向DIB對(duì)象調(diào)色板的指針//CPalette是一個(gè)封裝了Window
//調(diào)色板的類,Windows調(diào)色板是一個(gè)設(shè)備借口,應(yīng)用程序利用這個(gè)接口,使用設(shè)備的顏
//色處理能力** 返回值:* BOOL - 繪制成功返回TRUE,否則返回FALSE。** 說(shuō)明:* 該函數(shù)主要用來(lái)繪制DIB對(duì)象。其中調(diào)用了StretchDIBits()或者* SetDIBitsToDevice()來(lái)繪制DIB對(duì)象。輸出的設(shè)備由由參數(shù)hDC指* 定;繪制的矩形區(qū)域由參數(shù)lpDCRect指定;輸出DIB的區(qū)域由參數(shù)* lpDIBRect指定。*************************************************************************/BOOL WINAPI PaintDIB(HDC hDC,LPRECT lpDCRect,HDIB hDIB,LPRECT lpDIBRect,//應(yīng)該指在lpDCRect中的區(qū)域吧?CPalette* pPal)
{LPSTR lpDIBHdr; // BITMAPINFOHEADER指針,LPSTR是char*的別
//名LPSTR lpDIBBits; // DIB象素指針BOOL bSuccess=FALSE; // 成功標(biāo)志HPALETTE hPal=NULL; // DIB調(diào)色板,HPALETTE是一個(gè)結(jié)構(gòu)體指針,結(jié)
//構(gòu)體內(nèi)只有一個(gè)int 名為unusedHPALETTE hOldPal=NULL; // 以前的調(diào)色板// 判斷DIB對(duì)象是否為空if (hDIB == NULL){// 返回return FALSE;}// 鎖定DIBlpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);//HGLOBAL是一個(gè)void*,
只有鎖定了一塊內(nèi)存才能操作它,其實(shí)這個(gè)語(yǔ)句,把位圖的這塊內(nèi)存的地址放在了lpDIBHdr,這樣每次移動(dòng)剛好是一個(gè)字節(jié)// 找到DIB圖像象素起始位置lpDIBBits = ::FindDIBBits(lpDIBHdr);//找到位圖信息的開始地址// 獲取DIB調(diào)色板,并選中它if (pPal != NULL){hPal = (HPALETTE) pPal->m_hObject;//這個(gè)數(shù)據(jù)成員是一個(gè)句柄集包含很多綁定到對(duì)象的句柄// 選中調(diào)色板hOldPal = ::SelectPalette(hDC, hPal, TRUE);//該函數(shù)選擇指定的邏輯調(diào)色板到一個(gè)設(shè)備環(huán)境中,并給這個(gè)邏輯調(diào)色板映射一個(gè)物理調(diào)色板}// 設(shè)置顯示模式::SetStretchBltMode(hDC, COLORONCOLOR);設(shè)置顯示設(shè)備環(huán)境中的位圖拉伸模式,COLORONCOLOR:刪除像素。該模式刪除所有消除的像素行,不保留其信息。// 判斷是調(diào)用StretchDIBits()還是SetDIBitsToDevice()來(lái)繪制DIB對(duì)象if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&(RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))//#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left),
//#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top),這是兩個(gè)宏定義函數(shù),獲得矩形的寬度,獲得矩形的高度。
//如果繪圖區(qū)域大小和位圖圖像大小一樣,則不用拉伸{// 原始大小,不用拉伸。bSuccess = ::SetDIBitsToDevice(hDC, // hDC,輸出的設(shè)備lpDCRect->left, // DestX,繪圖區(qū)域的坐標(biāo)lpDCRect->top, // DestY,同上RECTWIDTH(lpDCRect), // nDestWidth,繪圖區(qū)域的寬度,調(diào)用了一個(gè)宏函數(shù)RECTHEIGHT(lpDCRect), // nDestHeight,繪圖區(qū)域的高度,調(diào)用了一個(gè)宏函數(shù)lpDIBRect->left, // SrcX,位圖起始坐標(biāo),這個(gè)坐標(biāo)在左下,這和位圖在內(nèi)存中是由左
//到右由下到上儲(chǔ)存有關(guān)(int)DIBHeight(lpDIBHdr) -lpDIBRect->top -RECTHEIGHT(lpDIBRect), // SrcY,y坐標(biāo)不知道怎么來(lái)的?????0, // nStartScan//繪圖區(qū)域開始掃描的行(WORD)DIBHeight(lpDIBHdr), // nNumScans//掃描位圖的行數(shù),從起始行開始掃描lpDIBBits, // lpBits//位圖內(nèi)存的起始位置(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo//把位圖文件的內(nèi)存直接轉(zhuǎn)換為指向位圖信息頭的指針,就可以獲 //得想要的內(nèi)存塊?
//typedef struct tagBITMAPINFO {// BITMAPINFOHEADER bmiHeader;// RGBQUAD bmiColors[1];
}DIB_RGB_COLORS); // wUsage表示顏色表包含原義的RGB值//如何理解這個(gè)函數(shù):以上都是個(gè)人看法}else{// 非原始大小,拉伸。bSuccess = ::StretchDIBits(hDC, // hDClpDCRect->left, // DestXlpDCRect->top, // DestYRECTWIDTH(lpDCRect), // nDestWidthRECTHEIGHT(lpDCRect), // nDestHeightlpDIBRect->left, // SrcXlpDIBRect->top, // SrcYRECTWIDTH(lpDIBRect), // wSrcWidthRECTHEIGHT(lpDIBRect), // wSrcHeightlpDIBBits, // lpBits(LPBITMAPINFO)lpDIBHdr, // lpBitsInfoDIB_RGB_COLORS, // wUsageSRCCOPY); // dwROP}// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 恢復(fù)以前的調(diào)色板if (hOldPal != NULL){::SelectPalette(hDC, hOldPal, TRUE);}// 返回return bSuccess;
}/*************************************************************************** 函數(shù)名稱:* CreateDIBPalette()** 參數(shù):* HDIB hDIB - 指向DIB對(duì)象的指針* CPalette* pPal - 指向DIB對(duì)象調(diào)色板的指針** 返回值:* BOOL - 創(chuàng)建成功返回TRUE,否則返回FALSE。** 說(shuō)明:* 該函數(shù)按照DIB創(chuàng)建一個(gè)邏輯調(diào)色板,從DIB中讀取顏色表并存到調(diào)色板中,* 最后按照該邏輯調(diào)色板創(chuàng)建一個(gè)新的Windows調(diào)色板,并返回該調(diào)色板的句柄。這樣* 可以用最好的顏色來(lái)顯示DIB圖像。*************************************************************************/BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal)
{// 指向邏輯調(diào)色板的指針LPLOGPALETTE lpPal;// 邏輯調(diào)色板的句柄HANDLE hLogPal;// 調(diào)色板的句柄HPALETTE hPal = NULL;// 循環(huán)變量int i;// 顏色表中的顏色數(shù)目WORD wNumColors;// 指向DIB的指針LPSTR lpbi;// 指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)LPBITMAPINFO lpbmi;// 指向BITMAPCOREINFO結(jié)構(gòu)的指針LPBITMAPCOREINFO lpbmc;// 表明是否是Win3.0 DIB的標(biāo)記BOOL bWinStyleDIB;// 創(chuàng)建結(jié)果BOOL bResult = FALSE;// 判斷DIB是否為空if (hDIB == NULL){// 返回FALSEreturn FALSE;}// 鎖定DIBlpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);// 獲取指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)lpbmi = (LPBITMAPINFO)lpbi;// 獲取指向BITMAPCOREINFO結(jié)構(gòu)的指針lpbmc = (LPBITMAPCOREINFO)lpbi;// 獲取DIB中顏色表中的顏色數(shù)目wNumColors = ::DIBNumColors(lpbi);if (wNumColors != 0){// 分配為邏輯調(diào)色板內(nèi)存hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)+ sizeof(PALETTEENTRY)* wNumColors);// 如果內(nèi)存不足,退出if (hLogPal == 0){// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 返回FALSEreturn FALSE;}lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);// 設(shè)置版本號(hào)lpPal->palVersion = PALVERSION;// 設(shè)置顏色數(shù)目lpPal->palNumEntries = (WORD)wNumColors;// 判斷是否是WIN3.0的DIBbWinStyleDIB = IS_WIN30_DIB(lpbi);// 讀取調(diào)色板for (i = 0; i < (int)wNumColors; i++){if (bWinStyleDIB){// 讀取紅色分量lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;// 讀取綠色分量lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;// 讀取藍(lán)色分量lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;// 保留位lpPal->palPalEntry[i].peFlags = 0;}else{// 讀取紅色分量lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;// 讀取綠色分量lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;// 讀取紅色分量lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;// 保留位lpPal->palPalEntry[i].peFlags = 0;}}// 按照邏輯調(diào)色板創(chuàng)建調(diào)色板,并返回指針bResult = pPal->CreatePalette(lpPal);// 解除鎖定::GlobalUnlock((HGLOBAL) hLogPal);// 釋放邏輯調(diào)色板::GlobalFree((HGLOBAL) hLogPal);}// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 返回結(jié)果return bResult;
}/*************************************************************************** 函數(shù)名稱:* FindDIBBits()** 參數(shù):* LPSTR lpbi - 指向DIB對(duì)象的指針** 返回值:* LPSTR - 指向DIB圖像象素起始位置** 說(shuō)明:* 該函數(shù)計(jì)算DIB中圖像象素的起始位置,并返回指向它的指針。*************************************************************************/LPSTR WINAPI FindDIBBits(LPSTR lpbi)
{return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));//這一句的邏輯是認(rèn)為位圖圖像是不包含BITMAPFILEHEADER的,大概句柄不包含F(xiàn)ILEHEADER了吧!
}/*************************************************************************** 函數(shù)名稱:* DIBWidth()** 參數(shù):* LPSTR lpbi - 指向DIB對(duì)象的指針** 返回值:* DWORD - DIB中圖像的寬度** 說(shuō)明:* 該函數(shù)返回DIB中圖像的寬度。對(duì)于Windows 3.0 DIB,返回BITMAPINFOHEADER* 中的biWidth值;對(duì)于其它返回BITMAPCOREHEADER中的bcWidth值。*************************************************************************/DWORD WINAPI DIBWidth(LPSTR lpDIB)
{// 指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)LPBITMAPINFOHEADER lpbmi;// 指向BITMAPCOREINFO結(jié)構(gòu)的指針LPBITMAPCOREHEADER lpbmc;// 獲取指針lpbmi = (LPBITMAPINFOHEADER)lpDIB;//竟然可以這樣獲取指針,好智能啊!!!!lpbmc = (LPBITMAPCOREHEADER)lpDIB;// 返回DIB中圖像的寬度if (IS_WIN30_DIB(lpDIB)){// 對(duì)于Windows 3.0 DIB,返回lpbmi->biWidthreturn lpbmi->biWidth;}else{// 對(duì)于其它格式的DIB,返回lpbmc->bcWidthreturn (DWORD)lpbmc->bcWidth;//位圖寬四個(gè)字節(jié)}
}/*************************************************************************** 函數(shù)名稱:* DIBHeight()** 參數(shù):* LPSTR lpDIB - 指向DIB對(duì)象的指針** 返回值:* DWORD - DIB中圖像的高度** 說(shuō)明:* 該函數(shù)返回DIB中圖像的高度。對(duì)于Windows 3.0 DIB,返回BITMAPINFOHEADER* 中的biHeight值;對(duì)于其它返回BITMAPCOREHEADER中的bcHeight值。
我覺(jué)得大部分都是3.0*************************************************************************/DWORD WINAPI DIBHeight(LPSTR lpDIB)
{// 指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)LPBITMAPINFOHEADER lpbmi;// 指向BITMAPCOREINFO結(jié)構(gòu)的指針LPBITMAPCOREHEADER lpbmc;// 獲取指針lpbmi = (LPBITMAPINFOHEADER)lpDIB;lpbmc = (LPBITMAPCOREHEADER)lpDIB;// 返回DIB中圖像的寬度if (IS_WIN30_DIB(lpDIB)){// 對(duì)于Windows 3.0 DIB,返回lpbmi->biHeightreturn lpbmi->biHeight;}else{// 對(duì)于其它格式的DIB,返回lpbmc->bcHeightreturn (DWORD)lpbmc->bcHeight;}
}//只考慮3.0就好了/*************************************************************************** 函數(shù)名稱:* PaletteSize()** 參數(shù):* LPSTR lpbi - 指向DIB對(duì)象的指針** 返回值:* WORD - DIB中調(diào)色板的大小** 說(shuō)明:* 該函數(shù)返回DIB中調(diào)色板的大小。對(duì)于Windows 3.0 DIB,返回顏色數(shù)目×* RGBQUAD的大小;對(duì)于其它返回顏色數(shù)目×RGBTRIPLE的大小。*************************************************************************/WORD WINAPI PaletteSize(LPSTR lpbi)
{// 計(jì)算DIB中調(diào)色板的大小if (IS_WIN30_DIB (lpbi)){//返回顏色數(shù)目×RGBQUAD的大小return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));//只考慮這種情況就好了}else{//返回顏色數(shù)目×RGBTRIPLE的大小return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));}
}/*************************************************************************** 函數(shù)名稱:* DIBNumColors()** 參數(shù):* LPSTR lpbi - 指向DIB對(duì)象的指針** 返回值:* WORD - 返回調(diào)色板中顏色的種數(shù)** 說(shuō)明:* 該函數(shù)返回DIB中調(diào)色板的顏色的種數(shù)。對(duì)于單色位圖,返回2,* 對(duì)于16色位圖,返回16,對(duì)于256色位圖,返回256;對(duì)于真彩色* 位圖(24位),沒(méi)有調(diào)色板,返回0。*************************************************************************/
WORD WINAPI DIBNumColors(LPSTR lpbi)
{WORD wBitCount;// 對(duì)于Windows的DIB, 實(shí)際顏色的數(shù)目可以比象素的位數(shù)要少。// 對(duì)于這種情況,則返回一個(gè)近似的數(shù)值。// 判斷是否是WIN3.0 DIBif (IS_WIN30_DIB(lpbi)){DWORD dwClrUsed;// 讀取dwClrUsed值dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;if (dwClrUsed != 0){// 如果dwClrUsed(實(shí)際用到的顏色數(shù))不為0,直接返回該值,如果為0,表示全部都用到了,或者沒(méi)有全部用到,但是沒(méi)有記錄要的數(shù)目return (WORD)dwClrUsed;}}// 讀取象素的位數(shù)if (IS_WIN30_DIB(lpbi)){// 讀取biBitCount值wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;}else{// 讀取biBitCount值wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;}// 按照象素的位數(shù)計(jì)算顏色數(shù)目switch (wBitCount){case 1:return 2;case 4:return 16;case 8:return 256;default:return 0;}
}//只考慮window 3.0的情況就可以了/*************************************************************************** 函數(shù)名稱:* DIBBitCount()** 參數(shù):* LPSTR lpbi - 指向DIB對(duì)象的指針** 返回值:* WORD - 返回調(diào)色板中顏色的種數(shù)** 說(shuō)明:* 該函數(shù)返回DIBBitCount。*************************************************************************/
WORD WINAPI DIBBitCount(LPSTR lpbi)
{WORD wBitCount;// 讀取象素的位數(shù)if (IS_WIN30_DIB(lpbi)){// 讀取biBitCount值wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;}else{// 讀取biBitCount值wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;}// 返回wBitCountreturn wBitCount;
}//返回像素值位數(shù)/*************************************************************************** 函數(shù)名稱:* CopyHandle()** 參數(shù):* HGLOBAL h - 要復(fù)制的內(nèi)存區(qū)域** 返回值:* HGLOBAL - 復(fù)制后的新內(nèi)存區(qū)域** 說(shuō)明:* 該函數(shù)復(fù)制指定的內(nèi)存區(qū)域。返回復(fù)制后的新內(nèi)存區(qū)域,出錯(cuò)時(shí)返回0。*************************************************************************/HGLOBAL WINAPI CopyHandle (HGLOBAL h)//HGLOBAL是void*類型
{if (h == NULL)return NULL;// 獲取指定內(nèi)存區(qū)域大小DWORD dwLen = ::GlobalSize((HGLOBAL) h);// 分配新內(nèi)存空間,GHND標(biāo)志分配的內(nèi)存是可以移動(dòng)的,且初始化為0,返回一個(gè)句柄。HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);// 判斷分配是否成功if (hCopy != NULL){// 鎖定內(nèi)存,獲得指針void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);void* lp = ::GlobalLock((HGLOBAL) h);// 復(fù)制memcpy(lpCopy, lp, dwLen);
//內(nèi)存拷貝函數(shù),向指定內(nèi)存起始地址拷貝從指定內(nèi)存地址開始的指定字節(jié)內(nèi)存內(nèi)容// 解除鎖定::GlobalUnlock(hCopy);::GlobalUnlock(h);}return hCopy;//返回新內(nèi)存塊的句柄
}/*************************************************************************** 函數(shù)名稱:* SaveDIB()** 參數(shù):* HDIB hDib - 要保存的DIB* CFile& file - 保存文件CFile** 返回值:* BOOL - 成功返回TRUE,否則返回FALSE或者CFileException** 說(shuō)明:* 該函數(shù)將指定的DIB對(duì)象保存到指定的CFile中。該CFile由調(diào)用程序打開和關(guān)閉。**************************************************************************/BOOL WINAPI SaveDIB(HDIB hDib, CFile& file)
{// Bitmap文件頭BITMAPFILEHEADER bmfHdr;// 指向BITMAPINFOHEADER的指針LPBITMAPINFOHEADER lpBI;// DIB大小DWORD dwDIBSize;if (hDib == NULL){// 如果DIB為空,返回FALSEreturn FALSE;}// 讀取BITMAPINFO結(jié)構(gòu),并鎖定lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);//獲得這個(gè)結(jié)構(gòu)體的指針的方法,直接鎖定位圖文件的內(nèi)存,再把它//強(qiáng)制類型轉(zhuǎn)換為BITMAPINFOHEADER指針即可,真是匪夷所思。if (lpBI == NULL){// 為空,返回FALSEreturn FALSE;}// 判斷是否是WIN3.0 DIBif (!IS_WIN30_DIB(lpBI))//都什么時(shí)代了還再考慮win3.0的事情。{// 不支持其它類型的DIB保存// 解除鎖定::GlobalUnlock((HGLOBAL) hDib);// 返回FALSEreturn FALSE;}// 填充文件頭// 文件類型"BM"bmfHdr.bfType = DIB_HEADER_MARKER;
//DIB_HEADER_MARKER是一個(gè)宏定義的操作
//構(gòu)造了 BM 這兩個(gè)字符在內(nèi)存中的表示,前文已述,它不是字符串。// 計(jì)算DIB大小時(shí),最簡(jiǎn)單的方法是調(diào)用GlobalSize()函數(shù)。但是全局內(nèi)存大小并// 不是DIB真正的大小,它總是多幾個(gè)字節(jié)。這樣就需要計(jì)算一下DIB的真實(shí)大小。// 文件頭大小+顏色表大小// (BITMAPINFOHEADER和BITMAPCOREHEADER結(jié)構(gòu)的第一個(gè)DWORD都是該結(jié)構(gòu)的大小)dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);
//這里強(qiáng)調(diào)了,dib文件的大小沒(méi)有包含文件頭。// 計(jì)算圖像大小if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
//對(duì)于壓縮類型無(wú)法計(jì)算{// 對(duì)于RLE位圖,沒(méi)法計(jì)算大小,只能信任biSizeImage內(nèi)的值dwDIBSize += lpBI->biSizeImage;}else{// 象素的大小DWORD dwBmBitsSize;// 大小為Width * HeightdwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
//WIDTHBYTES,這個(gè)宏計(jì)算行的字節(jié)數(shù),這個(gè)宏要求的參數(shù)是行的位數(shù)。// 計(jì)算出DIB真正的大小dwDIBSize += dwBmBitsSize;// 更新biSizeImage(很多BMP文件頭中biSizeImage的值是錯(cuò)誤的)lpBI->biSizeImage = dwBmBitsSize;}// 計(jì)算文件大小:DIB大小+BITMAPFILEHEADER結(jié)構(gòu)大小bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);// 兩個(gè)保留字bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;// 計(jì)算偏移量bfOffBits,它的大小為Bitmap文件頭大小+DIB頭大小+顏色表大小,這個(gè)偏移量就是位圖圖像的開始地址。bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize+ PaletteSize((LPSTR)lpBI);// 嘗試寫文件TRY{// 寫文件頭file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));// 寫DIB頭和象素file.WriteHuge(lpBI, dwDIBSize);//直接寫就可了嗎,或許MFC已經(jīng)為CFILE綁定好了文件。}CATCH (CFileException, e){// 解除鎖定::GlobalUnlock((HGLOBAL) hDib);// 拋出異常THROW_LAST();}END_CATCH// 解除鎖定::GlobalUnlock((HGLOBAL) hDib);// 返回TRUEreturn TRUE;
}/*************************************************************************** 函數(shù)名稱:* ReadDIBFile()** 參數(shù):* CFile& file - 要讀取得文件文件CFile** 返回值:* HDIB - 成功返回DIB的句柄,否則返回NULL。** 說(shuō)明:* 該函數(shù)將指定的文件中的DIB對(duì)象讀到指定的內(nèi)存區(qū)域中。除BITMAPFILEHEADER* 外的內(nèi)容都將被讀入內(nèi)存。**************************************************************************/HDIB WINAPI ReadDIBFile(CFile& file)
{BITMAPFILEHEADER bmfHeader;DWORD dwBitsSize;HDIB hDIB;LPSTR pDIB;//char*類型// 獲取DIB(文件)長(zhǎng)度(字節(jié))dwBitsSize = file.GetLength();//這個(gè)是全部DIB的大小// 嘗試讀取DIB文件頭if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader)){// 大小不對(duì),返回NULL。return NULL;}// 判斷是否是DIB對(duì)象,檢查頭兩個(gè)字節(jié)是否是"BM"if (bmfHeader.bfType != DIB_HEADER_MARKER){// 非DIB對(duì)象,返回NULL。return NULL;}// 為DIB分配內(nèi)存hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
//為DIB分配內(nèi)存,分配的內(nèi)存多余要求
//這個(gè)內(nèi)存是可動(dòng)的,初始化為0if (hDIB == 0){// 內(nèi)存分配失敗,返回NULL。return NULL;}// 鎖定pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);//鎖定內(nèi)存,獲得指針// 讀象素if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=dwBitsSize - sizeof(BITMAPFILEHEADER) ){// 大小不對(duì)。// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 釋放內(nèi)存::GlobalFree((HGLOBAL) hDIB);// 返回NULL。return NULL;}// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 返回DIB句柄return hDIB;
}//總結(jié),
//讀dib位圖文件,先把BITMAPFILEHEADER隨便讀到內(nèi)存中來(lái),判斷這是否是一個(gè)位圖圖
//像,如果是位圖文件,
//這分配一段內(nèi)存,把剩下的文件全部讀進(jìn)來(lái),
//可見,位圖句柄所指向的內(nèi)存
//包含位圖信息頭,調(diào)色板信息,位圖內(nèi)容,不包含位圖文件頭。
/*************************************************************************** 函數(shù)名稱:* DIBToPCX256()** 參數(shù):* LPSTR lpDIB - 指向DIB對(duì)象的指針* CFile& file - 要保存的文件** 返回值:* BOOL - 成功返回True,否則返回False。** 說(shuō)明:* 該函數(shù)將指定的256色DIB對(duì)象保存為256色PCX文件。**************************************************************************///以下兩個(gè)函數(shù)似乎沒(méi)有用到,暫時(shí)不研究了。BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file)
{// 循環(huán)變量LONG i;LONG j;// DIB高度WORD wHeight;// DIB寬度WORD wWidth;// 中間變量BYTE bChar1;BYTE bChar2;// 指向源圖像象素的指針BYTE * lpSrc;// 指向編碼后圖像數(shù)據(jù)的指針BYTE * lpDst;// 圖像每行的字節(jié)數(shù)LONG lLineBytes;// 重復(fù)像素計(jì)數(shù)int iCount;// 緩沖區(qū)已使用的字節(jié)數(shù)DWORD dwBuffUsed;// 指向DIB象素指針LPSTR lpDIBBits;// 獲取DIB高度wHeight = (WORD) DIBHeight(lpDIB);// 獲取DIB寬度wWidth = (WORD) DIBWidth(lpDIB);// 找到DIB圖像象素起始位置lpDIBBits = FindDIBBits(lpDIB);// 計(jì)算圖像每行的字節(jié)數(shù)lLineBytes = WIDTHBYTES(wWidth * 8);//*************************************************************************// PCX文件頭PCXHEADER pcxHdr;// 給文件頭賦值// PCX標(biāo)識(shí)碼pcxHdr.bManufacturer = 0x0A;// PCX版本號(hào)pcxHdr.bVersion = 5;// PCX編碼方式(1表示RLE編碼)pcxHdr.bEncoding = 1;// 像素位數(shù)(256色為8位)pcxHdr.bBpp = 8;// 圖像相對(duì)于屏幕的左上角X坐標(biāo)(以像素為單位)pcxHdr.wLeft = 0;// 圖像相對(duì)于屏幕的左上角Y坐標(biāo)(以像素為單位)pcxHdr.wTop = 0;// 圖像相對(duì)于屏幕的右下角X坐標(biāo)(以像素為單位)pcxHdr.wRight = wWidth - 1;// 圖像相對(duì)于屏幕的右下角Y坐標(biāo)(以像素為單位)pcxHdr.wBottom = wHeight - 1;// 圖像的水平分辨率pcxHdr.wXResolution = wWidth;// 圖像的垂直分辨率pcxHdr.wYResolution = wHeight;// 調(diào)色板數(shù)據(jù)(對(duì)于256色PCX無(wú)意義,直接賦值為0)for (i = 0; i < 48; i ++){pcxHdr.bPalette[i] = 0;}// 保留域,設(shè)定為0。pcxHdr.bReserved = 0;// 圖像色彩平面數(shù)目(對(duì)于256色PCX設(shè)定為1)。pcxHdr.bPlanes = 1;// 圖像的寬度(字節(jié)為單位),必須為偶數(shù)。
// if ((wWidth & 1) == 0)
// {pcxHdr.wLineBytes = wWidth;
// }
// else
// {
// pcxHdr.wLineBytes = wWidth + 1;
// }// 圖像調(diào)色板的類型,1表示彩色或者單色圖像,2表示圖像是灰度圖。pcxHdr.wPaletteType = 1;// 制作該圖像的屏幕寬度(像素為單位)pcxHdr.wSrcWidth = 0;// 制作該圖像的屏幕高度(像素為單位)pcxHdr.wSrcDepth = 0;// 保留域,取值設(shè)定為0。for (i = 0; i < 54; i ++){pcxHdr.bFiller[i] = 0;}// 寫入文件頭file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER));//*******************************************************************************// 開始編碼// 開辟一片緩沖區(qū)(2被原始圖像大小)以保存編碼結(jié)果lpDst = new BYTE[wHeight * wWidth * 2];// 指明當(dāng)前已經(jīng)用了多少緩沖區(qū)(字節(jié)數(shù))dwBuffUsed = 0;// 每行for (i = 0; i < wHeight; i++){// 指向DIB第i行,第0個(gè)象素的指針lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i);// 給bChar1賦值bChar1 = *lpSrc;// 設(shè)置iCount為1iCount = 1;// 剩余列for (j = 1; j < wWidth; j ++){// 指向DIB第i行,第j個(gè)象素的指針lpSrc++;// 讀取下一個(gè)像素bChar2 = *lpSrc;// 判斷是否和bChar1相同并且iCount < 63if ((bChar1 == bChar2) && (iCount < 63)){// 相同,計(jì)數(shù)加1iCount ++;// 繼續(xù)讀下一個(gè)}else{// 不同,或者iCount = 63// 寫入緩沖區(qū)if ((iCount > 1) || (bChar1 >= 0xC0)){// 保存碼長(zhǎng)信息lpDst[dwBuffUsed] = iCount | 0xC0;// 保存bChar1lpDst[dwBuffUsed + 1] = bChar1;// 更新dwBuffUseddwBuffUsed += 2;}else{// 直接保存該值lpDst[dwBuffUsed] = bChar1;// 更新dwBuffUseddwBuffUsed ++;}// 重新給bChar1賦值bChar1 = bChar2;// 設(shè)置iCount為1iCount = 1;}}// 保存每行最后一部分編碼if ((iCount > 1) || (bChar1 >= 0xC0)){// 保存碼長(zhǎng)信息lpDst[dwBuffUsed] = iCount | 0xC0;// 保存bChar1lpDst[dwBuffUsed + 1] = bChar1;// 更新dwBuffUseddwBuffUsed += 2;}else{// 直接保存該值lpDst[dwBuffUsed] = bChar1;// 更新dwBuffUseddwBuffUsed ++;}}// 寫入編碼結(jié)果file.WriteHuge((LPSTR)lpDst, dwBuffUsed);// 釋放內(nèi)存delete lpDst;//**************************************************************************// 寫入調(diào)色板信息// 指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)LPBITMAPINFO lpbmi;// 指向BITMAPCOREINFO結(jié)構(gòu)的指針LPBITMAPCOREINFO lpbmc;// 表明是否是Win3.0 DIB的標(biāo)記BOOL bWinStyleDIB;// 開辟一片緩沖區(qū)以保存調(diào)色板lpDst = new BYTE[769];// 調(diào)色板起始字節(jié)* lpDst = 0x0C;// 獲取指向BITMAPINFO結(jié)構(gòu)的指針(Win3.0)lpbmi = (LPBITMAPINFO)lpDIB;// 獲取指向BITMAPCOREINFO結(jié)構(gòu)的指針lpbmc = (LPBITMAPCOREINFO)lpDIB;// 判斷是否是WIN3.0的DIBbWinStyleDIB = IS_WIN30_DIB(lpDIB);// 讀取當(dāng)前DIB調(diào)色板for (i = 0; i < 256; i ++){if (bWinStyleDIB){// 讀取DIB調(diào)色板紅色分量lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed;// 讀取DIB調(diào)色板綠色分量lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen;// 讀取DIB調(diào)色板藍(lán)色分量lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue;}else{// 讀取DIB調(diào)色板紅色分量lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed;// 讀取DIB調(diào)色板綠色分量lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen;// 讀取DIB調(diào)色板藍(lán)色分量lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue;}}// 寫入調(diào)色板信息file.Write((LPSTR)lpDst, 769);// 返回return TRUE;
}/*************************************************************************** 函數(shù)名稱:* ReadPCX256()** 參數(shù):* CFile& file - 要讀取的文件** 返回值:* HDIB - 成功返回DIB的句柄,否則返回NULL。** 說(shuō)明:* 該函數(shù)將讀取指定的256色PCX文件。將讀取的結(jié)果保存在一個(gè)未壓縮* 編碼的DIB對(duì)象中。**************************************************************************/
HDIB WINAPI ReadPCX256(CFile& file)
{// PCX文件頭PCXHEADER pcxHdr;// DIB大小(字節(jié)數(shù))DWORD dwDIBSize;// DIB句柄HDIB hDIB;// DIB指針LPSTR pDIB;// 循環(huán)變量LONG i;LONG j;// 重復(fù)像素計(jì)數(shù)int iCount;// DIB高度WORD wHeight;// DIB寬度WORD wWidth;// 圖像每行的字節(jié)數(shù)LONG lLineBytes;// 中間變量BYTE bChar;// 指向源圖像象素的指針BYTE * lpSrc;// 指向編碼后圖像數(shù)據(jù)的指針BYTE * lpDst;// 臨時(shí)指針BYTE * lpTemp;// 嘗試讀取PCX文件頭if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER)){// 大小不對(duì),返回NULL。return NULL;}// 判斷是否是256色PCX文件,檢查第一個(gè)字節(jié)是否是0x0A,if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1)){// 非256色PCX文件,返回NULL。return NULL;}// 獲取圖像高度wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1;// 獲取圖像寬度wWidth = pcxHdr.wRight - pcxHdr.wLeft + 1;// 計(jì)算圖像每行的字節(jié)數(shù)lLineBytes = WIDTHBYTES(wWidth * 8);// 計(jì)算DIB長(zhǎng)度(字節(jié))dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes;// 為DIB分配內(nèi)存hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize);if (hDIB == 0){// 內(nèi)存分配失敗,返回NULL。return NULL;}// 鎖定pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);// 指向BITMAPINFOHEADER的指針LPBITMAPINFOHEADER lpBI;// 賦值lpBI = (LPBITMAPINFOHEADER) pDIB;// 給lpBI成員賦值lpBI->biSize = 40;lpBI->biWidth = wWidth;lpBI->biHeight = wHeight;lpBI->biPlanes = 1;lpBI->biBitCount = 8;lpBI->biCompression = BI_RGB;lpBI->biSizeImage = wHeight * lLineBytes;lpBI->biXPelsPerMeter = pcxHdr.wXResolution;lpBI->biYPelsPerMeter = pcxHdr.wYResolution;lpBI->biClrUsed = 0;lpBI->biClrImportant = 0;// 分配內(nèi)存以讀取編碼后的象素lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769];lpTemp = lpSrc;// 讀取編碼后的象素if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) !=file.GetLength() - sizeof(PCXHEADER) - 769 ){// 大小不對(duì)。// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 釋放內(nèi)存::GlobalFree((HGLOBAL) hDIB);// 返回NULL。return NULL;}// 計(jì)算DIB中像素位置lpDst = (BYTE *) FindDIBBits(pDIB);// 一行一行解碼for (j = 0; j <wHeight; j++){i = 0;while (i < wWidth){// 讀取一個(gè)字節(jié)bChar = *lpTemp;lpTemp++;if ((bChar & 0xC0) == 0xC0){// 行程iCount = bChar & 0x3F;// 讀取下一個(gè)字節(jié)bChar = *lpTemp;lpTemp++;// bChar重復(fù)iCount次保存memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount);// 已經(jīng)讀取像素的個(gè)數(shù)加iCounti += iCount;}else{// 保存當(dāng)前字節(jié)lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar;// 已經(jīng)讀取像素的個(gè)數(shù)加1i += 1;}}}// 釋放內(nèi)存delete lpSrc;//*************************************************************// 調(diào)色板// 讀調(diào)色板標(biāo)志位file.Read(&bChar, 1);if (bChar != 0x0C){// 出錯(cuò)// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 釋放內(nèi)存::GlobalFree((HGLOBAL) hDIB);// 返回NULL。return NULL;}// 分配內(nèi)存以讀取編碼后的象素lpSrc = new BYTE[768];// 計(jì)算DIB中調(diào)色板的位置lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER);// 讀取調(diào)色板if (file.Read(lpSrc, 768) != 768){// 大小不對(duì)。// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 釋放內(nèi)存::GlobalFree((HGLOBAL) hDIB);// 返回NULL。return NULL;}// 給調(diào)色板賦值for (i = 0; i < 256; i++){lpDst[i * 4] = lpSrc[i * 3 + 2];lpDst[i * 4 + 1] = lpSrc[i * 3 + 1];lpDst[i * 4 + 2] = lpSrc[i * 3];lpDst[i * 4 + 3] = 0;}// 釋放內(nèi)存delete lpSrc;// 解除鎖定::GlobalUnlock((HGLOBAL) hDIB);// 返回DIB句柄return hDIB;
}
總結(jié)
- 上一篇: 非接触式IC卡简介
- 下一篇: 计算机实训实验报告,计算机实训实验报告.