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_PNG:png_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_PNG:pnglib出现错误!");

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

4.使用pnglib读写png图片相关推荐

  1. C语言读写BMP图片(附Github下载链接和视频讲解地址)

    BMP全称(BITMAP)是微软WINDOWS系统默认使用的一种通用图片数据存储格式,特点是结构清晰,解析简单和多平台支持广泛.其文件结构由文件头结构体,文件信息头结构体,调色板(可选),以及图片数据 ...

  2. 负载与读写分离图片服务器集群模型

    对于绝大多数网站,图片资源是一个非常重要的元素.社区论坛里面图片相册,电子商务线上产品展示图,移动端应用图片分享功能等.都在说互联网正在处于读图时代,各大中小型网站都需要保持良好的图片处理能力.需要支 ...

  3. Python如何打开文件、进行读写以及图片读写操作

    一.文件操作 作用: 将数据持久化 将数据从瞬时状态转换为持久状态 (一)打开文件 open(参数1,参数2,参数3-) 打开文件,打开的是一个文件对象 参数1:路径和文件名 参数2:文件打开的方式 ...

  4. 批量读写变换图片(转)

    python数字图像处理(6):图像的批量处理 有些时候,我们不仅要对一张图片进行处理,可能还会对一批图片处理.这时候,我们可以通过循环来执行处理,也可以调用程序自带的图片集合来处理. 图片集合函数为 ...

  5. mac 上 Python 读写剪贴板图片、文字

    文章目录 一.使用 ImageGrab 二.使用 NSPasteboard 三.使用 pyperclip.clipboard 一.使用 ImageGrab 只能读,只能是图片. 只能获取截图后的.或是 ...

  6. 安装CTeX后Texworks不能读写.eps图片?

    因为CTeX是直接生成PDF的,在Texworks添加 \usepackage{epstopdf}

  7. Android开发笔记(三十三)文本文件和图片文件的读写

    文本文件读写 简单文件读写一般是借助于FileOutputStream和FileInputStream,其中FileOutputStream用于写文件,而FileInputStream用于读文件. 写 ...

  8. pytorch 多进程读写同一个文件

    torch 读写同一个图片 # -*- coding:utf-8 -*- from threading import Threadimport bind_cv as demo import timei ...

  9. JPEG图片扩展信息读取与改动

    近日项目中须要用到往jpg图片中写入信息(非水印),经调研发现Android中已经封装了读写jpg图片扩展信息的api(ExifInterface). 相应api地址:http://developer ...

最新文章

  1. CentOs下卸载程序
  2. 036_PageHeader页头
  3. U-BOOT介绍以及disk模块源码分析
  4. mysql数据库学习(一)--基础
  5. [C语言] va_start和va_end详解
  6. 若依如何修改数据监控登录账户密码?
  7. 结构体的空间分配和位定义
  8. 网络攻防|一次实战中的向日葵 RCE Bypass 360
  9. 2022Java后端之美团笔试题
  10. 计算机打开后任务栏有但桌面不显示不出来,任务栏不显示打开的窗口,教您打开的窗口在任务栏上显示不出来...
  11. 程序之外:由电影《少年的你》揭露的bug
  12. linux-centos7解决视频无法看问题(安装Adobe flash player)
  13. Android版疯狂填字第三关,iOS/安卓版《疯狂填字》答案攻略第三十八关
  14. 杂谈——如何合并两个有序链表(时间复杂度为O(n))
  15. 复旦大学《数学分析》教学大纲,读后有感
  16. 关于COM类工厂80070005和8000401a错误分析及解决办法(DCOM)
  17. 2022/1/22 北京 mysql 多表关联查询,等值连接、非等值连接,外连接,内连接、自连接
  18. share memory的bank conflict分析
  19. 4 灰色系统 - 关联度分析法 例子 源代码
  20. 视频教程-【吴刚】个人网站设计初级入门标准视频教程-UI

热门文章

  1. 【机器学习算法专题(蓄力计划)】十八、机器学习中SVM算法中的硬间隔和软间隔
  2. 八、Linux 常用 Shell 命令,控制台的快捷键以及 Shell 编程(中)
  3. 十七、深入Python异常处理
  4. C语言/C++零基础到大神全栈学习笔记
  5. 岗位内推 | 阿里巴巴高德动态信息部招聘算法工程师(可实习)
  6. 基于层次过滤的文本生成
  7. 计算未来轻沙龙 | 当深度学习遇上归纳推理,图神经网络有多强大?
  8. 蒙特卡洛梯度估计方法(MCGE)简述
  9. ICDAR 2019国际竞赛召开在即,百度联合学界重奖破局者!
  10. java第九章IO流与文件操作