VC++ 导出bmp图片

我们经常遇到这种情况,就是需要把当前桌面的指定区域大小保存为图片以供以后使用,类似于QQ的截图工具。

其实方法很简单,就是创建与指定设备兼容的内存设备上下文环境(DC),然后创建与指定的设备环境相关的设备兼容的位图,接着把这个设备兼容的位图选入到设备兼容的内存中。最后就是将这个位图导出即可。

不过在此之前需要了解一下两个知识点:一个是如何创建和使用与指定设备兼容的内存设备上下文环境,二是如何将位图导出为本地图片

1.与指定设备兼容的内存设备上下文环境(双缓冲)

HDC CreateCompatibleDC(HDC hdc);

平常我们在使用GetDC获取HDC直接与相关设备沟通,比如在一个对话框对应的类中直接使用GetDC获取的HDC就是直接与这个对话框相关联,而我们在这获取的设备兼容得到的HDC是和内存中的一个表面想关联。

内存设备上下文环境是仅在内存中存在的设备上下文环境,当内存中设备上下文被创建时,它的显示标准是一个单色像素宽和一个单色像素高,当一个应用程序使用设备上下文环境进行绘图之前,它必须选定一个高和宽都正确设定的位图到设备上下文环境中,这里可以使用CreateCompatibleBitmap函数指定高、宽和色彩组合以指定函数调用的需要来创建位图。实例:

CBitmap bitmap;
	CDC dcMemSave;
	dcMemSave.CreateCompatibleDC(NULL);
	CDC *pDC = GetDC();
	bitmap.CreateCompatibleBitmap(pDC,m_PaintRect.right-m_PaintRect.left,m_PaintRect.bottom-m_PaintRect.top);
	dcMemSave.SelectObject(&bitmap);
	dcMemSave.BitBlt(0,0,m_PaintRect.right-m_PaintRect.left,m_PaintRect.bottom-m_PaintRect.top,pDC,m_PaintRect.left,m_PaintRect.top,SRCCOPY);
	HBITMAP hBmp = (HBITMAP)bitmap;
	SaveBMP(hBmp); //保存位图到本地
	DeleteObject(bitmap);

CreateCompatibleDc函数只适用于支持光栅操作的设备,应用程序可以通过调用GetDeviceCaps函数来确定一个设备是否支持这些操作。当不再需要内存设备上下文环境时,可调用DeleteDc函数删除它。

2.将bmp保存到本地bmp图片

BMP是一种与硬件设备无关的图像文件格式,使用非常广。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。典型的BMP图像文件由三部分组成:位图文件头数据结构,它包含BMP图像文件的类型、显示内容等信息;

位图文件头(bitmap-file header)                                                                     

所用结构:
BITMAPFILEHEADER                                                     
包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段

位图信息头(bitmap-information header)                                                                                                        

所用结构:BITMAPINFOHEADER包含了位图信息头的大小、图像的宽高、图像的色深、压缩说明图像数据的大小和其他一些参数

彩色表/调色板(color table)

RGBQUAD颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,24色位图没有颜色表项,位图信息头BITMAPINFOHEADER和颜色表RGBQUAD组成位图信息BITMAPINFO

位图数据(bitmap-data)

char*位图数据信息HBITMAP格式

导出图片源码如下:

bool CDotChart::SaveBMP(HBITMAP &map)
{
	OpenFileDialog(m_hWnd);
	if(GetSaveFileName(&ofn))
	{	
		wsprintf(filepath,"%s",ofn.lpstrFile);		
	}
	else
	{
		return false;
	}
	
	//把位图的信息保存到bmpinfo
	BITMAP bmpinfo;
	GetObject(map,sizeof(BITMAP),&bmpinfo);
	DWORD dwBmBitsSize = ((bmpinfo.bmWidth * 32+31)/32) * 4 * bmpinfo.bmHeight; 

	//位图文件头 14字节
	BITMAPFILEHEADER bf;
	bf.bfType      = 0x4D42;                  //BM
	bf.bfSize      = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmBitsSize; 
	bf.bfReserved1 = 0; 
	bf.bfReserved2 = 0; 
	bf.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 

	//位图信息头
	BITMAPINFOHEADER bi;
	bi.biSize          = sizeof(BITMAPINFOHEADER);
	bi.biWidth         = bmpinfo.bmWidth;
	bi.biHeight        = bmpinfo.bmHeight;
	bi.biPlanes        = 1;
	bi.biBitCount      = 32;
	bi.biCompression   = BI_RGB;
	bi.biSizeImage     = 0;
	bi.biXPelsPerMeter = 0;
	bi.biYPelsPerMeter = 0;
	bi.biClrUsed       = 8;
	bi.biClrImportant  = 0;

	//颜色表由红、绿、蓝(RGB)三个直接值构成
	//调用GetDIBits直接绘制设备无关图,并复制到缓冲区中
	char* context = new char[dwBmBitsSize];
	HDC dc  = ::GetDC(NULL);
	GetDIBits(dc, map, 0, bi.biHeight, context, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
	//写位图到本地图片
	HANDLE file = ::CreateFile(filepath,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS		,FILE_ATTRIBUTE_NORMAL,NULL);
	DWORD Num;
	if(INVALID_HANDLE_VALUE != file )
	{
		WriteFile(file,&bf,sizeof(BITMAPFILEHEADER),&Num,NULL);
		WriteFile(file,&bi,sizeof(BITMAPINFOHEADER),&Num,NULL);
		WriteFile(file,context,dwBmBitsSize,&Num,NULL);
		::CloseHandle(file);
	}	
	delete context;
	return 0;
}
bool CDotChart::OpenFileDialog(HWND hWnd)
{
	char szFile[260]; // 用于文件名的缓冲区      
	// 初始化OPENFILENAME 
	ZeroMemory(&ofn, sizeof(OPENFILENAME)); 

	ofn.lStructSize = sizeof(OPENFILENAME); 
	ofn.lpstrTitle = "另存为";
	ofn.lpstrFile = szFile;
	ofn.hwndOwner = hWnd;      
	ofn.nMaxFile = sizeof(szFile); 
	ofn.lpstrFilter = TEXT("图片文件(*.bmp)\0*.bmp\0所有文件(*.*)\0*.*\0");
	ofn.lpstrDefExt = "*.bmp";
	ofn.nFilterIndex = 1; 
	ofn.lpstrFileTitle = "NULL"; 
	ofn.nMaxFileTitle = 0; 
	ofn.lpstrInitialDir = NULL; 
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值