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
相关产品推荐
相关产品推荐

