我的技术规范

C/C++, Algorithm
随笔 - 11, 文章 - 7, 评论 - 1, 引用 - 0
数据加载中……

render a png file, using libpng1.5.0


// 这个类用于显示 PNG 图像
// 需要 png_loader.cc 支持。
// author: panchao

#pragma once

class CImageRender
{
public:
    int width_, height_;

    CImageRender();
    ~CImageRender();

    void LoadImage( wchar_t *file_path);

    void LoadImage( const unsigned char *mem_source, int mem_source_len);

    inline bool good();

    void DrawImage( HDC hdc, int xDest, int yDest, int wDest = -1, int hDest = -1, 
        int xSrc = 0, int ySrc = 0, int wSrc = -1 , int hSrc = -1 );

private:
    HDC hdc_;
    HBITMAP old_bitmap_, bitmap_;
    bool is_alpha_;
};





// ImageRender.cc 显示 PNG 图像的实现部分
// 需要 png_loader.cc 支持。
// author: panchao

#include "stdafx.h"
#include "./ImageRender.h"

#include <fstream>
#include <vector>

bool LoadPNG( const unsigned char *mem_source, int mem_source_len, unsigned char** png_data, int* width, int* height, bool* is_alpha);

CImageRender::
CImageRender() 
{
    bitmap_ = NULL;
    old_bitmap_ = NULL;
    hdc_ = NULL;
    is_alpha_ = false;
}

CImageRender::
~CImageRender()

    if (bitmap_) { 
        _ASSERT( old_bitmap_ && hdc_);

        SelectObject( hdc_, old_bitmap_);
        DeleteObject( bitmap_);
        bitmap_ = NULL;
        old_bitmap_ = NULL;
    }

    if (hdc_) { 
        DeleteDC( hdc_);
        hdc_ = NULL;
    }
}

void 
CImageRender::
LoadImage( const unsigned char *mem_source, int mem_source_len)
{
    if ( mem_source == NULL || mem_source_len == 0)
        return;

    HDC hdc = GetDC( NULL);
    hdc_ = CreateCompatibleDC( hdc );
    ReleaseDC( NULL, hdc);

    if ( hdc_ == NULL )
        return;

    unsigned char* png_data;

    if ( ! LoadPNG( mem_source, mem_source_len, &png_data, &width_, &height_, &is_alpha_ )) 
        return;

    _ASSERT( png_data != NULL );

    width_ = width_;
    height_ = height_;
    is_alpha_ = is_alpha_;

    int width_dword_align = (width_ + 3 ) / 4 * 4;

    BITMAPINFO bmp_info;
    ::ZeroMemory(&bmp_info, sizeof(bmp_info));
    bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmp_info.bmiHeader.biWidth = width_dword_align;
    bmp_info.bmiHeader.biHeight = -height_;
    bmp_info.bmiHeader.biPlanes = 1;
    bmp_info.bmiHeader.biBitCount = 32;
    bmp_info.bmiHeader.biCompression = BI_RGB;

    _ASSERT( hdc_ != NULL && png_data!=NULL);

    void *ppvBits = NULL;
    bitmap_ = CreateDIBSection( hdc_, (LPBITMAPINFO)&bmp_info, DIB_RGB_COLORS, (void**)&ppvBits, NULL, 0);

    if ( bitmap_ != NULL )
    {
        memcpy ( ppvBits, png_data, height_ * width_ * 4);

        _ASSERT(bitmap_ != NULL);

        old_bitmap_ = (HBITMAP)SelectObject( hdc_, bitmap_);
    }
    else
    {
        DeleteDC( hdc_);
        hdc_ = NULL;
    }

    delete [] png_data;
}

void 
CImageRender::
LoadImage( wchar_t *file_path)
{
    std::ifstream fin;
    fin.open( file_path, std::ios::in | std::ios::binary);

    if ( ! fin.good())
        return;

    std::vector<char> data;

    fin.seekg(0, std::ios::end);
    size_t size = fin.tellg();
    data.resize(size);
    fin.read( &data[0], size );
    fin.close();

    LoadImage( (const unsigned char*)&data[0], size);
}

inline bool 
CImageRender::
good()
{
    return bitmap_ != NULL;
}

void 
CImageRender::
DrawImage( HDC hdc, int xDest, int yDest, int wDest, int hDest, 
          int xSrc, int ySrc, int wSrc, int hSrc )
{
    if ( ! good() ) 
        return ;

    if ( wDest == -1) wDest = width_;
    if ( hDest == -1) hDest = height_;
    if ( wSrc ==  -1) wSrc = width_;
    if ( hSrc ==  -1) hSrc = height_;

    if ( is_alpha_ )
    {
        BLENDFUNCTION func = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

        AlphaBlend( hdc, xDest, yDest, width_, height_, hdc_, xSrc, ySrc, width_, height_, func);
    }
    else
    {
        if ( wDest==wSrc && hDest==hSrc)
            BitBlt( hdc, xDest, yDest, wDest, hDest, hdc_, xSrc, ySrc, SRCCOPY);
        else
            StretchBlt( hdc, xDest, yDest, wDest, hDest, hdc_, xSrc, ySrc, wSrc, hSrc, SRCCOPY); 
    }
}





// 提供读取 .png 文件的方法:
// 使用 libpng 库。
// author: panchao

#include "./thirdparty/libpng-1.5.0/png.h"

bool LoadPNG( const unsigned char *mem_source, int mem_source_len, unsigned char** png_data, int* width, int* height, bool* is_alpha);
//bool LoadPNG( const wchar_t *file_path, unsigned char** png_data, int* width, int* height, bool* is_alpha);

unsigned char* doConvertRGB8(png_structp png_ptr, png_infop info_ptr, int width, int height);
unsigned char* doConvertRGBA8(png_structp png_ptr, png_infop info_ptr, int width, int height);
unsigned char* doConvertGrey8(png_structp png_ptr, png_infop info_ptr, int width, int height);
unsigned char* doConvertGreyA8(png_structp png_ptr, png_infop info_ptr, int width, int height);

// PNG文件的数据:
// 这个类主要用于 PNG读取数据时的回调函数。
class CPNGFileSource
{
public:
    const unsigned char* data;
    png_size_t size;
    png_size_t offset;

    //从内存读取PNG图片的回调函数
    static void 
    png_read_callback(png_structp png_ptr, png_bytep data, png_size_t length)
    {
        CPNGFileSource* isource = (CPNGFileSource*)png_get_io_ptr(png_ptr);

        if(isource->offset + length <= isource->size)
        {
            memcpy(data, isource->data+isource->offset, length);
            isource->offset += length;
        }
        else
            png_error(png_ptr, "png_read_callback failed, out of memory.");
    }
} ;


bool LoadPNG( const unsigned char *mem_source, int mem_source_len, 
             unsigned char** png_data, int* width, int* height, bool* is_alpha)
{
    if ( png_data == NULL)
        return false;

    *png_data = NULL;

    if ( mem_source == NULL)
        return false;

    //test if png, compare first 8 bytes
    int is_png = !png_sig_cmp( mem_source, 0, 8);
    if (!is_png) {
        return false;
    }

    //create png struct
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
        NULL, NULL);
    if (!png_ptr) {
        return false;
    }

    //create png info struct
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
        return false;
    }

    //create png info struct
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        return false;
    }

    //png error stuff, not sure libpng man suggests this.
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return false;
    }

    //init png reading
    
//png_init_io(png_ptr, fp);
    CPNGFileSource imgsource;
    imgsource.data = mem_source;
    imgsource.size = mem_source_len;
    imgsource.offset = 0;
    
    png_set_read_fn( png_ptr, &imgsource, CPNGFileSource::png_read_callback);

    //let libpng know you already read the first 8 bytes
    
//png_set_sig_bytes(png_ptr, 8);

    ////variables to pass to get info
    int bit_depth, color_type;
    png_uint_32 _width, _height;

    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);

    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);
    _width = png_get_image_width(png_ptr, info_ptr);
    _height = png_get_image_height(png_ptr, info_ptr);

    png_byte *_png_data = NULL;

    // rgb
    if (color_type == PNG_COLOR_TYPE_RGB)
    {
        _png_data = doConvertRGB8(png_ptr, info_ptr, _width, _height);
    }
    // rgb with opacity
    else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    {
        _png_data = doConvertRGBA8(png_ptr, info_ptr, _width, _height);
    }

    // 256 grey values
    else if (color_type == PNG_COLOR_TYPE_GRAY)
    {
        _png_data = doConvertGrey8(png_ptr, info_ptr, _width, _height);
    }

    // 256 grey values with opacity
    else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        _png_data = doConvertGreyA8(png_ptr, info_ptr, _width, _height);
    }

    *png_data = _png_data;
    *width = _width;
    *height = _height;
    *is_alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;

    //clean up memory and close stuff
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return _png_data != NULL;
}

