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 🙂