You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UIGraphicsImageRenderer中绘制并合并多个图层?

UIGraphicsImageRenderer中合并多图层的崩溃解决方法

问题描述

在将原有CGContext绘图代码迁移到UIGraphicsImageRenderer时,使用CGLayer绘制内容后调用cgContext.draw(layer, at: .zero)会崩溃,且仅当图层包含绘制内容时触发(空图层无报错)。移除该行代码后,主上下文绘制正常,但缺失图层内容。原代码示例:

let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { imageContext in

   let cgContext = imageContext.cgContext

   // 原有代码逻辑
   let layer = CGLayer(cgContext, size: size, auxiliaryInfo: nil)!
   let layerCGContext = layer.context!

   // 示例绘制操作(实际逻辑更复杂)
   cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)])
   layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)])

   // 此处崩溃:合并图层到主上下文
   cgContext.draw(layer, at: .zero)
}

崩溃原因

UIGraphicsImageRenderer的上下文是Apple针对iOS/macOS图形栈优化后的封装,直接使用CGLayer的上下文绘制后再将图层绘制回主上下文,会触发上下文状态的冲突,导致崩溃。

解决方案

方法一:嵌套使用UIGraphicsImageRenderer渲染图层内容

推荐使用这种方式,更贴合UIGraphicsImageRenderer的设计模式,避免上下文状态问题:

let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { imageContext in
    let cgContext = imageContext.cgContext
    
    // 主上下文绘制基础内容
    cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)])
    
    // 单独用渲染器生成图层内容的图像
    let layerRenderer = UIGraphicsImageRenderer(size: size)
    let layerImage = layerRenderer.image { layerContext in
        let layerCGContext = layerContext.cgContext
        // 执行图层的绘制操作
        layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)])
    }
    
    // 将图层图像绘制到主上下文
    layerImage.draw(at: .zero)
}

方法二:通过CGImage中转CGLayer内容(兼容原有CGLayer逻辑)

如果需要保留原有CGLayer的使用逻辑,可以将图层内容转为CGImage后再绘制到主上下文:

let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { imageContext in
    let cgContext = imageContext.cgContext
    
    // 主上下文绘制基础内容
    cgContext.fill([CGRect(x: 100, y: 100, width: 400, height: 200)])
    
    // 创建并绘制CGLayer
    let layer = CGLayer(cgContext, size: size, auxiliaryInfo: nil)!
    let layerCGContext = layer.context!
    layerCGContext.fill([CGRect(x: 150, y: 150, width: 200, height: 400)])
    
    // 将CGLayer转为CGImage再绘制到主上下文
    UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
    defer { UIGraphicsEndImageContext() }
    if let tempContext = UIGraphicsGetCurrentContext() {
        tempContext.draw(layer, at: .zero)
        if let layerCGImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage {
            cgContext.draw(layerCGImage, in: CGRect(origin: .zero, size: size))
        }
    }
}

说明

方法一是更优的选择,它利用UIGraphicsImageRenderer的封装特性,避免了手动管理上下文的状态冲突;方法二则适合需要快速兼容原有CGLayer代码的场景。

内容的提问来源于stack exchange,提问作者Ze Jibe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:44:57