AVCapturePhoto 在调用 cgImageRepresentation()!.takeUnretainedValue() 后逆时针旋转 90
AVCapturePhoto rotated 90 counterclockwise after calling `cgImageRepresentation()!.takeUnretainedValue()`
我正在开发一款应用程序,可以在 iOS 上使用 AVFoundation
拍摄方形照片。当我在photoOutput(_:, didFinishProcessingPhoto:, error:)
中使用以下语句保存图像时,我相册中保存的图像方向正确。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized else { return }
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo, data: photo.fileDataRepresentation()!, options: nil)
}, completionHandler: nil)
}
}
但是,当我用下面的代码来保存CGImage
对象时,我发现保存在我的相册中的图像被逆时针旋转了90。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let image = photo.cgImageRepresentation()!.takeUnretainedValue()
UIImageWriteToSavedPhotosAlbum(UIImage(cgImage: image), nil, nil, nil)
}
这是我的照片捕获管道配置。
private func initializeCapturePipeline() {
captureSession = AVCaptureSession()
captureSession?.sessionPreset = .photo
captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
videoInput = try! AVCaptureDeviceInput(device: captureDevice!)
imageOutput = AVCapturePhotoOutput()
captureSession?.addInput(videoInput!)
captureSession?.addOutput(imageOutput!)
imageOutput?.connection(with: .video)?.videoOrientation = .portrait
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
previewLayer?.videoGravity = .resizeAspectFill
videoContainerView.layer.addSublayer(previewLayer!)
captureSession?.startRunning()
}
我想知道是什么导致了这个问题?我该如何解决这个问题。
我的理解是两种情况下的底层图像数据是相同的,显示上的差异是由于 photo.cgImageRepresentation()
中缺少元数据造成的。照片应用程序了解图像元数据,并根据图像元数据中 "Orientation" 属性 的值自动应用必要的旋转 and/or 镜像。
使用 PHPhotoLibrary
函数生成带有嵌入元数据的图像副本。如 CGImagePropertyOrientation 中所述,iOS 正在保存方向为 .right
的对象。但是,直接从 AVCapturePhoto
对象创建的 CGImage
不包含关联的元数据。
有几个潜在的修复(这些尚未经过测试,但应该有助于找到有效的解决方案):
- 使用从照片元数据中获得的方向创建
UIImage
。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let image = photo.cgImageRepresentation()!.takeUnretainedValue()
let orientation = CGImageProperyOrientation(rawValue: photo.metadata["Orientation"] as! UInt32)
var uiImage: UIImage!
if orientation == .right {
uiImage = UIImage(cgImage: image, scale: 1.0, orientation: .right)
} else {
uiImage = UIImage(cgImage: image)
}
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}
使用 CGImageDestination
和 Image I/O framework 中的 CGImageDestinationAddImageAndMetadata
函数保存带有元数据的 CGImage
。
根据具体的用例,可能需要显式旋转图像数据。可以找到如何执行此操作的示例 here.
我正在开发一款应用程序,可以在 iOS 上使用 AVFoundation
拍摄方形照片。当我在photoOutput(_:, didFinishProcessingPhoto:, error:)
中使用以下语句保存图像时,我相册中保存的图像方向正确。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized else { return }
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo, data: photo.fileDataRepresentation()!, options: nil)
}, completionHandler: nil)
}
}
但是,当我用下面的代码来保存CGImage
对象时,我发现保存在我的相册中的图像被逆时针旋转了90。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let image = photo.cgImageRepresentation()!.takeUnretainedValue()
UIImageWriteToSavedPhotosAlbum(UIImage(cgImage: image), nil, nil, nil)
}
这是我的照片捕获管道配置。
private func initializeCapturePipeline() {
captureSession = AVCaptureSession()
captureSession?.sessionPreset = .photo
captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
videoInput = try! AVCaptureDeviceInput(device: captureDevice!)
imageOutput = AVCapturePhotoOutput()
captureSession?.addInput(videoInput!)
captureSession?.addOutput(imageOutput!)
imageOutput?.connection(with: .video)?.videoOrientation = .portrait
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
previewLayer?.videoGravity = .resizeAspectFill
videoContainerView.layer.addSublayer(previewLayer!)
captureSession?.startRunning()
}
我想知道是什么导致了这个问题?我该如何解决这个问题。
我的理解是两种情况下的底层图像数据是相同的,显示上的差异是由于 photo.cgImageRepresentation()
中缺少元数据造成的。照片应用程序了解图像元数据,并根据图像元数据中 "Orientation" 属性 的值自动应用必要的旋转 and/or 镜像。
使用 PHPhotoLibrary
函数生成带有嵌入元数据的图像副本。如 CGImagePropertyOrientation 中所述,iOS 正在保存方向为 .right
的对象。但是,直接从 AVCapturePhoto
对象创建的 CGImage
不包含关联的元数据。
有几个潜在的修复(这些尚未经过测试,但应该有助于找到有效的解决方案):
- 使用从照片元数据中获得的方向创建
UIImage
。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let image = photo.cgImageRepresentation()!.takeUnretainedValue()
let orientation = CGImageProperyOrientation(rawValue: photo.metadata["Orientation"] as! UInt32)
var uiImage: UIImage!
if orientation == .right {
uiImage = UIImage(cgImage: image, scale: 1.0, orientation: .right)
} else {
uiImage = UIImage(cgImage: image)
}
UIImageWriteToSavedPhotosAlbum(uiImage, nil, nil, nil)
}
使用
CGImageDestination
和 Image I/O framework 中的CGImageDestinationAddImageAndMetadata
函数保存带有元数据的CGImage
。根据具体的用例,可能需要显式旋转图像数据。可以找到如何执行此操作的示例 here.