UIImage CGImage CIImage 都是什么,该怎么理解

2 阅读5分钟

在 iOS 开发中,处理图像时你一定会遇到 UIImageCGImageCIImage 这三个类。它们分别属于不同的框架,承担着不同的职责,理解它们的区别和联系,能让你在加载、显示、编辑图像时做出正确的选择。


1. UIImage(UIKit 框架)

UIImage 是 UIKit 中用于管理图像数据的高级类。它是你日常开发中最常接触的“图像对象”。

核心特点

  • 面向显示:专门为界面显示而设计,可以直接赋值给 UIImageView、用作按钮背景等。
  • 封装性强:内部可能包含一个或多个 CGImage(例如 animated 图像),或者是从文件/数据加载的原始数据。你通常不需要关心它的底层表示。
  • 支持多种来源:可以通过文件、数据、CGImageCIImage 等方式创建,也可以读取 Asset Catalog 中的图片。
  • 具备缩放、拉伸等 UI 相关能力:如 resizableImage(withCapInsets:)

使用场景:绝大部分需要显示图像的场景,如 UIImageViewUIButtonsetImage(_:for:)、动画图像等。


2. CGImage(Core Graphics 框架)

CGImage 是 Core Graphics(Quartz 2D)中定义的位图图像(bitmap image)表示。它是一个不可变的像素数据容器,直接指向内存中的像素数据或图像源。

核心特点

  • 底层像素级:包含图像的宽度、高度、颜色空间、位图信息、数据提供者(CGDataProvider)等。可以访问和操作每个像素。
  • 不可变:一旦创建,内容不能修改(但可以通过绘制等方式生成新的 CGImage)。
  • 不包含显示信息:它只是一个像素数据模型,不涉及屏幕分辨率、方向等 UIKit 层面的概念。
  • 高性能:由于直接操作像素数据,适合进行图像绘制、像素级处理、图像合成等。

使用场景

  • 绘制图形(CGContext 绘制)。
  • 对图像进行裁剪、旋转、缩放等操作(通过 CGContextCGImage 的方法)。
  • 作为 CALayer 的内容(layer.contents)。
  • UIImage 相互转换进行底层处理。

3. CIImage(Core Image 框架)

CIImage 是 Core Image 框架中用于表示图像的处理管线表示。它并不一定包含实际的像素数据,而是一个“图像配方”,可以表示原始图像、滤镜链、甚至生成的图像。

核心特点

  • 延迟计算:创建 CIImage 时,通常不会立即渲染像素数据。它是一个“指令序列”,表示如何生成图像。只有在通过 CIContext 渲染(如转换为 CGImageUIImage)时,才会实际计算像素。
  • 面向滤镜:它是 Core Image 滤镜的输入和输出,适合构建复杂的图像处理流水线(滤镜链)。
  • 支持多种格式:可以通过 UIImageCGImage、数据、文件、像素缓冲区(CVPixelBuffer)等创建。
  • 颜色空间与上下文相关:渲染时需要 CIContext,可以指定输出颜色空间,支持 GPU/CPU 加速。

使用场景

  • 应用 Core Image 滤镜(如模糊、颜色调整、人脸检测等)。
  • 构建高效的图像处理管线,支持链式操作。
  • 实时处理视频帧或相机输出(配合 CVPixelBuffer)。

4. 三者关系对比

特性UIImageCGImageCIImage
所属框架UIKitCore 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 一般做滤镜 美颜处理。