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

📄 ddb.cpp

📁 《Visual C++数字图像与图形处理》一书中编译通过的图像显示程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/////////////////////////////////////////////////////////////////////////////////
//	
// Ddb.cpp: implementation of the CDdb class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming

#include "stdafx.h"
#include "Ddb.h"

IMPLEMENT_DYNAMIC(CDdb,  CObject)

CDdb::CDdb()
{
	m_pDdbData = NULL; 
	m_hDdbData = 0; 
}

CDdb::CDdb(CBitmap* pBitmap)
{
	m_pDdbData = NULL; 
	m_hDdbData = 0; 
	SetDdb(pBitmap); 
}


CDdb::~CDdb()
{
	ClearMemory(); 
}

void CDdb::ClearMemory()
{
	if(m_hDdbData != NULL)
		::GlobalFree(m_hDdbData); 
	m_pDdbData = NULL; 
	m_hDdbData = 0; 
}


//构造函数将调用它, 设置属性
void CDdb::SetDdb(CBitmap *pBitmap)
{
	ASSERT(pBitmap); 
	BITMAP bitmap; 
	pBitmap->GetObject(sizeof(BITMAP),  &bitmap); 
	//位图的宽度和高度
	m_nWidth = bitmap.bmWidth; 
	m_nHeight = bitmap.bmHeight; 

	//指向CBitmap对象的指针, 在运算的过程中不改变
	m_pDdb = pBitmap; 

	//获取设备描述表句柄
	HDC hDC = ::GetDC(NULL);  
	
	//每个像素位的颜色位数
	m_nBitCount = 24; 
	m_nBitCount = ::GetDeviceCaps(hDC,  BITSPIXEL); 

	//不支持16色显示模式
	if(m_nBitCount < 8)
	{
		AfxMessageBox(" Please Change your display mode.Thank you!");   
		return; 
	}

	//计算设备相关位图的行字节数
	m_nDdbWidthBytes = CalcDdbWidthBytes(m_nWidth,  m_nBitCount); 
	
	//Ddb位图的位数据大小
	DWORD dwDdbBitsSize = m_nDdbWidthBytes * m_nHeight; 
	
	
	//如果以前存在, 就释放内存.
	if(m_pDdbData != NULL)
	{
		::GlobalFree(m_hDdbData); 
		m_pDdbData = NULL; 
		m_hDdbData = 0; 
	}


	//分配全局内存
	m_hDdbData = (HGLOBAL) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,  dwDdbBitsSize); 
	if (m_hDdbData == 0)	return ; 

	//指向位数据的指针, 在运算的过程中不改变
	m_pDdbData =  (BYTE*)::GlobalLock(m_hDdbData); 
	if (m_pDdbData == NULL)
	{
		::GlobalUnlock(m_hDdbData); 
		::GlobalFree(m_hDdbData); 
		m_hDdbData = 0; 
		return; 
	}
	

	//从内存中获取Ddb数据
	m_pDdb->GetBitmapBits(dwDdbBitsSize, m_pDdbData); 



	::GlobalUnlock(m_hDdbData); 
	//释放DC
	::ReleaseDC(NULL, hDC); 
}

#ifdef _DEBUG
void CDdb::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc); 
}

void CDdb::AssertValid() const
{
	CObject::AssertValid(); 
	ASSERT(m_pDdb != NULL); 
	ASSERT(m_hDdbData != 0); 
	ASSERT(m_pDdbData != NULL); 
}
#endif


BYTE* CDdb::GetDdbData() const
{
	return m_pDdbData; 
}

BYTE CDdb::GetBitCount() const
{
	return m_nBitCount; 
}

LONG CDdb::GetWidth() const
{
	return m_nWidth; 
}

LONG CDdb::GetHeight() const
{
	return m_nHeight; 
}


LONG CDdb::GetDdbWidthBytes() const
{
	return m_nDdbWidthBytes; 

}

//计算设备相关位图的行字节宽度
LONG CDdb::CalcDdbWidthBytes(LONG nWidth,  BYTE byBitCount)
{
	//每行字节数必须被2整除
	return (((nWidth * byBitCount + 15) / 16) * 2); 
}

//计算设备无关位图的行字节宽度
LONG CDdb::CalcDibWidthBytes(LONG nWidth,  BYTE byBitCount)
{
	//每行字节数必须被4整除
	if(byBitCount == 8)
		return (((nWidth * 8 + 31) / 32) * 4); 
	else
		return (((nWidth * 24 + 31) / 32) * 4); 
}

