8

So I've been trying to figure out what I'm doing wrong for a while now and I can't figure it out. What I'm trying to accomplish is this:

  1. Take a photo with UIImagePickerController
  2. Take the resulting photo and crop off the top and bottom so it becomes a square (similar to Instagram)
  3. Display that image within a UIButton

For some reason, every time I take the photo it ends up distorted within the UIButton and it appears as though the cropping didn't work properly. Here's what I do. Within the didFinishPickingMediaWithInfo method I have the following code:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //Copy the image to the userImage variable
    [picker dismissModalViewControllerAnimated:YES];
    userImage = nil;

    //Rotate & resize image
    userImage = [self resizeAndRotatePhoto:(UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage]];
    NSLog(@"Userimage size, width: %f , height: %f", userImage.size.width , userImage.size.height);

    //Update the image form field with the image and set the image in the controller
    NSLog(@"Button size is height: %f , width: %f" , userImageAvatarButton.frame.size.height , userImageAvatarButton.frame.size.width);
   [userImageAvatarButton.layer setMasksToBounds:YES];
   [userImageAvatarButton.layer setCornerRadius:3.0];
   [userImageAvatarButton setImage:userImage forState:UIControlStateNormal];
}

I'll include the resizeAndRotatePhoto method momentarily but the result is below. Also, in the code above, @property (strong) (UIImage *)userImage; is defined in the ViewController's header file. The log output also results in:

2012-05-07 17:38:07.995 NewApp[10666:707] Userimage size, width: 1936.000000 , height: 1936.000000
2012-05-07 17:38:08.000 NewApp[10666:707] Button size is height: 60.000000 , width: 60.000000

As you see in the image below, it ends up distorted.
form with button

As for the resizeAndRotate method, here it is:

- (UIImage *)resizeAndRotatePhoto:(UIImage *)source
{
if( source.imageOrientation == UIImageOrientationRight )
{
    source = [self rotateImage:source byDegrees:90];
}
if( userImage.imageOrientation == UIImageOrientationLeft)
{
    source = [self rotateImage:source byDegrees:-90];
}

CGFloat x,y;
CGFloat size;
if( source.size.width > source.size.height ){
    size = source.size.height;
    x = (source.size.width - source.size.height)/2;
    y = 0;
}
else {
    size = source.size.width;
    x = 0;
    y = (source.size.height - source.size.width)/2;
}


CGImageRef imageRef = CGImageCreateWithImageInRect([source CGImage], CGRectMake(x,y,size,size) );
return [UIImage imageWithCGImage:imageRef];
}

At this point I have no idea how to get this image to show up undistorted. It appears to be cropping it wrong and displaying it wrong despite the system saying that the image is indeed a square.

4

1 回答 1

9

由于其他原因,我放弃了 vocaro.com 解决方案(该解决方案在与非典型图像格式(例如 CMYK)一起使用时会崩溃)。

无论如何,我现在使用imageByScalingAspectFillSize以下UIImage类别的方法来制作我的方形缩略图。

顺便说一句,这会自动应用设备主屏幕的比例(例如UIButton,在 Retina 设备上是 60x60 点的按钮,这将应用 2x(或 3x)的比例,即 120x120 或 180x180 图像)。

UIImage+SimpleResize.h:

/*  UIImage+SimpleResize.h
 *
 *  Modified by Robert Ryan on 5/19/11.
 */

@import UIKit;

/** Image resizing category.
 *
 *  Modified by Robert Ryan on 5/19/11.
 *
 *  Inspired by http://ofcodeandmen.poltras.com/2008/10/30/undocumented-uiimage-resizing/
 *  but adjusted to support AspectFill and AspectFit modes.
 */

@interface UIImage (SimpleResize)

/** Resize the image to be the required size, stretching it as needed.
 *
 * @param size         The new size of the image.
 * @param contentMode  The `UIViewContentMode` to be applied when resizing image.
 *                     Either `UIViewContentModeScaleToFill`, `UIViewContentModeScaleAspectFill`, or
 *                     `UIViewContentModeScaleAspectFit`.
 *
 * @return             Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode;

/** Resize the image to be the required size, stretching it as needed.
 *
 * @param size         The new size of the image.
 * @param contentMode  The `UIViewContentMode` to be applied when resizing image.
 *                     Either `UIViewContentModeScaleToFill`, `UIViewContentModeScaleAspectFill`, or
 *                     `UIViewContentModeScaleAspectFit`.
 * @param scale        The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
 *
 * @return             Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode scale:(CGFloat)scale;

/** Crop the image to be the required size.
 *
 * @param bounds       The bounds to which the new image should be cropped.
 *
 * @return             Cropped `UIImage`.
 */

- (UIImage * _Nullable)imageByCroppingToBounds:(CGRect)bounds;

/** Crop the image to be the required size.
 *
 * @param bounds       The bounds to which the new image should be cropped.
 * @param scale        The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
 *
 * @return             Cropped `UIImage`.
 */

