26

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
  • 11,995
  • 20
  • 81
  • 120

7 Answers7

34

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

Community
  • 1
  • 1
Mikhail
  • 4,271
  • 3
  • 27
  • 39
  • 1
    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; – Alex Oct 08 '15 at 11:15
  • What if you're using auto layout? Shouldn't you not be setting `frame`? – Liron Yahdav Oct 24 '17 at 18:54
25
- (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;
}
PatrickNLT
  • 4,075
  • 1
  • 25
  • 32
Rajneesh071
  • 30,846
  • 15
  • 61
  • 74
9

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))
JoeGalind
  • 3,545
  • 2
  • 29
  • 33
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
CainaSouza
  • 1,417
  • 2
  • 16
  • 31
3

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.

Baldoph
  • 229
  • 1
  • 9
  • 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 Feb 01 '13 at 15:28
0

I think what you want is a different content mode. Try using UIViewContentModeScaleToFill. This will scale the content to fit the size of ur UIImageView by changing the aspect ratio of the content if necessary.

Have a look to the content mode section on the official doc to get a better idea of the different content mode available (it is illustrated with images).

tiguero
  • 11,477
  • 5
  • 43
  • 61
0
   if([[SDWebImageManager sharedManager] diskImageExistsForURL:[NSURL URLWithString:@"URL STRING1"]])
   {
       NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:[NSURL URLWithString:@"URL STRING1"]];

       UIImage *tempImage=[self imageWithImage:[[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key] scaledToWidth:cell.imgview.bounds.size.width];
       cell.imgview.image=tempImage;

   }
   else
   {
       [cell.imgview sd_setImageWithURL:[NSURL URLWithString:@"URL STRING1"] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL)
        {
            UIImage *tempImage=[self imageWithImage:image scaledToWidth:cell.imgview.bounds.size.width];
            cell.imgview.image=tempImage;
//                [tableView beginUpdates];
//                [tableView endUpdates];

        }];
   }
Gami Nilesh
  • 581
  • 4
  • 19