如何以正确的方向从AVCapturePhoto生成UIImage?
我打电话给AVFoundation的委托方法来处理照片捕获,但我很难将其生成的AVCapturePhoto转换为正确方向的UIImage。虽然下面的例程是成功的,但我总是得到一个正确的UIImage(UIImage.imageOrientation = 3)。我没有办法在使用UIImage(data:image)时尝试先使用photo.cgImageRepresentation()?. takeRetainedValue()也没有帮助。请协助。如何以正确的方向从AVCapturePhoto生成UIImage?
由于生成的图像被送入Vision Framework工作流程,因此图像方向至关重要。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
// capture image finished
print("Image captured.")
if let imageData = photo.fileDataRepresentation() {
if let uiImage = UIImage(data: imageData){
// do stuff to UIImage
}
}
}
更新1: 阅读苹果的Photo Capture Programming Guide(过时的iOS11的),我还是设法找到一件事我做错了:
- 每次捕捉调用(self.capturePhotoOutput .capturePhoto)必须设置与PhotoOutput对象的连接并更新其方向以匹配拍摄照片时设备的方向。为此,我创建了UIDeviceOrientation的扩展,并将其用于我创建的snapPhoto()函数以调用捕获例程并等待didFinishProcessingPhoto委托方法执行。我添加了代码的快照,因为这里的代码示例分隔符似乎没有正确显示它们。
更新2 链接到完整的项目在GitHub上:https://github.com/agu3rra/Out-Loud
最后更新: 我跑了一些实验用的应用程序,并来到了以下结论:
-
kCGImagePropertyOrientation似乎并不影响您的应用程序,它里面所拍摄的图像的方向只每次您要调用capturePhoto方法时,如果更新photoOutput连接,则会随着设备方向而变化。所以:
FUNC snapPhoto(){// 准备和启动图像捕获例程
// if I leave the next 4 lines commented, the intented orientation of the image on display will be 6 (right top) - kCGImagePropertyOrientation let deviceOrientation = UIDevice.current.orientation // retrieve current orientation from the device guard let photoOutputConnection = capturePhotoOutput.connection(with: AVMediaType.video) else {fatalError("Unable to establish input>output connection")}// setup a connection that manages input > output guard let videoOrientation = deviceOrientation.getAVCaptureVideoOrientationFromDevice() else {return} photoOutputConnection.videoOrientation = videoOrientation // update photo's output connection to match device's orientation let photoSettings = AVCapturePhotoSettings() photoSettings.isAutoStillImageStabilizationEnabled = true photoSettings.isHighResolutionPhotoEnabled = true photoSettings.flashMode = .auto self.capturePhotoOutput.capturePhoto(with: photoSettings, delegate: self) // trigger image capture. It appears to work only if the capture session is running.
}
查看在调试器所生成的图像呈现出我,他们是如何被生成的,所以我可以推断出所需的旋转(UIImageOrientation)以使其直立显示。换句话说:更新UIImageOrientation会告诉您如何旋转图像,以便您以正确的方向查看图像。所以我就下表:
-
我不得不更新我的UIDeviceOrientation扩展到一个相当直观的形式:
扩展UIDeviceOrientation { FUNC getUIImageOrientationFromDevice() - > UIImageOrientation {// 返回基于CGImagePropertyOrientation on Device Orientation //这个扩展函数是根据UIImage如何显示的实验确定的。 开关自{ 情况UIDeviceOrientation.portrait,.faceUp:返回UIImageOrientation.right 情况UIDeviceOrientation.portraitUpsideDown,.faceDown:返回UIImageOrientation.left 情况UIDeviceOrientation.landscapeLeft:返回UIImageOrientation.up //这是基本方向 情况UIDeviceOrientation .landscapeRight:返回UIImageOrientation.down 情况下UIDeviceOrientation.unknown:返回UIImageOrientation.up }} }
-
这是我最后的委托方法现在的样子。它以预期的方向显示图像。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { // capture image finished print("Image captured.") let photoMetadata = photo.metadata // Returns corresponting NSCFNumber. It seems to specify the origin of the image // print("Metadata orientation: ",photoMetadata["Orientation"]) // Returns corresponting NSCFNumber. It seems to specify the origin of the image print("Metadata orientation with key: ",photoMetadata[String(kCGImagePropertyOrientation)] as Any) guard let imageData = photo.fileDataRepresentation() else { print("Error while generating image from photo capture data."); self.lastPhoto = nil; self.controller.goToProcessing(); return } guard let uiImage = UIImage(data: imageData) else { print("Unable to generate UIImage from image data."); self.lastPhoto = nil; self.controller.goToProcessing(); return } // generate a corresponding CGImage guard let cgImage = uiImage.cgImage else { print("Error generating CGImage");self.lastPhoto=nil;return } guard let deviceOrientationOnCapture = self.deviceOrientationOnCapture else { print("Error retrieving orientation on capture");self.lastPhoto=nil; return } self.lastPhoto = UIImage(cgImage: cgImage, scale: 1.0, orientation: deviceOrientationOnCapture.getUIImageOrientationFromDevice()) print(self.lastPhoto) print("UIImage generated. Orientation:(self.lastPhoto.imageOrientation.rawValue)") self.controller.goToProcessing() } func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) { print("Just about to take a photo.") // get device orientation on capture self.deviceOrientationOnCapture = UIDevice.current.orientation print("Device orientation: \(self.deviceOrientationOnCapture.rawValue)") }
有趣,和可能的[错误到文件(http://bugreport.apple.com)。如果将数据写入文件并使用基于文件的'UIImage'初始化程序,它是否似乎忽略方向? – rickster
在snapPhoto()例程(UPDATE 1)上添加了连接调用之后,它不再忽略方向,但它在我创建的UIImage上返回了不正确的方向值。 –
关于您的方向扩展。苹果已经发布了AVCam更新。有一个类似的扩展。 'extension UIDeviceOrientation {var VideoOrientation:AVCaptureVideoOrientation? { 开关自{ 情况.portrait:返回.portrait 情况.portraitUpsideDown:返回.portraitUpsideDown 情况.landscapeLeft:返回.landscapeRight 情况.landscapeRight:返回.landscapeLeft 默认:返回零 } } }' –