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

Core Graphics/Quartz 2D图片缩放功能崩溃问题求助

排查UIImage缩放函数崩溃问题

我来帮你定位这个基于CGBitmapContextCreate和CGContextDrawImage的图片缩放函数的崩溃原因,结合你的代码片段,常见的问题点和修复方案如下:

常见崩溃诱因及修复

1. 变量命名冲突导致逻辑异常

你在函数参数里已经定义了maxHeight和maxWidth,但函数内部又重新声明了同名常量,这会直接遮蔽外部参数,不仅逻辑混乱,还可能引发意想不到的计算错误(比如参数为0时的比例计算异常)。建议重命名内部变量:

let targetMaxHeight = round(maxHeight)
let targetMaxWidth = round(maxWidth)

2. CGBitmapContextCreate参数错误(高频崩溃点)

这个函数的参数稍有不慎就会返回nil,后续使用nil上下文操作必然崩溃。常见问题包括:

  • 未传入有效的颜色空间
  • bytesPerRow计算错误
  • 像素格式不匹配当前设备

正确的做法是使用通用RGB颜色空间,同时按像素格式计算字节数:

let colorSpace = CGColorSpaceCreateDeviceRGB()
let bytesPerRow = Int(scaledWidth) * 4 // RGBA格式每个像素占4字节
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue

3. 未处理上下文创建失败的情况

如果CGBitmapContextCreate因内存不足、参数错误返回nil,后续的绘制和图片生成操作会直接崩溃。必须先判断上下文有效性:

guard let context = CGBitmapContextCreate(...) else {
    return nil
}

4. Core Graphics坐标系翻转问题

UIKit坐标系原点在左上角,而Core Graphics在左下角,直接绘制可能引发内存访问错误或显示异常,需要先翻转上下文坐标系:

CGContextTranslateCTM(context, 0, scaledHeight)
CGContextScaleCTM(context, 1, -1)

修复后的完整缩放函数

extension UIImage {
    func scaledTo(maxHeight: CGFloat, maxWidth: CGFloat) -> UIImage? {
        guard let cgImage = self.cgImage else { return nil }
        let originalHeight = CGFloat(cgImage.height)
        let originalWidth = CGFloat(cgImage.width)
        
        guard originalHeight > 0, originalWidth > 0 else { return nil }
        
        let targetMaxHeight = round(maxHeight)
        let targetMaxWidth = round(maxWidth)
        
        // 计算缩放比例,保证图片不超过最大尺寸
        let heightRatio = targetMaxHeight / originalHeight
        let widthRatio = targetMaxWidth / originalWidth
        let scaleRatio = min(heightRatio, widthRatio)
        
        guard scaleRatio > 0 else { return nil }
        
        let scaledWidth = originalWidth * scaleRatio
        let scaledHeight = originalHeight * scaleRatio
        
        // 创建正确的位图上下文
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bytesPerRow = Int(scaledWidth) * 4
        let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
        
        guard let context = CGBitmapContextCreate(
            nil,
            Int(scaledWidth),
            Int(scaledHeight),
            8,
            bytesPerRow,
            colorSpace,
            bitmapInfo
        ) else {
            return nil
        }
        
        // 翻转坐标系适配UIKit
        CGContextTranslateCTM(context, 0, scaledHeight)
        CGContextScaleCTM(context, 1, -1)
        
        // 绘制缩放后的图片
        CGContextDrawImage(context, CGRect(x: 0, y: 0, width: scaledWidth, height: scaledHeight), cgImage)
        
        // 生成新图片
        guard let scaledCGImage = CGBitmapContextCreateImage(context) else { return nil }
        return UIImage(cgImage: scaledCGImage, scale: self.scale, orientation: self.imageOrientation)
    }
}

额外注意事项

  • 如果处理带透明通道的PNG图片,确保bitmapInfo使用premultipliedLast,避免透明层显示异常
  • 保留原图片的scale和imageOrientation,否则生成的图片可能在不同设备上模糊或方向错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:24:11