专栏首页天天P图攻城狮iOS减包实战:Compress PNG Files作用分析

iOS减包实战:Compress PNG Files作用分析

减包这个词大家应该都不陌生,在减包过程中,图片资源的优化这项应该是必经之路了,毕竟在包大小中,图片资源占的比重是很大,而且是可优化空间较大的一项,而在Xcode中有一个build setting就叫做"Compress PNG Files",翻译一下就是“压缩PNG文件”,看上去简直是完美,有木有!

然而,当把这个配置改为YES之后,打包之后发现ipa的大小不但没有减小,反而增大了。说好的Compress呢!!!

这就必须要好好研究下这个"Compress PNG Files"到底是干啥的了!先找到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/iphoneos-optimize这个脚本,其中有如下一段:

 Xcode就是执行了这条命令来进行图片优化的,command line tools中也自带了这么一个命令行工具,通过这个工具,我们可以看看图片经过所谓的Compress之后发生了什么变化。

以如下这张LUT图为例,为什么是这张图片呢,一是因为这种图片在图像处理的App中特别常见,是用来做滤镜调色时使用的,二是因为这种类型的图片差别特别明显。

从结果上来看,经过这个“优化”之后,图片大小从207KB,变成了750KB,整整大了500多K,为了排除偶然性,又选择了另一张图片处理

结果还是增大了非常多,说好的Compress呢!

接下来就要详细的分析下为什么会出现这种情况了。

首先先简单介绍一下PNG这种图片格式,PNG由文件标志和多个数据块组成,文件标志是固定的如下图所示:

数据块的格式如下:

名称

字节数

说明

Length (长度)

4字节

指定数据块中数据域的长度,其长度不超过(231 -1)字节

Chunk Type Code (数据块类型码)

4字节

数据块类型码由ASCII字母(A-Z和a-z)组成

Chunk Data (数据块数据)

可变长度

存储按照Chunk Type Code指定的数据

CRC (循环冗余检测)

4字节

存储用来检测是否有错误的循环冗余码

PNG中常见的数据块类型如下:

PNG文件格式中的数据块

数据块符号

数据块名称

多数据块

可选否

位置限制

IHDR

文件头数据块

第一块

cHRM

基色和白色点数据块

在PLTE和IDAT之前

gAMA

图像γ数据块

在PLTE和IDAT之前

sBIT

样本有效位数据块

在PLTE和IDAT之前

PLTE

调色板数据块

在IDAT之前

bKGD

背景颜色数据块

在PLTE之后IDAT之前

hIST

图像直方图数据块

在PLTE之后IDAT之前

tRNS

图像透明数据块

在PLTE之后IDAT之前

oFFs

(专用公共数据块)

在IDAT之前

pHYs

物理像素尺寸数据块

在IDAT之前

sCAL

(专用公共数据块)

在IDAT之前

IDAT

图像数据块

与其他IDAT连续

tIME

图像最后修改时间数据块

无限制

tEXt

文本信息数据块

无限制

zTXt

压缩文本数据块

无限制

fRAc

(专用公共数据块)

无限制

gIFg

(专用公共数据块)

无限制

gIFt

(专用公共数据块)

无限制

gIFx

(专用公共数据块)

无限制

IEND

图像结束数据

最后一个数据块

还是用之前那张图片作为例子来看,用pngcheck工具看一下文件信息:

这个图片包含了IHDR、tEXt、iTXt、IDAT、IEND等五个数据块,其中比较关键的数据块是IHDR、IDAT、IEND三个,而当我们同pngcheck查看处理之后图片的话,就会出现如下提示:

这里我们就会发现,这里的Compress PNG Files做的并不是单纯的压缩数据,而是把文件格式也做了修改,当我们去查阅相关资料的时候,可以发现其实Apple是将png图片转换成了一种CgBI格式:

