上一节讲到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