⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdib.cpp

📁 人民邮电出版社的——Visual C++数字图像处理典型算法及实现(源码) 希望大家能用上
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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;
	m_hPalette   = NULL;
	m_nBmihAlloc = m_nImageAlloc = noAlloc;
	Empty();
}


/*************************************************************************
 *
 * \函数名称:
 *   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;

	// 设置信息头中的信息
	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;
	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);
}


/*************************************************************************
 *
 * \函数名称:
 *   AttachMapFile()
 *
 * \输入参数:
 *   const	char* strPathname		- 映射文件的路径名
 *   BOOL	bShare				- 如果文件以共享形式打开,设置为TRUE
 *						- 默认值为FALSE
 *
 * \返回值:
 *   BOOL					- 如果成功,则为TRUE 
 *
 * \说明:
 *   以读模式打开内存映射文件,并将其与CDib对象进行关联。因为在文件使用之前并没有读入内存,
 *   所以它立即返回。不过,当访问这个DIB的时候,可能会有一些延迟,因为文件是分页的。
 *   DetachMapFile函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
 *   用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
 *   或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
 *   Windows堆栈用GlobalAlloc分配了。
 *   如果打开相同的文件两次,则Windows以另一个文件来对待 
 *
 ************************************************************************
 */
BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading
{
	// 获取文件句柄,并设置打开模式为共享
	HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
		bShare ? FILE_SHARE_READ : 0,
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	ASSERT(hFile != INVALID_HANDLE_VALUE);

	// 获取文件的尺寸
	DWORD dwFileSize = ::GetFileSize(hFile, NULL);

	// 创建文件映射对象,并设置文件映射的模式为读写
	HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
	DWORD dwErr = ::GetLastError();
	if(hMap == NULL) {
		AfxMessageBox("Empty bitmap file");
		return FALSE;
	}

	// 映射整个文件,注意FILE_MAP_WRITE为读写模式
	LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file
	ASSERT(lpvFile != NULL);

	// 确认为bmp格式文件
	if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
		AfxMessageBox("Invalid bitmap file");
		DetachMapFile();
		return FALSE;
	}

	// 将内存中的DIB与已有的CDib对象关联
	AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER));

	// 将这些有用的句柄设置为类数据成员
	m_lpvFile = lpvFile;
	m_hFile   = hFile;
	m_hMap    = hMap;

	// 返回
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   CopyToMapFile()
 *
 * \输入参数:
 *   const	char* strPathname		- 映射文件的路径名
 *
 * \返回值:
 *   BOOL					- 如果成功,则为TRUE 
 *
 * \说明:
 *   该函数可以创建一个新的内存映射文件,并将现有的CDib数据复制到该文件的内存
 *   释放以前的所有内存。并关闭现有的所有内存映射文件。实际上,直到新文件
 *   关闭的时候,才将这个数据写到磁盘,但是,当CDib对象被重复使用或被破坏
 *   时,也会发生写磁盘操作
 *
 ************************************************************************
 */
BOOL CDib::CopyToMapFile(const char* strPathname)
{
	BITMAPFILEHEADER bmfh;

	// 设置文件头信息
	bmfh.bfType	= 0x4d42;  
	bmfh.bfSize	= m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
			sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER);
	bmfh.bfReserved1= bmfh.bfReserved2 = 0;
	bmfh.bfOffBits	= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
			sizeof(RGBQUAD) * m_nColorTableEntries;	
	
	// 创建接收数据的文件
	HANDLE hFile	= ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	ASSERT(hFile != INVALID_HANDLE_VALUE);

	// 计算文件的大小尺寸
	int nSize	= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
				sizeof(RGBQUAD) * m_nColorTableEntries +  m_dwSizeImage;

	// 创建内存映射文件对象
	HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, NULL);
	DWORD dwErr = ::GetLastError();
	ASSERT(hMap != NULL);

	// 映射整个文件
	LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); 
	ASSERT(lpvFile != NULL);

	// 临时文件指针
	LPBYTE lpbCurrent = (LPBYTE) lpvFile;

	// 拷贝文件头信息到内存映射文件中
	memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER)); 

	// 计算信息头在文件中的地址,并拷贝信息头信息
	lpbCurrent += sizeof(BITMAPFILEHEADER);
	LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent;
	memcpy(lpbCurrent, m_lpBMIH,
		sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries); 

	// 计算调色板在文件中的地址,并拷贝调色板
	lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
	memcpy(lpbCurrent, m_lpImage, m_dwSizeImage); 

	// 暂时存放图象数据尺寸变量
	DWORD dwSizeImage = m_dwSizeImage;

	// 释放一起分配的所有内存
	Empty();

	// 设置图象数据尺寸并设置内存分配状态
	m_dwSizeImage = dwSizeImage;
	m_nBmihAlloc  = m_nImageAlloc = noAlloc;

	// 信息头指针重新指向文件中的位置
	m_lpBMIH = lpBMIH;

	// 图象数据指针重新指向文件中的数据地址
	m_lpImage = lpbCurrent;

	// 设置文件句柄
	m_hFile = hFile;

	// 设置映射对象句柄
	m_hMap = hMap;

	// 设置映射文件指针
	m_lpvFile = lpvFile;

	// 重新计算得到调色板尺寸
	ComputePaletteSize(m_lpBMIH->biBitCount);

	// 重新计算图象数据块大小,并设置调色板指针
	ComputeMetrics();

	// 如果调色板存在的话,读取并创建一个Windows调色板
	MakePalette();

	// 返回
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   AttachMemory()
 *
 * \输入参数:
 *   LPVOID	lpvMem			- 要关联的内存地址
 *   BOOL	bMustDelete		- 如果CDib类负责删除这个内存,标记为TRUE
 *					- 默认值为FALSE
 *   HGLOBAL	hGlobal			- 如果内存是通过Win32 GlobalAlloc得到的,
 *					- 则CDib对象必须保存该句柄,这样,以后
 *					- 可以释放句柄。这里假设bMustDelete设置为TRUE
 *
 * \返回值:
 *   BOOL					- 如果成功,则为TRUE 
 *
 * \说明:
 *   用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
 *   或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
 *   Windows堆栈用GlobalAlloc分配了。
 *
 ************************************************************************
 */
BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal)
{
	// 首先释放已经分配的内存
	Empty();

	m_hGlobal = hGlobal;
	
	// bMustDelete为TRUE表示此CDib类分配的内存,负责删除
	// 否则的设置信息头分配状态为noAlloc
	if(bMustDelete == FALSE) {
		m_nBmihAlloc = noAlloc;
	}
	else {
		m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc);
	}
	try {
		// 设置信息头指针
		m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem;

		// 重新计算得到图象数据块的大小,并设置调色板的指针
		ComputeMetrics();

		// 计算调色板的尺寸
		ComputePaletteSize(m_lpBMIH->biBitCount);

		// 设置图象数据指针
		m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries;

		// 如果调色板存在的话,读取它,并创建一个Windows调色板,
		// 并将调色板的句柄存放在数据成员中
		MakePalette();
	}

	// 错误处理
	catch(CException* pe) {
		AfxMessageBox("AttachMemory error");
		pe->Delete();
		return FALSE;
	}

	// 返回
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   UsePalette()
 *
 * \输入参数:
 *   CDC*	pDC			- 要实现调色板的设备上下文指针
 *   BOOL	bBackground		- 如果标记为FALSE(默认值),并且应用
 *					- 程序正在前台运行,则Windows将把该调
 *					- 色板作为前台调色板来实现(向系统调色
 *					- 板中复制尽可能多的颜色)。如果标记为
 *					- TURE,则Windows将把该调色板作为后台
 *					- 调色板来实现(尽可能相系统调色板映射
 *					- 逻辑调色板)
 *
 * \返回值:
 *   UINT				- 如果成功,则返回映射到系统调色板的逻
 *					- 辑调色板的表项数,否则返回GDI_ERROR 
 *
 * \说明:
 *   该函数将CDib对象的逻辑调色板选入设备上下文,然后实现该调色板。Draw成员函
 *   数在绘制DIB之前调用UsePalette。
 *
 ************************************************************************
 */
UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
{
	// 判断是否存在调色板
	if(m_hPalette == NULL) return 0;

	// 得到设备上下文句柄
	HDC hdc = pDC->GetSafeHdc();

	// 选择调色板到设备上下文
	::SelectPalette(hdc, m_hPalette, bBackground);

	// 实现该调色板
	return ::RealizePalette(hdc);
}


/*************************************************************************
 *
 * \函数名称:
 *   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;
}


/*************************************************************************
 *
 * \函数名称:
 *   CreateSection()
 *
 * \输入参数:
 *   CDC*	pDC			- 设备上下文指针
 *
 * \返回值:
 *   HBITMAP				- 到GDI位图的句柄。如果不成功,则为NULL。
 *					- 该句柄也是作为公共数据成员存储的
 *
 * \说明:
 *   通过调用Win32 SDK的CreateDIBSection函数创建一个DIB段。图象内存将不被初始化
 *
 ************************************************************************
 */
HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */)
{
	// 如果信息头为空,不作任何处理
	if(m_lpBMIH == NULL) return NULL;

	// 如果图象数据不存在,不作任何处理
	if(m_lpImage != NULL) return NULL; 

	// 创建一个DIB段
	m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
		DIB_RGB_COLORS,	(LPVOID*) &m_lpImage, NULL, 0);	
	ASSERT(m_lpImage != NULL);

	// 返回HBIMAP句柄
	return m_hBitmap;
}


/*************************************************************************
 *
 * \函数名称:
 *   MakePalette()
 *
 * \输入参数:
 *   无
 *
 * \返回值:
 *   BOOL				- 如果成功,则为TRUE

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -