Skip to content

Instantly share code, notes, and snippets.

@akshay1188
Last active June 10, 2023 16:42
Show Gist options
  • Save akshay1188/4749253 to your computer and use it in GitHub Desktop.
Save akshay1188/4749253 to your computer and use it in GitHub Desktop.
Whatsapp like image compression
- (UIImage *)compressImage:(UIImage *)image{
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float maxHeight = 600.0;
float maxWidth = 800.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];
}
@ikvision
Copy link

Usually when an image is already small enough in size, we would not want to reduce its quality to 50%

else{
           actualHeight = maxHeight;
           actualWidth = maxWidth;
           compressionQuality = 1;
        }

@GripsOnLtd
Copy link

Does anybody know what the swift code for the above is? Noobie not knowing how to modify the code for swift. also where would I place this code?

@GripsOnLtd
Copy link

I managed to complete it with swift code below:

@IBAction func signUp(sender: AnyObject) {

    let imageData = UIImagePNGRepresentation(self.profilePic.image)

    let image = UIImage(data: imageData)

    func compressImage(image:UIImage) -> NSData {
        // Reducing file size to a 10th

        var actualHeight : CGFloat = image.size.height
        var actualWidth : CGFloat = image.size.width
        var maxHeight : CGFloat = 1136.0
        var maxWidth : CGFloat = 640.0
        var imgRatio : CGFloat = actualWidth/actualHeight
        var maxRatio : CGFloat = maxWidth/maxHeight
        var compressionQuality : CGFloat = 0.5

        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;
                compressionQuality = 1;
            }
        }

        var rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
        UIGraphicsBeginImageContext(rect.size);
        image.drawInRect(rect)
        var img = UIGraphicsGetImageFromCurrentImageContext();
        let imageData = UIImageJPEGRepresentation(img, compressionQuality);
        UIGraphicsEndImageContext();

        return imageData;
    }

    let compressedImage = compressImage(image!)

    let picture = PFFile(name: "image.png", data: compressedImage)

    PFUser.currentUser()!.setObject(picture, forKey: "profilePic")
    PFUser.currentUser()!.saveInBackgroundWithBlock {
        (success: Bool, error: NSError?) -> Void in
        if (success) {
            println("image has been saved")
        } else {
            println("image failed")
        }
    }
}

@smn-khan
Copy link

smn-khan commented May 3, 2016

how to decompress the image compressed with above method ..

@NitzDKoder
Copy link

decompress ? you already have the uncompressed image right? whats the use case?

Once you compress the image data is changed..there is no option to get the original image back..

@mpc20001
Copy link

mpc20001 commented Jul 2, 2017

Modified for Swift 3

func compressImage(image:UIImage) -> Data? {
// Reducing file size to a 10th

    var actualHeight : CGFloat = image.size.height
    var actualWidth : CGFloat = image.size.width
    let maxHeight : CGFloat = 1136.0
    let maxWidth : CGFloat = 640.0
    var imgRatio : CGFloat = actualWidth/actualHeight
    let maxRatio : CGFloat = maxWidth/maxHeight
    var compressionQuality : CGFloat = 0.5

    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
            compressionQuality = 1
        }
    }

    let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
    UIGraphicsBeginImageContext(rect.size)
    image.draw(in: rect)
    guard let img = UIGraphicsGetImageFromCurrentImageContext() else {
        return nil
    }
    UIGraphicsEndImageContext()
    guard let imageData = UIImageJPEGRepresentation(img, compressionQuality)else{
        return nil
    }
    return imageData
}

@Ambarsetya
Copy link

the compression using pa algorithm? whether the method is lossy or lossless

@ranand16
Copy link

ranand16 commented Apr 5, 2018

why would someone use this technique on the client side( for swift )? It will be better to use this compression technique on the server side after the user uploads the image to server. Keep both the original and lower version of the image to use lower quality at thumbnails and original size at the time of some real use. Also this method would allow users to access images at lower bandwidth.

Can someone give the same method using javascript(node) (one may use Jimp or imagemagick)??

@rajeshm20
Copy link

useful thanks

@mikengyn
Copy link

mikengyn commented May 11, 2018

@ranand16 to improve uploading times and decrease data usage. Using a technique similar to this one I was able to save about 4-5mb on each of my photos before uploading them to my server. The images look almost identical in quality on device and I was able to shave 6-7 seconds on the time it took for the image to upload.

@ahmedAlmasri
Copy link

Migration swift 4 add extension

extension UIImage {
    
    func compressImage() -> UIImage? {
        // Reducing file size to a 10th
        var actualHeight: CGFloat = self.size.height
        var actualWidth: CGFloat = self.size.width
        let maxHeight: CGFloat = 1136.0
        let maxWidth: CGFloat = 640.0
        var imgRatio: CGFloat = actualWidth/actualHeight
        let maxRatio: CGFloat = maxWidth/maxHeight
        var compressionQuality: CGFloat = 0.5
        
        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
                compressionQuality = 1
            }
        }
        let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
        UIGraphicsBeginImageContext(rect.size)
        self.draw(in: rect)
        guard let img = UIGraphicsGetImageFromCurrentImageContext() else {
            return nil
        }
        UIGraphicsEndImageContext()
        guard let imageData = UIImageJPEGRepresentation(img, compressionQuality) else {
            return nil
        }
        return UIImage(data: imageData)
    }

}

