How to scale a UIImageView proportionally?
Asked Answered
P

17

349

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?

Proximity answered 9/10, 2008 at 1:58 Comment(3)
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'"Inharmonic
@Inharmonic It's UIImageView not UIImage ^^Polanco
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)]Barquisimeto
V
547

Fixed easily, once I found the documentation!

 imageView.contentMode = .scaleAspectFit
Vickivickie answered 20/2, 2010 at 0:29 Comment(5)
What did you actually answer? in Ronnie's question he mentioned that he uses itSkricki
Your imageView may not be clipping. Try imageView.layer.masksToBounds = YES;Vortex
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.Lujan
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.Maureen
translatesAutoresizingMaskIntoConstraints should not be set to false. Took me a long time before realising that this property is preventing the resizeAptitude
F
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

Fibroma answered 8/1, 2013 at 17:22 Comment(7)
How do you verticallu align when AspectFit is set?Sometimes
@Sometimes That should happen automatically. You might be able to find an override as needed but I don't know of one currently :|Fibroma
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?Gulley
@Gulley 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: chat.stackoverflow.com/rooms/81180/ios-autoresize-chatFibroma
@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.Landside
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)Ludwigshafen
@Ludwigshafen 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).Fibroma
B
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;
Baxter answered 11/2, 2009 at 16:44 Comment(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 blurryAw
W
39
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
Weather answered 11/12, 2012 at 7:16 Comment(0)
N
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;
Norvell answered 9/10, 2008 at 4:10 Comment(2)
setting imageView.frame = XXXX (anything) doesn't make any different to the output. any idea why?Encapsulate
@Encapsulate 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! :)Landside
D
14

This works fine for me Swift 2.x:

imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true;
Doggo answered 7/10, 2016 at 16:13 Comment(0)
F
13

one can resize an UIImage this way

image = [UIImage imageWithCGImage:[image CGImage] scale:2.0 orientation:UIImageOrientationUp];
Formless answered 25/5, 2011 at 14:55 Comment(0)
E
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)

Equiangular answered 15/6, 2011 at 18:10 Comment(0)
F
13

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

enter image description here

Faceharden answered 3/4, 2015 at 3:31 Comment(0)
N
12

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

enter image description here

Neotropical answered 16/12, 2016 at 9:37 Comment(0)
L
7

For Swift :

self.imageViews.contentMode = UIViewContentMode.ScaleToFill
Lacagnia answered 17/9, 2015 at 9:33 Comment(0)
T
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
Turban answered 20/11, 2013 at 16:22 Comment(0)
B
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.

Bicephalous answered 5/1, 2017 at 1:4 Comment(0)
H
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;
}
Havstad answered 25/2, 2016 at 8:8 Comment(0)
D
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
}
Discoloration answered 25/2, 2016 at 8:17 Comment(0)
A
0

I think you can do something like

image.center = [[imageView window] center];
Addi answered 9/10, 2008 at 3:4 Comment(1)
It will not scale the image but only center it.Edgewise
A
-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];
Alleman answered 10/10, 2008 at 22:17 Comment(3)
hi, do you know what the interpolationQuality: parameter does? thanksTurne
This is an undocumented method (the underscore is a dead giveaway) that could result in app rejection.Curacy
What does the interpolationQuality parameter do?Ethic

© 2022 - 2024 — McMap. All rights reserved.