Windows DIB文件操作详解-3.DDB转DIB

上一节讲到DIB转换成DDB以提高位图显示性能,那么这里自然想到DDB转DIB。DDB转DIB有什么用呢?最常见的应用场合就是你得到了一个屏幕截图的DDB,现在想把它保存到磁盘上,这时候就要用到DDB转DIB函数GetDIBits。


1.GetDIBits使用方法

函数定义如下
int GetDIBits(
  HDC hdc,           // handle to DC
  HBITMAP hbmp,      // handle to bitmap
  UINT uStartScan,   // first scan line to set
  UINT cScanLines,   // number of scan lines to copy
  LPVOID lpvBits,    // array for bitmap bits
  LPBITMAPINFO lpbi, // bitmap data buffer
  UINT uUsage        // RGB or palette index
);

这个函数获得hbmp的位图信息和数据填充到提前分配好的lpvBits和lpbi指针指向的内存中,完成DDB到DIB转换。

这个函数的使用步骤如下
1.定义BITMAPINFOHEADER bmih结构,设置结构的size,设置bitcount为0。lpvBits参数设为NULL而lpbi参数设为&bmih,如此调用GetDIBits函数,此函数会将hbmp的相关信息(大小、深度等信息)填充到bmih结构。
2.按照步骤1得到的信息分配lpbi和lpvBits结构内存。原则上当lpvBits结构lpvBits不为NULL时,lpbi的前6个参数必须设置,这里直接将bmih内容复制给lpbi。
3.传入分配好的lpbi和lpvBits结构内存地址,调用GetDIBits函数得到位图信息和数据。

一定要注意这里的lpvBits和lpbi内存是自己在调用函数前分配的。

2.屏幕截图保存到文件

这里贴上一个笔者写的截图软件中的屏幕截图DDB转DIB的实例代码,建议下载完整源代码查看

BOOL CScreenBitmap::ExportToFile(CDC *pDC, TCHAR *szBmpName,  RECT *pRect/*=NULL*/)
{
	HBITMAP hExportBmp;
	BITMAPFILEHEADER bmfh={0};

	/************************************************************************/
	/* 获得数据                                                                     */
	/************************************************************************/

	//获得要导出的DDB位图
	hExportBmp = CopyBitmap(pRect);

	//获得DDB信息
	BITMAPINFOHEADER bmih={0};
	bmih.biSize = sizeof(BITMAPINFOHEADER);
	bmih.biBitCount = 0;
	if (0 == GetDIBits(pDC->GetSafeHdc(), 
					   hExportBmp, 
					   0, 0, 
					   NULL, (BITMAPINFO *)&bmih, 
					   DIB_RGB_COLORS))
	{
		return FALSE;
	}
	
	//删除已经分配的存储区
	if (NULL != m_pbmi)
	{
		free(m_pbmi);
		m_pbmi = NULL;
	}

	if (NULL != m_pBits)
	{
		free(m_pBits);
		m_pBits = NULL;
	}

	//分配新的存储区
	DWORD dwInfoSize;
	DWORD dwBitsSize;

	if (bmih.biBitCount>=16 && BI_BITFIELDS==bmih.biCompression)
	{
		dwInfoSize = sizeof(BITMAPINFOHEADER) + 4*4;//字节对齐,RGBQUAD每个成员存储的内存大小为4字节

		TRACE("%d %d %d\n", sizeof(BITMAPINFO), sizeof(BITMAPINFOHEADER), sizeof(RGBQUAD));
	}
	else if (bmih.biBitCount>=16)
	{
		dwInfoSize = sizeof(BITMAPINFOHEADER);
	}
	else
	{
		dwInfoSize = sizeof(BITMAPINFOHEADER) + 4*4*bmih.biClrUsed;//字节对齐,RGBQUAD每个成员存储的内存大小为4字节
	}
	dwBitsSize = bmih.biHeight * 
				 (((bmih.biBitCount*bmih.biPlanes*bmih.biWidth + 31) & ~31) >> 3);

	//分配对应的内存区
	m_pbmi = (PBITMAPINFO)malloc(dwInfoSize);
	if (NULL == m_pbmi)
	{
		return FALSE;
	}

	m_pBits = (PBYTE)malloc(dwBitsSize);
	if (NULL == m_pBits)
	{
		free(m_pbmi);
		return FALSE;
	}

	//读入位图信息和位图数据
	CopyMemory(m_pbmi, &bmih, sizeof(BITMAPINFOHEADER));
	if (0 == GetDIBits( pDC->GetSafeHdc(), 
						hExportBmp, 
						0, bmih.biHeight, 
						m_pBits, m_pbmi, 
						DIB_RGB_COLORS))
	{
		free(m_pBits);
		free(m_pbmi);
		return FALSE;
	}

	/************************************************************************/
	/* 保存数据                                                                     */
	/************************************************************************/

	//计算文件头信息
	bmfh.bfType = *(WORD *)"BM";
	bmfh.bfSize = sizeof(BITMAPFILEHEADER) + dwInfoSize + dwBitsSize;
	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + dwInfoSize;

	//写入到对应BMP文件中
	HANDLE hFile = CreateFile(	szBmpName,
								GENERIC_WRITE, 0,
								NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	CFile m_saveFile(hFile);

	m_saveFile.Write(&bmfh, sizeof(BITMAPFILEHEADER));
	m_saveFile.Write(m_pbmi, dwInfoSize);
	m_saveFile.Write(m_pBits, dwBitsSize);

	m_saveFile.Close();

	::DeleteObject(hExportBmp);

	return TRUE;
}


最新完整截图软件 源代码下载链接,这里CScreenBitmap类中是封装好的截图操作,包括屏幕指定区域截图、复制截图到剪切板上及截图保存到磁盘上,你可以在自己的项目中直接使用它。
原创,转载请注明来自 http://blog.csdn.net/wenzhou1219
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值