4.使用pnglib读写png图片

原创 2017年06月20日 01:24:08

  4.使用pnglib读写png图片

  本章前言:

    这章就是为了读取png格式图像到32位位图(ARGB)中,逆之则然,废话少说开始正题。

  目标要点总结:

1.  使用pnglib读写文件

  最终效果:

    以下操作就能实现加载png图像到32位图像中:

    Image*img_bg=Image::Create(L"data/img/bg.png");

    以下操作就能实现导出png图像:

    img_bg->Save_To_PNG(L"bin/bg.png");

  前题简要:

    Image类用一个DWORD一维数组储存每个点,每个点由ARGB组成,例如0x66ff0000是半透明红色。假设要访问点(x,y),应该使用下标索引[y *w + x]。Image类还有图像的大小信息。

  具体实现:

    首先需要配置pnglib,其中还包括zlib。下载相应源码后,生成静态链接库链接到

项目。在代码中解析图片的cpp包含png.h。下面是解析png图片的具体实现,可结合注释理解。

    Image* Image::Create(constString&path)

    {

        //定义空图像

        Image* img =newImage;

        System_imp* sys =System_imp::Get_Instance();

        //String char字符数组

 

 

        char temp[512] ={NULL };

        path.Get_Multi_Byte_Str(temp, 512);

            ///////////////////////////////从文件加载/////////////////////////////////////

            //打开png文件

            FILE* fp = NULL;

            fopen_s(&fp,temp,"rb");

            if (!fp)

            {

                Debug::Instance()->Write_Line(String(L"文件打开失败:")+path);

                assert(0 &&L"Image加载时文件打开失败!");

                return NULL;

            }

            //判断是否为 png文件(用fread读取8字节,然后调用png_sig_cmp判断)

            size_t number = 8;

            png_bytep header = new png_byte[number];

            fread(header, 1,number,fp);

            bool is_png = !png_sig_cmp(header, 0,number);

            if (!is_png)

            {

                fclose(fp);

                Debug::Instance()->Write_Line(String(L"只支持png格式的图像读取:")+path);

                assert(0 &&L"Image加载时为非png格式图像!");

                return NULL;

            }

            //初始化pnglib

            static png_structppng_ptr =NULL;

            if (!png_ptr)

                png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,

                    NULL, NULL, NULL);

            if (!png_ptr)

            {

                fclose(fp);

                assert(0 &&L"Image加载时初始化pnglib失败!");

                return NULL;

            }

            //创建图像信息 info

            png_infop info_ptr = png_create_info_struct(png_ptr);

            if (!info_ptr)

            {

                fclose(fp);

                assert(0 &&L"Image加载时创建png_info失败!");

                return NULL;

            }

            //错误处理

            if (setjmp(png_jmpbuf(png_ptr)))

            {

                fclose(fp);

                png_destroy_read_struct(&png_ptr, &info_ptr,png_infopp_NULL);

                assert(0 &&L"Image加载时 pnglib出现错误!");

                return NULL;

            }

            //设置数据源

            png_init_io(png_ptr,fp);

            //表明文件头已处理

            png_set_sig_bytes(png_ptr, 8);

            //png

            png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);

            //info查询数据

            unsigned w = png_get_image_width(png_ptr, info_ptr);        //获得图片宽度

            unsigned h = png_get_image_height(png_ptr, info_ptr);        //获得图片高度

            int color_type = png_get_color_type(png_ptr,info_ptr);       //获得图片颜色

            //赋值给image

            img->m_size.w =w;

            img->m_size.h =h;

            img->m_buffer =newDWORD[w*h];

            //info复制到 image

            png_bytep *row_point =NULL;

            row_point = png_get_rows(png_ptr,info_ptr);

            //带透明通道一个点是4字节,否则为3字节

            int block_size = (color_type == 6 ? 4 : 3);

            //(A)RGB

            unsigned pos = 0;

            for (unsignedx = 0;x < h; ++x)

                for (unsignedy = 0;y < w*block_size;y +=block_size)

                {

                    ((unsigned char*)img->m_buffer)[pos + 0] =row_point[x][y + 2];//b;

                    ((unsigned char*)img->m_buffer)[pos + 1] =row_point[x][y + 1];//g

                    ((unsigned char*)img->m_buffer)[pos + 2] =row_point[x][y + 0];//r

                    if(color_type == 6)//不带透明通道就填充 0xff表示不透明

                        ((unsigned char*)img->m_buffer)[pos + 3] =row_point[x][y + 3];//a

                    else

                        ((unsigned char*)img->m_buffer)[pos + 3] = 0xff;                   pos += 4;

                }

            //关闭文件

            fclose(fp);

            //释放png内存

            png_destroy_read_struct(&png_ptr, &info_ptr,png_infopp_NULL);

            return img;

    }

 

    保存到png图像,如下调用:

