Trying to crop my UIImage to a 1:1 aspect ratio (square) but it keeps enlarging the image causing it to be blurry. Why?

StackOverflow https://stackoverflow.com/questions/20429420

Domanda

Given a UIImage, I'm trying to make it into a square. Just chop some of the largest dimension off to make it 1:1 in aspect ratio.

UIImage *pic = [UIImage imageNamed:@"pic"];
CGFloat originalWidth = pic.size.width;
CGFloat originalHeight = pic.size.height;

float smallestDimension = fminf(originalWidth, originalHeight);

CGRect square = CGRectMake(0, 0, smallestDimension, smallestDimension);
CGImageRef imageRef = CGImageCreateWithImageInRect([pic CGImage], square);

UIImage *squareImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

UIImageView *imageView = [[UIImageView alloc] initWithImage:squareImage];
imageView.frame = CGRectMake(100, 100, imageView.bounds.size.width, imageView.bounds.size.height);

[self.view addSubview:imageView];

But this is what it results in:

enter image description here

When it should look like this, but just a little narrower.

enter image description here

Why is this? The images are pic(150x114) / pic@2x(300x228).

È stato utile?

Soluzione

The problem is you're mixing up logical and pixel sizes. On non retina devices these two are the same, but on retina devices (like in your case) the pixel size is actually double the logical size.

Usually, when designing your GUI, you can always just think in logical sizes and coordinates, and iOS (or OS X) will make sure, that everything is doubled on retina screens. However, in some cases, especially when creating images yourself, you have to explicitly specify what size you mean.

UIImage's size method returns the logical size. That is the resolution on non-retina screens for instance. This is why CGImageCreateWithImageInRect will only create an new image, from the upper left half of the image.

Multiply your logical size with the scale of the image (1 on non-retina devices, 2 on retina devices):

CGFloat originalWidth = pic.size.width * pic.scale;
CGFloat originalHeight = pic.size.height * pic.scale;

This will make sure, that the new image is created from the full height (or width) of the original image. Now, one remaining problem is, that when you create a new UIImage using

UIImage *squareImage = [UIImage imageWithCGImage:imageRef];

iOS will think, this is a regular, non-retina image and it will display it twice as large as you would expect. To fix this, you have to specify the scale when you create the UIImage:

UIImage *squareImage = [UIImage imageWithCGImage:imageRef 
                                           scale:pic.scale 
                                     orientation:pic.imageOrientation];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top