PNG 图片压缩原理解析

转载自  PNG 图片压缩原理解析

什么是PNG

PNG的全称叫便携式网络图型(Portable Network Graphics)是目前最流行的网络传输和展示的图片格式,原因有如下几点:

  • 无损压缩:PNG图片采取了基于LZ77派生算法对文件进行压缩,使得它压缩比率更高,生成的文件体积更小,并且不损失数据。

  • 体积小:它利用特殊的编码方法标记重复出现的数据,使得同样格式的图片,PNG图片文件的体积更小。网络通讯中因受带宽制约,在保证图片清晰、逼真的前提下,优先选择PNG格式的图片。

  • 支持透明效果:PNG支持对原图像定义256个透明层次,使得图像的边缘能与任何背景平滑融合,这种功能是GIF和JPEG没有的。

PNG类型

PNG图片主要有三个类型,分别为 PNG 8/ PNG 24 / PNG 32。

  • PNG 8:PNG 8中的8,其实指的是8bits,相当于用2^8(2的8次方)大小来存储一张图片的颜色种类,2^8等于256,也就是说PNG 8能存储256种颜色,一张图片如果颜色种类很少,将它设置成PNG 8得图片类型是非常适合的。

  • PNG 24:PNG 24中的24,相当于3乘以8 等于 24,就是用三个8bits分别去表示 R(红)、G(绿)、B(蓝)。R(0255),G(0255),B(0~255),可以表达256乘以256乘以256=16777216种颜色的图片,这样PNG 24就能比PNG 8表示色彩更丰富的图片。但是所占用的空间相对就更大了。

  • PNG 32:PNG 32中的32,相当于PNG 24 加上 8bits的透明颜色通道,就相当于R(红)、G(绿)、B(蓝)、A(透明)。R(0255),G(0255),B(0255),A(0255)。比PNG 24多了一个A(透明),也就是说PNG 32能表示跟PNG 24一样多的色彩,并且还支持256种透明的颜色,能表示更加丰富的图片颜色类型。

怎么说呢,总的来说,PNG 8/ PNG 24 / PNG 32就相当于我们屌丝心中,把女神分为三类:

  • 一类女神 = PNG 8:屌丝舔狗们见到第一类女神,顿时会觉得心情愉悦、笑逐颜开,屌丝发黑的印堂逐渐舒展,确认过眼神,是心动的感觉。

  • 二类女神 = PNG 24:第二类女神开始厉害了,会给屌丝们一种菊花一紧、振聋发聩的心弦震撼,接触多了第二类女神能让屌丝每天精神抖擞,延年益寿。

  • 三类女神 = PNG 32:在第三类女神面前,所有的语言都显得苍白无力。那是一种看了让屌丝上下通透、手眼通天的至尊级存在。超凡脱俗、天神下凡都不足以描摹她美色的二分之一。我曾经只有在梦里才见到过。

哎。。。我的初恋,看着她现在的照片,应该是触及PNG 24这一等级了。

PNG图片数据结构

PNG图片的数据结构其实跟http请求的结构很像,都是一个数据头,后面跟着很多的数据块,如下图所示:

 

如果你用vim的查看编码模式打开一张png图片,会是下面这个样子:

握草,第一眼看到这一坨坨十六进制编码是不是感觉和女神的心思一样晦涩难懂?

老弟 莫慌,讲实话,如果撩妹纸有那一坨坨乱码那么简单,哥哥我早就妻妾成群啦。
接下来我就一一讲解这一堆十六进制编码的含义。

 

 

8950 4e47 0d0a 1a0a:这个是PNG图片的头,所有的PNG图片的头都是这一串编码,图片软件通过这串编码判定这个文件是不是PNG格式的图片。

0000 000d:是iHDR数据块的长度,为13。

4948 4452:是数据块的type,为IHDR,之后紧跟着是data。

0000 02bc:是图片的宽度。

0000 03a5:是高度。

以此类推,每一段十六进制编码就代表着一个特定的含义。下面其他的就不一一分析了,太多了,小伙伴们自己去查吧。

什么样的PNG图片更适合压缩

常规的png图片,颜色越单一,颜色值越少,压缩率就越大,比如下面这张图:

 

它仅仅由红色和绿色构成,如果用0代表红色,用1代表绿色,那用数字表示这张图就是下面这个样子:

00000000000000000

00000000000000000

00000000000000000

1111111111111111111111111

1111111111111111111111111

1111111111111111111111111

我们可以看到,这张图片是用了大量重复的数字,我们可以将重复的数字去掉,直接用数组形式的[0, 1]就可以直接表示出这张图片了,仅仅用两个数字,就能表示出一张很大的图片,这样就极大的压缩了一张png图片。

所以!颜色越单一,颜色值越少,颜色差异越小的png图片,压缩率就越大,体积就越小。

PNG的压缩

