vc++加载透明png图片方法.docx
- 文档编号:20190103
- 上传时间:2023-04-25
- 格式:DOCX
- 页数:15
- 大小:62.34KB
vc++加载透明png图片方法.docx
《vc++加载透明png图片方法.docx》由会员分享,可在线阅读,更多相关《vc++加载透明png图片方法.docx(15页珍藏版)》请在冰豆网上搜索。
vc++加载透明png图片方法
使用CImage画PNG,原本透明的图片,结果却显示白色/黑色底。
解决办法:
像素转换。
#include
{
if (Image.GetBPP() == 32)
{
for(inti=0;i { for(intj=0;j { UCHAR*cr=(UCHAR*)img.GetPixelAddress(i,j); cr[0]=cr[0]*cr[3]/255; cr[1]=cr[1]*cr[3]/255; cr[2]=cr[2]*cr[3]/255; } } } }//绘制pngCImageimg; img.Load("res/smiling.png"); CrossImage(img); img.AlphaBlend(dc,15,30); vc++加载透明png图片方法——GDI+和CImage两种 在加载png时遇到了麻烦,后来用了两个方法解决了。 一个是用GDI+,另外就是用MFC自带的CImage。 先看看GDI+的方法 方法1: 1.GDI+画透明图层(alpha)的png图片 stdafx加入如下: #include #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, 0, 0, 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, 0, 0); Image.Destroy(); ReleaseDC(pDC); 代码中内部的框架是对图像的再次处理,对原来进行了修正,这样得到的更加正常,代码实测如下 绘图后效果 为了方便,封装成一个通用函数: pWnd是需要显示图片的控件窗口,strPicPath是png图片地址,bAutoFit是否需要自动适应pWnd的窗口 [cpp] viewplaincopy 1.bool ShowPNGInCtrl(CWnd* pWnd,const CString& strPicPath,BOOL bAutoFit) 2.{ 3. if (NULL == pWnd) 4. { 5. return false; 6. } 7. if (NULL == pWnd->GetSafeHwnd()) 8. { 9. return false; 10. } 11. if (strPicPath.GetLength()<=0) 12. { 13. return false; 14. } 15. try 16. { 17. CImage img; 18. CRect rect; 19. int nDPx(0),nDPy(0);//画图的起点 20. int nDw(0),nDh(0);//画图的宽和高 21. pWnd->GetClientRect(rect); 22. HRESULT hr; 23. hr = img.Load(strPicPath); 24. if (S_OK ! = hr) 25. { 26. return false; 27. } 28. std: : unique_ptr 29. pDc.reset(new CClientDC(pWnd)); 30. 31. if (bAutoFit) 32. { 33. if (img.GetWidth()>img.GetHeight())//说明图片是长方形 34. { 35. nDw = rect.Width(); 36. nDh = (int)(nDw * img.GetHeight() / img.GetWidth()); 37. nDPx = 0; 38. nDPy = (int)(rect.Height()/2.0 - nDh/2.0); 39. if (nDh>rect.Height())//说明图片控件是横着放,这时候就要再次缩减 40. { 41. nDh =rect.Height(); 42. nDw =(int)( img.GetWidth()*nDh/img.GetHeight()); 43. nDPy = 0; 44. nDPx =(int) (rect.Width()/2.0 - nDw/2.0); 45. } 46. } 47. else//说明竖着比较明显 48. { 49. nDh = rect.Height(); 50. nDw =(int)( img.GetWidth()*nDh/img.GetHeight()); 51. nDPy = 0; 52. nDPx =(int) (rect.Width()/2.0 - nDw/2.0); 53. if (nDw>rect.Width())//说明是另外一种情况 54. { 55. nDw = rect.Width(); 56. nDh = (int)(nDw * img.GetHeight() / img.GetWidth()); 57. nDPx = 0; 58. nDPy = (int)(rect.Height()/2.0 - nDh/2.0); 59. } 60. } 61. } 62. else 63. { 64. nDw = img.GetWidth(); 65. nDh = img.GetHeight(); 66. } 67. if (img.GetBPP() == 32) //确认该图像包含Alpha通道 68. { 69. int i; 70. int j; 71. for (i=0; i 72. { 73. for (j=0; j 74. { 75. byte *pByte = (byte *)img.GetPixelAddress(i, j); 76. pByte[0] = pByte[0] * pByte[3] / 255; 77. pByte[1] = pByte[1] * pByte[3] / 255; 78. pByte[2] = pByte[2] * pByte[3] / 255; 79. } 80. } 81. } 82. 83. pDc->SetStretchBltMode(HALFTONE); 84. img.Draw(pDc->m_hDC,nDPx,nDPy,nDw,nDh); 85. //img.TransparentBlt(pDc->m_hDC,nDPx,nDPy,nDw,nDh,RGB(255, 255, 255)); 86. } 87. catch (...) 88. { 89. return false; 90. } 91. return true; 92.} ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 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, 0, 0,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 { for (j=0; 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重绘时可能会把之前的绘图全部清除
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- vc 加载 透明 png 图片 方法