图像解压缩
图片加载的工作流
当从磁盘加载一张图片,将其显示到屏幕上,中间的工作流如下:
- 假设使用
imageWithContentOfFile:
从磁盘加载一张图片,此时图片并没有解压缩 - 将生成的UIImage赋值给UIImageView
- 接着一个隐式的
CATransaction
(事务)捕获搭配UIImageView
图层树的变化 - 在主线程下一个runLoop到来时,
CoreAnimation
提交了这个隐式的CATransaction
,这个过程可能存在对图片的copy操作,受到图片是否字节对齐等因素的影响,这个copy操作可能会涉及以下部分或全部步骤:- 分配内存缓冲区用于管理文件IO和解压缩操作
- 将文件数据从磁盘读到内存中
- 将压缩的图片数据解码成未压缩位图形式,这是一个非常耗时的CPU操作
- 最后CoreAnimation使用未压缩的位图 渲染
UIImageView
图层
可以参考图片加载优化框架FastImageCache对这段的解释
图片的解压缩是一个非常耗时的操作,而且默认是在主线程中执行的。当需要加载的图片较多时,就会对应用响应造成严重影响,尤其在快速滑动的列表中。
为什么需要解压缩
图片是无法不解压缩而现实到屏幕上的,首先需要知道 什么事位图
位图就是一个像素数组,数组中每个像素就代表图片中的一个点。在应用中经常用到的JPEG和PNG图片就是位图。
解压缩之后的图片大小和原始文件大小没有任何关系,只与图片的像素有关
解压缩后的图片大小 = 图片的像素宽 * 图片的像素高 * 每个像素所占的字节数
事实上 不论是JPG和PNG都是压缩的位图形式。只是PNG是无损压缩的并且支持alpha通道和JPG是有损压缩,可以指定0-100%压缩比。
因此,在将磁盘中的图片渲染到屏幕上之前,必须得到图片的原始像素数据,才能执行后续绘制操作,这也是为什么要对图片进行解压缩原因
强制解压缩原理
当未解压缩的图片将要渲染到屏幕时,系统会在主线程对图片进行解压缩,而如果图片已经解压缩了,系统就不会再对图片进行解压缩了。
因此,我们可以再子线程提前对图片进行强制解压缩
原理就是对图片进行重新绘制,得要新的解压缩之后的位图
CG_EXTERN CGContextRef __nullable CGBitmapContextCreate(void * __nullable data,
size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
用于创建一个位图上下文,绘制宽width和高height'的位图。