- (UIImage * _Nullable)imageByCroppingToBounds:(CGRect)bounds scale:(CGFloat)scale;

/** Resize the image to fill the rectange of the specified size, preserving the aspect ratio, trimming if needed.
 *
 * @param size    The new size of the image.
 *
 * @return        Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingAspectFillSize:(CGSize)size;

/** Resize the image to fill the rectange of the specified size, preserving the aspect ratio, trimming if needed.
 *
 * @param size    The new size of the image.
 * @param scale   The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
 *
 * @return        Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingAspectFillSize:(CGSize)size scale:(CGFloat)scale;

/** Resize the image to be the required size, stretching it as needed.
 *
 * @param size    The new size of the image.
 *
 * @return        Resized `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingToFillSize:(CGSize)size;

/** Resize the image to be the required size, stretching it as needed.
 *
 * @param size    The new size of the image.
 * @param scale   The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
 *
 * @return        Resized `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingToFillSize:(CGSize)size scale:(CGFloat)scale;

/** Resize the image to fit within the required size, preserving the aspect ratio, with no trimming taking place.
 *
 * @param size    The new size of the image.
 *
 * @return        Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingAspectFitSize:(CGSize)size;

/** Resize the image to fit within the required size, preserving the aspect ratio, with no trimming taking place.
 *
 * @param size    The new size of the image.
 * @param scale   The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
 *
 * @return        Return `UIImage` of resized image.
 */

- (UIImage * _Nullable)imageByScalingAspectFitSize:(CGSize)size scale:(CGFloat)scale;

@end

UIImage+SimpleResize.m:

//  UIImage+SimpleResize.m
//
//  Created by Robert Ryan on 5/19/11.

#import "UIImage+SimpleResize.h"

@implementation UIImage (SimpleResize)

- (UIImage *)imageByScalingToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode {
    return [self imageByScalingToSize:size contentMode:contentMode scale:0];
}

- (UIImage *)imageByScalingToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode scale:(CGFloat)scale {
    if (contentMode == UIViewContentModeScaleToFill) {
        return [self imageByScalingToFillSize:size];
    }
    else if ((contentMode == UIViewContentModeScaleAspectFill) ||
             (contentMode == UIViewContentModeScaleAspectFit)) {
        CGFloat horizontalRatio   = self.size.width  / size.width;
        CGFloat verticalRatio     = self.size.height / size.height;
        CGFloat ratio;

        if (contentMode == UIViewContentModeScaleAspectFill)
            ratio = MIN(horizontalRatio, verticalRatio);
        else
            ratio = MAX(horizontalRatio, verticalRatio);

        CGSize  sizeForAspectScale = CGSizeMake(self.size.width / ratio, self.size.height / ratio);

        UIImage *image = [self imageByScalingToFillSize:sizeForAspectScale scale:scale];

        // if we're doing aspect fill, then the image still needs to be cropped

        if (contentMode == UIViewContentModeScaleAspectFill) {
            CGRect  subRect = CGRectMake(floor((sizeForAspectScale.width - size.width) / 2.0),
                                         floor((sizeForAspectScale.height - size.height) / 2.0),
                                         size.width,
                                         size.height);
            image = [image imageByCroppingToBounds:subRect];
        }

        return image;
    }

    return nil;
}

- (UIImage *)imageByCroppingToBounds:(CGRect)bounds {
    return [self imageByCroppingToBounds:bounds scale:0];
}

- (UIImage *)imageByCroppingToBounds:(CGRect)bounds scale:(CGFloat)scale {
    if (scale == 0) {
        scale = [[UIScreen mainScreen] scale];
    }
    CGRect rect = CGRectMake(bounds.origin.x * scale, bounds.origin.y * scale, bounds.size.width * scale, bounds.size.height * scale);
    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef scale:scale orientation:self.imageOrientation];
    CGImageRelease(imageRef);
    return croppedImage;
}

- (UIImage *)imageByScalingToFillSize:(CGSize)size {
    return [self imageByScalingToFillSize:size scale:0];
}

- (UIImage *)imageByScalingToFillSize:(CGSize)size scale:(CGFloat)scale {
    UIGraphicsBeginImageContextWithOptions(size, false, scale);
    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

- (UIImage *)imageByScalingAspectFillSize:(CGSize)size {
    return [self imageByScalingAspectFillSize:size scale:0];
}

- (UIImage *)imageByScalingAspectFillSize:(CGSize)size scale:(CGFloat)scale {
    return [self imageByScalingToSize:size contentMode:UIViewContentModeScaleAspectFill scale:scale];
}

- (UIImage *)imageByScalingAspectFitSize:(CGSize)size {
    return [self imageByScalingAspectFitSize:size scale:0];
}

- (UIImage *)imageByScalingAspectFitSize:(CGSize)size scale:(CGFloat)scale {
    return [self imageByScalingToSize:size contentMode:UIViewContentModeScaleAspectFit scale:scale];
}

@end
于 2012-05-08T02:18:52.713 回答