www.pudn.com > hongmoyuan.rar > CDIB.CPP


#include "stdafx.h" 
#include "math.h" 
#include "process.h" 
 
#include "cdib.h" 
#include "GlobalApi.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
// 声明串行化过程 
IMPLEMENT_SERIAL(CDib, CObject, 0); 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   CDib() 
 * 
 * \输入参数: 
 * 无 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   构造函数 
 * 
 ************************************************************************ 
 */ 
CDib::CDib() 
{ 
	m_hFile      = NULL;			//文件句柄 
	m_hBitmap    = NULL;			// BITMAP结构指针 
	m_hPalette   = NULL;			//调色板指针 
	m_nBmihAlloc = m_nImageAlloc = noAlloc;		//内存分配的情况 
	Empty();			// 清空DIB,释放已经分配的内存,并且关闭映射文件 
} 
/************************************************************************* 
 * 
 * \函数名称: 
 *   CDib() 
 * 
 * \输入参数: 
 * CSize	size			- 位图尺寸 
 * int		nBitCount		- 象素位数 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   构造函数 
 *   根据给定的位图尺寸和象素位数构造CDib对象,并对信息头和调色板分配内存 
 *   但并没有给位图数据分配内存 
 * 
 ************************************************************************ 
 */ 
CDib::CDib(CSize size, int nBitCount) 
{ 
	m_hFile      = NULL; 
	m_hBitmap    = NULL; 
	m_hPalette   = NULL; 
	m_nBmihAlloc = m_nImageAlloc = noAlloc;			//表示没有分配 
	Empty(); 
 
	// 根据象素位数计算调色板尺寸 
	ComputePaletteSize(nBitCount); 
 
	// 分配DIB信息头和调色板的内存 
	m_lpBMIH = (LPBITMAPINFOHEADER) new  
		char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries]; 
 
	// 设置信息头内存分配状态 
	m_nBmihAlloc = crtAlloc;			//表示分配了DIB信息头和调色板的内存,但是没有像素数据 
 
	// 设置信息头中的信息 
	m_lpBMIH->biSize	= sizeof(BITMAPINFOHEADER); 
	m_lpBMIH->biWidth	= size.cx;					//文件的宽度 
	m_lpBMIH->biHeight	= size.cy; 
	m_lpBMIH->biPlanes	= 1;						//平面数 
	m_lpBMIH->biBitCount	= nBitCount; 
	m_lpBMIH->biCompression = BI_RGB;				//压缩方式为RGB 
	m_lpBMIH->biSizeImage	= 0;					//图象数据内存大小		 
	m_lpBMIH->biXPelsPerMeter = 0; 
	m_lpBMIH->biYPelsPerMeter = 0; 
	m_lpBMIH->biClrUsed	= m_nColorTableEntries;		//调色板大小 
	m_lpBMIH->biClrImportant= m_nColorTableEntries;		 
 
	// 计算图象数据内存的大小,并设置此DIB的调色板的指针 
	ComputeMetrics(); 
 
	// 将此DIB的调色板初始化为0 
	memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries); 
 
	// 暂时不分配图象数据内存 
	m_lpImage = NULL;  
} 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   ~CDib() 
 * 
 * \输入参数: 
 * 无 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   析构函数,并释放所有分配的DIB内存 
 * 
 ************************************************************************ 
 */ 
CDib::~CDib() 
{ 
	Empty(); 
} 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   GetDimensions() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   CSize				- DIB的宽度和高度 
 * 
 * \说明: 
 *   返回以象素表示的DIB的宽度和高度 
 * 
 ************************************************************************ 
 */ 
CSize CDib::GetDimensions() 
{	 
	if(m_lpBMIH == NULL) return CSize(0, 0); 
	return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight); 
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   Draw() 
 * 
 * \输入参数: 
 *   CDC*	pDC			- 指向将要接收DIB图象的设备上下文指针 
 *   CPoint	origin			- 显示DIB的逻辑坐标 
 *   CSize	size			- 显示矩形的宽度和高度 
 * 
 * \返回值: 
 *   BOOL				- 如果成功,则为TRUE, 
 * 
 * \说明: 
 *   通过调用Win32 SDK的StretchDIBits函数将CDib对象输出到显示器(或者打印机)。 
 *   为了适合指定的矩形,位图可以进行必要的拉伸 
 * 
 ************************************************************************ 
 */ 
BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size) 
{ 
	// 如果信息头为空,表示尚未有数据,返回FALSE 
	if(m_lpBMIH == NULL) return FALSE; 
 
	// 如果调色板不为空,则将调色板选入设备上下文 
	if(m_hPalette != NULL) { 
		::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE); 
	} 
 
	// 设置显示模式 
	pDC->SetStretchBltMode(COLORONCOLOR); 
 
	// 在设备的origin位置上画出大小为size的图象 
	::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy, 
		0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight, 
		m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY); 
 
	// 返回 
	return TRUE; 
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   MakePalette() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   BOOL				- 如果成功,则为TRUE 
 * 
 * \说明: 
 *   如果颜色表存在的话,该函数将读取它,并创建一个Windows调色板。 
 *   HPALETTE存储在一个数据成员中。 
 * 
 ************************************************************************ 
 */ 
BOOL CDib::MakePalette() 
{ 
	// 如果不存在调色板,则返回FALSE 
	if(m_nColorTableEntries == 0) return FALSE; 
 
	if(m_hPalette != NULL) ::DeleteObject(m_hPalette); 
	TRACE("CDib::MakePalette -- m_nColorTableEntries = %d\n", m_nColorTableEntries); 
	 
	// 给逻辑调色板分配内存 
	LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) + 
		m_nColorTableEntries * sizeof(PALETTEENTRY)]; 
 
	// 设置逻辑调色板的信息 
	pLogPal->palVersion = 0x300; 
	pLogPal->palNumEntries = m_nColorTableEntries; 
 
	// 拷贝DIB中的颜色表到逻辑调色板 
	LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable; 
	for(int i = 0; i < m_nColorTableEntries; i++) { 
		pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed; 
		pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen; 
		pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue; 
		pLogPal->palPalEntry[i].peFlags = 0; 
		pDibQuad++; 
	} 
 
	// 创建逻辑调色板 
	m_hPalette = ::CreatePalette(pLogPal); 
 
	// 删除临时变量并返回TRUE 
	delete pLogPal; 
	return TRUE; 
}	 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   Read() 
 * 
 * \输入参数: 
 *   CFile*	pFile			- 指向CFile对象的指针 
 * 
 * \返回值: 
 *   BOOL				- 如果成功,则返回TRUE 
 * 
 * \说明: 
 *   该函数DIB从一个文件读入CDib对象。该文件必须成功打开。如果该文件是BMP文件 
 *   读取工作从文件头开始。如果该文件是一个文档,读取工作则从当前文件指针处开始  
 * 
 ************************************************************************ 
 */ 
BOOL CDib::Read(CFile* pFile) 
{ 
	// 释放已经分配的内存 
	Empty(); 
 
	// 临时存放信息的变量 
	int nCount, nSize; 
	BITMAPFILEHEADER bmfh; 
 
	// 进行读操作 
	try  
	{ 
		// 读取文件头 
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); 
		if(nCount != sizeof(BITMAPFILEHEADER)) { 
			throw new CException; 
		} 
 
		// 如果文件类型部位"BM",则返回并进行相应错误处理 
		if(bmfh.bfType != 0x4d42) { 
			throw new CException;							//? 
		} 
 
		// 计算信息头加上调色板的大小,并分配相应的内存 
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER); 
		m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]; 
		m_nBmihAlloc = m_nImageAlloc = crtAlloc; 
 
		// 读取信息头和调色板 
		nCount = pFile->Read(m_lpBMIH, nSize);  
 
		// 计算图象数据大小并设置调色板指针 
		ComputeMetrics(); 
 
		// 计算调色板的表项数 
		ComputePaletteSize(m_lpBMIH->biBitCount); 
 
		// 如果DIB中存在调色板,则创建一个Windows调色板 
		MakePalette(); 
 
		// 分配图象数据内存,并从文件中读取图象数据 
		m_lpImage = (LPBYTE) new char[m_dwSizeImage]; 
		nCount = pFile->Read(m_lpImage, m_dwSizeImage);  
	} 
 
	// 错误处理 
	catch(CException* pe)  
	{ 
		AfxMessageBox("Read error"); 
		pe->Delete(); 
		return FALSE; 
	} 
 
	// 返回 
	return TRUE; 
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   Write() 
 * 
 * \输入参数: 
 *   CFile*	pFile			- 指向CFile对象的指针 
 * 
 * \返回值: 
 *   BOOL				- 如果成功,则返回TRUE 
 * 
 * \说明: 
 *   该函数把DIB从CDib对象写进文件中。该文件必须成功打开或者创建 
 * 
 ************************************************************************ 
 */ 
BOOL CDib::Write(CFile* pFile) 
{ 
	BITMAPFILEHEADER bmfh; 
 
	// 设置文件头中文件类型为"BM" 
	bmfh.bfType = 0x4d42;   
 
	// 计算信息头和调色板的大小尺寸 
	int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries; 
 
	// 设置文件头信息 
	bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage; 
	bmfh.bfReserved1 = bmfh.bfReserved2 = 0; 
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 
			sizeof(RGBQUAD) * m_nColorTableEntries;	 
	 
	// 进行写操作 
	try { 
		pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER)); 
		pFile->Write((LPVOID) m_lpBMIH,  nSizeHdr); 
		pFile->Write((LPVOID) m_lpImage, m_dwSizeImage); 
	} 
 
	// 错误处理 
	catch(CException* pe) { 
		pe->Delete(); 
		AfxMessageBox("write error"); 
		return FALSE; 
	} 
 
	// 返回 
	return TRUE; 
} 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   Serialize() 
 * 
 * \输入参数: 
 *   CArchive&	ar			- 指向应用程序归档对象 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   该函数进行串行化过程,将CDib数据进行读入或者写出 
 * 
 ************************************************************************ 
 */ 
void CDib::Serialize(CArchive& ar) 
{ 
	DWORD dwPos; 
 
	// 获得此归档文件的CFile对象指针 
	dwPos = ar.GetFile()->GetPosition(); 
	TRACE("CDib::Serialize -- pos = %d\n", dwPos); 
 
	// 从归档文件缓冲区中冲掉未写入数据 
	ar.Flush(); 
 
	// 重新获得此归档文件的CFile对象指针 
	dwPos = ar.GetFile()->GetPosition(); 
	TRACE("CDib::Serialize -- pos = %d\n", dwPos); 
 
	// 确定归档文件是否被存储,是则进行存储	 
	if(ar.IsStoring()) { 
		Write(ar.GetFile()); 
	} 
 
	// 否则进行加载 
	else { 
		Read(ar.GetFile()); 
	} 
} 
/************************************************************************* 
 * 
 * \函数名称: 
 *   ComputePaletteSize() 
 * 
 * \输入参数: 
 *   int	nBitCount		- 指向CFile对象的指针 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   该函数根据位图象素位数计算调色板的尺寸 
 * 
 ************************************************************************ 
 */ 
void CDib::ComputePaletteSize(int nBitCount) 
{ 
	// 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方 
	if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) { 
		switch(nBitCount) { 
			case 1: 
				m_nColorTableEntries = 2; 
				break; 
			case 4: 
				m_nColorTableEntries = 16; 
				break; 
			case 8: 
				m_nColorTableEntries = 256; 
				break; 
			case 16: 
			case 24: 
			case 32: 
				m_nColorTableEntries = 0; 
				break; 
			default: 
				ASSERT(FALSE);				//? 
		} 
	} 
 
	// 否则调色板的表项数就是用到的颜色数目 
	else { 
		m_nColorTableEntries = m_lpBMIH->biClrUsed; 
	} 
 
	ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256));  
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   ComputeMetrics() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   该函数计算图象位图的尺寸,并对DIB中的调色板的指针进行赋值 
 * 
 ************************************************************************ 
 */ 
