如何调整 UIImage 的大小以减小上传图像的大小

Posted

技术标签:

【中文标题】如何调整 UIImage 的大小以减小上传图像的大小【英文标题】:How do I resize the UIImage to reduce upload image size 【发布时间】:2015-03-19 05:00:02 【问题描述】:

我一直在搜索谷歌,并且只遇到过降低高度/宽度或通过 CoreImage 编辑 UIImage 外观的库。但是我还没有看到或找到一个库,帖子解释了如何减小图像大小,所以当它上传时,它不是完整的图像大小。

到目前为止,我有这个:

        if image != nil 
        //let data = NSData(data: UIImagePNGRepresentation(image))
        let data = UIImagePNGRepresentation(image)
        body.appendString("--\(boundary)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"image\"; filename=\"randomName\"\r\n")
        body.appendString("Content-Type: image/png\r\n\r\n")
        body.appendData(data)
        body.appendString("\r\n")
    

它正在发送 12MB 的照片。我怎样才能把它减少到1mb?谢谢!

【问题讨论】:

***.com/a/68063203/3269536 你可以使用它,它可能对你有帮助。 【参考方案1】:

Xcode 9 • Swift 4 或更高版本

编辑/更新:对于 ios10+ 我们可以使用UIGraphicsImageRenderer。对于较旧的 Swift 语法检查编辑历史记录。

extension UIImage 
    func resized(withPercentage percentage: CGFloat, isOpaque: Bool = true) -> UIImage? 
        let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
        let format = imageRendererFormat
        format.opaque = isOpaque
        return UIGraphicsImageRenderer(size: canvas, format: format).image 
            _ in draw(in: CGRect(origin: .zero, size: canvas))
        
    
    func resized(toWidth width: CGFloat, isOpaque: Bool = true) -> UIImage? 
        let canvas = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
        let format = imageRendererFormat
        format.opaque = isOpaque
        return UIGraphicsImageRenderer(size: canvas, format: format).image 
            _ in draw(in: CGRect(origin: .zero, size: canvas))
        
    

用法:

let image = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))!

let thumb1 = image.resized(withPercentage: 0.1)
let thumb2 = image.resized(toWidth: 72.0)

【讨论】:

伟大的东西,狮子座。谢谢。 您应该在下面添加 swift 2 语法。有人复制/粘贴了您的代码并获得了 9 次支持。如果您问我,这是不值得的... LeoDabus,我认为这不是正确的答案,但对于其他问题来说是非常好的解决方案。这里的问题是我们如何不基于百分比或图像大小(宽度或高度)而是基于文件大小将 12MB 减少到 1MB。 @EBDOKUM 可能会产生这种结果,因为减小图像大小(宽度和高度)并不能保证文件大小减小。只有大小被缩小,但文件大小可以根据使用的图像增加或减少。 @ChrisW。不是在谈论 Photoshop 或网络引擎。随时发布您对如何在 iOS (Swift) 中压缩 PNG 的问题的答案。 您应该添加guard size.width > width else return self ,这样较小的图像就不会被调整为更大。【参考方案2】:

这是我调整图像大小的方式。

 -(UIImage *)resizeImage:(UIImage *)image

   float actualHeight = image.size.height;
   float actualWidth = image.size.width;
   float maxHeight = 300.0;
   float maxWidth = 400.0;
   float imgRatio = actualWidth/actualHeight;
   float maxRatio = maxWidth/maxHeight;
   float compressionQuality = 0.5;//50 percent compression

   if (actualHeight > maxHeight || actualWidth > maxWidth)
   
    if(imgRatio < maxRatio)
    
        //adjust width according to maxHeight
        imgRatio = maxHeight / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = maxHeight;
    
    else if(imgRatio > maxRatio)
    
        //adjust height according to maxWidth
        imgRatio = maxWidth / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = maxWidth;
    
    else
    
        actualHeight = maxHeight;
        actualWidth = maxWidth;
    
   

   CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
   UIGraphicsBeginImageContext(rect.size);
   [image drawInRect:rect];
   UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
   NSData *imageData = UIImageJPEGRepresentation(img, compressionQuality);
   UIGraphicsEndImageContext();

   return [UIImage imageWithData:imageData];


