下面就是壹個構造的DIB類,但是僅僅提供了最基本的壹些操作,代碼來自《Visual C++數字圖像處理典型算法及實現》。// DibImage.h: interface for the CDibImage class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_DIBIMAGE_H__254F3D1E_BB20_40DA_AE07_E8E0219DFA8C__INCLUDED_)
#define AFX_DIBIMAGE_H__254F3D1E_BB20_40DA_AE07_E8E0219DFA8C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
DECLARE_HANDLE(HDIB); // DIB句柄
#define PALVERSION 0x300 // DIB常量
/* DIB宏 */
// 判斷是否是Win 3.0的DIB
#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
// 計算矩形區域的寬度
#define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left)
// 計算矩形區域的高度
#define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top)
// 在計算圖像大小時,采用公式:biSizeImage = biWidth' × biHeight。
// 是biWidth',而不是biWidth,這裏的biWidth'必須是4的整倍數,表示
// 大於或等於biWidth的,離4最近的整倍數。WIDTHBYTES就是用來計算
// biWidth'
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
// Dib文件頭標誌(字符串"BM",寫DIB時用到該常數)
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
class CDibImage
{
// Constructor and Destructor ///////////////////////////////
public:
CDibImage();
virtual ~CDibImage();
// function /////////////////////////////////////////////////
public:
BOOL PaintDIB (HDC, LPRECT, HDIB, LPRECT, CPalette* pPal);
BOOL CreateDIBPalette(HDIB hDIB, CPalette* cPal);
LPSTR FindDIBBits (LPSTR lpbi);
DWORD DIBWidth (LPSTR lpDIB);
DWORD DIBHeight (LPSTR lpDIB);
WORD PaletteSize (LPSTR lpbi);
WORD DIBNumColors (LPSTR lpbi);
HGLOBAL CopyHandle (HGLOBAL h);
BOOL SaveDIB (HDIB hDib, CFile& file);
HDIB ReadDIBFile(CFile& file);
};
#endif // !defined(AFX_DIBIMAGE_H__254F3D1E_BB20_40DA_AE07_E8E0219DFA8C__INCLUDED_)
///////////////////////////////////////////////////////////////////////
// DibImage.cpp: implementation of the CDibImage class.
// DIB(Independent Bitmap) 函數:
//
// PaintDIB() - 繪制DIB對象
// CreateDIBPalette() - 創建DIB對象調色板
// FindDIBBits() - 返回DIB圖像象素起始位置
// DIBWidth() - 返回DIB寬度
// DIBHeight() - 返回DIB高度
// PaletteSize() - 返回DIB調色板大小
// DIBNumColors() - 計算DIB調色板顏色數目
// CopyHandle() - 拷貝內存塊
//
// SaveDIB() - 將DIB保存到指定文件中
// ReadDIBFile() - 重指定文件中讀取DIB對象
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DIBDisplay.h"
#include "DibImage.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDibImage::CDibImage()
{
}
CDibImage::~CDibImage()
{
}
//////////////////////////////////////////////////////////////////////
// function
//////////////////////////////////////////////////////////////////////
/*************************************************************************
* 函數名稱:
* PaintDIB()
* 參數:
* HDC hDC - 輸出設備DC
* LPRECT lpDCRect - 繪制矩形區域
* HDIB hDIB - 指向DIB對象的指針
* LPRECT lpDIBRect - 要輸出的DIB區域
* CPalette* pPal - 指向DIB對象調色板的指針
* 返回值:
* BOOL - 繪制成功返回TRUE,否則返回FALSE。
* 說明:
* 該函數主要用來繪制DIB對象。其中調用了StretchDIBits()或者
* SetDIBitsToDevice()來繪制DIB對象。輸出的設備由由參數hDC指
* 定;繪制的矩形區域由參數lpDCRect指定;輸出DIB的區域由參數
* lpDIBRect指定。
************************************************************************/
BOOL CDibImage::PaintDIB(HDC hDC,
LPRECT lpDCRect,
HDIB hDIB,
LPRECT lpDIBRect,
CPalette* pPal)
{
LPSTR lpDIBHdr; // BITMAPINFOHEADER指針
LPSTR lpDIBBits; // DIB象素指針
BOOL bSuccess=FALSE; // 成功標誌
HPALETTE hPal=NULL; // DIB調色板
HPALETTE hOldPal=NULL; // 以前的調色板
if (hDIB == NULL)
{
return FALSE;
}
lpDIBHdr = (LPSTR)::GlobalLock((HGLOBAL) hDIB);// 鎖定DIB
lpDIBBits = FindDIBBits(lpDIBHdr); // 找到DIB圖像象素起始位置
if (pPal != NULL) // 獲取DIB調色板,並選中它
{
hPal = (HPALETTE) pPal->m_hObject;
hOldPal = ::SelectPalette(hDC, hPal, TRUE); // 選中調色板
}
::SetStretchBltMode(hDC, COLORONCOLOR); // 設置顯示模式
// 判斷是調用StretchDIBits()還是SetDIBitsToDevice()來繪制DIB對象
if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&
(RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
{
// 原始大小,不用拉伸。
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
0, // nStartScan
(WORD)DIBHeight(lpDIBHdr), // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
}
else
{
// 非原始大小,拉伸。
bSuccess = ::StretchDIBits(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
lpDIBRect->top, // SrcY
RECTWIDTH(lpDIBRect), // wSrcWidth
RECTHEIGHT(lpDIBRect), // wSrcHeight
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // 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中讀取顏色表並存到調色板中,
* 最後按照該邏輯調色板創建壹個新的調色板,並返回該調色板的句柄。這樣
* 可以用最好的顏色來顯示DIB圖像。
************************************************************************/
BOOL CDibImage::CreateDIBPalette(HDIB hDIB, CPalette* pPal)
{
LPLOGPALETTE lpPal; // 指向邏輯調色板的指針
HANDLE hLogPal; // 邏輯調色板的句柄
HPALETTE hPal = NULL; // 調色板的句柄
int i; // 循環變量
WORD wNumColors; // 顏色表中的顏色數目
LPSTR lpbi; // 指向DIB的指針
LPBITMAPINFO lpbmi; // 指向BITMAPINFO結構的指針(Win3.0)
LPBITMAPCOREINFO lpbmc; // 指向BITMAPCOREINFO結構的指針
BOOL bWinStyleDIB; // 表明是否是Win3.0 DIB的標記
BOOL bResult = FALSE; // 創建結果
if (hDIB == NULL)
{
return FALSE;
}
lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); // 鎖定DIB
lpbmi = (LPBITMAPINFO)lpbi; // 獲取指向BITMAPINFO結構的指針(Win3.0)
lpbmc = (LPBITMAPCOREINFO)lpbi; // 獲取指向BITMAPCOREINFO結構的指針
wNumColors = DIBNumColors(lpbi);// 獲取DIB中顏色表中的顏色數目
if (wNumColors != 0)
{
// 分配為邏輯調色板內存
hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
+ sizeof(PALETTEENTRY)
* wNumColors);
// 如果內存不足,退出
if (hLogPal == 0)
{
::GlobalUnlock((HGLOBAL) hDIB); // 解除鎖定
return FALSE;
}
lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
lpPal->palVersion = PALVERSION; // 設置版本號
lpPal->palNumEntries = (WORD)wNumColors;// 設置顏色數目
bWinStyleDIB = IS_WIN30_DIB(lpbi); // 判斷是否是WIN3.0的DIB
// 讀取調色板
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 CDibImage::FindDIBBits(LPSTR lpbi)
{
return (lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi));
}
/*************************************************************************
* 函數名稱:
* DIBWidth()
* 參數:
* LPSTR lpbi - 指向DIB對象的指針
* 返回值:
* DWORD - DIB中圖像的寬度
* 說明:
* 該函數返回DIB中圖像的寬度。對於Windows 3.0 DIB,返回BITMAPINFOHEADER
* 中的biWidth值;對於其它返回BITMAPCOREHEADER中的bcWidth值。
************************************************************************/
DWORD CDibImage::DIBWidth(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // 指向BITMAPINFO結構的指針(Win3.0)
LPBITMAPCOREHEADER lpbmc; // 指向BITMAPCOREINFO結構的指針
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
// 返回DIB中圖像的寬度
if (IS_WIN30_DIB(lpDIB))
{
return lpbmi->biWidth; // 對於Windows 3.0 DIB,返回lpbmi->biWidth
}
else
{
return (DWORD)lpbmc->bcWidth; // 對於其它格式的DIB,返回lpbmc->bcWidth
}
}
/*************************************************************************
* 函數名稱:
* DIBHeight()
* 參數:
* LPSTR lpDIB - 指向DIB對象的指針
* 返回值:
* DWORD - DIB中圖像的高度
* 說明:
* 該函數返回DIB中圖像的高度。對於Windows 3.0 DIB,返回BITMAPINFOHEADER
* 中的biHeight值;對於其它返回BITMAPCOREHEADER中的bcHeight值。
************************************************************************/
DWORD CDibImage::DIBHeight(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // 指向BITMAPINFO結構的指針(Win3.0)
LPBITMAPCOREHEADER lpbmc; // 指向BITMAPCOREINFO結構的指針
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
// 返回DIB中圖像的寬度
if (IS_WIN30_DIB(lpDIB))
{
return lpbmi->biHeight; // 對於Windows 3.0 DIB,返回lpbmi->biHeight
}
else
{
return (DWORD)lpbmc->bcHeight; // 對於其它格式的DIB,返回lpbmc->bcHeight
}
}
/*************************************************************************
* 函數名稱:
* PaletteSize()
* 參數:
* LPSTR lpbi - 指向DIB對象的指針
* 返回值:
* WORD - DIB中調色板的大小
* 說明:
* 該函數返回DIB中調色板的大小。對於Windows 3.0 DIB,返回顏色數目×
* RGBQUAD的大小;對於其它返回顏色數目×RGBTRIPLE的大小。
************************************************************************/
WORD CDibImage::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 CDibImage::DIBNumColors(LPSTR lpbi)
{
WORD wBitCount;
// 對於Windows的DIB, 實際顏色的數目可以比象素的位數要少。
// 對於這種情況,則返回壹個近似的數值。
// 判斷是否是WIN3.0 DIB
if (IS_WIN30_DIB(lpbi))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed; // 讀取dwClrUsed值
if (dwClrUsed != 0)
{
// 如果dwClrUsed(實際用到的顏色數)不為0,直接返回該值
return (WORD)dwClrUsed;
}
}
// 讀取象素的位數
if (IS_WIN30_DIB(lpbi))
{
wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; // 讀取biBitCount值
}
else
{
wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount; // 讀取biBitCount值
}
// 按照象素的位數計算顏色數目
switch (wBitCount)
{
case 1:
return 2;
break;
case 4:
return 16;
break;
case 8:
return 256;
break;
default:
return 0;
break;
}
}
/*************************************************************************
* 函數名稱:
* CopyHandle()
* 參數:
* HGLOBAL h - 要復制的內存區域
* 返回值:
* HGLOBAL - 復制後的新內存區域
* 說明:
* 該函數復制指定的內存區域。返回復制後的新內存區域,出錯時返回0。
************************************************************************/
HGLOBAL CDibImage::CopyHandle (HGLOBAL h)
{
if (h == NULL)
{
return NULL;
}
DWORD dwLen = ::GlobalSize((HGLOBAL) h); // 獲取指定內存區域大小
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 CDibImage::SaveDIB(HDIB hDib, CFile& file)
{
BITMAPFILEHEADER bmfHdr; // Bitmap文件頭
LPBITMAPINFOHEADER lpBI; // 指向BITMAPINFOHEADER的指針
DWORD dwDIBSize; // DIB大小
if (hDib == NULL)
{
return FALSE;
}
// 讀取BITMAPINFO結構,並鎖定
lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
if (lpBI == NULL)
{
return FALSE;
}
// 判斷是否是WIN3.0 DIB
if (!IS_WIN30_DIB(lpBI))
{
// 不支持其它類型的DIB保存
::GlobalUnlock((HGLOBAL) hDib);
return FALSE;
}
////////////////////////////////////////////////////////////////////////
// 填充文件頭///////////////////////////////////////////////////////////
bmfHdr.bfType = DIB_HEADER_MARKER; // 文件類型"BM"
// 計算DIB大小時,最簡單的方法是調用GlobalSize()函數。但是全局內存大小並
// 不是DIB真正的大小,它總是多幾個字節。這樣就需要計算壹下DIB的真實大小。
// 文件頭大小+顏色表大小
// (BITMAPINFOHEADER和BITMAPCOREHEADER結構的第壹個DWORD都是該結構的大小)
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);
// 計算圖像大小
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
{
// 對於RLE位圖,沒法計算大小,只能信任biSizeImage內的值
dwDIBSize += lpBI->biSizeImage;
}
else
{
DWORD dwBmBitsSize; // 象素的大小
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))
* lpBI->biHeight; // 大小為Width * Height
dwDIBSize += dwBmBitsSize; // 計算出DIB真正的大小
// 更新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)); // 寫文件頭
file.WriteHuge(lpBI, dwDIBSize); // 寫DIB頭和象素
}
CATCH (CFileException, e)
{
::GlobalUnlock((HGLOBAL) hDib);
THROW_LAST();
}
END_CATCH
::GlobalUnlock((HGLOBAL) hDib);
return TRUE;
}
/*************************************************************************
* 函數名稱:
* ReadDIBFile()
* 參數:
* CFile& file - 要讀取得文件文件CFile
* 返回值:
* HDIB - 成功返回DIB的句柄,否則返回NULL。
* 說明:
* 該函數將指定的文件中的DIB對象讀到指定的內存區域中。除BITMAPFILEHEADER
* 外的內容都將被讀入內存。
*************************************************************************/
HDIB CDibImage::ReadDIBFile(CFile& file)
{
BITMAPFILEHEADER bmfHeader;
HDIB hDIB;
LPSTR pDIB;
DWORD dwBitsSize;
dwBitsSize = file.GetLength(); // 獲取DIB(文件)長度(字節)
// 嘗試讀取DIB文件頭
if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
{
return NULL;
}
// 判斷是否是DIB對象,檢查頭兩個字節是否是"BM"
if (bmfHeader.bfType != DIB_HEADER_MARKER)
{
return NULL;
}
// 為DIB分配內存
hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
if (hDIB == 0)
{
return NULL;
}
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
dwBitsSize - sizeof(BITMAPFILEHEADER) ) // 讀象素
{
::GlobalUnlock((HGLOBAL) hDIB);
::GlobalFree((HGLOBAL) hDIB);
return NULL;
}
::GlobalUnlock((HGLOBAL) hDIB);
return hDIB;
}