Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using avfoundation - crop visible portion of captured image represented in display layer

I am using PBJVision library to capture images.

Under the hood it is using AVFoundation.

I set up the camera to use the following options

    PBJVision *camera = [[PBJVision alloc] init];
    self.camera = camera;
    self.camera.delegate = self;
    [self.camera setCameraMode:PBJCameraModePhoto];
    [self.camera setCameraDevice:PBJCameraDeviceFront];
    [self.camera setCameraOrientation:PBJCameraOrientationPortrait];
    [self.camera setFocusMode:PBJFocusModeAutoFocus];
    [self.camera setPresentationFrame:self.previewView.frame];
    [self.camera previewLayer].frame = self.previewView.bounds;

    [self.camera previewLayer].videoGravity = AVLayerVideoGravityResizeAspectFill;

    [self.previewView.layer addSublayer:[self.camera previewLayer]];

because the preview layer gravity is set as AVLayerVideoGravityResizeAspectFill the captured image isn't identical to the previewed image.

How can I crop it according to the video gravity?

like image 808
Avner Barr Avatar asked Nov 01 '22 06:11

Avner Barr


1 Answers

Based on Erica Sadun's excellent Cookbook, adding the code below to your view controller will allow you to do
UIImage *newImage = [self.applyAspectFillImage: image InRect: self.previewView.bounds];

You can obtain the maximum image size by using the smaller edge (width or height) of the original photo image to size your destination rectangle.

CGFloat scaleW = image.size.width / previewView.bounds.size.width;
CGRect destRect = CGRectMake(0, 0, image.size.width, preview.bounds.size.height * scaleW);
UIImage *newImage = [self.applyAspectFillImage: image InRect: destRect];

The code:

CGRect CGRectCenteredInRect(CGRect rect, CGRect mainRect)
{
    CGFloat xOffset = CGRectGetMidX(mainRect)-CGRectGetMidX(rect);
    CGFloat yOffset = CGRectGetMidY(mainRect)-CGRectGetMidY(rect);
    return CGRectOffset(rect, xOffset, yOffset);
}


// Calculate the destination scale for filling
CGFloat CGAspectScaleFill(CGSize sourceSize, CGRect destRect)
{
    CGSize destSize = destRect.size;
    CGFloat scaleW = destSize.width / sourceSize.width;
    CGFloat scaleH = destSize.height / sourceSize.height;
    return MAX(scaleW, scaleH);
}


CGRect CGRectAspectFillRect(CGSize sourceSize, CGRect destRect)
{
    CGSize destSize = destRect.size;
    CGFloat destScale = CGAspectScaleFill(sourceSize, destRect);
    CGFloat newWidth = sourceSize.width * destScale;
    CGFloat newHeight = sourceSize.height * destScale;
    CGFloat dWidth = ((destSize.width - newWidth) / 2.0f);
    CGFloat dHeight = ((destSize.height - newHeight) / 2.0f);
    CGRect rect = CGRectMake (dWidth, dHeight, newWidth, newHeight);
    return rect;
}



- (UIImage *) applyAspectFillImage: (UIImage *) image InRect: (CGRect) bounds
{
    CGRect destRect;

    UIGraphicsBeginImageContext(bounds.size);
    CGRect rect = CGRectAspectFillRect(image.size, bounds);
    destRect = CGRectCenteredInRect(rect, bounds);

    [image drawInRect: destRect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;

}
like image 102
user3071962 Avatar answered Nov 15 '22 06:11

user3071962