PNG尺寸缩小实战

为了节省资源,我们希望在不同分辨率的前端上可以获取到不同尺寸的素材资源。由于最近的业务中使用的所有素材都是PNG格式的图片,并且对图片效果要求比较严格,并没有在市面上找到可以直接使用的服务,于是自行实现整个服务。

TL;DR

首先使用ImageMagick对图片进行缩放(假设输出是64*64的图片)和去模糊,再使用pngquant对缩放后的图片进行有损压缩(假设原图颜色数量为128)。

convert src.png -resize 64x64 resize.png
convert resize.png -unsharp 1.5x1+0.7+0.02 output.png
pngquant 128 -f --ext .png output.png

工具的选择的心路历程

图片缩放

最早使用了号称命令行上的Photoshop的ImageMagick来对图片进行缩放。当然功能可以实现,只是发现图片尺寸裁剪之后,文件本身的体积反而变大了。后来尝试了各种不同的工具,包括Java的ImageIO,Python的PIL,以及知名图片压缩服务TinyPng的SDK。不同的工具不仅裁剪后文件大小不同,效果也有所差异。其中TinyPng表现最好,大部分时候图片被缩小后文件尺寸也会随之减小,但是也有个别图片仍然存在同样的问题。
在查阅到相关资料png 裁剪时遇到问题,得到了较好的解释:

原图类型 Type: PaletteAlpha,Base type: TrueColorAlpha,本身就是经过压缩和优化了的。
resize 时,会进行各种差值,信息也会变多,类型也变成了 TrueColorAlpha。

这里涉及到了PNG文件具体格式相关资料,可以参考PNG-8、24、32区别介绍PNG的故事

图片颜色信息减少

在确认造成文件变大的原因是颜色信息增多之后,自然是选择将颜色信息适当减少。由于我们要处理的图片是缩小后的图片,需要的颜色应该不会比原图要更多,所以我们目标是将缩小后的图片的颜色数较少到和原图的颜色数相同。
这里我们使用一个有损压缩工具pngquant来压缩图片和减少颜色数量。选择他是为数不多能直接改变颜色数的压缩工具。
经过缩小压缩之后,裁剪后的图片文件已经明显小于原图。相关文件的具体信息可以通过ImageMagick的identify命令来直接查看:

identify -verbose src.png

到这一步大部分需求已经实现,但是却在个别边缘分明的素材上发现了明显的边缘模糊,导致视觉效果不佳。

图片去模糊

首先是排查原因。
起初我以为是我在压缩的过程中,过分减少了输出图片的颜色数量,导致细节丢失。后来发现那些边缘分明的图片在resize时就已经出现了模糊现象,那问题自然是在ImageMagick的使用上。
之后在ImageMagick的官方文档中找到了一片《Resampling Filter》,介绍了在图片缩放时候的会遇到的各种问题和各种参数的使用。例如:


在模糊问题上更是有另外一片文档《Resize Unsharp》来说明如何处理resize过程中的模糊问题。参照文档使用下列命令可以很好地锐化图片:

convert resize.png -unsharp 1.5x1+0.7+0.02 output.png

至此将三个步骤整合在一起,就可以达到令人满意的png缩小效果。

相关原理

Resize

Resize的实际处理过程叫做Resampling,即重采样。简单来说,可以看作操作一个数组,增加或者减少这个数组的元素,并且让处理的结果在人眼看起来不那么糟糕。其实这是一个非常复杂的问题,也有人专门从事这方面的研究,这里不展开讨论,还是要看《Resampling Filter》,里面介绍了各种Resampling的策略,也会说明为什么图片缩小后颜色数量会增多。
由于这个问题的复杂性,所以没有一套完美的方案可以解决所有场景下素材的resize,毕竟有太多的策略和参数可以选择,最终的方案是需要根据需求进行取舍的。

有损压缩

处理中关键的一部是使用pngquant进行有损压缩。为什么颜色变少之后文件尺寸迅速下降?首先是因为颜色数量如果少于255,输出的图片将可以保存为PNG-8格式,这样就减少了像素深度。另外主要缩小图片的原因还是PNG本身压缩过程中的Filtering和DEFLATE算法起作用。简而言之,如果一个数组内相似的元素越多,那么DEFLATE就可以将其压缩得越小。而Filtering步骤可以用差分编码的编码方式,即是记录当前数据和某个标准值的差距来存储当前数据。
比如说有这么一个数组[99, 100, 100, 102, 103],我们可以将其转存为[99, 1, 0, 2, 1]。转存的规则就是以数组第1位为标准值,标准值存储原始数据,后续均存储以前1位数据的差值。PNG一共支持5种Filtering,基本原理相似。通过类似这样的转换之后,DEFLATE就可以更好得压缩数据。

END

特别鸣谢:V友icyalala
参考资料
PNG-8、24、32区别介绍
Resampling Filter
减少PNG文件的大小
PNG的故事

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容