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