UIImage旋转后边缘出白边,多次旋转白边扩大问题求助
UIImage旋转后边缘白边及渲染性能问题
问题现象
开发图片编辑器时,点击旋转按钮调用rotateLeft函数旋转图片,多次旋转(需等待前一次完成)后,图片边缘的白边会逐渐变大。

现有旋转实现代码
最初使用UIGraphicsBeginImageContext实现旋转:
func rotateLeft() -> UIImage? { let radians = CGFloat.rotateRadians // Calculate the size of the rotated image var rotatedSize = CGRect(origin: .zero, size: size) .applying(CGAffineTransform(rotationAngle: radians)) .integral.size // Round the dimensions to the nearest whole number rotatedSize.width = round(rotatedSize.width) rotatedSize.height = round(rotatedSize.height) // Create a context for the rotated image UIGraphicsBeginImageContext(rotatedSize) defer { UIGraphicsEndImageContext() } if let context = UIGraphicsGetCurrentContext() { // Move the origin to the center of the image context.translateBy(x: rotatedSize.width / 2.0, y: rotatedSize.height / 2.0) // Rotate the context context.rotate(by: radians) // Draw the image draw(in: CGRect( x: -size.width / 2.0, y: -size.height / 2.0, width: size.width, height: size.height) ) // Get the rotated image from the context if let rotatedImage = UIGraphicsGetImageFromCurrentImageContext() { return rotatedImage } } return nil }
白边问题原因分析
- 误差累积:每次旋转都基于上一次旋转后的图片(已带有边缘误差)进行操作,导致白边逐次放大。
- 坐标与尺寸计算的浮点精度问题:使用
applying(CGAffineTransform)计算旋转后的尺寸,会产生浮点数值,即使做了round处理,仍会导致绘制时的像素对齐偏差,边缘出现空白或模糊。 - 上下文设置不严谨:
UIGraphicsBeginImageContext默认使用屏幕缩放因子,若原图片的缩放因子与屏幕不一致,绘制时会出现插值误差,多次叠加后形成明显白边。
优化方案
1. 基于原始图片旋转(核心解决累积问题)
不要每次用旋转后的图片作为下一次旋转的输入,始终保留原始图片的引用,旋转时直接从原始图片生成新的旋转结果。
2. 修正旋转尺寸计算与上下文设置
对于90度/270度这类正交旋转,直接互换宽高即可得到精确尺寸,无需通过变换计算。同时使用UIGraphicsBeginImageContextWithOptions指定正确的缩放因子和不透明属性:
func rotateLeft() -> UIImage? { let radians = CGFloat.rotateRadians // 应为-π/2(左旋转90度) // 90度旋转后尺寸直接互换宽高 let rotatedSize = CGSize(width: size.height, height: size.width) // 使用带参数的上下文创建方法,指定原图片的缩放因子,opaque根据图片是否透明设置 UIGraphicsBeginImageContextWithOptions(rotatedSize, true, self.scale) defer { UIGraphicsEndImageContext() } guard let context = UIGraphicsGetCurrentContext() else { return nil } // 平移到中心,旋转,绘制 context.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2) context.rotate(by: radians) draw(in: CGRect(x: -size.width/2, y: -size.height/2, width: size.width, height: size.height)) return UIGraphicsGetImageFromCurrentImageContext() }
3. 优化UIGraphicsImageRenderer的性能
若要使用UIGraphicsImageRenderer,需指定正确的缩放因子和格式,避免不必要的高分辨率绘制:
func rotateLeft() -> UIImage? { let radians = CGFloat.rotateRadians let rotatedSize = CGSize(width: size.height, height: size.width) // 自定义渲染格式,指定缩放因子为原图片的scale,设置opaque let format = UIGraphicsImageRendererFormat() format.scale = self.scale // 或者设为1,根据需求调整 format.opaque = true let renderer = UIGraphicsImageRenderer(size: rotatedSize, format: format) let rotatedImage = renderer.image { context in context.cgContext.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2) context.cgContext.rotate(by: radians) let origin = CGPoint(x: -size.width / 2, y: -size.height / 2) draw(at: origin) } return rotatedImage }
指定scale为原图片的缩放因子,避免渲染出3倍尺寸的大图,能大幅提升渲染速度。
内容的提问来源于stack exchange,提问作者Petr Bones
相关产品推荐
相关产品推荐

