图像解压缩

学习自谈谈 iOS 中图片的解压缩

图片加载的工作流

当从磁盘加载一张图片,将其显示到屏幕上,中间的工作流如下:

  1. 假设使用imageWithContentOfFile:从磁盘加载一张图片,此时图片并没有解压缩
  2. 将生成的UIImage赋值给UIImageView
  3. 接着一个隐式的CATransaction(事务)捕获搭配UIImageView图层树的变化
  4. 在主线程下一个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'的位图。