您的位置:首页 > 其它

在vc6实现png图像文件的显示方法

2010-07-01 14:10 183 查看
vc6本身不会提供对png图像文件的显示支持,在这篇文章中谈谈怎样借用libpnp开源代码来实现这一点。



1. 编译zlib

首先在http://zlib.net/下载zlib 源码,以zlib-1.2.4为例,解压到硬盘任何一个地方,假设为e:/zlib-1.2.4,

在e:/zlib-1.2.4/project/visualc6有vc6工程,用vc6打开zlib.dsw,编译产生静态库zlib.lib,zlibd.lib(debug), 并连同zconf.h,zlib.h拷贝一份放在vc6的系统目录下(include,lib),

2.编译libpng

http://www.libpng.org/下载最新的源码,这里以lpng141.zip为例,解压到硬盘任何一个地方,假设为e:/lpng141,在子目录projects中我们能发现有一个visualc6子目录,很显然,这里面放的是vc6的工程文件,用vc6打开libpng.dsw,编译产生静态库libpng.lib,libpngd.lib(debug), 并连同png.h,pngconf.h拷贝一份放在vc6的系统目录下(include,lib),



3.使用libpng,

建立一个SDI工程pngSDI,

实现如下的一个类,类的定义imagPNG.h:

// ImagPNG.h: interface for the CImagPNG class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_IMAGPNG_H__3A5C27AE_0B49_4506_BD0B_CCB61F2CF91D__INCLUDED_)
#define AFX_IMAGPNG_H__3A5C27AE_0B49_4506_BD0B_CCB61F2CF91D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <png.h>

#define ALPHABLED(b,f,a) (b * (255 -a ) + f * a )/255
#define MARGIN 0
class CImagPNG
{
public:
HBITMAP LoadResource(UINT nIDResource);
HBITMAP LoadFromFile(LPCTSTR lpFileName);
CImagPNG( int cxWinSize, int cyWinSize,HDC hdc);
virtual ~CImagPNG();

private:
HBITMAP Read( FILE *fl);
BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize);
BOOL FillBitmap (BYTE *pDiData,BYTE *pbImage,int cx,int cy,int cChannel);
HDC m_hdc ;
int m_cxWinSize;
int m_cyWinSize;
png_byte* m_pbImageData;
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
};

#endif // !defined(AFX_IMAGPNG_H__3A5C27AE_0B49_4506_BD0B_CCB61F2CF91D__INCLUDED_)

实现cpp文件:

// ImagPNG.cpp: implementation of the CImagPNG class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ImagPNG.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CImagPNG::CImagPNG( int cxWinSize, int cyWinSize,HDC hdc)
{
m_hdc = hdc;

m_cxWinSize = cxWinSize;
m_cyWinSize = cyWinSize;
m_pbImageData = NULL;
}

CImagPNG::~CImagPNG()
{
if (m_pbImageData)
{
free (m_pbImageData);
m_pbImageData = NULL;
}
}

void CImagPNG::png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;

/* fread() returns 0 on error, so it is OK to store this in a png_size_t
* instead of an int, which is what fread() actually returns.
*/
check = (png_size_t)fread(data, (png_size_t)1, length,
(FILE *)png_ptr->io_ptr);

if (check != length)
{
png_error(png_ptr, "Read Error");
}
}

HBITMAP CImagPNG::LoadFromFile(LPCTSTR lpFileName)
{

FILE *fpin;

if ((fpin = fopen(lpFileName, "rb")) == NULL)
{
return NULL;
}
HBITMAP hbp = Read(fpin);

fclose(fpin);
return hbp;
}

BOOL CImagPNG::FillBitmap(BYTE *pDiData, BYTE *pbImage, int cx, int cy,int cChannel)
{
BYTE *pStretchedImage;
BYTE *pImg;
BYTE *src, *dst;
BYTE r, g, b, a;
const int cDIChannels = 3;
WORD wImgRowBytes;
WORD wDIRowBytes;
int cxImgPos, cyImgPos;
int xImg, yImg;
int xWin, yWin;
int cxNewSize, cyNewSize;
int xOld, yOld;
int xNew, yNew;
COLORREF bkCol=GetSysColor(COLOR_BTNFACE);// RGB(100,120,120);//GetBkColor(m_hdc);

cxNewSize = m_cxWinSize - 2 * MARGIN;
cyNewSize = m_cyWinSize - 2 * MARGIN;

// stretch the image to it's window determined size

// the following two are the same, but the first has side-effects
// because of rounding
// if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize))
if ((cyNewSize * cx) > (cy * cxNewSize))
{
cyNewSize = cxNewSize * cy / cx;
cxImgPos = MARGIN;
cyImgPos = (m_cyWinSize - cyNewSize) / 2;
}
else
{
cxNewSize = cyNewSize * cx / cy;
cyImgPos = MARGIN;
cxImgPos = (m_cxWinSize - cxNewSize) / 2;
}

pStretchedImage =(BYTE*) malloc (cChannel * cxNewSize * cyNewSize);
pImg = pStretchedImage;

for (yNew = 0; yNew < cyNewSize; yNew++)
{
yOld = yNew * cy / cyNewSize;
for (xNew = 0; xNew < cxNewSize; xNew++)
{
xOld = xNew * cx / cxNewSize;

r = *(pbImage + cChannel * ((yOld * cx) + xOld) + 0);
g = *(pbImage + cChannel * ((yOld * cx) + xOld) + 1);
b = *(pbImage + cChannel * ((yOld * cx) + xOld) + 2);
*pImg++ = r;
*pImg++ = g;
*pImg++ = b;
if (cChannel == 4)
{
a = *(pbImage + cChannel * ((yOld * cx) + xOld)
+ 3);
*pImg++ = a;
}
}
}

// calculate row-bytes

wImgRowBytes = cChannel * cxNewSize;
wDIRowBytes = (WORD) ((cDIChannels * m_cxWinSize + 3L) >> 2) << 2;

// copy image to screen

for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++)
{
if (yWin >= m_cyWinSize - cyImgPos)
break;
src = pStretchedImage + yImg * wImgRowBytes;
dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;

for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++)
{
if (xWin >= m_cxWinSize - cxImgPos)
break;
r = *src++;
g = *src++;
b = *src++;
if (cChannel == 4)
{
a = *src++;
}
*dst++ = ALPHABLED(GetBValue(bkCol),b,a );// b; /* note the reverse order */
*dst++ = ALPHABLED(GetGValue(bkCol),g,a );//g;
*dst++ = ALPHABLED(GetRValue(bkCol),r,a );//r;
}
}

// free memory

if (pStretchedImage != NULL)
{
free (pStretchedImage);
pStretchedImage = NULL;
}

return TRUE;
// calculate the central position
cxImgPos = 0;
cyImgPos = 0;

// check for image larger than window

if (cxImgPos < MARGIN)
cxImgPos = MARGIN;
if (cyImgPos < MARGIN)
cyImgPos = MARGIN;
// calculate both row-bytes
wImgRowBytes = cChannel * cx;
wDIRowBytes = (WORD) ((cDIChannels * cx + 3L) >> 2) << 2;

// copy image to screen
for (yImg = 0, yWin = cyImgPos; yImg < cy; yImg++, yWin++)
{
if (yWin >= cy - MARGIN)
break;
src = pbImage + yImg * wImgRowBytes;
dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;

for (xImg = 0, xWin = cxImgPos; xImg < cx; xImg++, xWin++)
{
if (xWin >= cx - MARGIN)
break;
r = *src++;
g = *src++;
b = *src++;

if (cChannel == 4)
{
a = *src++;
// TRACE("Alpha %d /n",a);
}

*dst++ = ALPHABLED(GetBValue(bkCol),b,a );// b; /* note the reverse order */
*dst++ = ALPHABLED(GetGValue(bkCol),g,a );//g;
*dst++ = ALPHABLED(GetRValue(bkCol),r,a );//r;
}
}

return TRUE;
}

BOOL CImagPNG::InitBitmap(BYTE *pDiData, int cxWinSize, int cyWinSize)
{
BYTE *dst;
int x, y, col;

// initialize the background with gray

dst = pDiData;
for (y = 0; y < cyWinSize; y++)
{
// col = 0;
for (x = 0; x < cxWinSize; x++)
{
// fill with GRAY
*dst++ = 127;
*dst++ = 127;
*dst++ = 127;
col += 3;
}
// rows start on 4 byte boundaries
while ((col % 4) != 0)
{
dst++;
col++;
}
}

return TRUE;

}

HBITMAP CImagPNG::LoadResource(UINT nIDResource)
{
LPCTSTR szResourceName = MAKEINTRESOURCE(nIDResource);
HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,"PNG");
HGLOBAL hResData;
if (!hPicture || !(hResData = ::LoadResource(AfxGetResourceHandle(),hPicture)))
{
TRACE(_T("Load (resource): Error loading resource %s/n"),szResourceName);
return NULL;
};
DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture);

// hResData is not the real HGLOBAL (we can't lock it)
// let's make it real
LPVOID pSrc = LockResource(hResData);
FILE* stream = tmpfile();
if (NULL != stream)
{
fwrite(pSrc, dwSize, 1, stream);
fseek(stream,0,SEEK_SET);

}
FreeResource(hResData);
HBITMAP btmap = Read(stream);

fclose(stream);
return btmap;
}

HBITMAP CImagPNG::Read(FILE *fl)
{
png_structp read_ptr;
png_infop read_info_ptr, end_info_ptr;
png_bytep row_buf;
png_uint_32 iWidth, iHeight;
int iBitDepth, iColorType;

read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

read_info_ptr = png_create_info_struct(read_ptr);

if (setjmp(png_jmpbuf(read_ptr)))
{
png_free(read_ptr, row_buf);
row_buf = NULL;
png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
return NULL;
}




png_byte pbSig [8];
fread(pbSig, 1, 8, fl);
if (png_sig_cmp(pbSig, 0, 8))
{

return NULL;
}

png_set_read_fn(read_ptr, (png_voidp)fl, png_read_data);

png_set_sig_bytes(read_ptr, 8);
// read all PNG info up to image data

png_read_info(read_ptr, read_info_ptr);

// get width, height, bit-depth and color-type

png_get_IHDR(read_ptr, read_info_ptr, &iWidth, &iHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);

// expand images of all color-type and bit-depth to 3x8 bit RGB images
// let the library process things like alpha, transparency, background

if (iBitDepth == 16)
png_set_strip_16(read_ptr);
if (iColorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand(read_ptr);
if (iBitDepth < 8)
png_set_expand(read_ptr);
if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_tRNS))
png_set_expand(read_ptr);
if (iColorType == PNG_COLOR_TYPE_GRAY ||
iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(read_ptr);

png_color_16* pBackground;
png_color* pBkgColor ;
// set the background color to draw transparent and alpha images over.
if (png_get_bKGD(read_ptr, read_info_ptr, &pBackground))
{
png_set_background(read_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
pBkgColor->red = (byte) pBackground->red;
pBkgColor->green = (byte) pBackground->green;
pBkgColor->blue = (byte) pBackground->blue;
}
else
{
pBkgColor = NULL;
}

double dGamma;
// if required set gamma conversion
if (png_get_gAMA(read_ptr, read_info_ptr, &dGamma))
png_set_gamma(read_ptr, (double) 2.2, dGamma);

// after the transformations have been registered update info_ptr data

png_read_update_info(read_ptr, read_info_ptr);

// get again width, height and the new bit-depth and color-type

png_get_IHDR(read_ptr, read_info_ptr, &iWidth, &iHeight, &iBitDepth,
&iColorType, NULL, NULL, NULL);


// row_bytes is the width x number of channels
png_uint_32 ulRowBytes;
png_uint_32 ulChannels;
ulRowBytes = png_get_rowbytes(read_ptr, read_info_ptr);
ulChannels = png_get_channels(read_ptr, read_info_ptr);


// now we can allocate memory to store the image

static png_byte** ppbRowPointers = NULL;
if (m_pbImageData)
{
free (m_pbImageData);
m_pbImageData = NULL;
}
if ((m_pbImageData = (png_byte *) malloc(ulRowBytes * (iHeight)
* sizeof(png_byte))) == NULL)
{
png_error(read_ptr, "Visual PNG: out of memory");
return NULL;
}


// and allocate memory for an array of row-pointers

if ((ppbRowPointers = (png_bytepp) malloc((iHeight)
* sizeof(png_bytep))) == NULL)
{
png_error(read_ptr, "Visual PNG: out of memory");
return NULL;
}

// set the individual row-pointers to point at the correct offsets
int i;
for (i = 0; i < (iHeight); i++)
ppbRowPointers[i] = m_pbImageData + i * ulRowBytes;

// now we can go ahead and just read the whole image

png_read_image(read_ptr, ppbRowPointers);

// read the additional chunks in the PNG file (not really needed)

png_read_end(read_ptr, NULL);

// and we're done

free (ppbRowPointers);
ppbRowPointers = NULL;
png_destroy_read_struct(&read_ptr, &read_info_ptr, NULL);

//Display
WORD wDIRowBytes;
wDIRowBytes = (WORD) ((3 * iWidth + 3L) >> 2) << 2;
BYTE *pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) + wDIRowBytes * iHeight);
memset (pDib, 0, sizeof(BITMAPINFOHEADER));

BITMAPINFOHEADER *pbmih;
pbmih = (BITMAPINFOHEADER *) pDib;
pbmih->biSize = sizeof(BITMAPINFOHEADER);
pbmih->biWidth = m_cxWinSize;
pbmih->biHeight = -((long) m_cyWinSize);
pbmih->biPlanes = 1;
pbmih->biBitCount = 24;
pbmih->biCompression = BI_RGB;
BYTE *pDiData;
pDiData = pDib + sizeof(BITMAPINFOHEADER);
InitBitmap(pDiData,m_cxWinSize, m_cyWinSize);
FillBitmap (pDiData,m_pbImageData, iWidth, iHeight, ulChannels);
HBITMAP hbp=CreateDIBitmap(m_hdc,pbmih,CBM_INIT,pDiData,(BITMAPINFO *)pDib,DIB_RGB_COLORS);

return hbp;
}

其基本思想就是从png提取RGB数据来构造BITMAP对象,有两种方式:

HBITMAP CImagPNG::LoadResource(UINT nIDResource);
HBITMAP CImagPNG::LoadFromFile(LPCTSTR lpFileName);



分别是从资源和文件中构造BITMAP对象,



比如要把png图片放在toolbar上可以这样用:



int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{



。。。 。。。



//创建CImagPNG对象

m_pimgPNG = new CImagPNG(64,64,m_wndToolBar.GetDC()->m_hDC);



//创建CImaglist对象

m_imgTool.Create(64,64,ILC_COLOR32,1,0);



//从文件中构建bitmap对象

HBITMAP btmap=m_pimgPNG->LoadFromFile("d://25.png");



//加入到imagelist中
m_imgTool.Add(CBitmap::FromHandle(btmap),RGB(0,0,0));



btmap=m_pimgPNG->LoadFromFile("d://26.png");
m_imgTool.Add(CBitmap::FromHandle(btmap),RGB(0,0,0));



//从资源中构建bitmap对象

btmap=m_pimgPNG->LoadResource(IDR_PNG1);
m_imgTool.Add(CBitmap::FromHandle(btmap),RGB(0,0,0));



btmap=m_pimgPNG->LoadResource(IDR_PNG2);
m_imgTool.Add(CBitmap::FromHandle(btmap),RGB(0,0,0));



//最后把imaglist加入到工具条上
m_wndToolBar.GetToolBarCtrl().SetImageList(&m_imgTool);

效果图:





源码下载:http://download.csdn.net/source/2617355
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: