Swift - AVFoundation捕捉图像方向

7
我有一个自定义相机,可以以纵向模式拍照。
我的问题是,如果我尝试在横向模式下拍照并保存它,那么照片仍然以纵向模式保存。
我有这个函数来设置预览层:
 static func setupPreviewLayer(view: UIView) {
    cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    switch UIDevice.current.orientation {
    case .portrait:
        cameraPreviewLayer?.connection?.videoOrientation = 
       AVCaptureVideoOrientation.portrait
    case .portraitUpsideDown:
        cameraPreviewLayer?.connection?.videoOrientation = 
          AVCaptureVideoOrientation.portraitUpsideDown
    case .landscapeLeft:
        cameraPreviewLayer?.connection?.videoOrientation =
        AVCaptureVideoOrientation.landscapeLeft
    case .landscapeRight:
        cameraPreviewLayer?.connection?.videoOrientation = 
         AVCaptureVideoOrientation.landscapeRight
    default:
        cameraPreviewLayer?.connection?.videoOrientation = 
         AVCaptureVideoOrientation.portrait
    }
    cameraPreviewLayer?.frame = view.frame
    view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}

我在viewWillAppear中调用这个方法(我认为这不是正确的做法)。
然后我拍照:
@IBAction func takePhotoBtnPressed(_ sender: Any) {
    let settings = AVCapturePhotoSettings()
    useFlash(settings: settings)
    settings.isAutoStillImageStabilizationEnabled = true
    CustomCamera.photoOutput?.capturePhoto(with: settings, delegate: self)
}

并使用此扩展:
extension FishCameraVC: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    if let imageData = photo.fileDataRepresentation() {
        image = UIImage(data: imageData)


          performSegue(withIdentifier: "ShowTakenPhoto", sender: nil)
        }
    }
}

只要我拍摄肖像模式照片,一切都正常,但当我将手机旋转以拍摄横向照片时,照片仍然是以纵向拍摄的。
这是我第一次使用自定义相机,我真的不知道从哪里开始修复它... 如果有人能帮忙,我会非常感激。
谢谢!
---------------更新 我已经添加了这个功能:
func managePhotoOrientation() -> UIImageOrientation {
    var currentDevice: UIDevice
    currentDevice = .current
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
    var deviceOrientation: UIDeviceOrientation
    deviceOrientation = currentDevice.orientation

    var imageOrientation: UIImageOrientation!

    if deviceOrientation == .portrait {
        imageOrientation = .up
        print("Device: Portrait")
    }else if (deviceOrientation == .landscapeLeft){
        imageOrientation = .left
        print("Device: LandscapeLeft")
    }else if (deviceOrientation == .landscapeRight){
        imageOrientation = .right
        CustomCamera.cameraPreviewLayer?.connection?.videoOrientation = .landscapeRight
        print("Device LandscapeRight")
    }else if (deviceOrientation == .portraitUpsideDown){
        imageOrientation = .down
        print("Device PortraitUpsideDown")
    }else{
       imageOrientation = .up
    }
    return imageOrientation
}

并将我的扩展名更改为以下内容:
    extension FishCameraVC: AVCapturePhotoCaptureDelegate {
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            image = UIImage(data: imageData)
            let dataProvider  = CGDataProvider(data: imageData as CFData)
            let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
            self.image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: imageOrientation!)
            performSegue(withIdentifier: "ShowTakenPhoto", sender: nil)
        }
    }
}

这个图像在预览时显示的方向是正确的,但当我保存它时,它变成了纵向。

1
https://dev59.com/wGQo5IYBdhLWcg3wiv_A#69580115 - YodagamaHeshan
4个回答

11
在调用capturePhoto()之前,您需要运行以下代码:
if let photoOutputConnection = CustomCamera.photoOutput.connection(with: AVMediaType.video) {
    photoOutputConnection.videoOrientation = videoDeviceOrientation
}

你可以使用managePhotoOrientation()函数来获取videoDeviceOrientation。

谢谢您的答案,我已经完全按照苹果的建议改变了我的代码。以下是示例代码链接:https://developer.apple.com/library/content/samplecode/AVCam/Listings/Swift_AVCam_CameraViewController_swift.html#//apple_ref/doc/uid/DTS40010112-Swift_AVCam_CameraViewController_swift-DontLinkElementID_15 - Marco
AVCam是我基于其进行照片捕获的。你应该在那段代码中看到videoOrientation的设置。 - adamfowlerphoto
我明白了,你的答案确实是正确的。我只是想分享一下链接,以防有人需要它。但我想我可以接受这个答案。 - Marco

6

我曾遇到类似问题,通过基于拍摄的照片生成新图像来解决:

UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
image.draw(in: CGRect(origin: .zero, size: image.size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

显然,由iOS生成的图像元数据(包括方向)是不完整的,一些查看器(在我的情况下是Chrome和Safari浏览器)无法正确渲染图像。通过重新渲染,元数据似乎对所有查看器都设置正确了。
请注意,1)在我的应用程序中,我还缩小了图像(我认为这不会改变效果),并且2)我通过其他方式捕获图像(即UIImagePickerController);不过,您仍可以尝试我的hacky修复方法。

{btsdaf} - Marco
{btsdaf} - dr_barto
{btsdaf} - Marco
{btsdaf} - dr_barto
{btsdaf} - Marco

1

基于 dr_barto 的源代码,我为 UIImage 编写了一个扩展:

extension UIImage {
    var orientationCorrectedImage: UIImage? {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        self.draw(in: CGRect(origin: .zero, size: self.size))
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}

0

Swift 4.2最新的AVFoundation捕获图像方向语法(经过测试的代码)。

UIGraphicsBeginImageContextWithOptions((image?.size)!, false, (image?.scale)!)
image?.draw(in: CGRect(origin: .zero, size: (image?.size)!))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接