[iOS/OC]iOS10.3.3上APNG不动

0x0背景

原本是放到自己博客的,不怎么用了,把文章同步过来,原文地址[iOS/OC]iOS10.3.3上APNG不动

问题现象:有1张APNG动图,在其他系统上都OK,单单在iOS10.3.3上不动。特别迷,花了一下午的时间排查这个问题。最终咨询了@DreamPiggy ,才把这个问题搞清楚。

0x1原因

APNG的数据块有IHDR、acTL、fcTL、IDAT、fdAT等类型。每帧APNG的图像由1个FCTL,>=1个(通常是1~2个)IDAT图像组成。其中FCTL是每帧的控制信息,IDAT是图像信息。在iOS10.3.3系统中,当每帧APNG的fdAT>=3时,系统解码会出错,导致解码失败,并取第一帧信息作为解码结果,即展示PNG静图。

简单的说,即:
iOS 10.3.3系统BUG,在APNG较大且较复杂时,APNG解码失败,返回首帧PNG静图。

0x2APNG

分析过程中,第一步就是查询APNG的标准,发现这块文档十分匮乏,尤其是中文文档。在此,按个人理解整理一份。

1.APNG结构

一个流传甚广的图如下。PNG的基本结构是PNG签名(PNG Signature)+图像头(IHDR)+数据块(IDAT)+结束块(IEND),4部分组成,而APNG则是在此基础上扩展,主要是增加了acTL控制块保存整体动图控制信息,将N张图片的IDAT取出来作为每一帧的信息,并在每一帧增加fcTL控制卡保存每帧图像的控制信息。

[图片上传失败...(image-90acc5-1537881630217)]

2.手工解码APNG

只知道APNG的结构,当出现APNG相关问题的时候,你还是不知道是怎么回事。下面我以上面有问题的APNG为例,手工解码APNG。从结构上分,APNG有PNG签名、数据块,两种类型。

1)PNG签名

整个文件的前8个byte是PNG签名头,为8950 4e47 0d0a 1a0a,将这8个byte转为ascii就是PNG

[图片上传失败...(image-c96bb8-1537881630218)]

2)数据块类型

数据块(chunk)常见类型有:IHDR、acTL、fcTL、IDAT、fdAT、IEND

基本格式如下:

序号 描述 长度(byte)
1 chunk内容长度 4
2 chunk类型 4
3 chunk内容 由1chunk内容长度决定
4 校验码 4

其中chunk类型将其由hex转为ascii,即为对应的值,如:
[图片上传失败...(image-e3dd5b-1537881630218)]

①IHDR

长度(byte) 内容 意义
4 0000 000d chunk内容长度为13 byte
4 4948 4452 IDHR
13 0000 0465 0000 01ea 0806 0000 00 见下标
4 ad34 f3f4 校验码

IHDR的内容意义如下:

描述 长度(byte) 内容
图片宽度 4 byte 0000 0465
图片高度 4 byte 0000 01ea
图像深度 1 byte 8
颜色类型 1 byte 6
压缩方法 1 byte 0
过滤方式 1 byte 0
扫描方式 1 byte 0

②acTL

长度 内容 意义
4 byte 0000 0008 chunk内容长度为8 byte
4 byte 6163 544c acTL
8 byte 0000 000a 0000 0000 前4byte为帧数,10帧;后4byte为循环次数,无限循环;
4 byte ad34 f3f4 校验码

③fcTL

长度 内容 意义
4 byte 0000 001a chunk内容长度为26 byte
4 byte 6663 544c fcTL
26 byte 00 0000 0000 0004 6500 0001 ea00 0000 0000 0000 0000 0c00 6400 00
4 byte 50 8aec fb 校验码

④IDAT

长度 内容 意义
4 byte 00 0080 00 chunk内容长度为32768 byte
4 byte 4944 4154 IDAT
32768 byte
4 byte 876e ca46 校验码

3)数据块类型补充

在动图中,第1帧称为关键帧,其他帧信息在压缩算法下需要有第1帧计算得来。在APNG中,关键帧就是IDAT,第2帧开始为fdAT。

根据数据块类型可知,通常37byte开始,为acTL数据块,可以以此作为是否为APNG的标识。但是这个不是强制的,你也可以自己定义数据块类型,在IHDR之后添加相应信息。

例如,为APNG添加了签名和时间戳后,在Safari下显示是正常的,在Chrome下就无法正常加载。即:Chrome和Safari对于APNG的标准解读不同,且明显Chrome对APNG的标准支持不完善。

3.参考文章

PNG规范中文解读:png的故事:获取图片信息和像素内容

PNG标准英文文档:PNG (Portable Network Graphics) Specification, Version 1.2
APNG标准英文文档:APNG Specification
APNG介绍:APNG那些事

APNG分析网站:https://animatedpngs.com/
HEX转ascii网站:https://www.rapidtables.com/convert/number/hex-to-ascii.html

0x3问题分析

1.分析图片数据

在有以上的对APNG的知识储备后,就可以开始进行正式的问题分析了。

对多组图片手动解码,分析fdAT数据发现,fdAT在同一帧中连续3次或以上,会导致在iOS10.3.3上解码失败。结论以猜测为主,部分证实,暂无实锤。相关数据就不放了。有兴趣的同学可以自己解析一下看看。

2.ImageIO的符号断点

ImageIO有一个LogDebug函数,添加符号断点后,可以断到这个符号,侧面印证了此时系统APNG解码失败。

0x4总结

有必要总结下。各大厂对图片格式的解读是不一致的,尤其是在动图上,在一些特定场景下就会踩坑。目前我已知的有:

1.本文的问题,APNG的fdAT>=3时,苹果系统(iOS/mac os)解码失败,变为静图;
2.APNG添加签名后,Android解码失败,无法展示;
3.安卓和苹果对GIF的循环次数理解不一致,通常可以在苹果解GIF时循环次数加1,以保持多端一致;

其他隐藏的坑不知道还有多少。

你可能感兴趣的:([iOS/OC]iOS10.3.3上APNG不动)