iOS 图片渲染及优化

下图是一张超美的太空图,如果我的项目中要使用这么一张图片,我该怎么显示和优化了(如何显示和优化大图显示)。

图片资源原始网站:在这里

假如这张图大小为:52kb

图片显示流程

1.加载 (数据缓冲区)

图片通过网络请求或者本地加载到内存中,也可以称之为数据缓冲区,占用52kb(文件大小)。

2.解码(图像缓冲区)

解码是将图像转化为CPU能读取和理解的过程,同时将图像创建在图像缓冲区。这里解压所需要占用的内存取决于图片宽高及色域,具体查看下面【图片解码缓存内存大小计算】

解码阶段是消耗最大的。在这个阶段,iOS 会创建一块缓冲区 - 具体来说是一块图像缓冲区,也就是图像在内存中的表示。这解释了为啥内存占用大小和图像尺寸、屏幕是否为广色域有关,而不是文件大小。因此也可以理解,为什么在处理图片时,尺寸如此重要

3.渲染(帧缓冲区)

图像数据从图像缓冲区->缓存帧->屏幕。

 

图片解码缓存内存大小(单位b)计算

网传: 宽*高*4   [*4表示每个像素占用4byte]

精确: 高*每行bytes

由于广色域区别和不同屏幕,相同宽高图片,每行bytes都不一样, 所以网传不精准

 func imageMemorySize(aImage: UIImage) -> Int {
        let cgImg = aImage.cgImage!
        let size = cgImg.height*cgImg.bytesPerRow  // 高*每行byte(单位b)
        print("新图片内存大小:\(size)b")
        print("新图片内存大小:\(size/(1024*1024))M")
        return size
    }

所以上面的55kb照片由于尺寸是720*480 ,所以占用内存实际为1.3M

图片渲染优化

根据图片渲染过程中知道,解码过程消耗最大,且占用缓冲内存大小取决于图像大小,而不是文件大小。

根据缓存内存大小计算公式: 高度*每行bytes(取决于宽和颜色空间)

假如,一张500*500的广色域图片显示在50*50的UIImageView中时,占用的缓冲内存为500*(500*8) = 1.9M,不是50*(50*8), 面对这种情况的时候我们就会消耗相当大内存。

所以,如果你是使用整张图作为背景、加载不确定大小的图片、UITableView使用多过多图片显示时。就会应该考虑图片性能和渲染优化了。

UIGraphicsImageRenderer优化方案

UIGraphicsImageRenderer是iOS10 用来替换 Core Graphics 的UIGraphicsBeginImageContextWithOptions的, 可以理解为UIGraphicsImageRenderer是基于CoreGraphics的优化封装版本。

优点:

后者只使用sRGB,无法使用广色域,也无法智能节约空间(比如单色绘画操作,可以一个像素可以使用1byte)

不用管理颜色空间、缩放、Context

示例:使用不用方法分别绘制圆,会占用不同的内存。

UIGraphicsBEginImageContextWithOptions

let circleSize = CGSize(width: 60, height: 60)

UIGraphicsBeginImageContextWithOptions(circleSize, true, 0)  // 开启指定大小图片上下文
// 画一个园
let ctx = UIGraphicsGetCurrentContext()!
UIColor.red.setFill()  // 填充红色
ctx.setFillColor(UIColor.red.cgColor)
ctx.addEllipse(in: CGRect(x: 0, y: 0, width: circleSize.width, height: circleSize.height))
ctx.drawPath(using: .fill)

let circleImage = UIGraphicsGetImageFromCurrentImageContext()  // 获取图片
UIGraphicsEndImageContext()   // 关闭上下文

UIGraphicsImageRenderer

let circleSize = CGSize(width: 60, height: 60)
let renderer = UIGraphicsImageRenderer(bounds: CGRect(x: 0, y: 0, width: circleSize.width, height: circleSize.height))
// 画一个圆
let circleImage = renderer.image{ ctx in
    UIColor.red.setFill()
    ctx.cgContext.setFillColor(UIColor.red.cgColor)
    ctx.cgContext.addEllipse(in: CGRect(x: 0, y: 0, width: circleSize.width, height: circleSize.height)) // 添加一个椭圆
    ctx.cgContext.drawPath(using: .fill)
}

参考:

UIGraphicsImageRenderer官方文档

图像优化

图像渲染优化技巧

图像与图形的最佳实现(WWDC 2018 session 219) 图像渲染图文解析

Instruments内存分配性能调试 8.9.2

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值