To create our image with the correct orientation, we need to enter the correct UIImage.Orientation when we initialize the image.
It is best to use the CGImagePropertyOrientation which is returned from the photoOutput delegate to get the exact orientation that the camera session was in when the picture was taken. The only problem here is that although the enumeration values between UIImage.Orientation and CGImagePropertyOrientation same, the raw values are not. Apple offers a simple mapping to fix this.
https://developer.apple.com/documentation/imageio/cgimagepropertyorientation
Here is my implementation:
AVCapturePhotoCaptureDelegate
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { if let _ = error { // Handle Error } else if let cgImageRepresentation = photo.cgImageRepresentation(), let orientationInt = photo.metadata[String(kCGImagePropertyOrientation)] as? UInt32, let imageOrientation = UIImage.Orientation.orientation(fromCGOrientationRaw: orientationInt) { // Create image with proper orientation let cgImage = cgImageRepresentation.takeUnretainedValue() let image = UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation) } }
Mapping Extension
extension UIImage.Orientation { init(_ cgOrientation: CGImagePropertyOrientation) { // we need to map with enum values becuase raw values do not match switch cgOrientation { case .up: self = .up case .upMirrored: self = .upMirrored case .down: self = .down case .downMirrored: self = .downMirrored case .left: self = .left case .leftMirrored: self = .leftMirrored case .right: self = .right case .rightMirrored: self = .rightMirrored } } /// Returns a UIImage.Orientation based on the matching cgOrientation raw value static func orientation(fromCGOrientationRaw cgOrientationRaw: UInt32) -> UIImage.Orientation? { var orientation: UIImage.Orientation? if let cgOrientation = CGImagePropertyOrientation(rawValue: cgOrientationRaw) { orientation = UIImage.Orientation(cgOrientation) } else { orientation = nil // only hit if improper cgOrientation is passed } return orientation } }
source share