//
//bool LoadPNG( const wchar_t *file_path, unsigned char** png_data, int* width, int* height, bool* is_alpha)
//{
//    if ( png_data == NULL)
//        return false;
//
//    *png_data = NULL;
//
//    if ( file_path == NULL)
//        return false;
//
//    //open file as binary
//    FILE *fp = _wfopen( file_path, L"rb");
//    if (!fp) {
//        return false;
//    }
//
//    //read the header
//    png_byte header[8];
//    fread(header, 1, 8, fp);
//
//    //test if png
//    int is_png = !png_sig_cmp(header, 0, 8);
//    if (!is_png) {
//        fclose(fp);
//        return false;
//    }
//
//    //create png struct
//    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
//        NULL, NULL);
//    if (!png_ptr) {
//        fclose(fp);
//        return false;
//    }
//
//    //create png info struct
//    png_infop info_ptr = png_create_info_struct(png_ptr);
//    if (!info_ptr) {
//        png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
//        fclose(fp);
//        return false;
//    }
//
//    //create png info struct
//    png_infop end_info = png_create_info_struct(png_ptr);
//    if (!end_info) {
//        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
//        fclose(fp);
//        return false;
//    }
//
//    //png error stuff, not sure libpng man suggests this.
//    if (setjmp(png_jmpbuf(png_ptr))) {
//        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
//        fclose(fp);
//        return false;
//    }
//
//    //init png reading
//    png_init_io(png_ptr, fp);
//
//    //let libpng know you already read the first 8 bytes
//    png_set_sig_bytes(png_ptr, 8);
//
//    ////variables to pass to get info
//    int bit_depth, color_type;
//    png_uint_32 _width, _height;
//
//    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
//
//    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
//    color_type = png_get_color_type(png_ptr, info_ptr);
//    _width = png_get_image_width(png_ptr, info_ptr);
//    _height = png_get_image_height(png_ptr, info_ptr);
//
//    png_byte *_png_data = NULL;
//
//    // rgb
//    if (color_type == PNG_COLOR_TYPE_RGB)
//    {
//        _png_data = doConvertRGB8(png_ptr, info_ptr, _width, _height);
//    }
//    // rgb with opacity
//    else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
//    {
//        _png_data = doConvertRGBA8(png_ptr, info_ptr, _width, _height);
//    }
//
//    // 256 grey values
//    else if (color_type == PNG_COLOR_TYPE_GRAY)
//    {
//        _png_data = doConvertGrey8(png_ptr, info_ptr, _width, _height);
//    }
//
//    // 256 grey values with opacity
//    else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
//    {
//        _png_data = doConvertGreyA8(png_ptr, info_ptr, _width, _height);
//    }
//
//    *png_data = _png_data;
//    *width = _width;
//    *height = _height;
//    *is_alpha = (color_type & PNG_COLOR_MASK_ALPHA) != 0;
//
//    //clean up memory and close stuff
//    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
//    fclose(fp);
//
//    return _png_data != NULL;
//}

// -------------
// doConvertRGB8
// -------------
/*
*
* Gets the data from an 8-bit rgb image.
*
* @par Memory
* - The returned pointer is created by using the new[] operator.
* - You have to free the allocated memory yourself.
*
* @par Structure
* - The color-sequence is Blue-Green-Red-Alpha (8 bit each).
* - The first 4 values (RGBA) are located in the top-left corner of the image.
* - The last 4 values (RGBA) are located in the bottom-right corner of the image.
*/
unsigned char* doConvertRGB8(png_structp png_ptr, png_infop info_ptr, int width, int height)
{
    // calculate needed memory
    int size = height * width * 4;

    // allocate memory
    unsigned char* png_data, *rgba;

    png_data = rgba = new unsigned char[size];

    // get image rows
    png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);

    int pos = 0;
    png_bytep row;

    // get color values
    forint i = 0; i < height; ++ i )
    {
        row = row_pointers[i];

        for(int j = 0; j < (3 * width); j += 3)
        {
#ifdef LIBPNG_USING_OPENGL
            *rgba ++ = row[j];        // red
            *rgba ++ = row[j + 1];    // green
            *rgba ++ = row[j + 2];    // blue
#else
            *rgba ++ = row[j + 2];    // blue
            *rgba ++ = row[j + 1];    // green
            *rgba ++ = row[j];        // red
#endif
            *rgba ++ = 0;                        // alpha
        }
    }

    return png_data;
}