使用这种方法,我的 6.5 MB 图像减少到 104 KB。

Swift 4 代码:

func resize(_ image: UIImage) -> UIImage 
    var actualHeight = Float(image.size.height)
    var actualWidth = Float(image.size.width)
    let maxHeight: Float = 300.0
    let maxWidth: Float = 400.0
    var imgRatio: Float = actualWidth / actualHeight
    let maxRatio: Float = maxWidth / maxHeight
    let compressionQuality: Float = 0.5
    //50 percent compression
    if actualHeight > maxHeight || actualWidth > maxWidth 
        if imgRatio < maxRatio 
            //adjust width according to maxHeight
            imgRatio = maxHeight / actualHeight
            actualWidth = imgRatio * actualWidth
            actualHeight = maxHeight
        
        else if imgRatio > maxRatio 
            //adjust height according to maxWidth
            imgRatio = maxWidth / actualWidth
            actualHeight = imgRatio * actualHeight
            actualWidth = maxWidth
        
        else 
            actualHeight = maxHeight
            actualWidth = maxWidth
        
    
    let rect = CGRect(x: 0.0, y: 0.0, width: CGFloat(actualWidth), height: CGFloat(actualHeight))
    UIGraphicsBeginImageContext(rect.size)
    image.draw(in: rect)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    let imageData = img?.jpegData(compressionQuality: CGFloat(compressionQuality)) 
    UIGraphicsEndImageContext()
    return UIImage(data: imageData!) ?? UIImage()

【讨论】:

分辨率怎么样?我想让宽度最大为 1024,但高度将取决于图像,所以我可以保持纵横比。 这里我也在压缩图像。如果您想要相同的分辨率注释此行 NSData *imageData = UIImageJPEGRepresentation(img, compressionQuality);我们必须选择 maxHeight 和 maxWidth 以使纵横比应该相同。 如何给出最小宽度和高度。这样该图像就不会被压缩到特定大小以下 SWIFT 4.2 更改这一行:让 imageData = UIImageJPEGRepresentation(img!, CGFloat(compressionQuality)) 改为:让 imageData = img?.jpegData(compressionQuality: CGFloat(compressionQuality))【参考方案3】:

如果有人希望使用 Swift 3 和 4 将图像调整大小小于 1MB

只需复制和粘贴这个扩展:

extension UIImage 

func resized(withPercentage percentage: CGFloat) -> UIImage? 
    let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
    UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
    defer  UIGraphicsEndImageContext() 
    draw(in: CGRect(origin: .zero, size: canvasSize))
    return UIGraphicsGetImageFromCurrentImageContext()


func resizedTo1MB() -> UIImage? 
    guard let imageData = UIImagePNGRepresentation(self) else  return nil 

    var resizingImage = self
    var imageSizeKB = Double(imageData.count) / 1000.0 // ! Or devide for 1024 if you need KB but not kB

    while imageSizeKB > 1000  // ! Or use 1024 if you need KB but not kB
        guard let resizedImage = resizingImage.resized(withPercentage: 0.9),
            let imageData = UIImagePNGRepresentation(resizedImage)
            else  return nil 

        resizingImage = resizedImage
        imageSizeKB = Double(imageData.count) / 1000.0 // ! Or devide for 1024 if you need KB but not kB
    

    return resizingImage


并且使用:

let resizedImage = originalImage.resizedTo1MB()

编辑: 请注意它是阻塞用户界面,所以如果您认为这适合您的情况,请转到后台线程

【讨论】:

while 循环的guard 中,UIImagePNGRepresentation 调用应该使用resizedImage,而不是resizingImage。导致它做一个额外的循环......【参考方案4】:

Swift 5.4 和 Xcode 13