These modifications cause the generated images to be invalid as per the current version of the PNG standard.

  • extra critical chunk (CgBI)
  • byteswapped (RGBA -> BGRA) pixel data, presumably for high-speed direct blitting to the framebuffer
  • zlib header, footer, and CRC removed from the IDAT chunk
  • premultiplied alpha (color' = color * alpha / 255)

明显的改动就是在IHDR块之前插入了CgBI块来表示这种格式,同时修改了IDAT块中的数据,原因就是在iPhone中,图像是以BGRA格式在内存中处理的,到这里就可以发现,其实这个所谓的Compress PNG Files,最主要的目的并不是压缩图片的大小,而是将图片转换成iPhone能更方便处理的格式,加快处理速度。

接下来就要解释下为什么LUT这种图片的大小会变化这么大了,首先要看下Compress后的PNG的数据格式,这里通过hexdump可以查询到各个数据块的关键字

这里推荐一个查看CgBI文件数据的命令行工具,pngdefry,这个工具可以用来查看CgBI文件信息,同时可以用来将CgBI文件还原成png文件,当然这里还原之后的png文件和原始文件还是会有区别的,这里后续会有提到。

可以发现,这处理增加了CgBI数据块之外,还增加了一个iDot数据块,这里数据块是Apple自定义的数据块,在网上也没有找到相关的文档,所以暂时无法分析其作用,变化最大的就是IDAT数据块了,IDAT数据块中存放的是实际的图像数据,由于png本身就是一种压缩格式,所以IDAT数据块的数据本身就是经过压缩的,其大小取决于Filter方式、zlib的压缩方式等等。

关于filter方式http://www.libpng.org/pub/png/book/chapter09.html这篇文章讲的非常详细,有兴趣的同学可以看下。而Apple默认的filter方式就是filter0,也就是None这种方式,不同的filter方式对数据的压缩性是有很大影响的,同样是这张图片,使用不用的filter方式处理之后的大小如下:

不同的filter处理之后的图,放到实际工程中使用的话,效果上我测试下来是没有什么区别的,也就是说这几种类型,iPhone都可以解码,不过可以发现,即使是最小的文件也是217KB,还是比源文件207KB要大一些,这又是为什么呢?

xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations lutf0.png lut_revert.png

通过上面的命令,我们可以将图片还原成正常的png格式,然而还原出来的png图片是246KB,比原来的207KB还是大了不少,通过pngcheck,我们可以发现原因:

因为CgBI的IDAT是BGRA格式的,所以不管之前的IDAT是否有Alpha通道,在处理的时候,都会增加alpha通道,其次就是因为每一行数据的filter不同,apple处理的时候,默认每一行都使用相同的filter,而原始文件则可以通过更好的算法,对不同的数据行使用不同的filter,为后面的数据压缩提供更容易压缩的数据。

以上就是对Compress PNG Files这个编译选项的一些分析,当然并不是所有图片经过处理都会变得巨大,也有些图片会变小的,所以当Compress PNG Files这个属性已经开启,并且不确定关闭会不会对现有工程产生大量影响的时候,可以通过如下操作将这张图片排除出compress的方法,尤其是对于LUT图片:

修改为:

参考文献:

【1】http://iphonedevwiki.net/index.php/CgBI_file_format

【2】https://www.cnblogs.com/lidabo/p/3701197.html

作者简介:ash, 天天P图iOS工程师


文章后记: 天天P图是由腾讯公司开发的业内领先的图像处理,相机美拍的APP。欢迎扫码或搜索关注我们的微信公众号:“天天P图攻城狮”,那上面将陆续公开分享我们的技术实践,期待一起交流学习!

加入我们: 天天P图技术团队长期招聘: (1) AND / iOS 开发工程师 (2) 图像处理算法工程师  期待对我们感兴趣或者有推荐的技术牛人加入我们(base 上海)!联系方式:ttpic_dev@qq.com

本文分享自微信公众号 - 天天P图攻城狮(ttpic_dev)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JPEG文件格式解析(一) Exif 与 JFIF

    而我们通常说的JPEG指的是以JPEG格式压缩的图片(即文件后缀为.jpeg .jpe )。经过JPEG重新编码的图片,文件压缩率可以达到90%以上,而且图片本...

    天天P图攻城狮
  • Android OpenGL开发实践 - 基于OpenGL ES 2.0的Android相机实时图片涂鸦实现思路

    这篇文章将给大家讲解如何在Android系统上基于OpenGL ES 2.0来实现相机实时图片涂鸦效果,所涂内容跟随人脸出现、消失、移动、旋转及缩放,在这里,我...

    天天P图攻城狮
  • 终端图像处理实践-实时唇彩效果优化

    天天P图攻城狮
  • 石桥码农:小程序 6 个 UI 框架体验感受

    李艺
  • 还有这种操作?浅析为什么要看源码

    很多人都有一个疑惑,为什么面试都喜欢问原理,问源码.但是实际工作根本用不上,也就是大家常说的,面试造火箭,进去拧螺丝.我身边也有不少朋友问过我,我给他们的回答是...

    java进阶架构师
  • 为什么要看源码

    很多人都有一个疑惑,为什么面试都喜欢问原理,问源码.但是实际工作根本用不上,也就是大家常说的,面试造火箭,进去拧螺丝.我身边也有不少朋友问过我,我给他们的回答是...

    Java技术江湖
  • 资源 | TensorFlow分布式计算机制解读:以数据并行为重

    选自clindatsci 作者:Neil Tenenholtz 机器之心编译 参与:Jane W、黄小天 Tensorflow 是一个为数值计算(最常见的是训...

    机器之心
  • BAT面试题13:请简要说说一个完整机器学习项目的流程

    随着机器学习(ML)成为每个行业的重要组成部分,对机器学习工程师(MLE)的需求急剧增长。MLE需要将机器学习技能与软件工程专业知识相结合,为特定应用程序找到高...

    double
  • 成员网研会:用于持续软件更新的DevOps模式和反模式(视频+PDF)

    讲者:Baruch Sadogursky,DevOps倡导负责人和开发者倡导者 @JFrog

    CNCF
  • 【干货】TensorFlow 2.0官方风格与设计模式指南(附示例代码)

    【导读】TensorFlow 1.0并不友好的静态图开发体验使得众多开发者望而却步,而TensorFlow 2.0解决了这个问题。不仅仅是默认开启动态图模式,还...

    小小詹同学

扫码关注云+社区

领取腾讯云代金券