vc++載入透明png圖片方法——GDI+和CImage兩種
阿新 • • 發佈:2019-02-02
先看看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 objectImage 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; intj; 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);
程式碼中內部的框架是對影象的再次處理,對原來進行了修正,這樣得到的更加正常,程式碼實測如下
![](http://img.my.csdn.net/uploads/201209/10/1347289942_1906.jpg)
繪圖後效果
![](http://img.my.csdn.net/uploads/201209/10/1347289969_1259.jpg)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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<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重繪時可能會把之前的繪圖全部清除