canvas->Get_Image()->Save_To_PNG(L"bin/layer_image.png");

    上面的语句将画布(一个DrawCall)的图像导出到指定文件中。画布Canvas会拼接Sprite使用的Image成大图,从下面的图片可以看到拼接并导出后的效果(这是导出的layer_image.png的一部分,不是程序截图哈!):


  保存图像数据到PNG的实现如下:

    void Image::Save_To_PNG(constString&path)

    {

        FILE* fp;

        png_infop info_ptr;

       

        char cpath[MAX_PATH] = {NULL };

        path.Get_Multi_Byte_Str(cpath,MAX_PATH);

        //创建或覆盖文件

        fopen_s(&fp,cpath,"wb");

        if (fp ==NULL)

        {

            assert(0 && L"Save_To_PNG 创建文件失败!");

            return;

        }

        //初始化pnglib(注意相关的函数名read都变成了write

        static png_structppng_ptr =NULL;

        if (!png_ptr)

            png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,

                NULL, NULL,NULL);

        if (!png_ptr)

        {

            assert(0 && L"Save_To_PNG 创建文件时初始化pnglib失败!");

            return;

        }

        info_ptr = png_create_info_struct(png_ptr);

        if (info_ptr ==NULL)

        {

            fclose(fp);

            assert(0 && L"Save_To_PNGpng_create_info_struct失败!");

            return;

        }

        //错误处理

        if (setjmp(png_jmpbuf(png_ptr)))

        {

            fclose(fp);

            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

            assert(0 && L"Save_To_PNGpnglib出现错误!");

            return;

        }

        //颜色深度8,像素大小(ARGB 4字节),行字节宽度

        unsigned bit_depth = 8;

        unsigned pixel_byte = 4;

        unsigned row_byte =m_size.w *pixel_byte;

        //设置输出文件

        png_init_io(png_ptr,fp);

        //设置图像属性

        png_set_IHDR(png_ptr, info_ptr, m_size.w,m_size.h,bit_depth,

            PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,//交错无

            PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);

        //写头部

        png_write_info(png_ptr, info_ptr);

        //行指针

        png_bytepp row_pointers = (png_bytep*)malloc(m_size.h*sizeof(png_bytep));

        //填充数据

        for (unsignedx = 0;x < m_size.h; ++x)

        {//分配一行

            row_pointers[x] = (png_bytep)malloc(row_byte);

            for (unsignedy = 0;y < row_byte; y += pixel_byte)

            {

                row_pointers[x][y + 2] = ((unsignedchar*)m_buffer)[x *row_byte + y + 0];

                row_pointers[x][y + 1] = ((unsignedchar*)m_buffer)[x *row_byte + y + 1];

                row_pointers[x][y + 0] = ((unsignedchar*)m_buffer)[x *row_byte + y + 2];

                row_pointers[x][y + 3] = ((unsignedchar*)m_buffer)[x *row_byte + y + 3];

               

            }

        }

        //写入全部行

        png_write_image(png_ptr, row_pointers);

        //写尾部

        png_write_end(png_ptr, info_ptr);

        //释放png内存

        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

 

        for (unsignedx = 0;x < m_size.h; ++x)

        {//释放每行

            free(row_pointers[x]);

        }

        free(row_pointers);    

        fclose(fp);

    }

 

作者:略游

日期:17-06-20

QQ:1339484752

png.h全套内容PNGlib

  • 2012年09月11日 14:59
  • 190KB
  • 下载

linux上安装libpng库以及zlib库

(一)下载libpng的库: 我下载的是libpng-1.5.8 的安装包 如在这里下载http://download.chinaunix.net/download/0006000/5976.shtm...
  • bawenmao
  • bawenmao
  • 2015年11月26日 10:55
  • 11086

C/C++二进制读写png文件

为了弄OpenGl的纹理代码,发现书上没有图片像素的获取,然后就想写个来获取png的,结果花了一天的时间没弄清楚为什么出现数据个别正确其他的却是205,突然想起来以前弄软工的时候虽然那个网站只完成了登...
  • u014646950
  • u014646950
  • 2016年04月08日 22:14
  • 4451

Windows下zlib库和libPng库的编译和使用

转自:http://www.360doc.com/content/15/0804/11/26961978_489408309.shtml 这里inffas32.obj和match686.ob...
  • u012736279
  • u012736279
  • 2015年08月04日 11:33
  • 1941

教你如何使用libpng显示png图片

教你如何使用libpng显示png图片   2011-01-01 00:33:14|  分类: linux学习 |  标签:png_ptr  int  bgra  pngptr  infoptr...
  • carrie0728
  • carrie0728
  • 2013年09月17日 10:46
  • 2075

opencv——PNG格式图像读取转换函数

暑假培训学习了opencv,放图像时,PNG格式的Alpha通道没用啊图都自己去p颜色,用来加载时变颜色 工作量太大了,,于是花了一下午弄了个简易功能的PNG格式文件读取转化加载函数。 注:这里主...
  • ddkddkchen
  • ddkddkchen
  • 2015年08月03日 19:42
  • 3064

PNG格式图片原理

便携式网络图型( Portable Network Graphics [PNG])在过去几十年已经变成App开发里重要的组成部分。它广泛的运用在游戏开发、网页开发和Android开发里,但也可能被大量...
  • asdzheng
  • asdzheng
  • 2016年05月27日 15:38
  • 4589

Android png图片透明度的问题

关于alpha通道的问题  想看这篇文章 http://blog.csdn.net/id19870510/article/details/53925746 素材图片 Drawabl...
  • ID19870510
  • ID19870510
  • 2016年12月29日 11:52
  • 643

【加密】Cocos2d-x PNG图片资源加密(修改版)

这篇文章是对上一篇 【Cocos2d-x PNG图片资源加密】的补充和扩展,那篇文章转自【旧时尘安】的博客,文中已经对原理和使用讲解的很清晰,这里只是根据我自己的使用情况做一些小小的功能扩展,也是自己...
  • ldpjay
  • ldpjay
  • 2015年06月11日 11:05
  • 5632

PNG文件结构最简单解析(生成)

PNG文件结构最简单解析(生成)前言 本想写个从.wdf提前资源的生成位图的程序,无奈.bmp没有A(透明色),.gif编码复杂,所以选择.png作为理想的图片格式,饶了许多弯路,发出来与各位分享...
  • kk1751413376
  • kk1751413376
  • 2016年02月29日 12:34
  • 2720
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:4.使用pnglib读写png图片
举报原因:
原因补充:

(最多只允许输入30个字)