/*
DWORD SetBitmapBits( DWORD dwCount,  const void* lpBits )

Return Value

The number of bytes used in setting the bitmap bits;  0 if the function fails.

dwCount		Specifies the number of bytes pointed to by lpBits.
lpBits		Points to the BYTE array that contains the bit values to be copied to the CBitmap object.

*/
//设置DDB所使用的像素数据----整体
//lpBits----数据源, 扫描宽度字节数必须是2的倍数, 注意, 数据要充足
DWORD CDdb::SetBitmapBits(DWORD dwCount,  const void* lpbyBits) 
{
	ASSERT(lpbyBits); 
	return (m_pDdb->SetBitmapBits(dwCount, lpbyBits)); 
}

//设置DDB所使用的像素数据----局部
//x, y, nWidth, nHeight
//lpBits----数据源, 扫描宽度字节数必须是2的倍数
DWORD CDdb::SetBitmapBits(int x, int y, int nWidth, int nHeight, int nBitCount, LPBYTE lpbyBits)
{
	ASSERT(lpbyBits); 
	//类型不匹配, 则返回0, 表示没有设置任何数据
	if(nBitCount != m_nBitCount)return 0; 
	
	//进行参数合法性检测
	if((x > m_nWidth - 1) || (y > nHeight - 1))
	{
		AfxMessageBox("Cross the border!"); 
		return 0; 
	}
	//有效宽度和高度:w , h.
	LONG w = (LONG)min(nWidth, m_nWidth - x); 
	LONG h = (LONG)min(nHeight, m_nHeight - y); 
	
	//扫描宽度, 以字节为单位, 必须被2整除
	DWORD dwScanLength = CalcDdbWidthBytes(nWidth, nBitCount); 

	//实际拷贝的行字节长度:
	DWORD dwLength = w; 
	//数据偏移量
	DWORD dwOffset = x; 
	if(nBitCount == 16)
	{
		dwLength = w + w; 
		dwOffset = x + x; 
	}
	else if(nBitCount == 24)
	{
		dwLength = 3 * w; 
		dwOffset = 3 * x;  
	}
	else if(nBitCount == 32)
	{
		dwLength = 4 * w; 
		dwOffset = 4 * x; 
	}

	//指向与CDdb对象绑连的数据区
	BYTE* pbyDdbDst = m_pDdbData + y * m_nDdbWidthBytes + dwOffset; 
	
	//指向源数据的指针, 从外部而来
	BYTE* pbyDdbRsc = lpbyBits; 
	
	for(int i = 0; i < h; i++)
	{
		::CopyMemory(pbyDdbDst, pbyDdbRsc, dwLength); 
		pbyDdbRsc += dwScanLength; 		//from
		pbyDdbDst += m_nDdbWidthBytes; 	//to
	}
	m_pDdb->SetBitmapBits(m_nDdbWidthBytes * m_nHeight, m_pDdbData); 
	return (nWidth * nHeight * nBitCount); 
} 

//绘制设备相关的位图.当然由于该类是以CBitmap对象进行加工的, 因而事先必须有一个该对象, 所以该方法的作用显得不是很突出.因为完全不用该方法也能绘制DDB位图.
BOOL CDdb::Draw(CDC* pDstDC,  int x,  int y,  int nWidth,  int nHeight,  int xSrc,  int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop)
{
	CDC memoryDC; 
	memoryDC.CreateCompatibleDC(pDstDC); 
	CBitmap* pOldBitmap = memoryDC.SelectObject(m_pDdb); 

	BOOL bDraw = (pDstDC->StretchBlt(x, y, nWidth, nHeight, &memoryDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop )); 
	memoryDC.SelectObject(pOldBitmap); 
	return (bDraw); 

}

	/*
	//功能如下:
	1. 8位位图仍然保存为8位位图
	2. 16位位图将被保存为24位位图.16位位图只用于16位增强显示模式, 不在不同的系统间进行传递.
	3. 24位位图仍然被保存为24位位图.
	4. 32位Ddb位图将被保存为24位位图.
	5. 对于16色即4位位图, 不作处理.
	*/
