Core Graphics — 是什么,工作原理及2D图形框架

作者: IT Sectr 发布日期: 2026-07-21 阅读时间: 10 分钟

Core Graphics — Apple的2D渲染框架,属于Core Foundation的一部分,可在iOS、macOS、tvOS和watchOS上使用。它提供低级别的C-API用于处理矢量和光栅图形,包括绘制轮廓、渐变、阴影、图像和文本。Core Graphics是UIKit、SwiftUI和AppKit的基础。根据Apple Developer Documentation, 2026,该框架用于超过90%的iOS应用程序,因为每个可见元素都通过Core Graphics或其硬件对应物进行渲染。

要点

  • Core Graphics — Apple用于矢量和光栅渲染的基础2D框架。
  • CGContext — 框架的核心对象,所有绘图操作都通过它执行。
  • CGPath — 不可变的矢量轮廓,可在不同上下文中重复使用。
  • CGGradient — 用于创建线性和径向渐变并支持色彩空间的对象。
  • CGImage — 可以绘制、变换和遮罩的光栅图像。

什么是Core Graphics?

Core Graphics(也称为Quartz 2D)是实现Apple 2D图形引擎的框架。它基于可移植的Quartz图形库,使用基于页面的绘图模型(page-based),其中每个操作都是序列中的一条命令,类似于在纸上绘图。Core Graphics支持抗锯齿、透明度(alpha合成)和ICC色彩空间。

Core Graphics的架构围绕图形上下文(CGContext)构建,它封装了目标输出设备——屏幕、打印机、PDF文档或光栅缓冲区。上下文管理当前设置:颜色、线宽、变换、裁剪区域和字体。这种方法为不同的输出设备提供统一的API,而无需更改绘图代码。

Core Graphics主要在CPU上运行,使用矢量模型(分辨率无关)。这意味着线条和曲线在渲染时以设备的当前分辨率进行光栅化。与Metal不同,Core Graphics不需要显式管理GPU资源——系统承担所有优化。对于大多数2D任务(图形、图表、自定义UI元素),Core Graphics的性能足以保持60 FPS。

架构和主要类型

Core Graphics包含大约50种基本类型(不透明类型),每种类型负责特定的功能。所有类型都遵循Core Foundation的内存管理规则:通过名称中包含Create的函数创建,需要调用CGRelease,并且在Objective-C中不与ARC兼容(然而Swift通过CF_RETURNS_RETAINED注释自动管理内存)。

Core Graphics的关键类型

CGContext — 绘图上下文,框架的核心类型。CGPath — 不可变的矢量轮廓。CGColor — 带有色彩空间指定的颜色。CGGradient — 渐变填充。CGImage — 光栅图像。CGLayer — 针对重复绘图优化的离线缓冲区。CGDataProvider — 图像的数据源。CGColorSpace — 色彩空间(sRGB、Display P3、灰色)。

每种类型都设计为最小开销:CGPath可以在不同上下文之间缓存和重用,CGColor在传输时转换为GPU的硬件表示,CGLayer存储预先光栅化的内容。这种架构使Core Graphics既能在简单的UI任务中高效工作,也能在专业图形编辑器中表现出色。

类型用途内存管理
CGContext图形上下文CFRelease或在Swift中自动管理
CGPath矢量轮廓CFRelease(不可变)
CGColor色彩空间中的颜色CFRelease或CGColorCreate
CGImage光栅图像CFRelease(创建后)
CGLayer离线缓冲区CFRelease或CGLayerCreate

CGPath:矢量轮廓及其优化

CGPath — 一个不可变对象,描述一系列几何段:直线、贝塞尔曲线、弧线和闭合。与UIBezierPath不同,CGPath不包含绘图方法——它只存储几何信息。要绘图时,将CGPath添加到上下文(CGContextAddPath),然后通过strokePath或fillPath进行绘制。不可变性保证了线程安全性和缓存的可能性。

创建和优化轮廓

CGPathCreateMutable创建一个可变路径(CGMutablePathRef)用于逐步构建。在最终组装后,它转换为不可变的CGPathRef。Apple建议最小化CGPath中的点数——过于复杂的轮廓(超过1000个线段)会减慢光栅化速度。为了优化,使用CGPathCreateCopyBySimplifyingPath,它会移除多余的共线点。

