内存png读取程序

//pngReader.h

#ifndef _PNGREADER_H_

#define _PNGREADER_H_

 

#include "gfx/mstBitmap.h"

#include "png.h"

 

/* Transparency parameters */

#define PNG_ALPHA     -2         /* Use alpha channel in PNG file, if there is one */

#define PNG_SOLID     -1         /* No transparency                                */

#define PNG_STENCIL    0         /* Sets alpha to 0 for r=g=b=0, 1 otherwise       */

 

#define HEADER_BYTES_TO_CHECK  8 

 

typedef struct

{

     LPBYTE data;

     DWORD size;

     LPDWORD bytesRead;

}  ReadInfo, *ReadInfoPtr;

 

 

class PngReader

{

public:

     PngReader() {};

     ~PngReader() {};

     static MstBitmap* readPngStream( void* stream,int size);

     static MstBitmap* readPngFile( const char* fileName);

 

     static void png_error(png_structp png_ptr, png_const_charp message);

     static void png_warning(png_structp png_ptr, png_const_charp message);

 

protected:

     static void pngReadDataFn(png_structp png_ptr, png_bytep data, png_size_t length);

 

private: 

};

#endif

 

 

//pngReader.cpp

#include <windows.h>

 #include "pngReader.h"

 

#include <assert.h>

#include <iostream>

#include <GL/gl.h>

 

extern "C"

{

#include <zlib.h>

#include <png.h>

}

/**主要参考《libpng实现内存内位图的压缩及解压缩.mht》和osg2.2\src\osgplugins\pngReaderWriterPNG.cpp完成。

当bmds/trans,为透明png时,color为(PNG_COLOR_TYPE_RGB_ALPHA),即(PNG_COLOR_MASK_COLOR)|4(PNG_COLOR_MASK_ALPHA)。

当bmds/vect,png不透明时,color为(PNG_COLOR_TYPE_PALETTE),即(PNG_COLOR_MASK_COLOR)|1(PNG_COLOR_MASK_PALETTE)。

*/

MstBitmap* PngReader::readPngStream(void* stream,int size)

