348

I have a UIImageView and the objective is to scale it down proportionally by giving it either a height or width.

UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3092/2915896504_a88b69c9de.jpg"]]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 

//Add image view
[self.view addSubview:imageView];   

//set contentMode to scale aspect to fit
imageView.contentMode = UIViewContentModeScaleAspectFit;

//change width of frame
CGRect frame = imageView.frame;
frame.size.width = 100;
imageView.frame = frame;

The image did get resized but the position is not at the top left. What is the best approach to scaling image/imageView and how do I correct the position?

James Webster
  • 31,873
  • 11
  • 70
  • 114
Ronnie Liew
  • 18,220
  • 14
  • 46
  • 50
  • I have something similar to your code that doesn't work for me "UIImage *image = [UIImage imageNamed:imageString]; UIImageView *imageView = [[UIImage alloc] initWithImage:image];" trows an exeption that kills my app whit this "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage initWithImage:]: unrecognized selector sent to instance 0xd815930'" – Spire Mar 10 '11 at 09:05
  • 3
    @Spire It's UIImageView not UIImage ^^ – Thomas Decaux Apr 12 '13 at 19:39
  • 2
    This works for me. Remember to set the .contentMode to your UIImageView -- not your UIImage. -- Here is mine: UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,30,30)] – Jarrett Barnett Jun 18 '13 at 17:04

17 Answers17

546

Fixed easily, once I found the documentation!

 imageView.contentMode = .scaleAspectFit
Vatsal Manot
  • 17,695
  • 9
  • 44
  • 80
Ken Abrams
  • 5,485
  • 1
  • 16
  • 2
  • 20
    What did you actually answer? in Ronnie's question he mentioned that he uses it – Dejell Dec 09 '12 at 11:19
  • 3
    Your imageView may not be clipping. Try imageView.layer.masksToBounds = YES; – mackworth Jan 27 '14 at 04:20
  • I first tried with IB to make sure it would work as needed, but I don't remember the variable name to set. So I Google it and found this answer. – Dino Tw Feb 20 '14 at 17:38
  • 1
    For anyone having the same problem in Swift: `ScaleAspectFit` is now an `enum UIViewContentMode`, so you would set `imageView.contentMode = UIViewContentMode.ScaleAspectFit`. Note the period. – sudo make install Feb 14 '15 at 10:28
  • 2
    `translatesAutoresizingMaskIntoConstraints` should not be set to `false`. Took me a long time before realising that this property is preventing the resize – Gerald Jul 12 '16 at 03:41
401

I've seen a bit of conversation about scale types so I decided to put together an article regarding some of the most popular content mode scaling types.

The associated image is here:

enter image description here

Jacksonkr
  • 31,583
  • 39
  • 180
  • 284
  • How do you verticallu align when AspectFit is set? – esbenr Apr 09 '13 at 11:10
  • @esbenr That should happen automatically. You might be able to find an override as needed but I don't know of one currently :| – Jacksonkr Apr 12 '13 at 13:34
  • I want to use Aspect Fill but I also want to display the full image. Then I need to change 'Area to fit' size. How can I do this with auto-layout? – lee Jun 22 '15 at 08:32
  • @lee There are a number of options but it's really dependent on your situation. I've created a SOF chat so we can discuss your topic and I'll give you want info I have, head on over if you're so inclined: http://chat.stackoverflow.com/rooms/81180/ios-autoresize-chat – Jacksonkr Jun 22 '15 at 12:53
  • @Jackson That does not happen automatically at all. It chooses the height of the original image before the UIImageView scales it, so the height does NOT match the new Aspect Fitted height. If anybody figures out a nice way to do this, please let me know. – datWooWoo Jun 22 '15 at 17:33
  • For Aspect Fill: "One side is typically cropped, never both" is not accurate. I tested this and the cropped image is automatically centered, both sides cropped (the way to Google image is depicted) – pixelfreak Oct 16 '15 at 22:33
  • @pixelfreak I see your point. To disambiguate, "side" was used where "axis" could have been used. Thinking about it further, the image is shrunk until an axis fits flush (not cropped). – Jacksonkr Apr 18 '17 at 14:47
78

I just tried this, and UIImage does not support _imageScaledToSize.

I ended up adding a method to UIImage using a category - a suggestion I found on the Apple Dev forums.

In a project-wide .h -

@interface UIImage (Extras)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
@end;

Implementation:

@implementation UIImage (Extras)

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {

    UIImage *sourceImage = self;
    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor) 
            scaleFactor = widthFactor;
        else
            scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image

        if (widthFactor < heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
        } else if (widthFactor > heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }


    // this is actually the interesting part:

    UIGraphicsBeginImageContext(targetSize);

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    if(newImage == nil) NSLog(@"could not scale image");


    return newImage ;
}

@end;
john.k.doe
  • 7,533
  • 2
  • 37
  • 64
Jane Sales
  • 13,526
  • 3
  • 52
  • 57
  • 1
    instead of `UIGraphicsBeginImageContext(targetSize);` do if `([UIScreen instancesRespondToSelector:@selector(scale)]) { UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0.0f); } else { UIGraphicsBeginImageContext(targetSize); }` to support retina displays without making it blurry – bicycle Feb 24 '16 at 15:57
39
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
Li-chih Wu
  • 1,002
  • 1
  • 11
  • 19
30

You could try making the imageView size match the image. The following code is not tested.

CGSize kMaxImageViewSize = {.width = 100, .height = 100};
CGSize imageSize = image.size;
CGFloat aspectRatio = imageSize.width / imageSize.height;
CGRect frame = imageView.frame;
if (kMaxImageViewSize.width / aspectRatio <= kMaxImageViewSize.height) 
{
    frame.size.width = kMaxImageViewSize.width;
    frame.size.height = frame.size.width / aspectRatio;
} 
else 
{
    frame.size.height = kMaxImageViewSize.height;
    frame.size.width = frame.size.height * aspectRatio;
}
imageView.frame = frame;
P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
Chris Lundie
  • 6,023
  • 2
  • 27
  • 28
  • 1
    setting imageView.frame = XXXX (anything) doesn't make any different to the output. any idea why? – sramij Jul 02 '14 at 13:09
  • 1
    @sramij If you're using autolayout, make sure to mess with [setTranslatesAutoResize...] on the UIViews. If you don't know what that does check the documentation! :) – datWooWoo Jun 22 '15 at 17:36
14

This works fine for me Swift 2.x:

imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true;
vvamondes
  • 362
  • 2
  • 7
13

Set your ImageView by selecting Mode to Aspect Fill and check the Clip Subviews box.

enter image description here

Jeffrey Neo
  • 3,693
  • 2
  • 26
  • 30
13

one can resize an UIImage this way

image = [UIImage imageWithCGImage:[image CGImage] scale:2.0 orientation:UIImageOrientationUp];
neoneye
  • 50,398
  • 25
  • 166
  • 151
13
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3092/2915896504_a88b69c9de.jpg"]]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 


//set contentMode to scale aspect to fit
imageView.contentMode = UIViewContentModeScaleAspectFit;

//change width of frame
//CGRect frame = imageView.frame;
//frame.size.width = 100;
//imageView.frame = frame;

//original lines that deal with frame commented out, yo.
imageView.frame = CGRectMake(10, 20, 60, 60);

...

//Add image view
[myView addSubview:imageView]; 

The original code posted at the top worked well for me in iOS 4.2.

I found that creating a CGRect and specifying all the top, left, width, and height values was the easiest way to adjust the position in my case, which was using a UIImageView inside a table cell. (Still need to add code to release objects)

Nate Flink
  • 3,934
  • 2
  • 30
  • 18
12

Set your UIimageview by scale.........

enter image description here

P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
7

For Swift :

self.imageViews.contentMode = UIViewContentMode.ScaleToFill
Somir Saikia
  • 1,610
  • 1
  • 16
  • 21
5

UIImageView+Scale.h:

#import <Foundation/Foundation.h>

@interface UIImageView (Scale)

-(void) scaleAspectFit:(CGFloat) scaleFactor;

@end

UIImageView+Scale.m:

#import "UIImageView+Scale.h"

@implementation UIImageView (Scale)


-(void) scaleAspectFit:(CGFloat) scaleFactor{

    self.contentScaleFactor = scaleFactor;
    self.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);

    CGRect newRect = self.frame;
    newRect.origin.x = 0;
    newRect.origin.y = 0;
    self.frame = newRect;
}

@end
Peter Kreinz
  • 7,979
  • 1
  • 64
  • 49
3

If the solutions proposed here aren't working for you, and your image asset is actually a PDF, note that XCode actually treats PDFs differently than image files. In particular, it doesn't seem able to scale to fill properly with a PDF: it ends up tiled instead. This drove me crazy until I figured out that the issue was the PDF format. Convert to JPG and you should be good to go.

Lane Rettig
  • 6,640
  • 5
  • 42
  • 51
2

I used following code.where imageCoverView is UIView holds UIImageView

if (image.size.height<self.imageCoverView.bounds.size.height && image.size.width<self.imageCoverView.bounds.size.width)
{
    [self.profileImageView sizeToFit];
    self.profileImageView.contentMode =UIViewContentModeCenter
}
else
{
    self.profileImageView.contentMode =UIViewContentModeScaleAspectFit;
}
P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
Avijit Nagare
  • 8,482
  • 7
  • 39
  • 68
1

Usually I use this method for my apps (Swift 2.x compatible):

// Resize UIImage
func resizeImage(image:UIImage, scaleX:CGFloat,scaleY:CGFloat) ->UIImage {
    let size = CGSizeApplyAffineTransform(image.size, CGAffineTransformMakeScale(scaleX, scaleY))
    let hasAlpha = true
    let scale: CGFloat = 0.0 // Automatically use scale factor of main screen

    UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
    image.drawInRect(CGRect(origin: CGPointZero, size: size))

    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return scaledImage
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
0

I think you can do something like

image.center = [[imageView window] center];
CoolBeans
  • 20,654
  • 10
  • 86
  • 101
user26359
  • 25
  • 1
-3

Here is how you can scale it easily.

This works in 2.x with the Simulator and the iPhone.

UIImage *thumbnail = [originalImage _imageScaledToSize:CGSizeMake(40.0, 40.0) interpolationQuality:1];
kdbdallas
  • 4,513
  • 10
  • 38
  • 53