@fozoglu
Copy link

fozoglu commented Nov 21, 2018

Revised @ahmedAlmasri answer for swift 4.2

`
extension UIImage {

func compressImage() -> UIImage? {
    // Reducing file size to a 10th
    var actualHeight: CGFloat = self.size.height
    var actualWidth: CGFloat = self.size.width
    let maxHeight: CGFloat = 1136.0
    let maxWidth: CGFloat = 640.0
    var imgRatio: CGFloat = actualWidth/actualHeight
    let maxRatio: CGFloat = maxWidth/maxHeight
    var compressionQuality: CGFloat = 0.5
    
    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
            compressionQuality = 1
        }
    }
    let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
    UIGraphicsBeginImageContext(rect.size)
    self.draw(in: rect)
    guard let img = UIGraphicsGetImageFromCurrentImageContext() else {
        return nil
    }
    UIGraphicsEndImageContext()
    guard let imageData = img.jpegData(compressionQuality: compressionQuality) else {
        return nil
    }
    return UIImage(data: imageData)
}

}
`

@ankit21patel
Copy link

i was implement this below code but it's show me unused give me warning :- Result of call to 'compressImage(image:)' is unused

func compressImage(image:UIImage) -> Data? {
// Reducing file size to a 10th

    var actualHeight : CGFloat = image.size.height
    var actualWidth : CGFloat = image.size.width
    let maxHeight : CGFloat = 1136.0
    let maxWidth : CGFloat = 640.0
    var imgRatio : CGFloat = actualWidth/actualHeight
    let maxRatio : CGFloat = maxWidth/maxHeight
    var compressionQuality : CGFloat = 0.5
    
    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
            compressionQuality = 1
        }
    }
    
    let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
    UIGraphicsBeginImageContext(rect.size)
    image.draw(in: rect)
    guard let img = UIGraphicsGetImageFromCurrentImageContext() else {
        return nil
    }
    UIGraphicsEndImageContext()
    guard let imageData = img.jpegData(compressionQuality: compressionQuality)else{

        return nil
    }
    return imageData
}

@arindamIos
Copy link

great useful

@piyush23dez
Copy link

very helpful.

@GSerjo
Copy link

GSerjo commented Mar 19, 2020

swift 5

    func resize() -> Data? {
        
        let maxHeight: CGFloat = 1136
        let maxWidth: CGFloat = 640
        
        var actualHeight = self.size.height
        var actualWidth = self.size.width

        var imgRatio = actualWidth / actualHeight
        let maxRatio = maxWidth / maxHeight
        var compressionQuality : CGFloat = 0.6
        
        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
                compressionQuality = 1
            }
        }
        
        let canvas = CGSize(width: actualWidth, height: actualHeight)
        let format = imageRendererFormat
        format.opaque = true
        let result = UIGraphicsImageRenderer(size: canvas, format: format).image {
            _ in draw(in: CGRect(origin: .zero, size: canvas))
        }
        return result.jpegData(compressionQuality: compressionQuality)
    }

@diegogarciar
Copy link

Hello,
One question, from where does maxHeight and maxWidth come from? was it also taken from WhatsApp?

@GSerjo
Copy link

GSerjo commented Oct 4, 2020

Hi Diego,

maybe, a bit difficult to check (the initial version has been created 5 years ago).. in the current WhatsApp version I see 768*1024. here how you can see maxHeight and maxWidth

  • open WhatsApp on a computer
  • download an image
  • check dimensions

@diegogarciar
Copy link

Thanks, so I did that and it currently is 1280x960. But I disagree with compressionQuality = 1 in the else statement as that's the scenario where the ratios are the same, but the original image is obviously bigger, not smaller, so I do want it compressed.

@knox
Copy link

knox commented Jan 24, 2021

Resizing with UIGraphicsImageRenderer is dead simple but consumes a lot of memory. So i suggest to use CGContext instead:

extension UIImage {
    func compressedData() -> Data? {
        let maxHeight: CGFloat = 1136
        let maxWidth: CGFloat = 640

        var actualHeight = size.height
        var actualWidth = size.width

        var imgRatio = actualWidth / actualHeight
        let maxRatio = maxWidth / maxHeight
        var compressionQuality : CGFloat = 0.6

        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
                compressionQuality = 1
            }
        }

        guard let cgImage = cgImage else { return nil }

        let mutableData = NSMutableData()
        guard let imageDestinationRef = CGImageDestinationCreateWithData(mutableData as CFMutableData, kUTTypeJPEG, 1, nil) else { return nil }
        let options: NSDictionary = [
            kCGImageDestinationLossyCompressionQuality: compressionQuality
        ]
        CGImageDestinationAddImage(imageDestinationRef, cgImage, options)
        guard CGImageDestinationFinalize(imageDestinationRef) else { return nil }

        return mutableData as Data
    }
}

@YogeshPateliOS
Copy link

@knox kUTTypeJPEG deprecated

@MounikaMadishetti
Copy link

@YogeshPateliOS We can use UTType. jpeg.identifier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment