`
wx1569110409
  • 浏览: 18613 次
文章分类
社区版块
存档分类
最新评论

vc++加载透明png图片方法——GDI+和CImage两种

 
阅读更多

这几天放假在家无聊编一个程序,在加载png时遇到了麻烦,后来用了两个方法解决了。一个是用GDI+,另外就是用vs.net MFC自带的CImage

先看看GDI+的方法
方法1:

1.GDI+画透明图层(alpha)的png图片


stdafx加入如下:


#include <comdef.h>//初始化一下com口
#include "GdiPlus.h"
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")


开始初始化:
在app类的声明里(.h)加入:


ULONG_PTR m_gdiplusToken;


InitInstance()里加入://若没有usingnamespace Gdiplus; 就要在前面加Gdiplus::


GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);


重载ExitInstance,加入GdiplusShutdown(m_gdiplusToken);


int CxxxApp::ExitInstance()
{
	// TODO: 在此添加专用代码和/或调用基类
	GdiplusShutdown(m_gdiplusToken);
	return CWinApp::ExitInstance();
}


显示图片的过程如下

CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));
CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object
Image image(_T("1.png")); // Construct an image
graphics.DrawImage(&image, 00, image.GetWidth(), image.GetHeight());
delete pDC;

这是用GDI+来显示图片。


2.CImage绘制带alpha透明图层的png图片

用MFC自带的CImage也可以显示,不过要稍微进行转换才能得到正常的带α通道的png图片!

在画图前进行一次转换,其中Image是CImage的对象
if (Image.GetBPP() == 32//确认该图像包含Alpha通道
{
	int i;
	int j;
	for (i = 0; i < Image.GetWidth(); i++)
	{
		for (j = 0; j < Image.GetHeight(); j++)
		{
			byte *pByte = (byte *)Image.GetPixelAddress(i, j);
			pByte[0] = pByte[0] * pByte[3] / 255;
			pByte[1] = pByte[1] * pByte[3] / 255;
			pByte[2] = pByte[2] * pByte[3] / 255;
		}
	}
}

具体方法如下:


HWND hwnd = GetSafeHwnd(); //获取窗口的HWND
::InvalidateRect( hwnd, NULL, true ); //或者 ::InvalidateRect( hwnd, NULL, false );
::UpdateWindow(hwnd);
//若使用前不想把原来绘制的图片去掉,可以删去上面那三段
CDC *pDC = GetDC();
CImage Image;
Image.Load(strPath);
if (Image.IsNull())
{
	MessageBox(_T("没加载成功"));
	return -1;
}
if (Image.GetBPP() == 32//确认该图像包含Alpha通道
{
	int i;
	int j;
	for (i = 0; i < Image.GetWidth(); i++)
	{
		for (j = 0; j < Image.GetHeight(); j++)
		{
			byte *pByte = (byte *)Image.GetPixelAddress(i, j);
			pByte[0] = pByte[0] * pByte[3] / 255;
			pByte[1] = pByte[1] * pByte[3] / 255;
			pByte[2] = pByte[2] * pByte[3] / 255;
		}
	}
}
Image.Draw(pDC->m_hDC, 00);
Image.Destroy();
ReleaseDC(pDC);

代码中内部的框架是对图像的再次处理,对原来进行了修正,这样得到的更加正常,代码实测如下

绘图后效果


为了方便,封装成一个通用函数:
pWnd是需要显示图片的控件窗口,strPicPath是png图片地址,bAutoFit是否需要自动适应pWnd的窗口
bool ShowPNGInCtrl(CWnd* pWnd,const CString& strPicPath,BOOL bAutoFit)
{
	if (NULL == pWnd)
	{
		return false;
	}
	if (NULL == pWnd->GetSafeHwnd())
	{
		return false;
	}
	if (strPicPath.GetLength()<=0)
	{
		return false;
	}
	try
	{
		CImage img;
		CRect rect;
		int nDPx(0),nDPy(0);//画图的起点
		int nDw(0),nDh(0);//画图的宽和高
		pWnd->GetClientRect(rect);   
		HRESULT hr;
		hr = img.Load(strPicPath);
		if (S_OK != hr)
		{
			return false;
		}
		std::unique_ptr<CClientDC> pDc;
		pDc.reset(new CClientDC(pWnd));

		if (bAutoFit)
		{
			if (img.GetWidth()>img.GetHeight())//说明图片是长方形
			{
				nDw  = rect.Width();
				nDh  = (int)(nDw * img.GetHeight() / img.GetWidth());
				nDPx = 0;
				nDPy = (int)(rect.Height()/2.0 - nDh/2.0);
				if (nDh>rect.Height())//说明图片控件是横着放,这时候就要再次缩减
				{
					nDh	 =rect.Height();
					nDw  =(int)( img.GetWidth()*nDh/img.GetHeight());
					nDPy = 0;
					nDPx =(int) (rect.Width()/2.0 - nDw/2.0);
				}
			}
			else//说明竖着比较明显
			{
				nDh  = rect.Height();
				nDw  =(int)( img.GetWidth()*nDh/img.GetHeight());
				nDPy = 0;
				nDPx =(int) (rect.Width()/2.0 - nDw/2.0);
				if (nDw>rect.Width())//说明是另外一种情况
				{
					nDw  = rect.Width();
					nDh  = (int)(nDw * img.GetHeight() / img.GetWidth());
					nDPx = 0;
					nDPy = (int)(rect.Height()/2.0 - nDh/2.0);
				}
			}
		}
		else
		{
			nDw = img.GetWidth();
			nDh = img.GetHeight();
		}
		if (img.GetBPP() == 32) //确认该图像包含Alpha通道
		{
			int i;
			int j;
			for (i=0; i<img.GetWidth(); i++)
			{
				for (j=0; j<img.GetHeight(); j++)
				{
					byte *pByte = (byte *)img.GetPixelAddress(i, j);
					pByte[0] = pByte[0] * pByte[3] / 255;
					pByte[1] = pByte[1] * pByte[3] / 255;
					pByte[2] = pByte[2] * pByte[3] / 255;
				}
			}
		}

		pDc->SetStretchBltMode(HALFTONE);
		img.Draw(pDc->m_hDC,nDPx,nDPy,nDw,nDh);
		//img.TransparentBlt(pDc->m_hDC,nDPx,nDPy,nDw,nDh,RGB(255, 255, 255));
	}
	catch (...)
	{
		return false;
	}
	return true;
}




------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.如果图片是在资源里的时候加载方法又不一样


这时需要两个函数,
对于GDI+如下:

BOOL ImageFromIDResource(UINT nID, LPCTSTR sTR,Image *&pImg)
{
	HINSTANCE hInst = AfxGetResourceHandle();
	HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type
	if (!hRsrc)
		return FALSE;
	// load resource into memory
	DWORD len = SizeofResource(hInst, hRsrc);
	BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
	if (!lpRsrc)
		return FALSE;
	// Allocate global memory on which to create stream
	HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
	BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
	memcpy(pmem,lpRsrc,len);
	GlobalUnlock(m_hMem);
	IStream* pstm;
	CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
	// load from stream
	pImg=Gdiplus::Image::FromStream(pstm);
	// free/release stuff
	pstm->Release();
	FreeResource(lpRsrc);
	GlobalFree(m_hMem);
	return TRUE;
}


这时加载图片的代码变为:
CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));
CRect rect;
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object
Image *pimage; // Construct an image
ImageFromIDResource(IDB_PNG1,_T("PNG"),pimage);
graphics.DrawImage(pimage, 00,pimage->GetWidth(), pimage->GetHeight());
delete pDC;


CImage时需要如下函数:

BOOL LoadImageFromResource(CImage *pImage, UINT nResID,LPCTSTR lpTyp)
{
	if ( pImage == NULL) 
		return false;
	pImage->Destroy();
	// 查找资源
	HRSRC hRsrc = ::FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nResID), lpTyp);
	if (hRsrc == NULL) 
		return false;
	// 加载资源
	HGLOBAL hImgData = ::LoadResource(AfxGetResourceHandle(), hRsrc);
	if (hImgData == NULL)
	{
		::FreeResource(hImgData);
		return false;
	}
	// 锁定内存中的指定资源
	LPVOID lpVoid = ::LockResource(hImgData);
	LPSTREAM pStream = NULL;
	DWORD dwSize = ::SizeofResource(AfxGetResourceHandle(), hRsrc);
	HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);
	LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);
	::memcpy(lpByte, lpVoid, dwSize);
	// 解除内存中的指定资源
	::GlobalUnlock(hNew);
	// 从指定内存创建流对象
	HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);
	if ( ht != S_OK )
	{
		GlobalFree(hNew);
	}
	else
	{
		// 加载图片
		pImage->Load(pStream);
		GlobalFree(hNew);
	}
	// 释放资源
	::FreeResource(hImgData);
	return true;
}


这时加载图片的代码如下:
HWND hwnd = GetSafeHwnd(); //获取窗口的HWND
::InvalidateRect( hwnd, NULL, true ); //或者 ::InvalidateRect( hwnd, NULL, false );
::UpdateWindow(hwnd); 
CDC *pDC = GetDC();
CImage Image;
LoadImageFromResource(&Image,IDB_PNG1,_T("PNG"));
if (Image.IsNull())
{
	MessageBox(_T("没加载成功"));
	return;
}
if (Image.GetBPP() == 32//确认该图像包含Alpha通道int i;
	int j;
	for (i=0; i<Image.GetWidth(); i++)
	{
		for (j=0; j<Image.GetHeight(); j++)
		{
			byte *pByte = (byte *)Image.GetPixelAddress(i, j);
			pByte[0] = pByte[0] * pByte[3] / 255;
			pByte[1] = pByte[1] * pByte[3] / 255;
			pByte[2] = pByte[2] * pByte[3] / 255;
		}
	}
}
Image.Draw(pDC->m_hDC,0,0);
Image.Destroy();
ReleaseDC(pDC);



要注意的是,最好把绘图放在OnPaint消息响应里,否则,OnSize消息触发OnPaint重绘时可能会把之前的绘图全部清除


转载于:https://my.oschina.net/2nmjeSMen3/blog/674360

分享到:
评论

相关推荐

    GDI+的说明 GDI+的说明 GDI+的说明 GDI+的说明

    - **CImage类**:CImage是MFC对GDI+的封装,提供了一种方便的方式来创建、加载、保存和处理图像。 - **Graphics类**:作为GDI+的核心类,Graphics负责实际的绘图操作,包括绘制线条、曲线、填充区域等。 - **其他...

    VC++利用png图片做底图的漂亮窗口

    PNG图片因其优秀的透明度支持和高质量的图像表现,常被用于创建有特色的窗口背景。本教程将详细介绍如何在VC++项目中利用PNG图片作为窗口的底图,以实现漂亮的视觉效果。 首先,我们需要了解PNG图片的特点。PNG...

    GDI+加载图片,旋转CDC

    GDI+允许开发者创建丰富的可视化效果,包括加载和操作图片。在你的“GDI+加载图片,旋转CDC”的实践中,你可能正在探索如何使用GDI+来加载图像并对其进行旋转,这在用户界面设计或图像处理应用中是非常常见的需求。 ...

    GDI+编程CImage类

    CxImage类库是一个优秀的图像操作类库。它可以快捷地存取、显示、转换各种图像。本文档介绍CImage类的基本用法

    VC++ GDI+ CImageList缩略图 常用格式图片浏览器

    在本文中,我们将深入探讨如何使用VC++、GDI+和CImageList库来创建一个能够浏览常用图像格式(如PNG和JPG)的图片浏览器。这个项目是基于VS2008开发环境并在Windows 7操作系统上运行的。通过理解并应用以下知识点,...

    Cimage加载图片,并实现旋转缩放功能

    Cimage是一个轻量级的图像处理库,特别适用于在Windows环境下进行简单的图像操作,如加载、显示、旋转和缩放等。在这个项目中,我们将会深入探讨如何利用Cimage库在Visual Studio 2012中实现图片的旋转和缩放功能。 ...

    GDI+编程入门及简单例子

    CImage类是MFC和ATL共享的一个重要组件,它是GDI+在VC++.NET中的一个重要工具,弥补了Visual C++在处理图像文件方面的不足,尤其是对于外部图像文件的加载和显示。 CImage类概述: CImage类是专为处理各种图像格式...

    MFC png 图片加载

    在MFC应用中,我们常用以下两种方式来加载PNG图片: 1. **使用GDI+** GDI+是Windows操作系统提供的一种图形处理库,它支持多种图像格式,包括PNG。在MFC应用中,可以通过包含GDI+相关的头文件并进行初始化,然后...

    GDI+ MFC编写的图片浏览器

    3. **图像显示**:MFC中使用CImage类来加载和管理图像文件,CImage是MFC对GDI+的封装,支持多种常见的图像格式,如BMP、JPEG、PNG等。通过CImage类,程序可以轻松地读取和显示图像。 4. **用户交互**:MFC提供了...

    基于Visual C++.NET的GDI+开发教程

    ### 基于Visual C++.NET的GDI+开发教程 #### 一、GDI+概述 GDI+(Graphics Device Interface Plus)是微软在Windows操作...通过学习和掌握GDI+的核心概念和使用方法,可以有效地提高图形处理程序的性能和视觉效果。

    VC图片叠加和添加文字_vc++_图片叠加_

    在VC++编程环境中,图片叠加和添加文字是一项常见的图像处理任务,这通常涉及到对位图(Bitmap)对象的操作。在本教程中,我们将探讨如何利用Microsoft的MFC(Microsoft Foundation Classes)库或直接使用GDI+...

    CImage类打开和保存jpeg、bmp、gif和png格式图片

    CImage类提供了一种方式来加载和创建图像对象,通过`Load()`函数可以读取不同格式的图像文件,如JPEG、BMP、GIF和PNG。例如,如果你有一个名为"image.jpg"的JPEG文件,你可以使用以下代码来加载它: ```cpp CImage ...

    MFC按钮Button自绘类(GDI篇+PNG)

    首先,加载PNG图像到`CImage`对象,然后在`DrawItem()`中根据按钮状态(如焦点、按下、未按下等)调整图像的位置和透明度,最后调用`Draw()`方法将其绘制到按钮上。 为了实现“固定按钮”和“动态按钮”,我们可以...

    MFC加载不同格式图片

    除了CImage类,还可以使用GDI(Graphics Device Interface)或GDI+ API直接加载和处理图像,但这通常需要更多的代码。例如,使用GDI+的`Gdiplus::Bitmap`类加载图像。 在实际应用中,为了简化代码并提高复用性,...

    VC 下加载 JPG JPEG GIF PNG 图片最简单的方法.doc

    使用 CImage 类的 Load 函数是加载各种格式图片的最简单和最有效的方法。这项技术可以广泛应用于各种图形处理和图像处理领域。 知识点: * CImage 类的 Load 函数可以加载各种格式的图片,包括 JPG、JPEG、GIF、...

    vc用Cimage显示png图片

    用Cimage显示png图片,最简单的程序了。

    mfc加载png格式的图片.rar

    此外,对于PNG图片的加载,需要注意的是PNG是一种无损压缩的图像格式,它支持透明度和多种色彩深度。因此,确保MFC的`CImage`正确处理这些特性是很重要的。如果在加载过程中出现颜色失真或透明度丢失,可能是因为...

    PDF文档转PNG图片

    vc++代码, MuPDF转png图片,速度很快,效果也很好。...如果需要其它格式的图片,可以把png转为其它格式,这种转图片格式的库很多,VC++中可直接使用CImage,非常方便,也可以直接使用CImag来显示PNG图片。

    利用VC++显示各种格式的图片源代码

    CImage是ATL(Active Template Library)的一部分,可以方便地加载、显示和保存各种图像格式,如BMP、JPEG、PNG等。 4. **CView类派生**: 在MFC应用程序中,通常会从CView类派生出一个类来处理视图,这里可能有一...

Global site tag (gtag.js) - Google Analytics