A simple method to display a transparent PNG file
Introducing a simple method to display a transparent PNG file.
Introduction
If you are searching for a component to display a PNG32 image, this code may give you some tips.
Background
Some days ago, I needed a component to display a transparent PNG image in my code. Searching with the keyword "PNG" in CodeProject, I found a demo named PNGView. But, it does not deal with transparent PNGs. So I decided to do it on my own.
The basic idea is to simulate AlplaBlend's behavior, see the following code. In order to fasten the speed of display, the code's core part is optimized by using ASM. I am not very good at ASM, so if there are any shortcomings or bugs in my code, please let me know.
Hope this helps. Thanks for your attention!
Using the code
I have wrapped the code to a static library. The download includes a demo and the static library's source code.
In order to use this code, you should import the lib first, and then you can display a PNG32 image in just three steps.
Step 1: Load a PNG32 image
In order to simplify the code, I only support 32 pixel depth PNG images.
char szFileName[MAX_PATH]; strcpy(szFileName,"*.png") PNGINFO *pPng=Png32_Load(szFileName);
Step 2: Display the image in a HDC
Png32_Show(pDC->m_hDC,0,0,pPng->nWidth,pPng->nHeight,pPng,0,0);
Step 3: Free the occupied memory
Png32_Free(pPng);
The code
//display a 32 bit deep png image void Png32_Show(HDC hdc,int xDest,int yDest,int nWidth,int nHeight, PNGINFO *pPngInfo,int xSour,int ySour) { if(xSour+nWidth>(int)pPngInfo->nWidth) nWidth=pPngInfo->nWidth-xSour; if(ySour+nHeight>(int)pPngInfo->nHeight) nHeight=pPngInfo->nHeight-ySour; if(nWidth>0 && nHeight>0) { HDC hmemdc=0; LPBYTE pBitsDest=NULL; HBITMAP hbmpDest=0; HGDIOBJ hOldBmp=0; BITMAPINFO bmi; //sour memory unsigned char ** row_pointers = pPngInfo->ppbyRow+pPngInfo->nHeight-1-(pPngInfo->nHeight-ySour-nHeight); //Do alpla blend int nLineTailDest=WIDTHBYTES(24*nWidth)-3*nWidth; // Initialize header to 0s. ZeroMemory(&bmi, sizeof(bmi)); // Fill out the fields you care about. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = nHeight; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; // Create the surface. hmemdc=CreateCompatibleDC(hdc); // Get Dest Rectangle memory hbmpDest = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void **)&pBitsDest, NULL, 0); hOldBmp=SelectObject(hmemdc,hbmpDest); BitBlt(hmemdc,0,0,nWidth,nHeight,hdc,xDest,yDest,SRCCOPY); #ifdef ASM_CORE __asm { push esi push edi push eax push ebx push ecx push edx push es push ds mov ax,ds mov es,ax mov edi,pBitsDest mov ecx,nHeight beginy: mov ebx, row_pointers mov esi,[ebx] ;//offset picture's left margin mov eax,xSour imul eax,4 ;//4 bytes make up one pixel add esi,eax mov eax,nWidth beginx: ;//get alpla value xor ebx,ebx mov bl,[esi+3] ;//blue xor dx,dx mov dl,[edi]; imul dx,bx add dh,[esi+2] mov [edi],dh ;//save result to *pBitsDest inc edi ;//green xor dx,dx mov dl,[edi]; imul dx,bx add dh,[esi+1] mov [edi],dh ;//save result to *pBitsDest inc edi ;//red xor dx,dx mov dl,[edi]; imul dx,bx add dh,[esi] mov [edi],dh ;//save result to *pBitsDest inc edi add esi,4 dec eax cmp eax,0 jne beginx add edi,nLineTailDest sub row_pointers,4 ;//next line loop beginy pop ds pop es pop edx pop ecx pop ebx pop eax pop edi pop esi } #else//ASM_CORE { int i,j; BYTE *p1=pBitsDest; for(i=0;i<nHeight;i++) { BYTE *p2=*(row_pointers--); for(j=0;j<nWidth;j++) { *p1++=((p2[3]*(*p1))>>8)+p2[2]; *p1++=((p2[3]*(*p1))>>8)+p2[1]; *p1++=((p2[3]*(*p1))>>8)+p2[0]; p2+=4; } p1+=nLineTailDest; } } #endif//ASM_CORE //render BitBlt(hdc,xDest,yDest,nWidth,nHeight,hmemdc,0,0,SRCCOPY); SelectObject(hmemdc,hOldBmp); //Free memory DeleteObject(hbmpDest); DeleteDC(hmemdc); } }
Remark
The new version has a new interface, Png32_LoadFromMem
, with which you can easily load a 32 bit PNG image form memory. See CMfc_demoDlg::OnInitDialog
for an example.
To test this domo, you should compile the png32_helper project first, and then compile mfc_demo.
History
- 2008-04-17
Add the
Png32_LoadFromMem
interface. - 2007-09-07
Did pixel pre-multiplication.
- 2007-07-16
First submission.