void CDib::ComputeMetrics() 
{ 
	// 如果结构的长度不对,则进行错误处理 
	if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) { 
		TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n"); 
		throw new CException; 
	} 
 
	// 保存图象数据内存大小到CDib对象的数据成员中 
	m_dwSizeImage = m_lpBMIH->biSizeImage; 
 
	// 如果图象数据内存大小为0,则重新计算 
	if(m_dwSizeImage == 0) { 
		DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32; 
		if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) { 
			dwBytes++; 
		} 
		dwBytes *= 4; 
		m_dwSizeImage = dwBytes * m_lpBMIH->biHeight;	 
	} 
 
	// 设置DIB中的调色板指针 
	m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER); 
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   Empty() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   该函数清空DIB,释放已分配的内存,并且必要的时候关闭映射文件 
 * 
 ************************************************************************ 
 */ 
void CDib::Empty() 
{ 
	// 关闭内存映射文件的连接 
	DetachMapFile(); 
 
	// 根据内存分配的状态,调用相应的函数释放信息头 
	if(m_nBmihAlloc == crtAlloc) { 
		delete [] m_lpBMIH; 
	} 
	else if(m_nBmihAlloc == heapAlloc) { 
		::GlobalUnlock(m_hGlobal); 
		::GlobalFree(m_hGlobal); 
	} 
 
	// 释放图象数据内存 
	if(m_nImageAlloc == crtAlloc) delete [] m_lpImage; 
 
	// 释放调色板句柄 
	if(m_hPalette != NULL) ::DeleteObject(m_hPalette); 
 
	// 如果创建了BITMAP,则进行释放 
	if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap); 
 
	// 重新设置内存分配状态 
	m_nBmihAlloc = m_nImageAlloc = noAlloc; 
 
	// 释放内存后,还需要将指针设置为NULL并将相应的数据设置为0 
	m_hGlobal = NULL; 
	m_lpBMIH = NULL; 
	m_lpImage = NULL; 
	m_lpvColorTable = NULL; 
	m_nColorTableEntries = 0; 
	m_dwSizeImage = 0; 
	m_lpvFile = NULL; 
	m_hMap = NULL; 
	m_hFile = NULL; 
	m_hBitmap = NULL; 
	m_hPalette = NULL; 
} 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   DetachMapFile() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   无 
 * 
 * \说明: 
 *   函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。 
 * 
 ************************************************************************ 
 */ 
void CDib::DetachMapFile() 
{ 
	// 如果没有进行内存映射,则不进行处理 
	if(m_hFile == NULL) return; 
 
	// 关闭内存映射 
	::UnmapViewOfFile(m_lpvFile); 
 
	// 关闭内存映射对象和文件 
	::CloseHandle(m_hMap); 
	::CloseHandle(m_hFile); 
	m_hFile = NULL; 
} 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   IsEmpty() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   BOOL				- 如果信息头和图象数据为空,则返回TRUE 
 * 
 * \说明: 
 *   判断信息头和图象数据是否为空 
 * 
 ************************************************************************ 
 */ 
BOOL CDib::IsEmpty() 
{ 
 
	if(	m_lpBMIH == NULL&&m_lpImage == NULL) 
		return TRUE; 
	else 
		return FALSE; 
 
} 
 
 
/************************************************************************* 
 * 
 * \函数名称: 
 *   GetDibSaveDim() 
 * 
 * \输入参数: 
 *   无 
 * 
 * \返回值: 
 *   CSize			- DIB实际存储的高度和宽度 
 * 
 * \说明: 
 *   该函数函数用来得到dib的实际存储宽度(DWORD对齐) 
 * 
 ************************************************************************ 
 */ 
CSize CDib::GetDibSaveDim() 
{ 
	CSize sizeSaveDim; 
	sizeSaveDim.cx	= ( m_lpBMIH->biWidth * m_lpBMIH->biBitCount + 31)/32 * 4; 
	sizeSaveDim.cy	= m_lpBMIH->biHeight;  
	return sizeSaveDim; 
 
}