【pnglib】解析png格式的图像
解析png格式的图像
前言
鉴于有人收藏我07年写的博客,是关于解析png格式图像的那一篇。所以我打算再写一篇防止坑你们……
1.图像的内存表示
反复说到计算机中只有二进制表示,那图像如何以二进制表示呢?现在常用的规范是用4个字节表示颜色,分为4个通道ARGB,分别为透明度、红色、绿色、蓝色,这是比较常用的颜色表示方式。还有其他的色彩模型,例如HSV色彩模型,分别为色度、饱和度、纯度。还有HLS色彩模型,为色度、亮度、饱和度。
在绘图库和显示器等层面,能够直接处理的应该是RGB颜色模型。也就是通过3个变量控制最终的颜色(加上透明度是4个),而在显示器上则是1个像素包含3种颜色的灯,控制强度从而呈现不同的颜色(或许实现还有更多细节,也可能是不同的方法)。小时候如果你用眼睛贴到电视上,应该能够发现许多颜色不同的小条。以前低分辨率的手机屏幕也能发现类型的情形,现在之所以看不出来是因为像素点越来越小,不太容易看出来(人通过3种不同的视锥细胞感觉颜色)。真实世界的颜色是原子那么小的,渐变也更加平滑,而显示器的颜色实际是很大一颗一颗的,所以看显示器和看真实世界,背后的区别很大。
一般行业内都用十六进制来表示颜色,前面说了4个字节,1个字节表示1个通道。那么1个字节可表示256个值,用十六进制表示就需要2位。而十六进制用0123456789abcdef十六个符号表示,所以2位十六进制表示范围为[00, ff],那么一个颜色就需要8位十六进制表示,在代码中一般加前缀0x代表此数字是十六进制。所以颜色可以表示如下:
值 | A | R | G | B | 颜色 |
0xff000000 | 0xff | 0x00 | 0x00 | 0x00 | 不透明黑色 |
0xff00ff00 | 0xff | 0x00 | 0xff | 0x00 | 不透明绿色 |
0x66ff00ff | 0x66 | 0xff | 0x00 | 0xff | 半透明紫色(红配蓝为紫) |
0x00ffffff | 0x00 | 0xff | 0xff | 0xff | 全透明白色 |
在各种软件中,通过拾色器也能看到颜色代码。如果用十进制表示,则每个分量的范围为[0-255]。用整个十六进制数字表示即可以是6位,如果包含透明通道就是8位,如下图所示:
2.PNG格式
此时我们可以计算一下120*120像素的图像需要多大的空间保存,首先一个像素占4个字节,那么14400个像素就是占57600字节,也就是56.25kb。而一个png格式的图像,120*120的大小实际上,大概占几kb到二十几kb。
PNG格式全称Portable Network Graphics,中文翻译为便携式网络图形,是一种无损压缩位图格式。在不损失图像颜色信息的情况下,压缩保存图像数据。由于能够减小图像保存的大小,所以它才有存在的价值。相比JPEG格式,它是无损的,且带有透明通道,并且是可免费商用的,所以适用于游戏制作,但体积比jpeg略大。
关于PNG格式更详细的数据格式,此处就不展开了,只说怎么用libpng库来读取和保存png格式图像。
3.libpng库
libpng库依赖zlib库,所以需要二者都配置,具体怎么配置,可以参考我的其他文章(不过我现在还没写),也可以参考网上的教程。
4.读取过程
首先包含头文件:
#include <png>
#include <stdio.h>//这里使用C语言的读写文件
先以标准的读文件方式,读取图像文件:
FILE* fp = NULL;
_wfopen_s(&fp, "test.png", L"rb");
接着读取8个字节确认是不是png格式:
//判断是否为 png 文件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);//必须是png文件return NULL;}
创建必要的结构:
//创建read struct png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);if (!png_ptr){fclose(fp);return NULL;}//创建图像信息 infopng_infop info_ptr = png_create_info_struct(png_ptr);if (!info_ptr){fclose(fp);return NULL;}//错误处理if (setjmp(png_jmpbuf(png_ptr))){fclose(fp);//失败,则释放前面创建的结构,防止内存泄漏png_destroy_read_struct(&png_ptr, &info_ptr, NULL);return NULL;}
再进行以下步骤,完成后可以关闭文件句柄:
//设置数据源png_init_io(png_ptr, fp);//表明文件头已处理png_set_sig_bytes(png_ptr, number);//读png 这一步会实际分配内存png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);fclose(fp);
从info结构,可以获取图像的一些信息,其中color_type可以知道是否包含透明通道数据,之后处理需要用到它:
//从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); //获得图片颜色类型
接下来就是读取过程:
//分配内存保存从png解析出的数据img->_buffer = new DWORD[w*h];//从info 复制到 imagepng_bytep *row_point = NULL;row_point = png_get_rows(png_ptr, info_ptr);int block_size = (color_type == 6 ? 4 : 3);//(A)RGBunsigned pos = 0;for (unsigned x = 0; x < h; ++x)for (unsigned y = 0; y < w*block_size; y += block_size){((unsigned char*)img->_buffer)[pos + 0] = row_point[x][y + 2];//b;((unsigned char*)img->_buffer)[pos + 1] = row_point[x][y + 1];//g((unsigned char*)img->_buffer)[pos + 2] = row_point[x][y + 0];//rif (color_type == 6)((unsigned char*)img->_buffer)[pos + 3] = row_point[x][y + 3];//aelse((unsigned char*)img->_buffer)[pos + 3] = 0xff;//没有透明通道数据,则填充不透明0xffpos += 4;}//释放png内存png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
5.保存到文件
FILE* fp;png_infop info_ptr;//png_colorpfopen_s(&fp, L"test.png", "wb");if (fp == NULL){//创建文件失败!return;}//初始化pnglib static png_structp png_ptr = NULL;if (!png_ptr)png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL, NULL, NULL);if (!png_ptr){return;}info_ptr = png_create_info_struct(png_ptr);if (info_ptr == NULL){fclose(fp);return;}//错误处理if (setjmp(png_jmpbuf(png_ptr))){fclose(fp);png_destroy_write_struct(&png_ptr, (png_infopp)NULL);return;}unsigned bit_depth = 8;unsigned pixel_byte = 4;unsigned row_byte = _size.w * pixel_byte;//设置输出控制png_init_io(png_ptr, fp);//设置图像属性png_set_IHDR(png_ptr, info_ptr, _size.w, _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(_size.h*sizeof(png_bytep));for (unsigned x = 0; x < _size.h; ++x){//分配一行row_pointers[x] = (png_bytep)malloc(row_byte);for (unsigned y = 0; y < row_byte; y += pixel_byte){row_pointers[x][y + 2] = ((unsigned char*)_buffer)[x * row_byte + y + 0];row_pointers[x][y + 1] = ((unsigned char*)_buffer)[x * row_byte + y + 1];row_pointers[x][y + 0] = ((unsigned char*)_buffer)[x * row_byte + y + 2];row_pointers[x][y + 3] = ((unsigned char*)_buffer)[x * row_byte + y + 3];/*row_pointers[x][y + 2] =row_pointers[x][y + 1] =row_pointers[x][y + 0] =row_pointers[x][y + 3] = 0xff;*/}}//写入全部png_write_image(png_ptr, row_pointers);//写尾部png_write_end(png_ptr, info_ptr);//释放png内存png_destroy_write_struct(&png_ptr, (png_infopp) NULL);/* delete[] row_pointers;delete[] image;*/for (unsigned x = 0; x < _size.h; ++x){//释放每行free(row_pointers[x]);}free(row_pointers);fclose(fp);
结语
代码如上,短小精悍。其中错误处理,以及读取的数据处理,就需要自己看情况修改了。
【pnglib】解析png格式的图像相关推荐
- MIPI RAW和YUV常见图像格式的解析、格式转换和看图软件
设计初衷 在ISP的图像算法开发中,经常会涉及到YUV.RAW等格式的图像.例如,在YUV域,经常会涉及到I420.NV12和P010等数据格式之间的转换.在RAW域,又会经常涉及到MIPI RAW等 ...
- PCB javascript解析Gerber274X格式实现方法
解析钻Gerber274X格式前首先得了解此格式,这样才能更好的解析呀. 一个Gerber274X里面包含的基本信息如下: 1.单位:公式mm,英制inch 2.省零方式:前省零,后省零 3.坐标方式 ...
- urlparse模块(专门用来解析URL格式)
# -*- coding: utf-8 -*- #python 27 #xiaodeng #urlparse模块(专门用来解析URL格式)#URL格式: #protocol ://hostname[: ...
- python使用openCV加载图像、并将BGR格式转换成HSV格式、定义HSV格式中需要分离颜色的掩码(掩模)区间(mask)、并使用mask信息进行颜色分离、BGR格式的图像转化为RGB、并可视化
python使用openCV加载图像.并将BGR格式转换成HSV格式.定义HSV格式中需要分离颜色的掩码(掩模)区间(mask).并使用mask信息进行颜色分离.将BGR格式的图像转化为RGB.可视化 ...
- php获得帮助类数据_PHP解析xml格式数据工具类示例
本文实例讲述了PHP解析xml格式数据工具类.分享给大家供大家参考,具体如下: class ome_xml { /** * xml资源 * * @var resource * @see xml_par ...
- python中json模块_Python使用内置json模块解析json格式数据的方法
本文实例讲述了Python使用内置json模块解析json格式数据的方法.分享给大家供大家参考,具体如下: Python中解析json字符串非常简单,直接用内置的json模块就可以,不需要安装额外的模 ...
- XML系列之--解析电文格式的XML(二)
上一节介绍了XML的结构以及如何创建.讲到了XML可作为一种简单文本存储数据,把数据存储起来,以XML的方式进行传递.当接收到XML时,必不可少的就是对其进行解析,捞取有效数据,或者将第三方数据以节点 ...
- java jdom格式_Java全面解析XML格式串(JDOM解析)
搜索热词 Java全面解析XML格式串(JDOM解析) import java.io.IOException; import java.io.StringReader; import java.uti ...
- QT解析 JSON 格式的数据
QT解析 JSON 格式的数据 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON 采用完全独立于语言的文本格式,这些特性使 JSON 成为理想的数 ...
最新文章
- java中json重复数据结构_JS实现去除数组中重复json的方法示例
- 2004-10-26+ 用户输入的安全问题
- 如何在CentOS 7上安装Apache
- 从“美屋”到“打扮家”:线下VR家居馆中的科技新体验
- jquery validate常用方法及注意问题
- 彻底删除 XP 自带的 Windows Messenger方法
- linux c之用fwrite和fread实现文件的复制
- 坚实原则:接口隔离原则
- 两个向量之间的夹角公式_向量的内积
- FFmpeg--命令详解
- 【spine】原理介绍和程序实现
- 搭建Mock Server实践(一)理论篇
- STL之vector去重三步曲(利用unique函数)
- 【WIN问题】微软Microsoft onenote/store 无法连接网络无法同步解决
- 最经典的10部爱情小说
- 体验与对比新版EBS gp3 vs gp2
- Springer-Verlag免费下载图书400本
- FPGA CDC跨时钟域设计学习(一)亚稳态
- 2015年6月9日晨_学习
- Mac电脑 zsh: command not found: vue
热门文章
- mint java_Linux Mint19安装jdk1.8.0.191过程
- l2的最优回归_【机器学习】逻辑回归(非常详细)
- 【小白学习C++ 教程】二、C++基础语法、注释和变量
- 六十五、SpringBoot配置拦截器拦截静态资源和区域解析器实现登陆功能
- java的死锁是什么意思_Java面试题:什么是死锁?如何手写一个死锁(Dead Lock)...
- 北京内推 | 微软亚洲研究院MSRA STCA招聘多模态算法实习生
- AAAI 2022 | 北航提出基于特征纯化的视线估计算法,让机器更好地“看见”
- 语音合成:模拟最像人类声音的系统
- 知识图谱实体链接:一份“由浅入深”的综述
- 线下沙龙 × 报名 | “大规模数据存储与挖掘”博士生研讨会