436

In my iPhone app, I take a picture with the camera, then I want to resize it to 290*390 pixels. I was using this method to resize the image :

UIImage *newImage = [image _imageScaledToSize:CGSizeMake(290, 390)
                         interpolationQuality:1];    

It works perfectly, but it's an undocumented function, so I can't use it anymore with iPhone OS4.

So... what is the simplest way to resize an UIImage ?

Erik Godard
  • 5,930
  • 6
  • 30
  • 33
pimpampoum
  • 5,816
  • 6
  • 24
  • 27

34 Answers34

788

The simplest way is to set the frame of your UIImageView and set the contentMode to one of the resizing options.

Or you can use this utility method, if you actually need to resize an image:

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    //UIGraphicsBeginImageContext(newSize);
    // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
    // Pass 1.0 to force exact pixel size.
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

Example usage:

#import "MYUtil.h"
…
UIImage *myIcon = [MYUtil imageWithImage:myUIImageInstance scaledToSize:CGSizeMake(20, 20)];
Paul Lynch
  • 19,769
  • 4
  • 37
  • 41
  • 29
    [As of iOS 4.0](http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html#//apple_ref/doc/uid/TP40009559-SW29), the UIGraphics* functions are all thread-safe. – BJ Homer Feb 18 '11 at 21:00
  • 1
    Just want to note here if you're using this in share extension (where memory is limitted ~100MB). You should use scale factor 0 in UIGraphicsBeginImageContextWithOptions. Otherwise, extension can be crash with some big image – Tran Quan Mar 22 '21 at 13:47
117

Proper Swift 3.0 for iOS 10+ solution: Using ImageRenderer and closure syntax:

extension UIImage {
    func imageWith(newSize: CGSize) -> UIImage {
        let image = UIGraphicsImageRenderer(size: newSize).image { _ in
            draw(in: CGRect(origin: .zero, size: newSize))
        }
        
        return image.withRenderingMode(renderingMode)
    }
}

And here's the Objective-C version:

@implementation UIImage (ResizeCategory)
- (UIImage *)imageWithSize:(CGSize)newSize
{
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize];
    UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) {
        [self drawInRect:(CGRect) {.origin = CGPointZero, .size = newSize}];
    }];
    return [image imageWithRenderingMode:self.renderingMode];
}
@end
Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
Jakub Průša
  • 2,255
  • 1
  • 14
  • 19
  • 2
    This is better than elegant, it's correct. Apple's api docs advise new code to use UIGraphicsRenderer as this code does. Thank you – Paul Bruneau Jul 27 '17 at 16:47
  • 1
    @appsunited The question is almost 8 years old . And this method only works for **iOS10+** as stated. –  Jul 29 '17 at 15:53
  • When copying the new image object to the clipboard it produces a white block for me. It's not actually resizing the image view? – Oliver Dixon Mar 18 '19 at 21:01
  • 1
    this function returning an image of 0 height and 0 width, expect height is 9000 height and 9000 width. – krishan kumar May 16 '19 at 06:14
  • Note that this doesn't resize the underlying CGImage (at least in iOS 12.1). Which is okay based on the question, but if you are writing out the image, you'll have to use the cgImage, and you'll get the original image. – prewett Jun 14 '19 at 20:40
  • This doesn't work for me. The resized image is completely corrupt, and cause my app to crash. – NeoWang Jun 21 '19 at 06:42
  • As @prewett said this doesn't resize the underlying image so if you try and write it out with a call to .pngData() it gives you the original size. The accepted answer does give you the exact size you want if you use 1.0 as the scale. – Locutus Nov 04 '19 at 02:01
  • this creates pure white image as a result. does not work for me. – IDev Nov 12 '21 at 07:35
  • @prewett As of Xcode 13.2.1, `UIGraphicsImageRenderer` creates a new `CGImage` with a new size to reflect the new `UIImage`. – Gary Feb 10 '22 at 08:59
92

Here's a Swift version of Paul Lynch's answer

func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
    image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

And as an extension:

public extension UIImage {
    func copy(newSize: CGSize, retina: Bool = true) -> UIImage? {
        // In next line, pass 0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
        // Pass 1 to force exact pixel size.
        UIGraphicsBeginImageContextWithOptions(
            /* size: */ newSize,
            /* opaque: */ false,
            /* scale: */ retina ? 0 : 1
        )
        defer { UIGraphicsEndImageContext() }

        self.draw(in: CGRect(origin: .zero, size: newSize))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}
Ky -
  • 30,724
  • 51
  • 192
  • 308
Rogerio Chaves
  • 2,719
  • 2
  • 25
  • 24
  • 2
    just noted that, in iOS, your newSize will multiple by 2x, 3x based on device – Sruit A.Suk Aug 22 '15 at 08:56
  • 9
    UIGraphicsBeginImageContextWithOptions(newSize, false, image.scale); for all devices – phnmnn May 02 '16 at 13:02
  • Note that this doesn't resize the underlying CGImage (at least in iOS 12.1). Which is okay based on the question, but if you are writing out the image, you'll have to use the cgImage, and you'll get the original image. – prewett Jun 14 '19 at 20:41
  • that scale for scaleToFill only – famfamfam Apr 04 '21 at 12:36
66

A more compact version for Swift 4 and iOS 10+:

extension UIImage {
    func resized(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

Usage:

let resizedImage = image.resized(to: CGSize(width: 50, height: 50))
neave
  • 2,482
  • 1
  • 26
  • 18
40

Swift solution for Stretch Fill, Aspect Fill and Aspect Fit

extension UIImage {
    enum ContentMode {
        case contentFill
        case contentAspectFill
        case contentAspectFit
    }
    
    func resize(withSize size: CGSize, contentMode: ContentMode = .contentAspectFill) -> UIImage? {
        let aspectWidth = size.width / self.size.width
        let aspectHeight = size.height / self.size.height
        
        switch contentMode {
        case .contentFill:
            return resize(withSize: size)
        case .contentAspectFit:
            let aspectRatio = min(aspectWidth, aspectHeight)
            return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
        case .contentAspectFill:
            let aspectRatio = max(aspectWidth, aspectHeight)
            return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
        }
    }
    
    private func resize(withSize size: CGSize) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

and to use you can do the following:

let image = UIImage(named: "image.png")!
let newImage = image.resize(withSize: CGSize(width: 200, height: 150), contentMode: .contentAspectFill)

Thanks to abdullahselek for his original solution.

Community
  • 1
  • 1
Josh Bernfeld
  • 4,246
  • 2
  • 32
  • 35
30

Trevor Howard has some UIImage categories that handle resize quite nicely. If nothing else you can use the code as examples.

Note: As of iOS 5.1, this answer maybe invalid. See comment below.

TechZen
  • 64,370
  • 15
  • 118
  • 145
  • 2
    I needed to resize some images too, and I first tried out Trevor's additions to UIImage, but got some weird bugs on PNG's (something about the alpha channel). The accepted answer to this question worked out nicely though. – Sorig Nov 02 '10 at 22:11
  • 1
    This is no longer valid (at least with iOS5.1 – Jann Mar 22 '12 at 17:54
  • @Jann, have a look at the commits below the post. – vikingosegundo Apr 06 '12 at 21:53
  • @Jann If you follow the fixes suggested in the comments go with "Matt says: November 22, 2011 at 5:39 pm" because he releases the colorspaceref (unlike horseshoe7's similar solution). – Ben Flynn Apr 21 '12 at 00:19
  • 1
    @sanmai using any of these resizing methods the images loosing its sharp ness. is there any way to achieve the sharpness – vamsi575kg Oct 01 '13 at 05:43
  • 2
    I recommend that you improve or self-delete your answer because currently: (1) it's just a link; (2) it's outdated. – Cœur Oct 24 '18 at 16:16
26

I've also seen this done as well (which I use on UIButtons for Normal and Selected state since buttons don't resize to fit). Credit goes to whoever the original author was.

First make an empty .h and .m file called UIImageResizing.h and UIImageResizing.m

// Put this in UIImageResizing.h
@interface UIImage (Resize)
- (UIImage*)scaleToSize:(CGSize)size;
@end

// Put this in UIImageResizing.m
@implementation UIImage (Resize)

- (UIImage*)scaleToSize:(CGSize)size {
UIGraphicsBeginImageContext(size);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage);

UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return scaledImage;
}

@end

Include that .h file in whatever .m file you're going to use the function in and then call it like this:

UIImage* image = [UIImage imageNamed:@"largeImage.png"];
UIImage* smallImage = [image scaleToSize:CGSizeMake(100.0f,100.0f)];
Rishil Patel
  • 1,977
  • 3
  • 14
  • 30
iwasrobbed
  • 46,496
  • 21
  • 150
  • 195
20

This improvement to Paul's code will give you a sharp high res image on an iPhone with a retina display. Otherwise when scaling down it's blurry.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    if ([[UIScreen mainScreen] scale] == 2.0) {
        UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);
    } else {
        UIGraphicsBeginImageContext(newSize);
    }
} else {
    UIGraphicsBeginImageContext(newSize);
}
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
UIGraphicsEndImageContext();
return newImage;
}
malhal
  • 26,330
  • 7
  • 115
  • 133
  • 13
    Just FYI, the changes you have made are unnecessary, since supplying a value of 0.0 for the scale in `UIGraphicsBeginImageContextWithOptions` will automatically use the main screen's scale (as of iOS 3.2). – Andrew R. Apr 23 '12 at 03:36
16

Here is a simple way:

    UIImage * image = [UIImage imageNamed:@"image"];
    CGSize sacleSize = CGSizeMake(10, 10);
    UIGraphicsBeginImageContextWithOptions(sacleSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, sacleSize.width, sacleSize.height)];
    UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

resizedImage is a new image.

asmad
  • 387
  • 4
  • 13
16

Here's a modification of the category written by iWasRobbed above. It keeps the aspect ratio of the original image instead of distorting it.

- (UIImage*)scaleToSizeKeepAspect:(CGSize)size {
    UIGraphicsBeginImageContext(size);

    CGFloat ws = size.width/self.size.width;
    CGFloat hs = size.height/self.size.height;

    if (ws > hs) {
        ws = hs/ws;
        hs = 1.0;
    } else {
        hs = ws/hs;
        ws = 1.0;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0.0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextDrawImage(context, CGRectMake(size.width/2-(size.width*ws)/2,
        size.height/2-(size.height*hs)/2, size.width*ws,
        size.height*hs), self.CGImage);

    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}
Scott Means
  • 635
  • 6
  • 8
13

Why so complicated? I think using system API can achieve the same result:

UIImage *largeImage;
CGFloat ratio = 0.4; // you want to get a new image that is 40% the size of large image.
UIImage *newImage = [UIImage imageWithCGImage:largeImage.CGImage
                                        scale:1/ratio
                                  orientation:largeImage.imageOrientation];
// notice the second argument, it is 1/ratio, not ratio.

The only gotcha is you should pass inverse of target ratio as the second argument, as according to the document the second parameter specifies the ratio of original image compared to the new scaled one.

Eddie Deng
  • 1,399
  • 1
  • 18
  • 30
13

When using iOS 15 or newer, you can use the new prepareThumbnail method of UIImage:

sourceImage.prepareThumbnail(of: thumbnailSize) { thumbnail in
    // Do something with the resized image
    DispatchQueue.main.async {
        cell.imageView?.image = thumbnail
    }
}

More info here: https://developer.apple.com/documentation/uikit/uiimage/3750845-preparethumbnail

Ely
  • 8,259
  • 1
  • 54
  • 67
  • Do you know @Ely if that method takes the screen scale value into account ? – Blazej SLEBODA Aug 31 '21 at 09:16
  • @BlazejSLEBODA No, it doesn't multiply the thumbnail size parameter value with `UIScreen.main.scale`, you have to do that yourself. – Ely Aug 31 '21 at 09:41
12

For Swift 5:

extension UIImage {
  func resized(to newSize: CGSize) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
    defer { UIGraphicsEndImageContext() }

    draw(in: CGRect(origin: .zero, size: newSize))
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}
Vadoff
  • 9,219
  • 6
  • 43
  • 39
  • Doesn't this drain your memory unessecarily? I think it is better to use UIGraphicsImageRenderer. Source: https://developer.apple.com/videos/play/wwdc2018/416/ – Thel Dec 03 '22 at 08:30
11

If you just want an image smaller and don't care about exact size:

+ (UIImage *)imageWithImage:(UIImage *)image scaledToScale:(CGFloat)scale
{
    UIGraphicsBeginImageContextWithOptions(self.size, YES, scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

Setting scale to 0.25f will give you a 816 by 612 image from a 8MP camera.

Here's a category UIImage+Scale for those who needs one.

sanmai
  • 29,083
  • 12
  • 64
  • 76
11

This is an UIImage extension compatible with Swift 3 and Swift 4 which scales image to given size with an aspect ratio

extension UIImage {

    func scaledImage(withSize size: CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
        return UIGraphicsGetImageFromCurrentImageContext()!
    }

    func scaleImageToFitSize(size: CGSize) -> UIImage {
        let aspect = self.size.width / self.size.height
        if size.width / aspect <= size.height {
            return scaledImage(withSize: CGSize(width: size.width, height: size.width / aspect))
        } else {
            return scaledImage(withSize: CGSize(width: size.height * aspect, height: size.height))
        }
    }

}

Example usage

let image = UIImage(named: "apple")
let scaledImage = image.scaleImageToFitSize(size: CGSize(width: 45.0, height: 45.0))
abdullahselek
  • 7,893
  • 3
  • 50
  • 40
  • I would recommend to name the function `scaledImage(with size:)` or `scaledWithSize(_:)`. Also `UIGraphicsGetImageFromCurrentImageContext` cannot really return `nil`, therefore `!` would work as well. You can also simplify rect creation to `CGRect(origin: .zero, size: size)`. – Sulthan Aug 22 '17 at 19:10
8

I found a category for UIImage in Apple's own examples which does the same trick. Here's the link: https://developer.apple.com/library/ios/samplecode/sc2273/Listings/AirDropSample_UIImage_Resize_m.html.

You'll just have to change the call:

UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);

in imageWithImage:scaledToSize:inRect: with:

UIGraphicsBeginImageContextWithOptions(newSize, NO, 2.0);

In order to consider the alpha channel in the image.

aubykhan
  • 254
  • 2
  • 6
8

For my fellow Xamarians, here is a Xamarin.iOS C# version of @Paul Lynch answer.

private UIImage ResizeImage(UIImage image, CGSize newSize) 
{
    UIGraphics.BeginImageContextWithOptions(newSize, false, 0.0f);
    image.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
    UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return newImage;
}
Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
6
 func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage 
{
        let scale = newWidth / image.size.width
        let newHeight = image.size.height * scale
        UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
        image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
}
ashwini
  • 102
  • 1
  • 10
6

Effective approach without stretching image Swift 4

// Method to resize image
func resize(image: UIImage, toScaleSize:CGSize) -> UIImage {
                UIGraphicsBeginImageContextWithOptions(toScaleSize, true, image.scale)
                        image.draw(in: CGRect(x: 0, y: 0, width: toScaleSize.width, height: toScaleSize.height))
                        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
                        UIGraphicsEndImageContext()
                        return scaledImage!
                }

// Call method

    let resizedImage = self.resize(image: UIImage(named: "YourImageName")!, toScaleSize: CGSize(width: 290, height: 390))
5

If you want to make a thumbnail of a UIImage (with proportional resizing or maybe some cropping involved), check out UIImage+Resize category that allows you to use concise, ImageMagick-like syntax:

UIImage* squareImage       = [image resizedImageByMagick: @"320x320#"];
Vlad Andersen
  • 366
  • 2
  • 3
5

Rogerio Chaves answer as a swift extension

func scaledTo(size: CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0);
    self.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
}

And also bonus

func scaledTo(height: CGFloat) -> UIImage{
    let width = height*self.size.width/self.size.height
    return scaledTo(size: CGSize(width: width, height: height))
}
Community
  • 1
  • 1
user160917
  • 9,211
  • 4
  • 53
  • 63
5

[cf Chris] To resize to a desired size:

UIImage *after = [UIImage imageWithCGImage:before.CGImage
                                     scale:CGImageGetHeight(before.CGImage)/DESIREDHEIGHT
                               orientation:UIImageOrientationUp];

or, equivalently, substitute CGImageGetWidth(...)/DESIREDWIDTH

tiritea
  • 1,229
  • 13
  • 18
  • Note that the image data itself is not resized but a scale factor is applied which means image is of the same size in memory. – inkredibl Dec 28 '19 at 12:44
5

Swift 3.0 with failsafe option (returns the original image in case of error):

func resize(image: UIImage, toSize size: CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(size,false,1.0)
    image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let resizedImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return resizedImage
    }
    UIGraphicsEndImageContext()
    return image
}
rowel
  • 136
  • 1
  • 3
5

(Swift 4 compatible) iOS 10+ and iOS < 10 solution (using UIGraphicsImageRenderer if possible, UIGraphicsGetImageFromCurrentImageContext otherwise)

/// Resizes an image
///
/// - Parameter newSize: New size
/// - Returns: Resized image
func scaled(to newSize: CGSize) -> UIImage {
    let rect = CGRect(origin: .zero, size: newSize)

    if #available(iOS 10, *) {
        let renderer = UIGraphicsImageRenderer(size: newSize)
        return renderer.image { _ in
            self.draw(in: rect)
        }
    } else {
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}
nathan
  • 9,329
  • 4
  • 37
  • 51
3

use this extension

extension UIImage {
    public func resize(size:CGSize, completionHandler:(resizedImage:UIImage, data:NSData?)->()) {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), { () -> Void in
            let newSize:CGSize = size
            let rect = CGRectMake(0, 0, newSize.width, newSize.height)
            UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
            self.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            let imageData = UIImageJPEGRepresentation(newImage, 0.5)
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completionHandler(resizedImage: newImage, data:imageData)
            })
        })
    }
}
M.Othman
  • 5,132
  • 3
  • 35
  • 39
Beslan Tularov
  • 3,111
  • 1
  • 21
  • 34
3

@Paul Lynch's answer is great, but it would change the image ratio. if you don`t want to change the image ratio, and still want the new image fit for new size, try this.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {

// calculate a new size which ratio is same to original image
CGFloat ratioW = image.size.width / newSize.width;
CGFloat ratioH = image.size.height / newSize.height;

CGFloat ratio = image.size.width / image.size.height;

CGSize showSize = CGSizeZero;
if (ratioW > 1 && ratioH > 1) { 

    if (ratioW > ratioH) { 
        showSize.width = newSize.width;
        showSize.height = showSize.width / ratio;
    } else {
        showSize.height = newSize.height;
        showSize.width = showSize.height * ratio;
    }

} else if (ratioW > 1) {

    showSize.width = showSize.width;
    showSize.height = showSize.width / ratio;

} else if (ratioH > 1) {

    showSize.height = showSize.height;
    showSize.width = showSize.height * ratio;

}

//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(showSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, showSize.width, showSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;}
wossoneri
  • 317
  • 2
  • 11
3

Yet another way of resizing an UIImage:

// Resize to height = 100 points.
let originalImage = UIImage(named: "MyOriginalImage")!
let resizingFactor = 100 / originalImage.size.height
let newImage = UIImage(cgImage: originalImage.cgImage!, scale: originalImage.scale / resizingFactor, orientation: .up)
Sergio
  • 49
  • 2
3

Some time your image have scale large than 1 so that resize image will make an image unexpected. This is my solution for this case.

extension UIImage {
    func resizeTo(newSize: CGSize) -> UIImage {
        // Important thing here
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        
        let image = UIGraphicsImageRenderer(size: newSize, format: format).image { _ in
            draw(in: CGRect(origin: .zero, size: newSize))
        }
            
        return image.withRenderingMode(renderingMode)
    }
}
Binh Ho
  • 3,690
  • 1
  • 31
  • 31
2

Here my somewhat-verbose Swift code

func scaleImage(image:UIImage,  toSize:CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(toSize, false, 0.0);

    let aspectRatioAwareSize = self.aspectRatioAwareSize(image.size, boxSize: toSize, useLetterBox: false)


    let leftMargin = (toSize.width - aspectRatioAwareSize.width) * 0.5
    let topMargin = (toSize.height - aspectRatioAwareSize.height) * 0.5


    image.drawInRect(CGRectMake(leftMargin, topMargin, aspectRatioAwareSize.width , aspectRatioAwareSize.height))
    let retVal = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return retVal
}

func aspectRatioAwareSize(imageSize: CGSize, boxSize: CGSize, useLetterBox: Bool) -> CGSize {
    // aspect ratio aware size
    // http://stackoverflow.com/a/6565988/8047
    let imageWidth = imageSize.width
    let imageHeight = imageSize.height
    let containerWidth = boxSize.width
    let containerHeight = boxSize.height

    let imageAspectRatio = imageWidth/imageHeight
    let containerAspectRatio = containerWidth/containerHeight

    let retVal : CGSize
    // use the else at your own risk: it seems to work, but I don't know 
    // the math
    if (useLetterBox) {
        retVal = containerAspectRatio > imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
    } else {
        retVal = containerAspectRatio < imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
    }

    return retVal
}
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • useful, but act weird after segue and coming back activities, see here plz: http://stackoverflow.com/questions/30978685/wrong-size-with-scaling-imaging-as-background-after-ios-segue-rotations – He Yifei 何一非 Jun 24 '15 at 12:51
  • Please note: You might want to add a precondition (`guard`) to the `aspectRatioAwareSize` function such that it won't throw a divide by zero exception if the input parameters for either imageSize or boxSize are `CGSize.zero` – pkluz Dec 28 '16 at 20:45
  • @pkluz this is a good suggestion, but you'd need them all over the function, I think, since each variable is the divisor of another line... I'm going to leave this as is for clarity. For production or a library for github, you might want to beef this up... More than a guard, I'm concerned that the function uses short variable names that don't say much. I'd probably fix that first, and then add guards for other things, and then add unit tests. – Dan Rosenstark Dec 28 '16 at 20:58
2

Swift 2.0 :

let image = UIImage(named: "imageName")
let newSize = CGSize(width: 10, height: 10)

UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image?.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let imageResized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Phil
  • 4,730
  • 1
  • 41
  • 39
2

Swift 4 answer:

func scaleDown(image: UIImage, withSize: CGSize) -> UIImage {
    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(withSize, false, scale)
    image.draw(in: CGRect(x: 0, y: 0, width: withSize.width, height: withSize.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
}
DanielEdrisian
  • 716
  • 1
  • 4
  • 17
  • 1
    No need to set the real scale: `The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.` – nathan Aug 29 '17 at 14:54
2

Use this extension, in case you need to resize width/height only with aspect ratio.

extension UIImage {
    func resize(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
    func resize(width: CGFloat) -> UIImage {
        return resize(to: CGSize(width: width, height: width / (size.width / size.height)))
    }
    func resize(height: CGFloat) -> UIImage {
        return resize(to: CGSize(width: height * (size.width / size.height), height: height))
    }
}
Jeffrey Neo
  • 3,693
  • 2
  • 26
  • 30
1

I've discovered that it's difficult to find an answer that you can use out-of-the box in your Swift 3 project. The main problem of other answers that they don't honor the alpha-channel of the image. Here is the technique that I'm using in my projects.

extension UIImage {

    func scaledToFit(toSize newSize: CGSize) -> UIImage {
        if (size.width < newSize.width && size.height < newSize.height) {
            return copy() as! UIImage
        }

        let widthScale = newSize.width / size.width
        let heightScale = newSize.height / size.height

        let scaleFactor = widthScale < heightScale ? widthScale : heightScale
        let scaledSize = CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor)

        return self.scaled(toSize: scaledSize, in: CGRect(x: 0.0, y: 0.0, width: scaledSize.width, height: scaledSize.height))
    }

    func scaled(toSize newSize: CGSize, in rect: CGRect) -> UIImage {
        if UIScreen.main.scale == 2.0 {
            UIGraphicsBeginImageContextWithOptions(newSize, !hasAlphaChannel, 2.0)
        }
        else {
            UIGraphicsBeginImageContext(newSize)
        }

        draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage ?? UIImage()
    }

    var hasAlphaChannel: Bool {
        guard let alpha = cgImage?.alphaInfo else {
            return false
        }
        return alpha == CGImageAlphaInfo.first ||
            alpha == CGImageAlphaInfo.last ||
            alpha == CGImageAlphaInfo.premultipliedFirst ||
            alpha == CGImageAlphaInfo.premultipliedLast
    }
}

Example of usage:

override func viewDidLoad() {
    super.viewDidLoad()

    let size = CGSize(width: 14.0, height: 14.0)
    if let image = UIImage(named: "barbell")?.scaledToFit(toSize: size) {
        let imageView = UIImageView(image: image)
        imageView.center = CGPoint(x: 100, y: 100)
        view.addSubview(imageView)
    }
}

This code is a rewrite of Apple's extension with added support for images with and without alpha channel.

As a further reading I recommend checking this article for different image resizing techniques. Current approach offers decent performance, it operates high-level APIs and easy to understand. I recommend sticking to it unless you find that image resizing is a bottleneck in your performance.

Vadim Bulavin
  • 3,697
  • 25
  • 19
1

Swift 5:

func imageWithImage(_ image: UIImage?, scaledToSize newSize: CGSize) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
    image?.draw(in: CGRect(x: 0.0, y: 0.0, width: newSize.width, height: newSize.height))
    let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

Usage:

let img: UIImage? = imageWithImage(UIImage(named: "DefaultAvatar"), scaledToSize:CGSize(width: 20.0, height: 20.0))
Donald
  • 321
  • 1
  • 2
  • 10