如何减小 PNG 图片大小

2016-05-19 Roger 更多博文 » 博客 » GitHub »

翻译

原文链接 http://www.rogerblog.cn/2016/05/19/Reducing-PNG-file-Size/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


如何减小PNG图片大小

减小PNG图片大小

在谷歌工作的一个优势就是我可以看到很多的 android 应用,寻找它们中能够被提高的地方。

然后,我察觉到了一个可怕的趋势:日益膨胀的PNG图片。

上一次我提到他们时,PNG是一个非常棒的、异常灵活的图片格式。它能很好的控制质量,并且支持透明度。因此,它成为开发人员所寻求的支持透明度的图片格式已经数十年。

最大的问题是我们很容易就将PNG图片变得异常大,只是将宽度增加两个像素就可能会将图片大小扩大一倍。所以,这很容易认识到我们使用的所有PNG图片并没有得到应得的照顾。

所以,现在我已经调查过将近100个 apk ,我决定将我减小 png 图片的建议传递下去。这些建议是基于我在人们正在使用的 APP 中发现的 。 不过如果你的应用只是被机器人使用,或是十分小众的应用,那么这些建议将因人而异。

你应该使用一个优化工具

一旦你理解PNG文件格式,你将会知道有一些很明显的方法是可以减小图片文件大小的:

  • 移除不必要的区域块
  • 减少不同的颜色
  • 优化逐行过滤选项
  • 优化默认压缩

这些并不是新的知识,PNG 优化问题许久以前已经是一个老大难问题,20年前, Ken Silverman 写了第一篇十分出名的 PNG 优化文章,PNGOUT . (成为了著名的毁灭公爵3D引擎的基础) 后来,许多 PNG 优化方案层出不穷,用 google 搜一下你将会看到你将会有这么多的选项:

PNGQuant, ImageMagick , PNGGauntlet, PNGOut, PNGCrush, OptiPNG, CryoPNG, PNG Compressor, Yahoo Smush.it, PNGOptimizer, PunyPNG, TinyPNG, PNGWolf, Advpng, DeflOpt, Defluff, Huffmix, TruePNG, PNGnq-s9, Median Cut Posterizer, scriptpng, pngslim, zopfliPNG

这其中的门道就是,似乎一个工具就能把所有的事情都给做了,每个工具都做了一系列的工作。所以不存在最好的工具来完成这项工作,请花时间谨慎选择评估最适合你的工具,然后采用他。

无论如何,就我个人的喜好而言在这个列表中最好的将是 zopfiliPNG 。它通过提供更加高效、强大的压缩算法来减小 png 图片的大小,而这个算法是可以是从文件数据中匹配出来的。这将减小 PNG 图片大概5%的大小,并且完全不会影响图片的质量。虽然它的压缩速度的确比较慢,但是它强大的改进效果还是令人印象深刻的。

这里的重点是,如果你应用有非常大的数据需要显示,你应该在上传、分发这些图片之前就使用 PNG 优化工具进行优化压缩,来防止 PNG 图片的日益膨胀。

减少颜色

现在,如果以上的工具都没什么效果,或者你想在使用这些工具之前做一些手动的优化,那么自己动手也是不错的选择。

尽管有许多事情是可以手动做的,我仍然建议你应该专注在减小图片颜色种类上,然后使用一个工具来完成后面的工作。

让你专注在减小图片颜色的原因是,这能直接影响在各个阶段的压缩潜力,让工具完成剩下的工作。

由此可见,相邻像素的颜色值是影响压缩步骤中滤镜过程的主要因素。这样减少在相邻的象素的颜色值,将减少特有的颜色的数量,减小颜色筛选的动态范围。

这样做的结果就是,其余默认的压缩步骤将发现更多相同的颜色值,使得压缩效果更好。

值得注意的是,虽然我们减少了图片中不同颜色的颜色值,但是这是一个对图片有损的步骤。这就是为什么需要你手动处理这部分工作的原因。压缩工具很难理解人们在各种情况下的实际需求,在某些情况下,一些工具中的小错误在人们眼里看起来将是十分巨大的问题。但是,如果处理得当,这将不被用户所察觉,而且能够减小巨大的空间。

PSA:请选择正确的像素格式

这应该不用我提醒,但我在并非少数的APK中看到了错误的例子:

你应该确定你的PNG图片使用的像素格式是正确的。

例如,在图像中你不需要有透明度的值,那么使用 RGBA 32bpp 的格式选项将会浪费整整四分之一的大小,而如果使用 24bpp 的真彩(或者直接使用jpg),你将节省这些空间。同样的,如果你的照片是黑白的,你只需要使用 8bpp 的格式。

基本上,请确保你不会在无意中使用了错误的像素格式使你的PNG图片大小变得巨大。

使用索引图像!

继续,减少颜色值的第一步应该是优化颜色让图片能定位为索引图像的格式。索引颜色模式,主要是使用256种最常用的颜色值,并且将图片中的所有像素替换为这256种颜色的索引代码。其结果就是将一千六百万种颜色(24bpp)转换成256种,这将是一个明显的改进。

下面是一个示例的图片,还有索引的数量:

image

这个 Google 的涂鸦图片是通过 Photoshop 的以网络格式保存图片功能保存的,它的图片格式是 PNG8 ,足以显示这个调色板。

