iosswiftuiimage

How do I resize the UIImage to reduce upload image size


I've been searching google, and have only come across libraries that either reduce the height/width or some how edit the UIImage appearance via CoreImage. But I have not seen or found one library, post that explains how to reduce image size so when it uploads, it's not the full image size.

so far I have this:

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

and it's sending 12MB photos. How can I reduce this to 1mb? thanks!


Solution

  • Swift 5 & Xcode 15

    I was not satisfied with the solutions here, which generate an image based on a given KB size, since most of them used .jpegData(compressionQuality: x). This method won't work with large images, since even with compression quality set to 0.0, the large image will remain large, e.g. a 10 MB produced by portrait mode of a newer iPhone still will be above 1 MB with compressionQuality set to 0.0.

    Therefore I used some answers here and rewrote a Helper Struct which converts an image in a background que:

    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 percentageDecrease = getPercentageToDecreaseTo(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 -= percentageDecrease
                }
                completion(iterationImage)
            }
        }
    
        private static func getPercentageToDecreaseTo(forDataCount dataCount: Int) -> CGFloat {
            switch dataCount {
            case 0..<5000000: return 0.03
            case 5000000..<10000000: return 0.1
            default: return 0.2
            }
        }
    }
    

    Compress an image to max 2 MB:

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