当前位置: 首页 > news >正文

图形图像基础 之 png介绍

文章目录

    • 一、png相关概念
      • png---一种无损压缩算法的位图格式
      • png和bmp、jpeg图片比较
      • libpng---一款C语言编写的读写PNG文件的跨平台的库
    • 二、png文件格式---文件标签+特定格式数据块
      • 2.1 PNG文件标签,8字节---用于识别png文件
      • 2.2 PNG关键块critical chunk介绍
        • 2.2.1 文件头数据块IHDR(header chunk)
        • 2.2.2 调色板数据块PLTE(palette chunk)
        • 2.2.3 图像数据块IDAT(image data chunk)
        • 2.2.4 图像结束数据IEND(image trailer chunk)
    • 三、libpng使用基础
      • 3.1 libpng库 的下载编译安装
      • 3.2 libpng库的解码图片示例
    • 参考

一、png相关概念

png—一种无损压缩算法的位图格式

PNG:Portable Network Graphics,是一种支持无损压缩(使用从LZ77派生的无损数据压缩算法)的位图图形格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。PNG的开发目标是改善并取代GIF作为适合网络传输的格式而不需专利许可,所以被广泛应用于互联网及其他方面上。

png和bmp、jpeg图片比较

bmp常见是非压缩的,它size最大但是显示简单,主要是最后用作本地存储 和 显示阶段-无需解压, 传输都会选择png和jpeg。jpeg图片的优势是压缩比例大,它由于存在转换到yuv域并进行下采样420,通过有损压缩算法 能得到比png更高的压缩效率,常见的大图都会选择jpeg而非png。png相对jpeg它的优势是包含alpha通道(可以做半透明效果,而jpeg是不存在的alpha通道),并且常用无损压缩,常见用在一些精细小图标,或者必须带上aplha透明度的图片的使用场景。

libpng—一款C语言编写的读写PNG文件的跨平台的库

libpng是一款C语言编写的读写PNG文件的跨平台的库,libpng 可作为 ANSI C (C89) 源代码使用,并且需要zlib 1.0.4 或更高版本提供压缩算法支持。

二、png文件格式—文件标签+特定格式数据块

PNG图像格式文件由一个8字节的PNG文件标签file signature按特定结构组织的3个以上的后续数据块chunk组成
1、文件标签file signature为一组固定8字节文件署名,用于识别png文件。
2、数据块chunk分为 :1、关键块critical chunk,是文件必须包含的关键块,读取软件也必须支持解析;2、辅助块ancillary chunks,允许软件忽略它不认识的附加块,允许PNG格式在扩展时仍能保持与旧版本兼容。每个数据块都由下面所示的的4个域组成:
在这里插入图片描述
CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中。
在这里插入图片描述
我们选择如下图片做举例:
请添加图片描述
在这里插入图片描述

2.1 PNG文件标签,8字节—用于识别png文件

PNG文件包括8字节文件署名(89 50 4E 47 0D 0A 1A 0A,十六进制),用来识别PNG格式
在这里插入图片描述在这里插入图片描述

2.2 PNG关键块critical chunk介绍

关键块critical chunk*中有4个标准数据块:
文件头数据块IHDR(header chunk):包含有图像基本信息,作为第一个数据块出现并只出现一次。
调色板数据块PLTE(palette chunk):必须放在图像数据块之前。
图像数据块IDAT(image data chunk):存储实际图像数据。PNG数据允许包含多个连续的图像数据块。
图像结束数据IEND(image trailer chunk):放在文件尾部,表示PNG数据流结束。

2.2.1 文件头数据块IHDR(header chunk)

IHDR含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG文件中只能有一个文件头数据块。文件头数据块由13字节组成,它的格式如下表所示
在这里插入图片描述
在这里插入图片描述
8~ 11字节:0xd表示IHDR长度13字节,12~ 15字节:就是ASCII码的IHDR字符表示块类型;紧接着13个字节为IHDR的内容:0x27b 宽度635,0x19b 高度 411,0x8 色深度 8bit,0x6 颜色类型,带alpha通道的真彩,0x0 压缩算法LZ77派生算法,0x0 滤波器方法,0x0 非隔行扫描;剩下的是CRC校验码;

2.2.2 调色板数据块PLTE(palette chunk)

PLTE包含有与索引彩色图像((indexed-color image))相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。真彩色的PNG数据流也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。(类似bmp也有相同的调色板机制)
在这里插入图片描述
调色板实际是一个彩色索引查找表,它的表项数目可以是1~256中的一个数,每个表项有3字节,因此调色板数据块所包含的最大字节数为768。

2.2.3 图像数据块IDAT(image data chunk)

它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

2.2.4 图像结束数据IEND(image trailer chunk)

它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。内容为 00 00 00 00 49 45 4E 44 AE 42 60 82
在这里插入图片描述

三、libpng使用基础

3.1 libpng库 的下载编译安装

1、下载libpng源码:https://sourceforge.net/projects/libpng/files/,这里我下载的最新libpng-1.6.37版本。
2、阅读INSTALL文件进行编译

# prefix=path是可添加的附加参数,表示指定编译结果安装的目录
./configure --prefix=/home/study/libpng/libpng_build
make check
make install

3、编译后查看编译出内容:其中最关键的是静态库libpng16.a和动态库libpng16.so,还有输出的文档

├── bin
│   ├── // 略
├── include
│   ├── libpng16
│   │   ├── pngconf.h
│   │   ├── png.h
│   │   └── pnglibconf.h
│   ├── pngconf.h -> libpng16/pngconf.h
│   ├── png.h -> libpng16/png.h
│   └── pnglibconf.h -> libpng16/pnglibconf.h
├── lib
│   ├── libpng16.a
│   ├── // 略
│   ├── libpng.so -> libpng16.so
└── share└── man

3.2 libpng库的解码图片示例

接下来通过libpng库写一个png的解析程序,用来解析一张png图片,代码可以参考源码目录的example.c举例。
libpng的整体用法和libjpeg的设计非常类似,都是先注册一个异常跳转的调用函数方便调用库失败异常通知和处理,然后设置输入流可以来源文件或者内存,再调用解析头函数,然后可以查看到png文件各种属性,接下来根据需要有选择的进行一些输出属性设置(比如位宽控制,是否丢弃alpha通道,是否做缩放,格式转化 如把灰度数据转化为RGB存储数据,数据排序调整,滤波设置),然后申请内存,调用读取接口把png的数据读出。

#include <png.h>
#include "stdio.h"
#include "stdlib.h"
#include <string.h>int main(int argc, char *argv[]) {if (argc < 2) {printf("please intput like: ./a.out xxx.png\n");return -1;}// 打开输入文件FILE *infile = fopen(argv[1], "rb");if (infile == NULL) {printf("intput file %s open failed!\n", argv[1]);return -1;}// 创建输出文件FILE *outfile = fopen("./output.bit", "w+");if (outfile == NULL) {printf("out file open failed!\n");return -1;}png_structp png_ptr = NULL;png_infop info_ptr = NULL;png_uint_32 width, height;int bit_depth, colortype, interlace_type;// 创建libpng库依赖的解码示例上下文png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);if (png_ptr == NULL) {printf("png_create_read_struct failed!\n");return -1;}info_ptr = png_create_info_struct(png_ptr);if (info_ptr == NULL) {printf("png_create_info_struct failed!\n");return -1;}if (setjmp(png_jmpbuf(png_ptr))) {printf("setjmp failed!\n");   	return -1;}// 设置输入流png_init_io(png_ptr, infile);// 读取png文件头png_read_info(png_ptr, info_ptr);// 获取png文件解析信息png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &colortype, &interlace_type, NULL, NULL);// 根据获取文件信息做输出属性调整,得打ARGB8888的输出格式if(colortype == PNG_COLOR_TYPE_PALETTE)png_set_palette_to_rgb(png_ptr);// 要求转换索引颜色到RGBif(colortype == PNG_COLOR_TYPE_GRAY && bit_depth < 8)png_set_expand_gray_1_2_4_to_8(png_ptr);// 低于8bit深度强制8bitif(bit_depth == 16)png_set_strip_16(png_ptr); // 16bit深度要求强制8bitif(png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS))png_set_tRNS_to_alpha(png_ptr); // 扩展RGB数据的alpha通道到ARGB数据类型if(colortype == PNG_COLOR_TYPE_GRAY || colortype == PNG_COLOR_TYPE_GRAY_ALPHA)png_set_gray_to_rgb(png_ptr); //灰度必须转换成RGB// 申请读取sizeint size = width * height * 4; // 输出类型为argb8888每个像素4字节char *outbuf = malloc(size);if (outbuf == NULL) {printf("malloc failed!\n");   	return -1;}png_bytep *row_pointers = (png_bytep *)malloc(height * sizeof(char *)); // 申请行指针数组用于读取if (row_pointers == NULL) {printf("malloc failed!\n");   	return -1;}int row;for (row = 0; row < height; row++)row_pointers[row] = outbuf + row * width * 4;// 读取数据,这里使用一次读取完成的方式png_read_image(png_ptr, row_pointers);png_read_end(png_ptr, info_ptr);// 读取的数据写到输出文件fwrite(outbuf, size, 1, outfile);// 销毁解码示例上下文png_destroy_read_struct(&png_ptr, &info_ptr, NULL);// 关闭全部文件free(outbuf);fclose(infile);fclose(outfile);return 0;
}