{

     if( !stream|| size<max(1, HEADER_BYTES_TO_CHECK))

         return FALSE;

 

     if(png_sig_cmp( (unsigned char *)stream, (png_size_t)0, HEADER_BYTES_TO_CHECK))//libpng新版本用png_sig_cmp取代png_check_sig

         return NULL;

 

     //是否剔除Alpha信息,剔除时,选择PNG_SOLID

     int trans = PNG_ALPHA;//PNG_SOLID;

 

     png_structp png;

     png_infop   info;

     png_infop   endinfo;

     png_bytep   data;

     png_bytep  *row_p;

     double  fileGamma;

 

     png_uint_32 width, height;

     int depth, color;

 

     png_uint_32 i;

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

     info = png_create_info_struct(png);

     endinfo = png_create_info_struct(png);

 

     png_set_error_fn(png, NULL, PngReader::png_error, PngReader::png_warning);

 

     if(setjmp(png_jmpbuf(png)))

         return NULL;

    

     //由于是内存源,比对标志后不需要恢复当前文件指针,所以一定要设置成零,不然会造成后续png_read_info等函数指针越界等连锁错误。

     //png_set_sig_bytes(png, 8);/*HEADER_BYTES_TO_CHECK*/

     png_set_sig_bytes(png, 0);

 

     ReadInfo readInfo;

     readInfo.data = (unsigned char *)stream;

     readInfo.size = size;

     unsigned int bytes = 0;

     readInfo.bytesRead = (LPDWORD)&bytes;

     png_set_read_fn(png, &readInfo, PngReader::pngReadDataFn);

 

     png_read_info(png, info);

     png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);

 

     if(!(width > 0 && height > 0) )

         return NULL;

 

     if ( (color&PNG_COLOR_MASK_ALPHA) && trans != PNG_ALPHA)

     {

         png_set_strip_alpha(png);//剔除alpha信息

         color &= ~PNG_COLOR_MASK_ALPHA;

     }

 

     if (color == PNG_COLOR_TYPE_PALETTE)

         png_set_palette_to_rgb(png);

     if (color == PNG_COLOR_TYPE_GRAY && depth < 8)

         png_set_gray_1_2_4_to_8(png);

     if (png_get_valid(png, info, PNG_INFO_tRNS))

     {

         png_set_tRNS_to_alpha(png);

         trans = PNG_ALPHA;

     }

 

     // Make sure that files of small depth are packed properly.

     if (depth < 8)

         png_set_packing(png);

 

     /*--GAMMA--*/

     //    checkForGammaEnv();

     double screenGamma = 2.2 / 1.0;

     if (png_get_gAMA(png, info, &fileGamma))

         png_set_gamma(png, screenGamma, fileGamma);

     else

         png_set_gamma(png, screenGamma, 1.0/2.2);

 

     png_read_update_info(png, info);

 

     //必须在png_read_update_info后调用png_get_rowbytes,否则得到的是转化前的rowBytes;

     //必须注意! 否则后面分配内存出错导致png_read_image或delete[] row_p出现奇怪的错误。

     png_uint_32 rowBytes = png_get_rowbytes(png, info);

 

     data = (png_bytep) new unsigned char [png_get_rowbytes(png, info)/*rowBytes*/ *height];

     row_p = new png_bytep [height];

 

     //bool StandardOrientation = true;

     bool StandardOrientation = false;

     for (i = 0; i < height; i++)

     {

         if (StandardOrientation)

              row_p[height - 1 - i] = &data[rowBytes*i];

         else

              row_p[i] = &data[rowBytes*i];

     }

 

     png_read_image(png, row_p); //Decode

 

     delete[] row_p;

 

     png_read_end(png, endinfo);

     png_destroy_read_struct(&png, &info, &endinfo);

 

     GLenum pixelFormat = 0;

     GLenum dataType = depth<=8 ? GL_UNSIGNED_BYTE :GL_UNSIGNED_SHORT;

     switch(color)

     {

     case(PNG_SOLID): pixelFormat = GL_LUMINANCE; break;

     case(PNG_ALPHA): pixelFormat = GL_ALPHA; break;

     case(PNG_COLOR_TYPE_GRAY): pixelFormat = GL_LUMINANCE ; break;

     case(PNG_COLOR_TYPE_GRAY_ALPHA): pixelFormat = GL_LUMINANCE_ALPHA; break;

     case(PNG_COLOR_TYPE_RGB): pixelFormat = GL_RGB; break;

     case(PNG_COLOR_TYPE_PALETTE): pixelFormat = GL_RGB; break;

     case(PNG_COLOR_TYPE_RGB_ALPHA): pixelFormat = GL_RGBA; break;

     default: break;               

     }

 

     // Some paletted images contain alpha information.  To be

     // able to give that back to the calling program, we need to

     // check the number of channels in the image.  However, the

     // call might not return correct information unless

     // png_read_end is called first.  See libpng man page.

     if (pixelFormat == GL_RGB && png_get_channels(png, info) == 4)

         pixelFormat = GL_RGBA;

 

     int internalFormat = pixelFormat;

 

 

     MstBitmap *pbi = (MstBitmap*)malloc(sizeof(MstBitmap));//存放JPEG数据

 

     if (pbi != NULL)

     {

         pbi->width = width;

         pbi->height = height;

         pbi->pixelFormat = pixelFormat;

         pbi->internalFormat = internalFormat;

         pbi->dataType = dataType;

         pbi->data = (unsigned char *)data;

     }

     return pbi;

}

 

void PngReader::pngReadDataFn(png_structp png, png_bytep data, png_size_t length)

{

     if(!png )

         return;

     ReadInfoPtr pwd=(ReadInfoPtr)png_get_io_ptr(png);

     if(!pwd || !pwd->bytesRead)

         return;

     if(pwd->data)

     {

         if(*pwd->bytesRead+length>pwd->size)

           return;

         memcpy(data, pwd->data+ (*pwd->bytesRead), length);

         *pwd->bytesRead += length;

     }

}

 

void PngReader::png_warning(png_structp png, png_const_charp message)

{

     fprintf(stdout, "libpng warning: %s\n", message);

}

 

void PngReader::png_error(png_structp png, png_const_charp message)

{

     PngReader::png_warning(png, message);

}

posted @ 2010-07-27 20:01  米麦  阅读(3151)  评论(0)    收藏  举报