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 🙂