Win32实现HBITMAP转BITMAP并且保存文件

Home / C++ MrLee 2016-10-10 6366

我这里强调的是Win32标准C++而不是MFC,所以没用到CBITMAP,属于比较底层一点。直接上代码了!
static bool BMP_SaveFile(const char* szFile, const void* pBmp, int width, int height, int bitCount=32)
{
	HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, 0,  NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	assert(hFile != NULL);
	int bmp_size = width*height*(bitCount/8);
	// 【写位图文件头】
	BITMAPFILEHEADER bmpHeader;
	bmpHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmp_size;	// BMP图像文件的大小
	bmpHeader.bfType = 0x4D42;	// 位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为‘BM’
	bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);			// BMP图像数据的偏移位置
	bmpHeader.bfReserved1 = 0;	// 总为0
	bmpHeader.bfReserved2 = 0;	// 总为0
	DWORD dwBytesWritten = 0;
	WriteFile(hFile, (LPSTR)&bmpHeader, sizeof(bmpHeader), &dwBytesWritten, NULL);
	BITMAPINFOHEADER bmiHeader;
	bmiHeader.biSize = sizeof(bmiHeader);				// 本结构所占用字节数,即sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth = width;							// 位图宽度(单位:像素)
	bmiHeader.biHeight = height;						// 位图高度(单位:像素)
	bmiHeader.biPlanes = 1;								// 目标设备的级别,必须为1
	bmiHeader.biBitCount = bitCount;					// 像素的位数(每个像素所需的位数,范围:1、4、8、24、32)
	bmiHeader.biCompression = 0;						// 压缩类型(0:不压缩 1:BI_RLE8压缩类型 2:BI_RLE4压缩类型)
	bmiHeader.biSizeImage = bmp_size;					// 位图大小(单位:字节)
	bmiHeader.biXPelsPerMeter = 0;						// 水平分辨率(像素/米)
	bmiHeader.biYPelsPerMeter = 0;						// 垂直分辨率(像素/米)
	bmiHeader.biClrUsed = 0;							// 位图实际使用的彩色表中的颜色索引数
	bmiHeader.biClrImportant = 0;						// 对图象显示有重要影响的颜色索引的数目
	// 【写位图信息头(BITMAPINFO的bmiHeader成员)】
	WriteFile(hFile, (LPSTR)&bmiHeader, sizeof(bmiHeader), &dwBytesWritten, NULL);
	// 【写像素内容】
	WriteFile(hFile, pBmp, bmp_size, &dwBytesWritten, NULL);
	CloseHandle(hFile);
	return true;
}
/*
*基于GDI截图到粘贴板
*/
static void Capture(HWND hWnd,int width,int height,bool save=false,string fileName="pic.bmp")
{
	//尝试BITBLT截图
	HDC hSrcDC = ::GetDC(hWnd);
	HDC hMemDC = ::CreateCompatibleDC(hSrcDC);
	HBITMAP hbmp = ::CreateCompatibleBitmap(hSrcDC, width, height);
	HBITMAP hOldbmp = (HBITMAP) ::SelectObject(hMemDC, hbmp);
	::BitBlt(hMemDC, 0, 0, width, height, hSrcDC, 0, 0, SRCCOPY);
	OpenClipboard(NULL);
	EmptyClipboard();
	SetClipboardData(CF_BITMAP,hbmp);
	CloseClipboard();
	if(save)
	{
		int bmp_size = width*height*4;//32/8
		byte* pData = new byte[bmp_size];//位图片的数据
		BITMAPINFOHEADER bmiHeader;
		bmiHeader.biSize = sizeof(bmiHeader);				// 本结构所占用字节数,即sizeof(BITMAPINFOHEADER);
		bmiHeader.biWidth = width;							// 位图宽度(单位:像素)
		bmiHeader.biHeight = height;						// 位图高度(单位:像素)
		bmiHeader.biPlanes = 1;								// 目标设备的级别,必须为1
		bmiHeader.biBitCount = 32;							// 像素的位数(每个像素所需的位数,范围:1、4、8、24、32)
		bmiHeader.biCompression = 0;						// 压缩类型(0:不压缩 1:BI_RLE8压缩类型 2:BI_RLE4压缩类型)
		bmiHeader.biSizeImage = bmp_size;					// 位图大小(单位:字节)
		bmiHeader.biXPelsPerMeter = 0;						// 水平分辨率(像素/米)
		bmiHeader.biYPelsPerMeter = 0;						// 垂直分辨率(像素/米)
		bmiHeader.biClrUsed = 0;							// 位图实际使用的彩色表中的颜色索引数
		bmiHeader.biClrImportant = 0;						// 对图象显示有重要影响的颜色索引的数目
		int ret = GetDIBits(hSrcDC,hbmp,0,height,pData,(LPBITMAPINFO)&bmiHeader,DIB_RGB_COLORS);
		if(ret)BMP_SaveFile(fileName.c_str(),pData,width,height);
		if(pData)delete pData;//删除开辟的内存空间
	}
	//释放
	::SelectObject(hMemDC,hOldbmp);
	DeleteDC(hMemDC);
	DeleteObject(hbmp);
	ReleaseDC(NULL, hSrcDC);
}

获取位图数据核心函数就是GetDIBits,通过它来获取位图的二进制数据。

本文链接:https://www.it72.com/10892.htm

推荐阅读
最新回复 (0)
返回