Crop image to a square according to the size of a UIView/CGRect
Asked Answered
T

3

11

I have an implementation of AVCaptureSession and my goal is for the user to take a photo and only save the part of the image within the red square border, as shown below:

UIViewController with an implementation of AVCaptureSession

AVCaptureSession's previewLayer (the camera) spans from (0,0) (top left) to the bottom of my camera controls bar (the bar just above the view that contains the shutter). My navigation bar and controls bar are semi-transparent, so the camera can show through.

I'm using [captureSession setSessionPreset:AVCaptureSessionPresetPhoto]; to ensure that the original image being saved to the camera roll is like Apple's camera.

The user will be able to take the photo in portrait, landscape left and right, so the cropping method must take this into account.

So far, I've tried to crop the original image using this code:

DDLogVerbose(@"%@: Image crop rect: (%f, %f, %f, %f)", THIS_FILE, self.imageCropRect.origin.x, self.imageCropRect.origin.y, self.imageCropRect.size.width, self.imageCropRect.size.height);

// Create new image context (retina safe)
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.imageCropRect.size.width, self.imageCropRect.size.width), NO, 0.0);

// Create rect for image
CGRect rect = self.imageCropRect;

// Draw the image into the rect
[self.captureManager.stillImage drawInRect:rect];

// Saving the image, ending image context
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();

However, when I look at the cropped image in the camera roll, it seems that it has just squashed the original image, and not discarded the top and bottom parts of the image like I'd like. It also results in 53 pixels of white space at the top of the "cropped" image, likely because of the y position of my CGRect.

This is my logging output for the CGRect:

 Image crop rect: (0.000000, 53.000000, 320.000000, 322.000000)

This also describes the frame of the red bordered view in the superview.

Is there something crucial I'm overlooking?

P.S. The original image size (taken with a camera in portrait mode) is:

Original image size: (2448.000000, 3264.000000)
Tubuliflorous answered 9/1, 2014 at 4:36 Comment(0)
J
7

You can crop images with CGImageCreateWithImageInRect:

CGImageRef imageRef = CGImageCreateWithImageInRect([uncroppedImage CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
Juju answered 9/1, 2014 at 5:14 Comment(3)
I've edited your answer. Because original image size may differ with image what we have shown in screen. :)Sting
@Sting Thanks. I actually didn't mean to suggest one image vs another in my answer, but rather to show a generic cropping routine. (It actually is adapted from a UIImage category that obviously just referenced self rather than any particular image). I've changed my variable name to avoid future readers from jumping to any such conclusions. Whether one takes a snapshot and crops that, or whether one goes back to the original image (adjusting the crop CGRect accordingly) before cropping is a function of the app's requirements.Juju
very important note! Can't really explain it, but can just suppose that Core Graphics processes the axis inverted, x stands for y and y stands for x. At least for me in the portrait mode when transforming the image into core graphics image it's width and height is reversed. So take care when you crop something especially if you want to crop from a specific x or y and not from (0,0).Greensand
W
5

Don't forget to add scale parameter otherwise you will get low resolution image

CGImageRef imageRef = CGImageCreateWithImageInRect([uncroppedImage CGImage], CGRectMake(0, 0, 30, 120));
[imageView setImage:[UIImage imageWithCGImage:imageRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp]];
CGImageRelease(imageRef);
Watertight answered 11/1, 2014 at 17:50 Comment(0)
W
3

Swift 3:

let imageRef:CGImage = uncroppedImage.cgImage!.cropping(to: bounds)!
let croppedImage:UIImage = UIImage(cgImage: imageRef)
Wrinkly answered 12/10, 2016 at 3:6 Comment(2)
When I did this, it rotates the image 90 degrees counter-clockwise. Do you know how to fix the rotation?Glee
To prevent from rotation use: let croppedImage = UIImage(cgImage: imageRef, scale: UIScreen.main.scale, orientation: .right)Asperity

© 2022 - 2024 — McMap. All rights reserved.