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

Ios 如何调整UIImage的大小以减小上载图像的大小,ios,swift,uiimage,Ios,Swift,Uiimage,我一直在谷歌上搜索,只遇到过一些库,它们要么降低了高度/宽度,要么通过CoreImage编辑UIImage的外观。但我还没有看到或找到一个库,这篇文章解释了如何减少图像大小,所以当它上传时,它不是完整的图像大小 到目前为止,我有: if image != nil { //let data = NSData(data: UIImagePNGRepresentation(image)) let data = UIImagePNGRepresentati

我一直在谷歌上搜索,只遇到过一些库,它们要么降低了高度/宽度,要么通过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?谢谢

如果要以
NSData
格式上载图像,请使用以下方法:

NSData *imageData = UIImageJPEGRepresentation(yourImage, floatValue);
yourImage
是您的
UIImage
floatvalue
是压缩值(0.0到1.0)

以上是将图像转换为
JPEG

对于
PNG
使用:
UIImagePNGRepresentation


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

这是我调整图像大小所遵循的方法

 -(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];

}
-(UIImage*)大小图像:(UIImage*)图像
{
浮动实际高度=image.size.height;
浮动实际宽度=image.size.width;
浮动最大高度=300.0;
浮动最大宽度=400.0;
浮动高度=实际宽度/实际高度;
浮点最大比值=最大宽度/最大高度;
浮点压缩质量=0.5;//50%压缩
如果(实际高度>最大高度| |实际宽度>最大宽度)
{
if(imgRatiomaxRatio)
{
//根据maxWidth调整高度
imgRatio=最大宽度/实际宽度;
实际高度=平均*实际高度;
实际宽度=最大宽度;
}
其他的
{
实际高度=最大高度;
实际宽度=最大宽度;
}
}
CGRect rect=CGRectMake(0.0,0.0,实际宽度,实际高度);
UIGraphicsBeginImageContext(矩形大小);
[image drawInRect:rect];
UIImage*img=UIGraphicsGetImageFromCurrentImageContext();
NSData*imageData=UIIMAGEJPEG表示法(img,压缩质量);
UIGraphicsSendImageContext();
返回[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()
}
let resizedImage = originalImage.resizedTo1MB()
func resize(image:UIImage)->UIImage{
var actualHeight=Float(image.size.height)
var actualWidth=Float(image.size.width)
设最大高度:浮动=300.0
设maxWidth:Float=400.0
变量imgRatio:Float=实际宽度/实际高度
设maxRatio:Float=maxWidth/maxHeight
让压缩质量:浮动=0.5
//50%压缩
如果实际高度>最大高度| |实际宽度>最大宽度{
如果imgRatiomaxRatio{
//根据maxWidth调整高度
imgRatio=最大宽度/实际宽度
实际高度=绝对高度*实际高度
实际宽度=最大宽度
}
否则{
实际高度=最大高度
实际宽度=最大宽度
}
}
设rect=CGRect(x:0.0,y:0.0,宽度:CGFloat(实际宽度),高度:CGFloat(实际高度))
UIGraphicsBeginImageContext(矩形大小)
image.draw(in:rect)
设img=UIGraphicsGetImageFromCurrentImageContext()
让imageData=img?.jpegData(压缩质量:CGFloat(压缩质量))
UIGraphicsSendImageContext()
返回UIImage(数据:imageData!)??UIImage()
}

Xcode 9•Swift 4或更高版本

编辑/更新:对于iOS10+我们可以使用。对于较旧的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)

与Leo答案相同,但对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
    }
}

以下是user4261201的答案,但使用的是swift,我目前正在使用:

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)!

}

如果有人正在使用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
}
}
使用:

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()
}
let resizedImage = originalImage.resizedTo1MB()
编辑:
请注意,它正在阻止UI,因此如果您认为这是适合您的情况的正确方法,请转到背景线程。

使用.resizeToMaximumBytes调整UIImage的大小。这是我在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)

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

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)
}
}

使用此选项,您可以控制所需的大小:

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。

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

让imageData=yourImageTobeCompressed.jpegData(压缩质量:0.5)

您可以将这些图像数据上传到服务器。

Swift4.2

  let imagedata = yourImage.jpegData(compressionQuality: 0.1)!
目标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];

当我尝试使用公认的答案来调整图像大小以便在我的项目中使用时,它会变得非常像素化和模糊。最后,我编写了一段代码,可以在不添加像素或模糊的情况下调整图像大小:

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
    }

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

如果不需要压缩到特定大小,则使用
func-jpegData(压缩质量:CGFloat)->Data?
效果很好。但是,在某些情况下,我发现能够压缩到指定的文件大小以下是很有用的。在里面
let data = image.compress(to: 1000)
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
        }
    }
}
        ImageCompressor.compress(image: image, maxByte: 1000000) { image in
            guard let compressedImage = image else { return }
            // Use compressedImage
        }
    }