专栏首页天天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图攻城狮

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

如有侵权,请联系 yunjia_community@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 正经分析iOS包大小优化

    包大小优化是项目开发中不可避免会遇到的,网上关于包大小优化的文章很多,每篇文章说的都不尽相同,笔者曾经根据网上的文章做过包大小优化,但效果不尽人意;因此笔者想根...

    莫空9081
  • 《HelloGitHub》第 61 期

    内容包括:有趣、入门级的开源项目、开源书籍、实战项目、企业级项目等,让你在短时间内感受到开源的魅力,对开源和编程产生兴趣!

    HelloGitHub
  • 扒虫篇-Bug日志Ⅳ

    解决办法:other linker flag -ObjC 造成的,有些时候设置other linker flag 为-ObjC会出现多次导入的报错。

    進无尽
  • golang zip 压缩,解压(含目录文件)

    李海彬
  • 微信朋友圈千亿访问量背后的技术挑战和实践总结

    微信朋友圈包括图片和视频两套业务架构组成,朋友圈图片的特点是请求量大、消耗计算资源较多,视频则主要消耗带宽。

    JackJiang
  • 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

    特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途。如本文内容有不妥之处,请联系JackJiang进行处理!

    JackJiang
  • Android 开发者如何函数式编程 (三)

    Android 开发者
  • 如何在页面极速渲染3D模型

    腾讯ISUX isux.tencent.com 社交用户体验设计 朋友们,还记得 QQ 20 周年 H5 中可可爱爱的太空鹅吗? 为了实现旋转和换肤功...

    腾讯ISUX
  • 给 iOS 模拟器 “安装”app 文件

    刚刚接触iOS的时候,我就一直很好奇,模拟器上面能不能直接安装app呢?如果可以,我们就直接在模拟器上面聊QQ和微信了。直到昨天和朋友们聊到了这个话题,没有想到...

    一缕殇流化隐半边冰霜
  • 苹果iOS13.2.2正式版修复闷杀后台问题了?别担心,"PerfDog"帮你来检测!

    导语   苹果于上周推送了iOS 13.2版本,带来了用户备受期待的图像处理系统深度融合(Deep Fusion),新增70多个表情、HomeKit安全视频、...

    WeTest质量开放平台团队
  • Golang使用pprof监控性能及GC调优

    作者:峰云就她了 链接:http://xiaorui.cc/?p=3000 來源:个人博客

    李海彬
  • 18个网站优化技巧

    18个网站优化技巧 快速的页面加载对提升搜索引擎排名、网站转化率和整体的用户体验是非常重要的。网站页面的加载速度也是衡量网站性能的一个重要因素。 ?   ...

    小小科
  • ​PNG图片压缩对比分析

    随着版本的迭代,业务的增加,QQ音乐apk的大小已经超过25M,其中res目录占用的大小超过5.5M,所以提出了对安装包进行瘦身的技术需求。

    QQ音乐技术团队
  • 深耕品质,腾讯WeTest《2018中国移动游戏质量白皮书》正式发布

    原文链接:https://wetest.qq.com/lab/view/437.html

    WeTest质量开放平台团队

扫码关注云+社区

领取腾讯云代金券