// --------------
// doConvertRGBA8
// --------------
/*
*
* Gets the data from an 8-bit rgb image with alpha values.
*
* @par Memory
* - The returned pointer is created by using the new[] operator.
* - You have to free the allocated memory yourself.
*
* @par Structure
* - The color-sequence is Blue-Green-Red-Alpha (8 bit each).
* - The first 4 values (RGBA) are located in the top-left corner of the image.
* - The last 4 values (RGBA) are located in the bottom-right corner of the image.
*/
unsigned char* doConvertRGBA8(png_structp png_ptr, png_infop info_ptr, int width, int height)
{
    // calculate needed memory
    int size = height * width * 4;

    // allocate memory
    unsigned char* png_data, *rgba;

    png_data = rgba = new unsigned char[size];

    // get image rows
    png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);

    int pos = 0;

    png_bytep row;
    unsigned char alpha;

    // get color values
    forint i = 0; i < height; ++ i )
    {
        row = row_pointers[i];

        for(int j = 0; j < (4 * width); j += 4)
        {
            alpha = row[j + 3];

#ifdef LIBPNG_USING_OPENGL
            *rgba ++ = row[j];        // red
            *rgba ++ = row[j + 1];    // green
            *rgba ++ = row[j + 2];    // blue
#else
            *rgba ++ = row[j + 2] * alpha / 0xff;    // blue
            *rgba ++ = row[j + 1] * alpha / 0xff;    // green
            *rgba ++ = row[j] * alpha / 0xff;        // red
#endif
            *rgba ++ = alpha;    // alpha
        }
    }

    return png_data;
}

// --------------
// doConvertGrey8
// --------------
/*
*
* Gets the data from an 8-bit monochrome image.
*
* @par Memory
* - The returned pointer is created by using the new[] operator.
* - You have to free the allocated memory yourself.
*
* @par Structure
* - The color-sequence is Blue-Green-Red-Alpha (8 bit each).
* - The first 4 values (RGBA) are located in the top-left corner of the image.
* - The last 4 values (RGBA) are located in the bottom-right corner of the image.
*/
unsigned char* doConvertGrey8(png_structp png_ptr, png_infop info_ptr, int width, int height)
{
    // calculate needed memory
    int size = height * width * 4;

    // allocate memory
    unsigned char* png_data, *rgba;

    png_data = rgba = new unsigned char[size];

    // get image rows
    png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);

    int pos = 0;
    png_bytep row;

    // get color values
    forint i = 0; i < height; ++ i )
    {
        row = row_pointers[i];

        for(int j = 0; j < width; j++)
        {
#ifdef LIBPNG_USING_OPENGL
            *rgba ++ = row[j];    // red
            *rgba ++ = row[j];    // green
            *rgba ++ = row[j];    // blue
#else
            *rgba ++ = row[j];    // blue
            *rgba ++ = row[j];    // green
            *rgba ++ = row[j];    // red
#endif
            *rgba ++ = 0;                    // alpha
        }
    }

    return png_data;
}


// ---------------
// doConvertGreyA8
// ---------------
/*
*
* Gets the data from an 8-bit monochrome image with alpha values.
*/
unsigned char* doConvertGreyA8(png_structp png_ptr, png_infop info_ptr, int width, int height)
{
    // calculate needed memory
    int size = height * width * 4;

    // allocate memory
    unsigned char* png_data, *rgba;

    png_data = rgba = new unsigned char[size];

    // get image rows
    png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);

    int pos = 0;
    png_bytep row;
    unsigned char alpha;

    // get color values
    forint i = 0; i < height; ++ i )
    {
        row = row_pointers[i];

        for(int j = 0; j < (2 * width); j += 2)
        {
            alpha = row_pointers[i][j + 1];

#ifdef LIBPNG_USING_OPENGL
            *rgba ++ = row[j];        // red
            *rgba ++ = row[j];        // green
            *rgba ++ = row[j];        // blue
#else
            *rgba ++ = row[j] * alpha / 0xff;        // blue
            *rgba ++ = row[j] * alpha / 0xff;        // green
            *rgba ++ = row[j] * alpha / 0xff;        // red
#endif
            *rgba ++ = alpha;    // alpha
        }
    }

    return png_data;
}

posted on 2012-02-17 09:08 panchao 阅读(435) 评论(0)  编辑 收藏 引用 所属分类: utils


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理