Getting a Properly Rotated UIImage from AVCaptureSession

Recently I started work on a custom camera for You Doodle. As part of this, I was overhauling the camera picker, moving away from UIImagePickerController to my own custom camera. This required diving into AVFoundation. While I have a lot of experience with this framework, one piece took much longer than expected – rotating the final image to an ‘up’ orientation with a proper width and height value.

After several hours of hair pulling I finally conjured up this function:

// this method rotates the UIImage captured by the capture session manager based on the device orientation when the image was captured ([AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];)
- (UIImage*) imageRotated:(UIImage*)image position:(AVCaptureDevicePosition)position orientation:(AVCaptureVideoOrientation)orientation
{
    CGAffineTransform transform = CGAffineTransformIdentity;
    CGFloat w = image.size.width * image.scale;
    CGFloat h = image.size.height * image.scale;
    CGFloat dw = w;
    CGFloat dh = h;
    image = [UIImage imageWithCGImage:image.CGImage scale:1.0f orientation:UIImageOrientationUp];
    
    switch (self.captureLayer.connection.videoOrientation)
    {
        case AVCaptureVideoOrientationPortraitUpsideDown:
            dw = h;
            dh = w;
            transform = CGAffineTransformTranslate(transform, 0.0f, w);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
            
        case AVCaptureVideoOrientationLandscapeLeft:
            if (position == AVCaptureDevicePositionBack)
            {
                transform = CGAffineTransformTranslate(transform, w, h);
                transform = CGAffineTransformScale(transform, -1.0f, -1.0f);
                break;
            }
            else
            {
                return image;
            }
            
        case AVCaptureVideoOrientationLandscapeRight:
            if (position == AVCaptureDevicePositionBack)
            {
                return image;
            }
            else
            {
                transform = CGAffineTransformTranslate(transform, w, h);
                transform = CGAffineTransformScale(transform, -1.0f, -1.0f);
                break;
            }
            
        default: // portrait
            dw = h;
            dh = w;
            transform = CGAffineTransformTranslate(transform, h, 0.0f);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

    }

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(dw, dh), YES, 1.0f);
    CGContextConcatCTM(UIGraphicsGetCurrentContext(), transform);
    [image drawInRect:CGRectMake(0.0f, 0.0f, w, h) blendMode:kCGBlendModeCopy alpha:1.0f];
    @autoreleasepool
    {
        image = UIGraphicsGetImageFromCurrentImageContext();
    }
    UIGraphicsEndImageContext();
    
    return image;
}

// and of course to get the image to begin with:
NSData* imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage* image = [UIImage imageWithData:imageData];

 

May it serve you well if you are in the bowels of AVFoundation 🙂

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments