UIGraphicsImageRenderer 的内存占用问题


let renderer = UIGraphicsImageRenderer(size: size)

let newImage = renderer.image { context in   
 
    // ...
}

这是最简单的 UIGraphicsImageRenderer 用法,但用这种方法处理图片有可能占用大量内存。

分辨率问题

图片占内存大小并不是由图片文件大小决定的,而是由图片尺寸决定。假设上述代码中的 size 是 8000 * 8000,每像素大小为 4 字节,那这样最后生成的图片会占用大约 2.25GB 内存。

这是因为在默认情况下,UIGraphicsImageRenderer 会根据屏幕分辨率生成图片,iPhone 的分辨率一般都是 3x,所以最后生成的图片实际尺寸是 24000 * 24000。

如果想要确保 1:1 的显示比例,可以添加如下代码:

let format = UIGraphicsImageRendererFormat()
format.scale = 1

let renderer = UIGraphicsImageRenderer(size: size, format: format)

// ...

这样最终生成的图片的尺寸就是 8000 * 8000,内存占用则只有 250MB 左右。

色域问题

由于 UIGraphicsImageRenderer 会根据图片上下文自动确定色域,例如 sRGB、广色域等,所以在处理广色域图片时,内存也可能会暴增。

在 sRGB 色域下,每像素大小为 4 字节,在广色域下,每像素大小为 8 字节。如果上文提到的图片的色域是广色域,那图片在不做任何优化的情况下,会占用到 4.5GB 左右内存。

所以确定不需要广色域时,可以使用以下代码,指定 sRGB 色域:

let format = UIGraphicsImageRendererFormat()
format.preferredRange = .standard

let renderer = UIGraphicsImageRenderer(size: size, format: format)

// ...

最后

再提一下 UIGraphicsBeginImageContextWithOptions,这位老前辈只支持 sRGB 色域,不支持广色域,这也是应该造成 UIGraphicsBeginImageContextWithOptions 性能比 UIGraphicsImageRenderer 好这种误解的原因。