关于GDI+,随便写写

时间:2021-07-30 17:38:49
最近在写个截图程序,碰到了GDI+,发现还不错,功能很强大,也很实用。不同于GDI,GDI+是与设备无关的,因此想用GDI+直接针对屏幕显示像素处理恐怕不好实现。它的优势,个人看来是图像的处理,格式的转化,这一块做的相当强大,即便对图像格式不是很了解,也能迅速开发程序。我在写程序的过程中发现,将GDI与GDI+混合使用倒也蛮好的,取长补短,一个善于直接正对显示设备的像素处理,另一个可对图像进行各种变换。联系此二者的,可以用CBitmap类。比如,可以用CDC将CBitmap对象选入其中,然后进行图像写入,写完了再选出来,有了这个CBitmap对象,我们便可想干嘛干嘛:-)如果我们想要调用GDI+对该图像进行处理,可以利用CBitmap返回HBITMAP构造Bitmap对象,Bitmap是GDI+中的派生于Image的类,功能很实用,如Save功能,可以直接保存成各种格式。如果想要绘制Bitmap对象,需要用到Graphics类。Graphics类的DrawImage也对Bitmap进行一些显示上的处理,可以利用ImageAttributes设置ColorMatrix,可以对Bitmap做一些处理后显示。
最后,贴点代码吧:

用GDI 和GDI+混合编写的屏幕截图的代码

int m_iScreenCX;
int m_iScreenCY;
m_iScreenCX=::GetSystemMetrics(SM_CXSCREEN);
m_iScreenCY=::GetSystemMetrics(SM_CYSCREEN);


CWindowDC dc(this->GetDesktopWindow()); // 在对话框中调用


CBitmap m_screenBitmap; // 用于保存图像的对象
m_screenBitmap.CreateCompatibleBitmap(&dc,m_iScreenCX,m_iScreenCY);


CDC memDC;
memDC.CreateCompatibleDC(&dc);


CBitmap *pOldBitmap = memDC.SelectObject(&m_screenBitmap);
memDC.BitBlt(0,0,m_iScreenCX,m_iScreenCY,&dc,0,0,SRCCOPY); // 保存屏幕截图
memDC.SelectObject(pOldBitmap);


Bitmap bitmap((HBITMAP)m_screenBitmap.GetSafeHandle(),NULL);


CLSID picClsid; // 同样也可保存至PNG文件
GetEncoderClsid(L"image/bmp", &picClsid); //GetEncoderClsid(L"image/png", &picClsid);
bitmap.Save(L"screen.bmp", &picClsid, NULL); //bitmap.Save(L"screen.png", &picClsid, NULL);
还有个用GDI+写的SaveBitmapToFile 好处在于可以直接保存成其他格式如PNG 、GIF、 JPG等

int SaveBitmapToFile(HBITMAP hBitmap, LPSTR lpFileName)
{
	Bitmap savedBitmap(hBitmap,NULL);
	CLSID bmpClsid;
	GetEncoderClsid(L"image/bmp", &bmpClsid);

	CString strFileName(lpFileName);

	size_t bufSize,strSize;
	strSize=strFileName.GetLength();

	bufSize=MultiByteToWideChar(CP_ACP,NULL,strFileName.GetBuffer(strSize),strSize,NULL,0);
		
	if(bufSize) 
	{	
		wchar_t * pwStrFileName = new wchar_t[bufSize+1];
			
		if(MultiByteToWideChar(CP_ACP, NULL,strFileName.GetBuffer(strSize),strSize, pwStrFileName, bufSize))
		{
			pwStrFileName[bufSize]=L'\0';
			
			savedBitmap.Save(pwStrFileName, &bmpClsid, NULL);
			
			if(pwStrFileName)
				delete [] pwStrFileName;

			return TRUE;
		}else
			return FALSE;
	}else
		return FALSE;
}

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	ImageCodecInfo* pImageCodecInfo = NULL;

	GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // Failure

	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1;  // Failure

	GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}    
	}

	free(pImageCodecInfo);
	return -1;  // Failure
}