在 iOS 开发中,处理图像时你一定会遇到 UIImage、CGImage 和 CIImage 这三个类。它们分别属于不同的框架,承担着不同的职责,理解它们的区别和联系,能让你在加载、显示、编辑图像时做出正确的选择。
1. UIImage(UIKit 框架)
UIImage 是 UIKit 中用于管理图像数据的高级类。它是你日常开发中最常接触的“图像对象”。
核心特点:
- 面向显示:专门为界面显示而设计,可以直接赋值给
UIImageView、用作按钮背景等。 - 封装性强:内部可能包含一个或多个
CGImage(例如animated图像),或者是从文件/数据加载的原始数据。你通常不需要关心它的底层表示。 - 支持多种来源:可以通过文件、数据、
CGImage、CIImage等方式创建,也可以读取 Asset Catalog 中的图片。 - 具备缩放、拉伸等 UI 相关能力:如
resizableImage(withCapInsets:)。
使用场景:绝大部分需要显示图像的场景,如 UIImageView、UIButton 的 setImage(_:for:)、动画图像等。
2. CGImage(Core Graphics 框架)
CGImage 是 Core Graphics(Quartz 2D)中定义的位图图像(bitmap image)表示。它是一个不可变的像素数据容器,直接指向内存中的像素数据或图像源。
核心特点:
- 底层像素级:包含图像的宽度、高度、颜色空间、位图信息、数据提供者(
CGDataProvider)等。可以访问和操作每个像素。 - 不可变:一旦创建,内容不能修改(但可以通过绘制等方式生成新的
CGImage)。 - 不包含显示信息:它只是一个像素数据模型,不涉及屏幕分辨率、方向等 UIKit 层面的概念。
- 高性能:由于直接操作像素数据,适合进行图像绘制、像素级处理、图像合成等。
使用场景:
- 绘制图形(
CGContext绘制)。 - 对图像进行裁剪、旋转、缩放等操作(通过
CGContext或CGImage的方法)。 - 作为
CALayer的内容(layer.contents)。 - 与
UIImage相互转换进行底层处理。
3. CIImage(Core Image 框架)
CIImage 是 Core Image 框架中用于表示图像的处理管线表示。它并不一定包含实际的像素数据,而是一个“图像配方”,可以表示原始图像、滤镜链、甚至生成的图像。
核心特点:
- 延迟计算:创建
CIImage时,通常不会立即渲染像素数据。它是一个“指令序列”,表示如何生成图像。只有在通过CIContext渲染(如转换为CGImage或UIImage)时,才会实际计算像素。 - 面向滤镜:它是 Core Image 滤镜的输入和输出,适合构建复杂的图像处理流水线(滤镜链)。
- 支持多种格式:可以通过
UIImage、CGImage、数据、文件、像素缓冲区(CVPixelBuffer)等创建。 - 颜色空间与上下文相关:渲染时需要
CIContext,可以指定输出颜色空间,支持 GPU/CPU 加速。
使用场景:
- 应用 Core Image 滤镜(如模糊、颜色调整、人脸检测等)。
- 构建高效的图像处理管线,支持链式操作。
- 实时处理视频帧或相机输出(配合
CVPixelBuffer)。
4. 三者关系对比
| 特性 | UIImage | CGImage | CIImage |
|---|---|---|---|
| 所属框架 | UIKit | Core Graphics (Quartz 2D) | Core Image |
| 抽象层次 | 高级 UI 对象 | 底层位图数据 | 图像处理管线 |
| 可变性 | 不可变(但可以生成新对象) | 不可变 | 不可变,但滤镜链可组合 |
| 存储形式 | 可能包含多张图(如动图)或引用底层数据 | 纯位图数据(像素矩阵) | 图像处理的“配方”,可能延迟计算 |
| 主要用途 | 显示、界面交互 | 像素级操作、绘制 | 滤镜处理、图像分析 |
| 性能特点 | 适合显示,创建/转换可能较慢 | 内存占用直接,操作高效 | 滤镜处理快(GPU),渲染时开销可控 |
| 转换关系 | uiImage.cgImage 获取(若存在)UIImage(ciImage:) 从 CIImage 创建 | cgImage 可创建 UIImage可被用于创建 CIImage | CIImage(image:) 从 UIImage 创建CIImage(cgImage:) 从 CGImage 创建 |
理解要点:
UIImage是“成品”,拿来就能显示。CGImage是“裸像素”,适合动手绘制和加工。CIImage是“配方”,适合批量滤镜处理,但最后需要“烹饪”(渲染)才能显示。
5. 常见转换与使用示例
import UIKit
import CoreImage
// 假设有一个 UIImage
let uiImage = UIImage(named: "photo")!
// 1. UIImage → CGImage
let cgImage = uiImage.cgImage
// 2. CGImage → UIImage
let backToUIImage = UIImage(cgImage: cgImage!)
// 3. UIImage → CIImage
let ciImage = CIImage(image: uiImage)
// 4. CIImage → UIImage(需要渲染)
let context = CIContext()
if let outputCGImage = context.createCGImage(ciImage!, from: ciImage!.extent) {
let resultUIImage = UIImage(cgImage: outputCGImage)
}
// 5. 使用滤镜:CIImage → 滤镜 → CIImage → UIImage
let filter = CIFilter(name: "CISepiaTone")!
filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(0.8, forKey: kCIInputIntensityKey)
if let outputCIImage = filter.outputImage {
let outputCGImage = context.createCGImage(outputCIImage, from: outputCIImage.extent)
let filteredUIImage = UIImage(cgImage: outputCGImage!)
}
6. 如何选择?
- 只需要显示图片 → 直接使用
UIImage,从 Asset 或网络加载。 - 需要对图片进行绘制、裁剪、合成 → 用
CGImage配合CGContext,效率高且可控。 - 需要应用滤镜、人脸检测、颜色调整 → 使用
CIImage+CIFilter,代码简洁且性能好(尤其在 GPU 上)。 - 处理视频帧或相机输出 → 通常获得的是
CVPixelBuffer,可转为CIImage进行滤镜,再转为CVPixelBuffer或显示。
总结
UIImage是 UIKit 的“门面”,用于界面显示。CGImage是 Core Graphics 的位图基础,用于底层绘图和像素操作。CIImage是 Core Image 的处理对象,用于高效滤镜和图像分析。
三者可以互相转换,分工明确。在实际开发中,根据任务选择合适的表示,既能写出清晰的代码,也能获得较好的性能。
自己理解使用
首先分属于不同框架 CIImage 一般做滤镜 美颜处理。