PNG图片的压缩,分两个阶段:

  • 预解析(Prediction):这个阶段就是对png图片进行一个预处理,处理后让它更方便后续的压缩。说白了,就是一个女神,在化妆前,会先打底,先涂乳液和精华,方便后续上妆、美白、眼影、打光等等。

  • 压缩(Compression):执行Deflate压缩,该算法结合了 LZ77 算法和 Huffman 算法对图片进行编码。

预解析(Prediction)

png图片用差分编码(Delta encoding)对图片进行预处理,处理每一个的像素点中每条通道的值,差分编码主要有几种:

  • 不过滤

  • X-A

  • X-B

  • X-(A+B)/2(又称平均值)

  • Paeth推断(这种比较复杂)

假设,一张png图片如下:

 

这张图片是一个红色逐渐增强的渐变色图,它的红色从左到右逐渐加强,映射成数组的值为[1,2,3,4,5,6,7,8],使用X-A的差分编码的话,那就是:

[2-1=1, 3-2=1, 4-3=1, 5-4=1, 6-5=1, 7-6=1, 8-7=1]

得到的结果为

[1,1,1,1,1,1,1]

最后的[1,1,1,1,1,1,1]这个结果出现了大量的重复数字,这样就非常适合进行压缩。

这就是为什么渐变色图片、颜色值变化不大并且颜色单一的图片更容易压缩的原理。

差分编码的目的,就是尽可能的将png图片数据值转换成一组重复的、低的值,这样的值更容易被压缩。

最后还要注意的是,差分编码处理的是每一个的像素点中每条颜色通道的值,R(红)、G(绿)、B(蓝)、A(透明)四个颜色通道的值分别进行处理。

压缩(Compression)

压缩阶段会将预处理阶段得到的结果进行Deflate压缩,它由 Huffman 编码 和 LZ77压缩构成。

如前面所说,Deflate压缩会标记图片所有的重复数据,并记录数据特征和结构,会得到一个压缩比最大的png图片 编码数据。

Deflate是一种压缩数据流的算法. 任何需要流式压缩的地方都可以用。

还有就是我们前面说过,一个png图片,是由很多的数据块构成的,但是数据块里面的一些信息其实是没有用的,比如用Photoshop保存了一张png图片,图片里就会有一个区块记录“这张图片是由photshop创建的”,很多类似这些信息都是无用的,如果用photoshop的“导出web格式”就能去掉这些无用信息。导出web格式前后对比效果如下图所示:

 

可以看到,导出web格式,去除了很多无用信息后,图片明显小了很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323658.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

element ui实现多层级复杂表单的操作(添加与回显)之表单操作交互操作

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月3日11:47:15!劳动节假期已经过去了三天了,今天是被封家里的第7天,也是解封的第一天。 说实话,在家里的工作效率一点都…

POJ2182-Lost Cows【树状数组,二分】

正题 题目链接:http://poj.org/problem?id2182 题目大意 给出每头牛前面有多少个比它高的,求每头牛的最大高度。 解题思路 建立一个01序列,表示每个高度是否被占用过,然后倒序扫描每次找到一个没有被占用的第Ai1个位置,然后标…

TypeScript 2.5 发布,增加语言级重构

在 TypeScript 2.5 版本中,Microsoft 专注于提高开发人员的生产力,其范围已经超出了代码编辑器所提供的常见功能。 习惯于类型语言(如 C#)的开发人员喜欢使用那些可以轻松执行常见重构的工具。现在 TypeScript 可以利…

永远不要在 MySQL 中使用 UTF-8

转载自 永远不要在 MySQL 中使用 UTF-8 最近我遇到了一个 bug&#xff0c;我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串&#xff0c;然后出现了一个离奇的错误&#xff1a; Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘sum…

element ui实现多层级复杂表单的操作(添加与回显)之添加功能实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月3日13:35:15&#xff01;文接上篇。[element ui实现多层级复杂表单的操作&#xff08;添加与回显&#xff09;之表单操作交互操作](element ui实现多层级复杂表单的操…

POJ1151-Atlantis【线段树,扫描线,离散化】

正题 题目链接:http://poj.org/problem?id1151 题目大意 有n个矩形&#xff0c;求所以矩形的覆盖面积。 解题思路 我们用离散化一个坐标&#xff0c;然后每次用线段树维护这个宽度内覆盖高度和&#xff0c;然后定义左上的点是加入&#xff0c;右下的点是弹出。 code #incl…

Entity Framework Core Like 查询揭秘

在Entity Framework Core 2.0中增加一个很酷的功能&#xff1a;EF.Functions.Like()&#xff0c;最终解析为SQL中的Like语句&#xff0c;以便于在 LINQ 查询中直接调用。 不过Entity Framework 中默认提供了StartsWith、Contains和EndsWith方法用于解决模糊查询&#xff0c;那…

JVM发生OOM的 8 种原因、及解决办法

转载自 JVM发生OOM的 8 种原因、及解决办法 1、Java 堆空间 发生频率&#xff1a;5颗星 造成原因 无法在 Java 堆中分配对象 吞吐量增加 应用程序无意中保存了对象引用&#xff0c;对象无法被 GC 回收 应用程序过度使用 finalizer。finalizer 对象不能被 GC 立刻回收。fina…

element ui实现多层级复杂表单的操作(添加与回显)之回显功能实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月3日17:02:30&#xff01;文接上两篇。 [element ui实现多层级复杂表单的操作&#xff08;添加与回显&#xff09;之表单操作交互操作](element ui实现多层级复杂表单…

在Mac的Docker中运行DotNetCore2.0

最近学习Angular4&#xff0c;服务端准备使用DotNetCore API来实现&#xff0c;本文简单介绍下在Mac中怎样将DotNetCore程序部署在Docker中&#xff0c;并使用Nginx做反向代理让程序可以跑起来。 具体步骤如下 安装Docker拉取DotNetCore镜像使用VS For Mac创建DotNetCore应用…

POJ2482-Stars in Your Window【线段树,扫描线,离散化】

正题 题目链接:http://poj.org/problem?id2482 题目大意 有若干个点&#xff0c;每个点有不同的权值&#xff0c;求用一个h*w的矩阵扩起来的权值最大。 解题思路 先离散化一个坐标&#xff0c;然后另一个坐标就在x∼xw−1x∼xw−1这个区域加上权值&#xff0c;然后每个点的…

20个高级Java面试题汇总

转载自 20个高级Java面试题汇总 译文链接&#xff1a;http://www.codeceo.com/article/20-java-advanced-interview-questions.html 英文原文&#xff1a;Advanced Java Interview Questions 翻译作者&#xff1a;码农网 – 小峰 这是一个高级Java面试系列题中的部分。这一部分…

springboot实现复杂业务下的更新操作

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月4日19:25:55&#xff01;今天写了个这样的功能&#xff1a; 某用户在一天内有多个训练项目&#xff0c;比如&#xff1a;晨跑&#xff0c;有氧训练&#xff0c;跳绳这…

HDOJ5542-The Battle of Chibi【树状数组,dp】

正题 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid5542 题目大意 求序列A有多少个长度为M的递增子序列。 解题思路 用fi,jfi,j表示长度为i&#xff0c;以AjAj结尾的序列的个数。然后显然得出动态转移方程通过上一次从任意一个地方转移&#xff0c;动态转移方程&…

ASP.NET Core中为指定类添加WebApi服务功能

POCO Controller是 ASP.NET Core 中的一个特性&#xff0c;虽然在2015年刚发布的时候就有这个特性了&#xff0c;可是大多数开发者都只是按原有的方式去写&#xff0c;而没有用到这个特性。其实&#xff0c;如果利用这个特性进行稍微封装后&#xff0c;用在SOA架构中Service层的…

elementui解决el-dialog不清空内容的问题,el-dialog关闭时销毁子组件

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年5月5日22:48:21&#xff01; 今天在使用element-ui中的el-dialog的时候遇到了个这样的问题&#xff1a;页面上点击添加的按钮&#xff0c;弹出el-dialog对话框&#xff…

MySQL 中的重做日志,回滚日志以及二进制日志的简单总结

转载自 MySQL 中的重做日志&#xff0c;回滚日志以及二进制日志的简单总结 MySQL中有六种日志文件&#xff0c;分别是&#xff1a;重做日志&#xff08;redo log&#xff09;、回滚日志&#xff08;undo log&#xff09;、二进制日志&#xff08;binlog&#xff09;、错误日志…

c语言分离三位数

#include<stdio.h> main(){ int k,l,m,n;printf("请输入一个三位数"); scanf("%d",&k);lk/100;mk/10%10;nk%10;printf("这个三位数的百位是:%d\n",l);printf("这个三位数的十位是:%d\n",m);printf("这个三位数的个位是…

POJ1821-Fence【单调队列,dp】

正题 题目链接:http://poj.org/problem?id1821 题目大意 有n个木板,m个工人&#xff0c;每个木板只能被粉刷一次&#xff0c;第i个工人如果刷的话必须刷木板SiSi&#xff0c;连续的不超过LiLi的&#xff0c;没一块PiPi。 解题思路 用fi,jfi,j表示前j块木板&#xff0c;前i个…

分布式ID自增算法 Snowflake

近在尝试EF的多数据库移植&#xff0c;但是原始项目中主键用的Sqlserver的GUID。MySQL没法移植了。 其实发现GUID也没法保证数据的递增性&#xff0c;又不太想使用int递增主键&#xff0c;就开始探索别的ID形式。 后来发现twitter的Snowflake算法。 一开始我尝试过直接引用N…