1

I would like to upload some square cropped images from the photo library, but somehow the uploaded image's aspect ratio will be corrupted. I don't understand why, because i crop it to 440 x 440, so the ratio should be the same.

I would be very happy if somebody could show me the proper way how can i crop images to square shape, and resize them without any deformations and quality loss. I have to do it only with the images from the device's photo library.

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{

    else if (buttonIndex == 1)
    {
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == YES) {

            UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
            imagePicker.sourceType =  UIImagePickerControllerSourceTypePhotoLibrary;

            imagePicker.delegate = self;

            imagePicker.allowsEditing = YES;
            [self presentViewController:imagePicker animated:YES completion:nil];
            [self.tableView reloadData];
        }
    }
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{

    UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

    [picker dismissViewControllerAnimated:YES completion:nil];

    // resize image
    UIGraphicsBeginImageContext(CGSizeMake(440, 440));
    [image drawInRect: CGRectMake(0, 0, 440, 440)];
    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    NSData *imageData = UIImageJPEGRepresentation(smallImage, 1.0);
    [self uploadImage:imageData];
}
rihekopo
  • 3,241
  • 4
  • 34
  • 63
  • 1
    You're not cropping them by using `drawInRect`. This is probably what you want:http://stackoverflow.com/questions/14203951/cropping-center-square-of-uiimage – Jack Jul 04 '14 at 22:10

3 Answers3

4
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{    
    UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];

    [picker dismissViewControllerAnimated:YES completion:nil];

    // Fixing orientation and transform of picked image
    image = [image fixOrientation];

    // Crop the image
    UIImage *smallImage = [image cropToRect:CGRectMake(0, 0, 440, 440)];

    NSData *imageData = UIImageJPEGRepresentation(smallImage, 1.0);
    [self uploadImage:imageData];
}

Make a category on UIImage with following methods

@implementation UIImage (FixOrientation)

- (UIImage *)cropToRect:(CGRect)rect {
    rect.size.height = rect.size.height * [self scale];
    rect.size.width = rect.size.width * [self scale];
    rect.origin.x = rect.origin.x * [self scale];
    rect.origin.y = rect.origin.y * [self scale];
    CGImageRef sourceImageRef = [self CGImage];
    CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:[self scale] orientation:[self imageOrientation]];
    CGImageRelease(newImageRef);

    return newImage;
}

- (UIImage *)fixOrientation
{        
    // No-op if the orientation is already correct
    if (self.imageOrientation == UIImageOrientationUp) return self;

    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    CGAffineTransform transform = CGAffineTransformIdentity;

    switch (self.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            break;
    }

    switch (self.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationDown:
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
            break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
                                             CGImageGetBitsPerComponent(self.CGImage), 0,
                                             CGImageGetColorSpace(self.CGImage),
                                             CGImageGetBitmapInfo(self.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (self.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
            break;

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
            break;
    }

    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}

@end
arturdev
  • 10,884
  • 2
  • 39
  • 67
0

drawInRect: is forcing the image to change its aspect to fit in the square area. You need to calculate an area with the original aspect ratio that covers your square area.

Code from an UIImage category that does this:

- (UIImage *)imageCroppedToFill:(CGSize)size
{
    CGFloat factor = MAX(size.width / self.size.width,
                         size.height / self.size.height);

    UIGraphicsBeginImageContextWithOptions(size,
                                           YES,                     // Opaque
                                           self.scale);             // Use image scale

    CGRect rect = CGRectMake((size.width - nearbyintf(self.size.width * factor)) / 2.0,
                             (size.height - nearbyintf(self.size.height * factor)) / 2.0,
                             nearbyintf(self.size.width * factor),
                             nearbyintf(self.size.height * factor));
    [self drawInRect:rect];
    UIImage * croppedImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    NBULogInfo(@"Image %@ %@ cropped to %@ %@",
               self,
               NSStringFromCGSize(self.size),
               croppedImage,
               NSStringFromCGSize(croppedImage.size));

    return croppedImage;
}
Rivera
  • 10,792
  • 3
  • 58
  • 102
0

You can use CoreGraphics to draw the mask dynamically. Check this, I hope this could help you;

https://stackoverflow.com/a/9585892/2622013

Community
  • 1
  • 1
Göktuğ Aral
  • 1,409
  • 1
  • 13
  • 28