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

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值