要在两个CGPath之间进行形状动画,可以在CAShapeLayer的path属性上使用CABasicAnimation。限制:两个CGPath必须具有相同数量的线段(控制点)。CGPathApply函数允许遍历路径的所有元素并比较它们的结构。如果线段不匹配,动画将不平滑——在这种情况下,使用CADisplayLink手动插值点。

swift
// 创建可变路径
let mutablePath = CGMutablePath()
mutablePath.moveTo(to: CGPoint(x: 0, y: 0))
mutablePath.addLine(to: CGPoint(x: 100, y: 0))
mutablePath.addLine(to: CGPoint(x: 100, y: 100))
mutablePath.closeSubpath()

// 转换为不可变以安全缓存
let immutablePath: CGPath = mutablePath
CATransaction.perform {
    shapeLayer.path = immutablePath
}

渐变:CGGradient和CGShading

CGGradient — 定义两种或多种颜色之间沿直线(线性渐变)或从中心到边缘(径向渐变)平滑过渡的对象。CGGradient通过指定色彩空间、CGColorRef数组和从0.0到1.0的停止位置数组来创建。创建后,渐变可以在不同的上下文中多次使用。

用于高级渐变的CGShading

CGShading — 更强大的机制,允许定义沿路径的颜色变化函数。与使用固定颜色集的CGGradient不同,CGShading使用回调函数(CGFunctionRef)来计算每个点的颜色。这使得可以创建具有非线性过渡和复合配色方案的复杂渐变。

要在形状内部绘制渐变,需要对该形状的轮廓进行裁剪(clip)。顺序:将路径添加到上下文,调用CGContextClip,然后绘制渐变。没有裁剪,渐变会填充整个上下文。在iOS中,建议使用CGGradient作为更简单和高效的选项——CGShading仅对非标准颜色变化函数是合理的。

swift
func drawGradient(ctx: CGContext, rect: CGRect) {
    let colors = [UIColor.red.cgColor, UIColor.blue.cgColor] as CFArray
    guard let gradient = CGGradient(
        colorsSpace: CGColorSpaceCreateDeviceRGB(),
        colors: colors,
        locations: [0.0, 1.0]
    ) else { return }

    ctx.saveGState()
    ctx.addEllipse(in: rect)
    ctx.clip()
    ctx.drawLinearGradient(
        gradient,
        start: CGPoint(x: rect.midX, y: rect.minY),
        end: CGPoint(x: rect.midX, y: rect.maxY),
        options: []
    )
    ctx.restoreGState()
}

图像处理:CGImage和CGLayer

CGImage — Core Graphics中的光栅图像,可以从文件加载、编程创建或从UIImage获取。CGImage包含像素数据、色彩空间信息、大小、位深度和数据布局。与UIImage不同,CGImage不管理Retina的缩放——这个责任由开发人员通过scale参数承担。

CGLayer — 重复绘图的优化

CGLayer — 用于预光栅化静态内容的离线缓冲区。如果同一组图形命令重复绘制(例如背景图案),CGLayer将其光栅化一次,然后简单地复制到上下文中。根据Apple的数据,使用CGLayer可以将重复绘图加速2-5倍(CPU)和高达10倍(硬件加速)。

对于加载图像,使用CGImageSource — 一个强大的API,用于读取元数据、缩略图和来自GIF/APNG的单个帧。CGImageSource允许渐进式加载图像并仅获取必要的片段。在处理大图像(超过屏幕尺寸)时,建议创建具有磁盘缓存选项的CGImageSource,并使用CGImageSourceCreateThumbnailAtIndex显示缩小的版本。

swift
func createLayer(ctx: CGContext, size: CGSize) -> CGLayer? {
    guard let layer = CGLayer(ctx, size: size, auxiliaryInfo: nil) else { return nil }
    let layerCtx = layer.context !

    // 绘制一次
    layerCtx.setFillColor(UIColor.lightGray.cgColor)
    layerCtx.addEllipse(in: CGRect(origin: .zero, size: size))
    layerCtx.fillPath()
    return layer
}

// 在draw()中使用
for i in 0..<20 {
    ctx.draw(layer, at: CGPoint(x: CGFloat(i) * 30, y: 0))
}

Core Graphics使用示例

我们将开发一个自定义View,使用Core Graphics在图像上显示水印。水印包括半透明文本和矢量徽标,叠加在原始图像上。代码演示了在单个上下文中处理CGContext、CGImage、文本和透明度。

swift
class WatermarkView: UIView {

    private let watermarkText = "IT Sectr"
    private let watermarkOpacity: CGFloat = 0.3

    override func draw(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }

        // 绘制背景图像
        UIImage(named: "background")?.draw(in: rect)

        // 配置水印透明度
        ctx.saveGState()
        ctx.translateBy(x: rect.midX, y: rect.midY)
        ctx.rotate(by: -.pi / 6)

        // 半透明文本
        let attributes: NSAttributedString.Attributes = [
            .font: UIFont.boldSystemFont(ofSize: 48),
            .foregroundColor: UIColor.white.withAlphaComponent(watermarkOpacity)
        ]
        let textSize = watermarkText.size(withAttributes: attributes)
        watermarkText.draw(
            at: CGPoint(x: -textSize.width / 2, y: -textSize.height / 2),
            withAttributes: attributes
        )

        // 文本下方的矢量图标(带叉的圆)
        ctx.setStrokeColor(UIColor.white.withAlphaComponent(watermarkOpacity).cgColor)
        ctx.setLineWidth(3)
        ctx.addEllipse(in: CGRect(x: -25, y: -75, width: 50, height: 50))
        ctx.strokePath()
        ctx.moveTo(x: -15, y: -50)
        ctx.addLineTo(x: 15, y: -50)
        ctx.moveTo(x: 0, y: -65)
        ctx.addLineTo(x: 0, y: -35)
        ctx.strokePath()

        ctx.restoreGState()
    }
}

代码中使用了Core Graphics的关键功能:saveGState/restoreGState用于将水印效果与背景隔离,translateBy和rotate用于定位和旋转,通过withAlphaComponent实现半透明文本,以及通过addEllipse和addLineTo实现矢量图标。整个水印在背景图像之后作为一个整体绘制。

在生产环境中为照片创建水印时,考虑性能很重要。如果图像大于屏幕,在应用水印之前通过CGImageSourceCreateThumbnailAtIndex缩小它。Core Graphics在CPU上处理所有操作——对于批量处理数十张图像,使用后台队列和CGBitmapContext以避免阻塞UI。

常见问题

Core Graphics与UIKit有何不同?

UIKit — 高级UI框架,内部使用Core Graphics进行渲染。Core Graphics — 用于2D图形的低级C-API。UIKit对于标准元素更方便,Core Graphics提供对每个像素的完全控制。

何时使用Core Graphics而不是Metal?

Core Graphics适用于静态2D图形、图表和自定义UI元素。Metal — 用于3D图形、复杂动画和通过GPU加速处理大型像素数组。对于95%的UI任务,Core Graphics已经足够。

如何使用CGImage节省内存?

使用CGImageSource通过createThumbnailAtIndex加载缩略图而不是完整加载。要显示大图像,创建带有downsample选项的CGImage。当不再需要时,通过CGImageRelease释放CGImage。

Core Graphics支持PDF吗?

是的,Core Graphics通过CGPDFDocument用于读取和CGPDFContext用于创建PDF文档,提供完整的PDF支持。可以将任何CGContext内容直接绘制到PDF页面并保留矢量。

如何确保绘图时的Retina质量?

Core Graphics在屏幕上渲染时自动使用设备的分辨率。对于离线上下文,使用参数scale = 0(系统缩放比例)的UIGraphicsBeginImageContextWithOptions,或为Retina/Retina HD明确指定2.0/3.0。

总结

  • Core Graphics — Apple用于CPU上矢量和光栅渲染的基础2D框架。
  • CGContext — 管理状态栈和目标输出设备的中心对象。
  • CGPath — 不可变的矢量轮廓,用于安全缓存和线程安全的重用。
  • CGGradientCGShading — 创建线性、径向和函数渐变的机制。
  • CGImage — 支持不同色彩空间和位深度的光栅图像。
  • CGLayer — 用于将重复绘图加速2-5倍的离线缓冲区。
  • Core Graphics是UIKit、SwiftUI和AppKit的基础——iOS中每个可见元素都通过它处理。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读