Resize UIImage and change the size of UIImageView

108,494

Solution 1

When you get the width and height of a resized image Get width of a resized image after UIViewContentModeScaleAspectFit, you can resize your imageView:

imageView.frame = CGRectMake(0, 0, resizedWidth, resizedHeight);
imageView.center = imageView.superview.center;

I haven't checked if it works, but I think all should be OK

Solution 2

- (UIImage *)image:(UIImage*)originalImage scaledToSize:(CGSize)size
{
    //avoid redundant drawing
    if (CGSizeEqualToSize(originalImage.size, size))
    {
        return originalImage;
    }

    //create drawing context
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);

    //draw
    [originalImage drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];

    //capture resultant image
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    //return image
    return image;
}

Solution 3

This is the Swift equivalent for Rajneesh071's answer, using extensions

UIImage {
  func scaleToSize(aSize :CGSize) -> UIImage {
    if (CGSizeEqualToSize(self.size, aSize)) {
      return self
    }

    UIGraphicsBeginImageContextWithOptions(aSize, false, 0.0)
    self.drawInRect(CGRectMake(0.0, 0.0, aSize.width, aSize.height))
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
  }
}

Usage:

let image = UIImage(named: "Icon")
item.icon = image?.scaleToSize(CGSize(width: 30.0, height: 30.0))

Solution 4

Use the category below and then apply border from Quartz into your image:

[yourimage.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[yourimage.layer setBorderWidth:2];

The category: UIImage+AutoScaleResize.h

#import <Foundation/Foundation.h>

@interface UIImage (AutoScaleResize)

- (UIImage *)imageByScalingAndCroppingForSize:(CGSize)targetSize;

@end

UIImage+AutoScaleResize.m

#import "UIImage+AutoScaleResize.h"

@implementation UIImage (AutoScaleResize)

- (UIImage *)imageByScalingAndCroppingForSize:(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; // scale to fit height
        }
        else
        {
            scaleFactor = heightFactor; // scale to fit width
        }

        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;
            }
        }
    }

    UIGraphicsBeginImageContext(targetSize); // this will crop

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

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();

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

    //pop the context to get back to the default
    UIGraphicsEndImageContext();

    return newImage;
}

@end

Solution 5

If you have the size of the image, why don't you set the frame.size of the image view to be of this size?

EDIT----

Ok, so seeing your comment I propose this:

UIImageView *imageView;
//so let's say you're image view size is set to the maximum size you want

CGFloat maxWidth = imageView.frame.size.width;
CGFloat maxHeight = imageView.frame.size.height;

CGFloat viewRatio = maxWidth / maxHeight;
CGFloat imageRatio = image.size.height / image.size.width;

if (imageRatio > viewRatio) {
    CGFloat imageViewHeight = round(maxWidth * imageRatio);
    imageView.frame = CGRectMake(0, ceil((self.bounds.size.height - imageViewHeight) / 2.f), maxWidth, imageViewHeight);
}
else if (imageRatio < viewRatio) {
    CGFloat imageViewWidth = roundf(maxHeight / imageRatio);
    imageView.frame = CGRectMake(ceil((maxWidth - imageViewWidth) / 2.f), 0, imageViewWidth, maxHeight);
} else {
    //your image view is already at the good size
}

This code will resize your image view to its image ratio, and also position the image view to the same centre as your "default" position.

PS: I hope you're setting imageView.layer.shouldRasterise = YES and imageView.layer.rasterizationScale = [UIScreen mainScreen].scale;

if you're using CALayer shadow effect ;) It will greatly improve the performance of your UI.

Share:
108,494

Related videos on Youtube

Sergey Grischyov
Author by

Sergey Grischyov

St. Petersburg State University graduate. Cocoa Controls contributor.

Updated on March 01, 2020

Comments

  • Sergey Grischyov
    Sergey Grischyov about 4 years

    I have this UIImageView and I have the values of its max height and max width. What I want to achieve is that I want to take the image (with any aspect ratio and any resolution) and I want it to fit in the borders, so the picture does not exceed them, but it can shrink them as it wants. (marked red in the picture):

    enter image description here

    Right now the image fits the necessary size properly, but I have 2 worries: 1. The UIImageView is not equal the size of the resized image, thus leaving red background (and I don't want that) 2. If the image is smaller that the height of my UIImageView it is not resized to be smaller, it stays the same height.

    Here's my code and I know its wrong:

    UIImage *actualImage = [attachmentsArray lastObject];
    UIImageView *attachmentImageNew = [[UIImageView alloc] initWithFrame:CGRectMake(5.5, 6.5, 245, 134)];
    attachmentImageNew.image = actualImage;
    attachmentImageNew.backgroundColor = [UIColor redColor];
    attachmentImageNew.contentMode = UIViewContentModeScaleAspectFit;
    

    So how do I dynamically change the size not only of the UIImageView.image, but of the whole UIImageView, thus making its size totally adjustable to its content. Any help would be much appreciated, thanks!

  • Sergey Grischyov
    Sergey Grischyov about 11 years
    Why do you think I'm resizing it with attachmentImageNew.contentMode = UIViewContentModeScaleAspectFit? Because the image is too big. I can't set the size of the imageView to be the exact of the size of its image, because I have the max value for its height and width. And pretty much 90% of the images have to be resized.
  • Sergey Grischyov
    Sergey Grischyov about 11 years
    I tried that and it goes beyond the limits of my UIImageView into the galaxy far far away
  • tiguero
    tiguero about 11 years
    That sounds like a star wars bug then :-)
  • Sergey Grischyov
    Sergey Grischyov about 11 years
    Well, it's no bug, it just behaves like that, I don't think I need contentMode at all, I need something more powerful
  • tiguero
    tiguero about 11 years
    There is always a default mode for the contentMode it is not as if you don't need one. The default is UIViewContentModeScaleToFill
  • Alex
    Alex over 8 years
    if after superview I don't add '!' it give me error 'value of optional type 'UIView?' not unwrapped' is fixed if I use '!' : imageView.center = imageView.superview!.center;
  • Rob
    Rob over 6 years
    What if you're using auto layout? Shouldn't you not be setting frame?
  • TheTravloper
    TheTravloper about 5 years
    how to use it btw
  • Wei
    Wei over 3 years
    Thanks you save me a day to change image inside an uibutton.