我对这里的解决方案不满意,它根据给定的 KB 大小生成图像,因为它们中的大多数使用.jpegData(compressionQuality: x)。此方法不适用于大图像,因为即使将压缩质量设置为 0.0,大图像也会保持较大,例如在compressionQuality 设置为 0.0 的情况下,较新 iPhone 的纵向模式生成的 10 MB 仍将高于 1 MB。

因此,我在这里使用了一些答案,并重写了一个 Helper Struct,它可以在背景队列中转换图像:

import UIKit

struct ImageCompressor 
    static func compress(image: UIImage, maxByte: Int,
                         completion: @escaping (UIImage?) -> ()) 
        DispatchQueue.global(qos: .userInitiated).async 
            guard let currentImageSize = image.jpegData(compressionQuality: 1.0)?.count else 
                return completion(nil)
            
        
            var iterationImage: UIImage? = image
            var iterationImageSize = currentImageSize
            var iterationCompression: CGFloat = 1.0
        
            while iterationImageSize > maxByte && iterationCompression > 0.01 
                let percantageDecrease = getPercantageToDecreaseTo(forDataCount: iterationImageSize)
            
                let canvasSize = CGSize(width: image.size.width * iterationCompression,
                                        height: image.size.height * iterationCompression)
                UIGraphicsBeginImageContextWithOptions(canvasSize, false, image.scale)
                defer  UIGraphicsEndImageContext() 
                image.draw(in: CGRect(origin: .zero, size: canvasSize))
                iterationImage = UIGraphicsGetImageFromCurrentImageContext()
            
                guard let newImageSize = iterationImage?.jpegData(compressionQuality: 1.0)?.count else 
                    return completion(nil)
                
                iterationImageSize = newImageSize
                iterationCompression -= percantageDecrease
            
            completion(iterationImage)
        
    

    private static func getPercantageToDecreaseTo(forDataCount dataCount: Int) -> CGFloat 
        switch dataCount 
        case 0..<3000000: return 0.05
        case 3000000..<10000000: return 0.1
        default: return 0.2
        
    

将图像压缩到最大 1 MB:

        ImageCompressor.compress(image: image, maxByte: 1000000)  image in
            guard let compressedImage = image else  return 
            // Use compressedImage
        
    

【讨论】:

希望我能投票 100 次。真正的答案伙计们。 在我看来,迄今为止最好的答案。竖起大拇指。 此功能使性能优于其他功能。但是我有一个问题,使用此功能后创建了浅色边框。我怎样才能防止这种情况?提前谢谢你! @MyWill 你确定你使用的是上面的版本吗?我曾经也遇到过生成图像周围有黑色边框的问题,但是我更改了实现并在此处对其进行了更新,现在它对我来说工作正常。您使用的是哪个 iOS 版本和设备? @AliPacman 我使用了最新版本的代码,并在 iPhone X、iPhone 11、iOS 14 中进行了测试。生成的图像周围有一个浅色边框,而不是黑色边框。你可以在这里看到:imgur.com/a/EViUjva【参考方案5】:

与 Leo Answer 相同,但对 SWIFT 2.0 的修改很少

 extension UIImage 
    func resizeWithPercentage(percentage: CGFloat) -> UIImage? 
        let imageView = UIImageView(frame: CGRect(origin: .zero, size: CGSize(width: size.width * percentage, height: size.height * percentage)))
        imageView.contentMode = .ScaleAspectFit
        imageView.image = self
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
        guard let context = UIGraphicsGetCurrentContext() else  return nil 
        imageView.layer.renderInContext(context)
        guard let result = UIGraphicsGetImageFromCurrentImageContext() else  return nil 
        UIGraphicsEndImageContext()
        return result
    

    func resizeWithWidth(width: CGFloat) -> UIImage? 
        let imageView = UIImageView(frame: CGRect(origin: .zero, size: CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))))
        imageView.contentMode = .ScaleAspectFit
        imageView.image = self
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
        guard let context = UIGraphicsGetCurrentContext() else  return nil 
        imageView.layer.renderInContext(context)
        guard let result = UIGraphicsGetImageFromCurrentImageContext() else  return nil 
        UIGraphicsEndImageContext()
        return result
    