编译执行:

gcc sample_png2.c -lpng
./a.out ./test.png

解析出来的工具用裸数据 ARGB格式查看output.bit如下,说明解析ok:
在这里插入图片描述

参考

维基百科png介绍:https://chi.jinzhao.wiki/wiki/PNG
libpng官网:http://www.libpng.org/pub/png/libpng.html
libpng源码:https://sourceforge.net/projects/libpng/files/
https://www.w3.org/TR/PNG/#4Concepts.Sourceimage
https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm
https://blog.csdn.net/hherima/article/details/45847043


http://www.taodudu.cc/news/show-4282106.html

相关文章:

  • 【physx/wasm】在physx中添加自定义接口并重新编译wasm
  • excel---常用操作
  • Lora训练Windows[笔记]
  • linux基础指令讲解(ls、pwd、cd、touch、mkdir)
  • InnoDB 事务处理机制
  • 启明云端ESP32 C3 模组WT32C3通过 MQTT 连接 AWS
  • 端到端的图像压缩----《Joint Autoregressive and Hierarchical Priors for Learned Image Compression》 论文笔记
  • 端到端的图像压缩----《Channel-wise Autoregressive Entropy Models For Learned Image Compression》论文笔记
  • 论文阅读《Fast-MVSNet: Sparse-to-Dense Multi-View StereoWith Learned Propagation and Gauss-Newton Refine》
  • Learned-Mixin +H(LMH)
  • HPatches A benchmark and evaluation of handcrafted and learned local descriptors——2017.04
  • 人体姿态2018(五)Can 3D Pose be Learned from 2D Projections Alone?
  • [CVPR 2020] RPM-Net: Robust Point Matching using Learned Features
  • Learned Motion Matching-动作生成算法
  • Altium designer AD原理图导入word文档、pdf,生成矢量图的方法;
  • PCB_原理图绘制
  • 浅谈Linux USB设备驱动
  • 06_USB设备驱动
  • 微信小程序项目转换成uniapp项目
  • 半监督学习matlab,基于自适应图的半监督学习方法与流程
  • 系列之 H5+js 游戏 遍历象棋(待更新)
  • Android 引导页开发管理2
  • 1.实现将整数转换成字符串
  • Hadoop Ha (High avilable)配置
  • Hadoop Ha集群配置
  • “eclipse在编译代码时运行结果始终是之前程序的结果”如何解决?
  • 车道线检测1-传统算法相关简介
  • 论文笔记-Understanding Convolution for Semantic Segmentation
  • kaggle新手入门第一篇——Titanic
  • leetcode 每天10道travl
  • HRNet+OCR
  • MVP简单封装,不用再手写了
  • ERFNet网络的演化
  • 提高篇 第四部分 数据结构 第1章 树状树组
  • 架构演进|研究mvp到mvvm(传统架构mvvm和Jetpack下的区别)
  • 字节码插桩(javassist)之插入代码块|IOC框架(Hilt)之对象注入~研究