iOS Custom UIImagePickerController Camera Crop to Square

31,263

Solution 1

Here's the easiest way to do it (without reimplementing UIImagePickerController). First, use an overlay to make the camera field look square. Here's an example for 3.5" screens (you'd need to update it to work for iPhone 5):

UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = source;

if (source == UIImagePickerControllerSourceTypeCamera) {
    //Create camera overlay
    CGRect f = imagePickerController.view.bounds;
    f.size.height -= imagePickerController.navigationBar.bounds.size.height;
    CGFloat barHeight = (f.size.height - f.size.width) / 2;
    UIGraphicsBeginImageContext(f.size);
    [[UIColor colorWithWhite:0 alpha:.5] set];
    UIRectFillUsingBlendMode(CGRectMake(0, 0, f.size.width, barHeight), kCGBlendModeNormal);
    UIRectFillUsingBlendMode(CGRectMake(0, f.size.height - barHeight, f.size.width, barHeight), kCGBlendModeNormal);
    UIImage *overlayImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImageView *overlayIV = [[UIImageView alloc] initWithFrame:f];
    overlayIV.image = overlayImage;
    [imagePickerController.cameraOverlayView addSubview:overlayIV];
}

imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];

Then, after you get a picture back from the UIImagePickerController, crop it to a square with something like this:

//Crop the image to a square
CGSize imageSize = image.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
if (width != height) {
    CGFloat newDimension = MIN(width, height);
    CGFloat widthOffset = (width - newDimension) / 2;
    CGFloat heightOffset = (height - newDimension) / 2;
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(newDimension, newDimension), NO, 0.);
    [image drawAtPoint:CGPointMake(-widthOffset, -heightOffset)
                   blendMode:kCGBlendModeCopy
                       alpha:1.];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

And you're done.

Solution 2

@Anders answer was very close to correct for me on iPhone 5. I made the following modification to add an overlay hardcoded for iPhone 5:

CGRect f = imagePickerController.view.bounds;
f.size.height -= imagePickerController.navigationBar.bounds.size.height;
UIGraphicsBeginImageContext(f.size);
[[UIColor colorWithWhite:0 alpha:.5] set];
UIRectFillUsingBlendMode(CGRectMake(0, 0, f.size.width, 124.0), kCGBlendModeNormal);
UIRectFillUsingBlendMode(CGRectMake(0, 444, f.size.width, 52), kCGBlendModeNormal);
UIImage *overlayImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

UIImageView *overlayIV = [[UIImageView alloc] initWithFrame:f];
overlayIV.image = overlayImage;
overlayIV.alpha = 0.7f;
[imagePickerController setCameraOverlayView:overlayIV];`

I hope this helps someone.

Share:
31,263
NSDavidObject
Author by

NSDavidObject

Updated on October 19, 2020

Comments

  • NSDavidObject
    NSDavidObject over 3 years

    I'm trying to create a camera like Instagram where the user can see a box and the image would crop to that box. For Some reason the camera doesn't go all the way to the bottom of the screen and cuts off near the end. I'm also wondering how would I go about cropping the image to be 320x320 exactly inside that square?

    enter image description here

  • NSDavidObject
    NSDavidObject almost 11 years
    Thanks works great! I was wondering if there's anyway I can make the camera opening animation go on top of the overlay?
  • Ander
    Ander almost 11 years
    No, unfortunately there is no way of doing this using publicly documented APIs (i.e. without doing something that would cause Apple to reject the App). If you wanted to do this you properly you would need to reimplement UIImagePickerController.
  • Bastien Beurier
    Bastien Beurier over 10 years
    What should we change to make it work on both iphone 5 and previous iphones?
  • Mark Lummus
    Mark Lummus about 10 years
    My experience with this on IOS7 on an iPhone 5 was not great. specifically, I could see the overlay, but I could not use the native zoom controls. finally, when I took the photo and the "Retake" and "Use Photo" buttons, appeared, I was not able to click either button. YMMV
  • Boosa Ramesh
    Boosa Ramesh almost 10 years
    here may i know source is which type of variable and in which image picker delegate method we need to write above code
  • PaperThick
    PaperThick over 9 years
    worked great at first but now I am getting memory issues when running this code. Anyone experiencing the same issue?
  • Martin Berger
    Martin Berger about 8 years
    This solution uses imagePickerController.cameraOverlayView but that only works if source type is UIImagePickerControllerSourceTypeCamera. docs
  • frank
    frank almost 8 years
    The square frame and the crop frame are slightly, but very noticeably, offset.