【讨论】:

评论有什么区别会很好 逻辑是一样的,但 leo 的答案是针对 swift 3.0 的,而我所做的只是在 swift 2.0 中编写它。【参考方案6】:

这是用户 4261201 的答案,但很快,我正在使用:

func compressImage (_ image: UIImage) -> UIImage 

    let actualHeight:CGFloat = image.size.height
    let actualWidth:CGFloat = image.size.width
    let imgRatio:CGFloat = actualWidth/actualHeight
    let maxWidth:CGFloat = 1024.0
    let resizedHeight:CGFloat = maxWidth/imgRatio
    let compressionQuality:CGFloat = 0.5

    let rect:CGRect = CGRect(x: 0, y: 0, width: maxWidth, height: resizedHeight)
    UIGraphicsBeginImageContext(rect.size)
    image.draw(in: rect)
    let img: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    let imageData:Data = UIImageJPEGRepresentation(img, compressionQuality)!
    UIGraphicsEndImageContext()

    return UIImage(data: imageData)!


【讨论】:

将 UIImage 转换为数据并返回 UIImage 是没有意义的。顺便说一句,您正在降低压缩它的图像质量。 @LeoDabus 感谢您的洞察力,我会选择您的答案作为正确答案!【参考方案7】:

Swift4.2

  let imagedata = yourImage.jpegData(compressionQuality: 0.1)!

【讨论】:

【参考方案8】:

我认为这里问题的核心是如何在上传到服务器之前可靠地将 UIImage 的数据缩小到一定大小,而不是仅仅缩小 UIImage 本身。

如果您不需要压缩到特定大小,则使用 func jpegData(compressionQuality: CGFloat) -&gt; Data? 效果很好。但是,在某些情况下,我发现能够压缩到某个指定的文件大小以下很有用。在这种情况下,jpegData 是不可靠的,并且以这种方式迭代压缩图像会导致文件大小停滞(并且可能非常昂贵)。相反,我更喜欢像Leo's answer 那样减小 UIImage 本身的大小,然后转换为 jpegData 并反复检查减小的大小是否低于我选择的值(在我设置的边距内)。我根据当前文件大小与所需文件大小的比率调整压缩步骤乘数,以加快最昂贵的第一次迭代(因为此时文件大小最大)。

斯威夫特 5

extension UIImage 
    func resized(withPercentage percentage: CGFloat, isOpaque: Bool = true) -> UIImage? 
        let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
        let format = imageRendererFormat
        format.opaque = isOpaque
        return UIGraphicsImageRenderer(size: canvas, format: format).image 
            _ in draw(in: CGRect(origin: .zero, size: canvas))
        
    
    
    func compress(to kb: Int, allowedMargin: CGFloat = 0.2) -> Data 
        guard kb > 10 else  return Data()  // Prevents user from compressing below a limit (10kb in this case).
        let bytes = kb * 1024
        var compression: CGFloat = 1.0
        let step: CGFloat = 0.05
        var holderImage = self
        var complete = false
        while(!complete) 
            guard let data = holderImage.jpegData(compressionQuality: 1.0) else  break 
            let ratio = data.count / bytes
            if data.count < Int(CGFloat(bytes) * (1 + allowedMargin)) 
                complete = true
                return data
             else 
                let multiplier:CGFloat = CGFloat((ratio / 5) + 1)
                compression -= (step * multiplier)
            
            guard let newImage = holderImage.resized(withPercentage: compression) else  break 
            holderImage = newImage
        
        
        return Data()
    

 

及用法:

let data = image.compress(to: 1000)

【讨论】:

您返回的是一个空数据。我猜你的意思是return data @BawenangRukmokoPardianPutra 在这个函数中没有被调用,它只是满足函数的返回类型。数据在 while 循环的 if 语句中返回。我可能应该重构抛出或使用选项的答案,但为了使用简单。我还应该添加一个保护语句,以不允许压缩到不切实际的小值。 添加了保护语句以防止compress to 0 的情况,并将压缩限制在一个合理的值(本例中为 10kb)。 啊,是的,我的错。我现在看到了。 @Begbie 那行有点武断。最初的目的是根据current data size : target data size的比例来调整压缩百分比。 5 稍微减慢了压缩率,这样您就不会根据完整比率压缩数据,这会导致最终数据大小不准确。 1 确保它始终在压缩直到达到目标大小,从而防止无限循环。这条线/神奇的数字可以改进。【参考方案9】:

如果您以NSData 格式上传图片,请使用:

NSData *imageData = UIImageJPEGRepresentation(yourImage, floatValue);

yourImage 是您的UIImagefloatvalue 是压缩值(0.0 到 1.0)

以上是将图片转换为JPEG

对于PNG使用:UIImagePNGRepresentation

注意:以上代码在 Objective-C 中。请检查如何在 Swift 中定义 NSData。

【讨论】:

如果我担心分辨率,我将如何设置最大宽度,但让高度由图像本身决定? UIImagePNGRepresentation 没有压缩选项。【参考方案10】:

根据Tung Fam的回答。调整为特定文件大小。像 0.7 MB 一样,您可以使用此代码。

extension UIImage 

func resize(withPercentage percentage: CGFloat) -> UIImage? 
    var newRect = CGRect(origin: .zero, size: CGSize(width: size.width*percentage, height: size.height*percentage))
    UIGraphicsBeginImageContextWithOptions(newRect.size, true, 1)
    self.draw(in: newRect)
    defer UIGraphicsEndImageContext()
    return UIGraphicsGetImageFromCurrentImageContext()


func resizeTo(MB: Double) -> UIImage? 
    guard let fileSize = self.pngData()?.count else return nil
    let fileSizeInMB = CGFloat(fileSize)/(1024.0*1024.0)//form bytes to MB
    let percentage = 1/fileSizeInMB
    return resize(withPercentage: percentage)


【讨论】:

您的 MB 变量未使用,导致创建的图像很小【参考方案11】:

使用它你可以控制你想要的大小:

func jpegImage(image: UIImage, maxSize: Int, minSize: Int, times: Int) -> Data? 
    var maxQuality: CGFloat = 1.0
    var minQuality: CGFloat = 0.0
    var bestData: Data?
    for _ in 1...times 
        let thisQuality = (maxQuality + minQuality) / 2
        guard let data = image.jpegData(compressionQuality: thisQuality) else  return nil 
        let thisSize = data.count
        if thisSize > maxSize 
            maxQuality = thisQuality
         else 
            minQuality = thisQuality
            bestData = data
            if thisSize > minSize 
                return bestData
            
        
    
    return bestData

方法调用示例:

jpegImage(image: image, maxSize: 500000, minSize: 400000, times: 10)  

它将尝试获取介于 maxSize 和 minSize 的最大和最小大小之间的文件,但只会尝试多次。如果在这段时间内失败,它将返回 nil。

【讨论】:

【参考方案12】:

我认为最简单的方法是swift本身提供的将图像压缩成压缩数据的方法,下面是swift 4.2中的代码

let imageData = yourImageTobeCompressed.jpegData(compressionQuality: 0.5)

你可以发送这个 imageData 上传到服务器。

【讨论】:

【参考方案13】:

这是我在 swift 3 中为调整 UIImage 大小所做的。它将图像大小减小到小于 100kb。它按比例工作!

extension UIImage 
    class func scaleImageWithDivisor(img: UIImage, divisor: CGFloat) -> UIImage 
        let size = CGSize(width: img.size.width/divisor, height: img.size.height/divisor)
        UIGraphicsBeginImageContext(size)
        img.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return scaledImage!
    

用法:

let scaledImage = UIImage.scaleImageWithDivisor(img: capturedImage!, divisor: 3)

【讨论】:

【参考方案14】:

在 Objective-C 中也一样:

界面:

@interface UIImage (Resize)

- (UIImage *)resizedWithPercentage:(CGFloat)percentage;
- (UIImage *)resizeTo:(CGFloat)weight isPng:(BOOL)isPng jpegCompressionQuality:(CGFloat)compressionQuality;

@end

实施:

#import "UIImage+Resize.h"

@implementation UIImage (Resize)

- (UIImage *)resizedWithPercentage:(CGFloat)percentage 
    CGSize canvasSize = CGSizeMake(self.size.width * percentage, self.size.height * percentage);
    UIGraphicsBeginImageContextWithOptions(canvasSize, false, self.scale);
    [self drawInRect:CGRectMake(0, 0, canvasSize.width, canvasSize.height)];
    UIImage *sizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return sizedImage;


- (UIImage *)resizeTo:(CGFloat)weight isPng:(BOOL)isPng jpegCompressionQuality:(CGFloat)compressionQuality 
    NSData *imageData = isPng ? UIImagePNGRepresentation(self) : UIImageJPEGRepresentation(self, compressionQuality);
    if (imageData && [imageData length] > 0) 
        UIImage *resizingImage = self;
        double imageSizeKB = [imageData length] / weight;

        while (imageSizeKB > weight) 
            UIImage *resizedImage = [resizingImage resizedWithPercentage:0.9];
            imageData = isPng ? UIImagePNGRepresentation(resizedImage) : UIImageJPEGRepresentation(resizedImage, compressionQuality);
            resizingImage = resizedImage;
            imageSizeKB = (double)(imageData.length / weight);
        

        return resizingImage;
    
    return nil;

用法:

#import "UIImage+Resize.h"

UIImage *resizedImage = [self.picture resizeTo:2048 isPng:NO jpegCompressionQuality:1.0];

【讨论】:

【参考方案15】:

当我尝试使用公认的答案来调整图像大小以用于我的项目时,它会变得非常像素化和模糊。我最终得到了这段代码来调整图像大小而不添加像素化或模糊:

func scale(withPercentage percentage: CGFloat)-> UIImage? 
        let cgSize = CGSize(width: size.width * percentage, height: size.height * percentage)

        let hasAlpha = true
        let scale: CGFloat = 0.0 // Use scale factor of main screen

        UIGraphicsBeginImageContextWithOptions(cgSize, !hasAlpha, scale)
        self.draw(in: CGRect(origin: CGPoint.zero, size: cgSize))

        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        return scaledImage
    

【讨论】:

【参考方案16】:

我在研究 Swift 中的图像压缩和导出时遇到了这个问题,并以此为起点来更好地理解问题并推导出更好的技术。

UIGraphicsBeginImageContext()、UIGraphicsGetImageFromCurrentImageContext()、UIGraphicsEndImageContext() 过程是一种较旧的技术,已被 UIGraphicsImageRenderer 取代,如 iron_john_bonney 和 leo-dabus 使用的那样。他们的示例是作为 UIImage 的扩展编写的,而我选择编写一个独立的函数。方法上所需的差异可以通过比较来识别(查看和靠近 UIGraphicsImageRenderer 调用),并且可以很容易地移植回 UIImage 扩展。

我认为这里使用的压缩算法有改进的潜力,所以我采取了一种方法,首先将图像调整为具有给定的总像素数,然后通过调整 jpeg 压缩来压缩它以达到指定的最终文件大小。指定像素总数的目的是避免陷入图像纵横比问题。虽然我没有做过详尽的调查,但我怀疑将图像缩放到指定的总像素数会使最终的 jpeg 图像文件大小在一个一般范围内,然后可以使用 jpeg 压缩来确保文件大小限制以可接受的图像质量实现,前提是初始像素数不太高。

在使用 UIGraphicsImageRenderer 时,CGRect 在主机 Apple 设备上以 逻辑 像素指定,这与输出 jpeg 中的实际像素不同。查找设备像素比率以了解这一点。为了获得设备像素比,我尝试从环境中提取它,但这些技术导致 Playground 崩溃,因此我使用了一种效率较低的技术。

如果您将此代码粘贴到 Xcode playround 中并将适当的 .jpg 文件放置在 Resources 文件夹中,则输出文件将放置在 Playground 输出文件夹中(使用实时视图中的快速查看来查找此位置)。

import UIKit

func compressUIImage(_ image: UIImage?, numPixels: Int, fileSizeLimitKB: Double, exportImage: Bool) -> Data 
    var returnData: Data
    if let origWidth = image?.size.width,
       let origHeight = image?.size.height 
        print("Original image size =", origWidth, "*", origHeight, "pixels")

        let imgMult = min(sqrt(CGFloat(numPixels)/(origWidth * origHeight)), 1) // This multiplier scales the image to have the desired number of pixels
        print("imageMultiplier =", imgMult)

        let cgRect = CGRect(origin: .zero, size: CGSize(width: origWidth * imgMult, height: origHeight * imgMult)) // This is in *logical* pixels
        let renderer = UIGraphicsImageRenderer(size: cgRect.size)
        
        let img = renderer.image  ctx in
            image?.draw(in: cgRect)
        
        
        // Now get the device pixel ratio if needed...
        var img_scale: CGFloat = 1
        if exportImage 
            img_scale = img.scale
        
        print("Image scaling factor =", img_scale)

        // ...and use to ensure *output* image has desired number of pixels
        let cgRect_scaled = CGRect(origin: .zero, size: CGSize(width: origWidth * imgMult/img_scale, height: origHeight * imgMult/img_scale)) // This is in *logical* pixels
        print("New image size (in logical pixels) =", cgRect_scaled.width, "*", cgRect_scaled.height, "pixels") // Due to device pixel ratios, can have fractional pixel dimensions

        let renderer_scaled = UIGraphicsImageRenderer(size: cgRect_scaled.size)

        let img_scaled = renderer_scaled.image  ctx in
            image?.draw(in: cgRect_scaled)
        

        var compQual = CGFloat(1.0)

        returnData = img_scaled.jpegData(compressionQuality: 1.0)!
        var imageSizeKB = Double(returnData.count) / 1000.0
        
        print("compressionQuality =", compQual, "=> imageSizeKB =", imageSizeKB, "KB")
        while imageSizeKB > fileSizeLimitKB 
            compQual *= 0.9
            returnData = img_scaled.jpegData(compressionQuality: compQual)!
            imageSizeKB = Double(returnData.count) / 1000.0
            print("compressionQuality =", compQual, "=> imageSizeKB =", imageSizeKB, "KB")
        
     else 
        returnData = Data()
    
    return returnData


let image_orig = UIImage(named: "input.jpg")

let image_comp_data = compressUIImage(image_orig, numPixels: Int(4e6), fileSizeLimitKB: 1300, exportImage: true)

func getDocumentsDirectory() -> URL 
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return paths[0]


let filename = getDocumentsDirectory().appendingPathComponent("output.jpg")

try? image_comp_data.write(to: filename)

来源包括Jordan Morgan和Hacking with Swift。

【讨论】:

【参考方案17】:
extension UIImage 
func resized(toValue value: CGFloat) -> UIImage 
    if size.width > size.height 
        return self.resize(toWidth: value)!
     else 
        return self.resize(toHeight: value)!
    

【讨论】:

【参考方案18】:

使用 .resizeToMaximumBytes 调整 UIImage 的大小

【讨论】:

以上是关于如何调整 UIImage 的大小以减小上传图像的大小的主要内容,如果未能解决你的问题,请参考以下文章

UIImage 大小(宽度和高度)在旋转后减小

在上传到Google Cloud存储之前调整图像大小并进行压缩

调整uiimage中的图像大小并将其以新大小保存到相册

如何将 UIImage 调整为特定大小

iOS Swift UIImage 调整大小影响性能的问题;调整大小时出现意外尺寸[重复]

从解析仪表板上传时如何减小图像大小