How to crop an image from AVCapture to a rect seen on the display How to crop an image from AVCapture to a rect seen on the display ios ios

How to crop an image from AVCapture to a rect seen on the display


In Swift 3:

private func cropToPreviewLayer(originalImage: UIImage) -> UIImage {    let outputRect = previewLayer.metadataOutputRectConverted(fromLayerRect: previewLayer.bounds)    var cgImage = originalImage.cgImage!    let width = CGFloat(cgImage.width)    let height = CGFloat(cgImage.height)    let cropRect = CGRect(x: outputRect.origin.x * width, y: outputRect.origin.y * height, width: outputRect.size.width * width, height: outputRect.size.height * height)        cgImage = cgImage.cropping(to: cropRect)!    let croppedUIImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: originalImage.imageOrientation)        return croppedUIImage}


I've solved this problem by using metadataOutputRectOfInterestForRect function.

It works with any orientation.

[_stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection                                               completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {     if (error)     {         [_delegate cameraView:self error:@"Take picture failed"];     }     else     {         NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];         UIImage *takenImage = [UIImage imageWithData:jpegData];         CGRect outputRect = [_previewLayer metadataOutputRectOfInterestForRect:_previewLayer.bounds];         CGImageRef takenCGImage = takenImage.CGImage;         size_t width = CGImageGetWidth(takenCGImage);         size_t height = CGImageGetHeight(takenCGImage);         CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, outputRect.size.width * width, outputRect.size.height * height);         CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect);         takenImage = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:takenImage.imageOrientation];         CGImageRelease(cropCGImage);     } } ];

The takenImage is still imageOrientation dependent image. You can delete orientation information for further image processing.

UIGraphicsBeginImageContext(takenImage.size);[takenImage drawAtPoint:CGPointZero];takenImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();


In Swift 4:

I prefer to never force-unwrap to avoid crashes, so I use optionals and guards in mine.

private func cropToPreviewLayer(originalImage: UIImage) -> UIImage? {    guard let cgImage = originalImage.cgImage else { return nil }    let outputRect = previewLayer.metadataOutputRectConverted(fromLayerRect: previewLayer.bounds)    let width = CGFloat(cgImage.width)    let height = CGFloat(cgImage.height)    let cropRect = CGRect(x: outputRect.origin.x * width, y: outputRect.origin.y * height, width: outputRect.size.width * width, height: outputRect.size.height * height)    if let croppedCGImage = cgImage.cropping(to: cropRect) {        return UIImage(cgImage: croppedCGImage, scale: 1.0, orientation: originalImage.imageOrientation)    }    return nil}