vc++加载透明png图片方法.docx
《vc++加载透明png图片方法.docx》由会员分享,可在线阅读,更多相关《vc++加载透明png图片方法.docx(15页珍藏版)》请在冰豆网上搜索。
vc++加载透明png图片方法
使用CImage画PNG,原本透明的图片,结果却显示白色/黑色底。
解决办法:
像素转换。
#includevoidCrossImage(CImage&img)//对像素进行转换
{
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 //初始化一下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 objectImage image(_T("1.png")); // Construct an imagegraphics.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] viewplaincopy1.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 pDc; 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; i72. { 73. for (j=0; j74. { 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); // typeif (!hRsrc)return FALSE;// load resource into memoryDWORD len = SizeofResource(hInst, hRsrc);BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);if (!lpRsrc)return FALSE;// Allocate global memory on which to create streamHGLOBAL 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 streampImg=Gdiplus::Image::FromStream(pstm);// free/release stuffpstm->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 objectImage *pimage; // Construct an imageImageFromIDResource(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重绘时可能会把之前的绘图全部清除
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 //初始化一下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 objectImage image(_T("1.png")); // Construct an imagegraphics.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] viewplaincopy1.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 pDc; 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; i72. { 73. for (j=0; j74. { 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); // typeif (!hRsrc)return FALSE;// load resource into memoryDWORD len = SizeofResource(hInst, hRsrc);BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);if (!lpRsrc)return FALSE;// Allocate global memory on which to create streamHGLOBAL 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 streampImg=Gdiplus::Image::FromStream(pstm);// free/release stuffpstm->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 objectImage *pimage; // Construct an imageImageFromIDResource(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重绘时可能会把之前的绘图全部清除
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 //初始化一下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, 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;
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 pDc;
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; i72. { 73. for (j=0; j74. { 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); // typeif (!hRsrc)return FALSE;// load resource into memoryDWORD len = SizeofResource(hInst, hRsrc);BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);if (!lpRsrc)return FALSE;// Allocate global memory on which to create streamHGLOBAL 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 streampImg=Gdiplus::Image::FromStream(pstm);// free/release stuffpstm->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 objectImage *pimage; // Construct an imageImageFromIDResource(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重绘时可能会把之前的绘图全部清除
72. {
73. for (j=0; j74. { 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); // typeif (!hRsrc)return FALSE;// load resource into memoryDWORD len = SizeofResource(hInst, hRsrc);BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);if (!lpRsrc)return FALSE;// Allocate global memory on which to create streamHGLOBAL 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 streampImg=Gdiplus::Image::FromStream(pstm);// free/release stuffpstm->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 objectImage *pimage; // Construct an imageImageFromIDResource(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重绘时可能会把之前的绘图全部清除
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);
lpRsrc)
// 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;
这时加载图片的代码变为:
Image *pimage; // Construct an image
ImageFromIDResource(IDB_PNG1,_T("PNG"),pimage);
graphics.DrawImage(pimage, 0, 0,pimage->GetWidth(), pimage->GetHeight());
用CImage时需要如下函数:
BOOL LoadImageFromResource(CImage *pImage, UINT nResID,LPCTSTR lpTyp)
if ( pImage == NULL)
return false;
pImage->Destroy();
// 查找资源
FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nResID), lpTyp);
if (hRsrc == NULL)
// 加载资源
HGLOBAL hImgData = :
LoadResource(AfxGetResourceHandle(), hRsrc);
if (hImgData == NULL)
FreeResource(hImgData);
// 锁定内存中的指定资源
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);
// 释放资源
return true;
这时加载图片的代码如下:
LoadImageFromResource(&Image,IDB_PNG1,_T("PNG"));
return;
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重绘时可能会把之前的绘图全部清除
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重绘时可能会把之前的绘图全部清除
Image.Draw(pDC->m_hDC,0,0);
另
要注意的是,最好把绘图放在OnPaint消息响应里,否则,OnSize消息触发OnPaint重绘时可能会把之前的绘图全部清除
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1