4.使用pnglib读写png图片

  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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值