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

带透明背景调整图片尺寸后CGImage大小变化及内存优化问题

问题分析与解决:图片放大加白边后尺寸异常及内存过高问题

我需要实现放大图片并用白色填充空白区域的功能,编写了如下Swift代码:

func resizeImageWithTransparentBackground(originalImage: UIImage, targetSize: CGSize) -> UIImage? {

    let originalSize = originalImage.size
    let widthRatio = originalSize.width / targetSize.width
    let heightRatio = originalSize.height / targetSize.height

    var newSize = CGSizeZero
    //scale width or height
    if widthRatio - heightRatio >= 0.01 {
        newSize = CGSize(width: originalSize.width, height: originalSize.width)
    } else {
        newSize = CGSize(width: originalSize.height, height: originalSize.height)
    }
     
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
    UIColor.white.setFill()
    UIRectFill(CGRect(origin: .zero, size: newSize))
    
    // Center the original image
    let originX = (newSize.width - originalSize.width) / 2
    let originY = (newSize.height - originalSize.height) / 2
    let rect = CGRect(x: originX, y: originY, width: originalSize.width, height: originalSize.height)
    CGBitmapInfo(rawValue: 0)
    
    originalImage.draw(in: rect)
    
    let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
    
    UIGraphicsEndImageContext()
    
    return resizedImage
}

执行后出现两个问题:

  • CGImage尺寸不符合预期(原图片比例被改变,最终尺寸与目标要求不符)
  • 内存占用过高

问题原因

1. 尺寸异常的核心原因

  • 完全忽略targetSize:计算newSize的逻辑错误,直接将其设为原图片宽或高的正方形,完全没用到传入的目标尺寸,导致生成的图片和需求无关。
  • 未处理图片scale属性:UIImage.size是逻辑尺寸,对应的CGImage是像素尺寸,直接用逻辑尺寸计算会导致像素层面的尺寸偏差。
  • 无效代码干扰:CGBitmapInfo(rawValue: 0)这行代码无任何实际作用,属于冗余代码。

2. 内存占用过高的原因

  • 上下文尺寸不合理:直接基于原图片尺寸创建绘图上下文,若原图片像素量极大,上下文的内存开销会远超预期。
  • 未及时释放资源:没有确保绘图上下文被及时销毁,可能导致内存泄漏。

修复后的代码

func resizeImageWithWhiteBackground(originalImage: UIImage, targetSize: CGSize) -> UIImage? {
    // 适配设备屏幕scale,避免尺寸偏差和模糊
    let screenScale = UIScreen.main.scale
    let targetPixelSize = CGSize(width: targetSize.width * screenScale, height: targetSize.height * screenScale)
    
    // 计算原图片的实际像素尺寸(区分逻辑尺寸与像素尺寸)
    let originalPixelSize = CGSize(width: originalImage.size.width * originalImage.scale, 
                                   height: originalImage.size.height * originalImage.scale)
    
    // 计算等比缩放比例,确保图片完整放入目标尺寸
    let widthScale = targetPixelSize.width / originalPixelSize.width
    let heightScale = targetPixelSize.height / originalPixelSize.height
    let minScale = min(widthScale, heightScale)
    
    // 缩放后的图片像素尺寸
    let scaledPixelSize = CGSize(width: originalPixelSize.width * minScale, 
                                 height: originalPixelSize.height * minScale)
    
    // 创建不透明上下文(背景为白色,减少内存占用),并确保及时释放
    UIGraphicsBeginImageContextWithOptions(targetPixelSize, true, screenScale)
    defer { UIGraphicsEndImageContext() }
    
    // 填充白色背景
    UIColor.white.setFill()
    UIRectFill(CGRect(origin: .zero, size: targetPixelSize))
    
    // 计算图片居中位置
    let originX = (targetPixelSize.width - scaledPixelSize.width) / 2
    let originY = (targetPixelSize.height - scaledPixelSize.height) / 2
    let drawRect = CGRect(x: originX, y: originY, width: scaledPixelSize.width, height: scaledPixelSize.height)
    
    // 绘制缩放后的图片
    originalImage.draw(in: drawRect)
    
    return UIGraphicsGetImageFromCurrentImageContext()
}

关键优化点

  • 正确响应targetSize:基于目标尺寸计算缩放比例,确保最终生成的图片符合需求,同时保留原图片宽高比。
  • 处理scale属性:区分逻辑尺寸与像素尺寸,解决CGImage尺寸偏差问题。
  • 内存优化:
    • 使用defer确保绘图上下文被及时释放,避免内存泄漏。
    • 设置上下文为不透明(opaque: true),内存占用比透明上下文减少一半。
    • 先计算合理缩放比例,直接绘制缩放后的图片,避免创建过大的上下文。
  • 移除冗余代码:删除无意义的CGBitmapInfo(rawValue: 0)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:57:43