image

基本上,通过转变为索引图像,图片中的每一个像素的颜色值都将被替换成一个索引值。其结果就是将每一个像素的大小从 32bit 减小到 8bit ,作为减小图片大小的第一步成效还是不错的。

当你考虑如何实现过滤和压缩阶段时,这种模式将提供进一步的压缩效果:

  1. 不同的像素颜色数量已经被减小,意味着更多的相邻的像素将有同样的颜色值。
  2. 因为相似的相邻颜色数量的增加,过滤阶段将会产生更多相同的值,这样 LZ77 压缩阶段就可以得到更好的压缩效果。

如果你的图片能被处理成上图调色板一样的格式,那么你已经显著减小了图片的文件大小,所以花时间查看你项目中的图片是否能被优化是十分值得的。

优化完全透明的像素

索引模式的一个很棒的功能就是你可以将调色板中特定颜色转换为“透明”。当 PNG 图片在内存中被解码成 RGBA 图片时,相应的透明像素将被被设置。有趣的是,这种透明模式完全是二进制的;给定像素要么是可见的,要么就不是。

image

一张索引图片,有多个识别透明度值

这种 “punch through” 类型的透明度在压缩中是十分有效的,这一般使用在大片的透明背景中,例如上图中,就有许多在压缩过程中能被优化的相同的像素

但是这只有在索引模式下才能被设置,在许多情况下你想要使用 “punch through” 透明度,但是同时也需要使用完整的 RGB 格式。

在这种情况中,很容易犯的一个错误是不适当的屏蔽不可见的像素。在以下的例子中,两张图片都支持 透明/真彩 ,但是其中一张明显更小。

image

这两张图片看起来一样,但是大小确完全不同。

当你禁用透明度通道时,两张图片的大小区别将变得非常明显。

image

当这两张图片显示在屏幕上时,左边图片的像素在 RGB 通道都拥有完整的色彩数据以绘制出透明度。尽管用户不会看到这些数据,压缩中任然需要对这些数据进行处理。

尽管透明通道将仅仅允许部分图片被呈现,完整的像素信息也会被存在 RGB 层中,这意味着过滤/默认阶段仍然将要对完整的数据进行优化处理。

相对的,如果你知道这些像素将不被察觉,请确保他们的均匀的。这样我们可以用一个值来代替这些不可见的像素,通过这样来处理那些图像中不被看到的部分。

这样做的结果就是每一行都是一个颜色,因此在默认的差值预测阶段中,将会产生更好的压缩效果。基本上这是一个在真彩模式中让你得到 “punch-through” 透明度的一个黑科技,并且将得到一个更小的图片文件。

有损预处理

索引模式的 PNG 图片的确是神奇的,但是可惜的是,并非所有的图片都能用 256 种颜色完全显示。有些也许需要 257 ,310, 512 种甚至 912 种颜色才能正确的显示出来。由于索引模式只支持256种颜色值,所以尽管也许只有一小部分颜色值是需要的,我们也只能用完整的 24bpp 格式。

但是尽管如此,手动的减少颜色值也能让你接近索引图像的保存方法。

创建一个索引图像的过程形容起来比较像是一个矢量量化的过程。这是一种多维数字的舍入过程,更直接的说,所有的颜色将在你的图片中基于他们的相同之处得到分组。对于其中的任意一个分组,组中所有的颜色值将会被一个 “中心点” 的值所代替,最大限度的减少错误的颜色误差。

以下的图片展示在一个 2D 的数组值中这个过程是如何进行的。

image

绿色的点代表 2D 空间中所有的输入值。蓝色的线代表相同颜色的“细胞”或是“团体”,红色的点表示这个“细胞”中主要的颜色。矢量量化的过程意味着对图像的每个像素,取而代之的是矢量量化的代表颜色。

对一个图片使用矢量量化的过程能够减少不同颜色值的数量,用一个单一的颜色来代替看起来十分相近的颜色。

同样的也提供了设置不同颜色数量最大值的能力。

例如,下面这张图片显示了 24-bit-per-pixel (真彩)格式的鹦鹉头像,对比于一张只允许 16 种不同颜色(矢量量化)的图像。

image

你能迅速的发现这过程中图片质量的损失,大部分的渐变颜色都被取代,使得实际看起来有 “条带” 的效果,很明显这张图片需要不止 16 种不同的颜色值来显示。

在使用图片之前加入一个图片矢量量化的过程能帮助你得到图片中使用的真正独特需要的颜色值,能显著的帮助你减小图片大小。不过,遗憾的是我不知道除了 pngquant 外任何图像优化工具,允许您手动指定这些值。所以,除非你使用 pngquant ,否则你可能需要创建自己的矢量量化代码。

协作是关键

事实上,你应该使用一个工具来帮助你尽可能的减小 PNG 图片的大小,这些工具的作者已经花费了大量的时间来研究如何解决这些问题,直接利用他们的工作成果是十分便捷的。话虽这么说,还是有很多工作可以通过你自己来做的,然后再使用其他工具来实现他们的魔法吧。

所以,让咱们的 PNG 图片越来越小吧!

嘿!

想知道 JPG 图片是如何工作的吗?想知道如何减小 JPG 图片的大小吗?

想要更多的干货?请买我的书!