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

iOS中UIImage缩放后转Data上传时尺寸复原问题求助

问题根源

你的缩放方法错误地基于UIImage的逻辑尺寸(size属性)计算缩放因子,忽略了UIImage的scale属性——该属性决定了逻辑尺寸对应的实际像素数量(像素尺寸 = 逻辑尺寸 × scale)。此外,使用UIGraphicsBeginImageContextWithOptions时传入scale: 0会采用当前屏幕的缩放比例(如2x或3x),导致生成的UIImage实际像素尺寸远大于预期的逻辑尺寸,最终转成JPEG Data后出现“尺寸复原”的假象(实际是像素尺寸未正确缩放)。

解决方案

方案1:修正原UIGraphics方法,基于像素尺寸计算

修改缩放逻辑,以实际像素尺寸为基准计算缩放因子,并强制上下文scale为1(确保生成的UIImage逻辑尺寸等于像素尺寸):

extension UIImage {
    func resizedImage(minimumPixelSize: CGFloat, maximumPixelSize: CGFloat) -> UIImage? {
        // 计算原始图像的实际像素尺寸
        let originalPixelWidth = size.width * scale
        let originalPixelHeight = size.height * scale

        var scaleFactor: CGFloat = 1.0

        // 根据像素尺寸范围计算缩放因子
        if originalPixelWidth < minimumPixelSize || originalPixelHeight < minimumPixelSize {
            scaleFactor = max(minimumPixelSize / originalPixelWidth, minimumPixelSize / originalPixelHeight)
        } else if originalPixelWidth > maximumPixelSize || originalPixelHeight > maximumPixelSize {
            scaleFactor = min(maximumPixelSize / originalPixelWidth, maximumPixelSize / originalPixelHeight)
        }

        let targetPixelWidth = originalPixelWidth * scaleFactor
        let targetPixelHeight = originalPixelHeight * scaleFactor

        // 创建scale=1的上下文,确保逻辑尺寸与像素尺寸一致
        UIGraphicsBeginImageContextWithOptions(CGSize(width: targetPixelWidth, height: targetPixelHeight), false, 1.0)
        draw(in: CGRect(x: 0, y: 0, width: targetPixelWidth, height: targetPixelHeight))
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return resizedImage
    }
}

调用方式:

if let resizedImage = image.resizedImage(minimumPixelSize: 320, maximumPixelSize: 1536) {
    if let imageData = resizedImage.jpegData(compressionQuality: 1.0) {
        // 上传imageData
    }
}

方案2:使用Core Graphics直接操作CGImage(更可靠)

避免UIImage的scale干扰,直接基于CGImage的像素尺寸处理,适合对精度要求高的场景:

extension UIImage {
    func resizedImage(minimumPixelSize: CGFloat, maximumPixelSize: CGFloat) -> UIImage? {
        guard let cgImage = self.cgImage else { return nil }

        let originalPixelWidth = CGFloat(cgImage.width)
        let originalPixelHeight = CGFloat(cgImage.height)

        var scaleFactor: CGFloat = 1.0

        if originalPixelWidth < minimumPixelSize || originalPixelHeight < minimumPixelSize {
            scaleFactor = max(minimumPixelSize / originalPixelWidth, minimumPixelSize / originalPixelHeight)
        } else if originalPixelWidth > maximumPixelSize || originalPixelHeight > maximumPixelSize {
            scaleFactor = min(maximumPixelSize / originalPixelWidth, maximumPixelSize / originalPixelHeight)
        }

        let targetPixelWidth = Int(originalPixelWidth * scaleFactor)
        let targetPixelHeight = Int(originalPixelHeight * scaleFactor)

        // 创建Core Graphics上下文
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = cgImage.bitmapInfo.rawValue | CGImageAlphaInfo.premultipliedLast.rawValue

        guard let context = CGContext(data: nil,
                                      width: targetPixelWidth,
                                      height: targetPixelHeight,
                                      bitsPerComponent: cgImage.bitsPerComponent,
                                      bytesPerRow: 0,
                                      space: colorSpace,
                                      bitmapInfo: bitmapInfo) else { return nil }

        context.interpolationQuality = .high // 设置高质量插值
        context.draw(cgImage, in: CGRect(x: 0, y: 0, width: targetPixelWidth, height: targetPixelHeight))

        guard let resizedCGImage = context.makeImage() else { return nil }
        return UIImage(cgImage: resizedCGImage)
    }
}
验证方法

你可以通过以下代码确认缩放后的图像像素尺寸:

if let resizedImage = image.resizedImage(minimumPixelSize: 320, maximumPixelSize: 1536) {
    let pixelWidth = resizedImage.size.width * resizedImage.scale
    let pixelHeight = resizedImage.size.height * resizedImage.scale
    print("缩放后像素尺寸:\(pixelWidth)x\(pixelHeight)")
    
    if let imageData = resizedImage.jpegData(compressionQuality: 1.0),
       let reloadedImage = UIImage(data: imageData) {
        let reloadedPixelWidth = reloadedImage.size.width * reloadedImage.scale
        let reloadedPixelHeight = reloadedImage.size.height * reloadedImage.scale
        print("转Data后重新加载的像素尺寸:\(reloadedPixelWidth)x\(reloadedPixelHeight)")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:50:11