//将Ddb位图保存成Dib位图:被保存的区域由, x, y, nWidth, nHeight来定义
void CDdb::Save(const char *pszDibFileName, int x, int y, int nWidth, int nHeight)
{
	ASSERT(pszDibFileName); 
	//首先进行参数合法性检测
	if((x > m_nWidth - 1) || (y > nHeight - 1))
	{
		AfxMessageBox("Cross the border!"); 
		return; 
	}
	
	AfxGetApp()->BeginWaitCursor(); 

	//被保存的最后有效宽度和高度:w , h.
	LONG w = (LONG)min(nWidth, m_nWidth - x); 
	LONG h = (LONG)min(nHeight, m_nHeight - y); 


	//被保存位图每行的字节数
	DWORD dwSaveWidthBytes = CalcDibWidthBytes(w, m_nBitCount); 
	
	//DIB位图数据大小, 以字节为单位
	DWORD dwDibBitsSize = dwSaveWidthBytes * m_nHeight; 
	
	//计算整个Dib文件的大小dwFileSize
	DWORD dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwDibBitsSize; 
	if(m_nBitCount == 8) dwFileSize += (256 * sizeof(RGBQUAD)); 

	//计算位图信息到位图数据间的偏移量(字节)
	DWORD dwOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
	if(m_nBitCount == 8) dwOffBits += (256 * sizeof(RGBQUAD)); 


	//位图文件头结构和位图信息结构
	BITMAPFILEHEADER bmFileHeader; 
	BITMAPINFOHEADER bmInfo; 

	//填充BITMAPFILEHEADER结构
	bmFileHeader.bfType=0x4d42; 
	bmFileHeader.bfSize = dwFileSize; 
	bmFileHeader.bfReserved1 = 0; 
	bmFileHeader.bfReserved2 = 0;  
    bmFileHeader.bfOffBits = dwOffBits; 

	//填充BITMAPINFOHEADER结构:8位仍然保存为8位, 其它均被保存为24位.最低显示模式为8位.
	WORD wBitsPixel = (WORD)m_nBitCount; 
	if(m_nBitCount != 8)wBitsPixel = 24; 
	bmInfo.biSize = sizeof(BITMAPINFOHEADER);    
	bmInfo.biWidth = w;     
	bmInfo.biHeight = h;     
	bmInfo.biPlanes = 1;  
	bmInfo.biBitCount = wBitsPixel;     
	bmInfo.biCompression = 0;     
	bmInfo.biSizeImage = 0;  
	bmInfo.biXPelsPerMeter = 0;     
	bmInfo.biYPelsPerMeter = 0;     
	bmInfo.biClrUsed = 0;  
	bmInfo.biClrImportant = 0; 	

	try
	{
		//	请创建自己的目录或获取当前目录:
		CFile file((LPCTSTR )pszDibFileName, CFile::modeCreate |
			CFile::modeReadWrite | CFile::shareExclusive); 

		//写入文件头和位图信息
		file.Write((LPSTR)&bmFileHeader, sizeof(BITMAPFILEHEADER)); 
		file.Write((LPSTR)&bmInfo, sizeof(BITMAPINFOHEADER)); 

		//如果是8位显示模式, 还需要写入调色盘表项
		if(m_nBitCount == 8)
		{
			//为8位显示模式准备调色盘
			RGBQUAD* pRGBQuad = new RGBQUAD[256]; 
			if(pRGBQuad == NULL)return; 
			
			//初始化为0
			memset(pRGBQuad, 0, 256 * sizeof(RGBQUAD)); 
			
			//创建表项:可能丢失颜色
			GetSystemPaletteEntries(pRGBQuad); 
			
			//写入数据
			file.Write((LPSTR)pRGBQuad, 256 * sizeof(RGBQUAD)); 
			
			delete[] pRGBQuad; 
		}

		switch(m_nBitCount)
		{
		case 8:
		case 24:
			{
				//每行需要补0的个数
				DWORD dwLength = (m_nBitCount == 8) ? w : (3 * w); 
				UINT nZero =  dwSaveWidthBytes - dwLength; 
				BYTE abyZero[] =  {0, 0, 0}; 

				//数据索引基数, 从下往上读
				DWORD dwBaseIndex = (y + h - 1) * m_nDdbWidthBytes + ((m_nBitCount == 8) ? x : (3 * x)); 
				for(LONG i = 0; i < h ; i++)
				{
					
					LPSTR lpsRaw = (LPSTR)(m_pDdbData + dwBaseIndex); 

					//写入子数据, 注意数据量小于64k, 位图宽度可达22767个像素单位或更高
					file.Write(lpsRaw, dwLength); //
					
					//结尾补0
					if(nZero > 0) file.Write((LPSTR)abyZero, nZero); 
					dwBaseIndex -= m_nDdbWidthBytes; 
			
				}
			}
			break; 

		case 16:
		case 32:

⌨️ 快捷键说明

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