swift 拍摄照片时正确设置正确的图片方向

oknrviil  于 2023-08-02  发布在  Swift
关注(0)|答案(3)|浏览(313)

在我用Swift编写的iOS应用程序中,我需要拍照并将其保存在画廊中;作为苹果文档,所有的照片都采取了横向也如果手机是在纵向;如果我们按原样保存图片,它将被旋转90°保存。

问题:如何正确管理保存图片时的设备方向?

感谢一些搜索,我使用了这个解决方案:

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        // ...error handling here

        guard let imageData = photo.fileDataRepresentation(with: self) else {
            NSLog("Fail to convert pixel buffer")
            return
        }
        
        // Save image to gallery here
    }

字符串
我的类是AVCapturePhotoFileDataRepresentationCustomizer delegate,所以:

func replacementMetadata(for photo: AVCapturePhoto) -> [String : Any]? {
        var properties = photo.metadata

        // Image orientation
        properties[kCGImagePropertyOrientation as String] = CGImagePropertyOrientation.right
        
        let exifData = NSMutableDictionary(dictionary: properties[kCGImagePropertyExifDictionary as String] as! NSDictionary)
        let xDimension = exifData[kCGImagePropertyExifPixelYDimension as String]
        let yDimension = exifData[kCGImagePropertyExifPixelXDimension as String]
        
        if xDimension != nil && yDimension != nil {
            exifData[kCGImagePropertyExifPixelXDimension as String] = xDimension
            exifData[kCGImagePropertyExifPixelYDimension as String] = yDimension
            
            properties[kCGImagePropertyExifDictionary as String] = exifData
        }
        
        return properties
    }


因为图像是纵向拍摄的,方向是.right,我在搜索中读到,exif数据中的X和Y维度也应该交换。
不幸的是,一切都没有结果:使用exif资源管理器图像方向检查保存的图像时,仍为0=未知值,X和Y为原始设置。
我确信数据是正确设置和写入的,因为:

  1. return properties上的断点强调方向标记设置正确;此外,如果标签未正确设置或未知,则应用程序崩溃……
    1.在相同的replacementMetadata函数中,我还设置了GPS数据(为了简单起见,我在这里将其删除!),我写了一些测试值(如heading = 101),这些数据在最终的图像元数据中正确报告。
    所以我的问题是...感谢您用代码片段或文档为我指明了正确的方向。
jtjikinw

jtjikinw1#

您可以通过设置AVCapturePhotoOutputvideoOrientation将拍摄方向设置为任何您喜欢的方向。
要使其与当前设备方向相匹配,您可以使用UIDevice.current.orientation手动转换为AVCaptureVideoOrientation

let photoOutput = AVCapturePhotoOutput()

func takeShot() {

    // set whatever orientation you like
    let myShotOrientation = UIDevice.current.orientation.asCaptureVideoOrientation

    if let photoOutputConnection = self.photoOutput.connection(with: .video) {
        photoOutputConnection.videoOrientation = myShotOrientation
    }

    photoOutput.capturePhoto(...)
}

字符串
UIDeviceOrientation转换为AVCaptureVideoOrientation

extension UIDeviceOrientation {
    
    ///
    var asCaptureVideoOrientation: AVCaptureVideoOrientation {
        switch self {
        // YES, that's not a mistake
        case .landscapeLeft: return .landscapeRight
        case .landscapeRight: return .landscapeLeft
        case .portraitUpsideDown: return .portraitUpsideDown
        default: return .portrait
        }
    }
}

sdnqo3pr

sdnqo3pr2#

import Foundation
import CoreMotion
import AVFoundation
import UIKit

protocol OrientationHandlerDelegate: class {
   func didChange(deviceOrientation: UIDeviceOrientation)
}

class OrientationHandler {

  private let motionManager = CMMotionManager()
  private let queue = OperationQueue()
  private var deviceOrientation: UIDeviceOrientation = .unknown
  weak var delegate: OrientationHandlerDelegate?

  init() {
    motionManager.accelerometerUpdateInterval = 1.0
    motionManager.deviceMotionUpdateInterval = 1.0
    motionManager.gyroUpdateInterval = 1.0
    motionManager.magnetometerUpdateInterval = 1.0
  }

  func startMeasuring() {
    guard motionManager.isDeviceMotionAvailable else {
        return
    }
    motionManager.startAccelerometerUpdates(to: queue) { [weak self] (accelerometerData, error) in
        guard let strongSelf = self else {
            return
        }
        guard let accelerometerData = accelerometerData else {
            return
        }

        let acceleration = accelerometerData.acceleration
        let xx = -acceleration.x
        let yy = acceleration.y
        let z = acceleration.z
        let angle = atan2(yy, xx)
        var deviceOrientation = strongSelf.deviceOrientation
        let absoluteZ = fabs(z)

        if deviceOrientation == .faceUp || deviceOrientation == .faceDown {
            if absoluteZ < 0.845 {
                if angle < -2.6 {
                    deviceOrientation = .landscapeRight
                } else if angle > -2.05 && angle < -1.1 {
                    deviceOrientation = .portrait
                } else if angle > -0.48 && angle < 0.48 {
                    deviceOrientation = .landscapeLeft
                } else if angle > 1.08 && angle < 2.08 {
                    deviceOrientation = .portraitUpsideDown
                }
            } else if z < 0 {
                deviceOrientation = .faceUp
            } else if z > 0 {
                deviceOrientation = .faceDown
            }
        } else {
            if z > 0.875 {
                deviceOrientation = .faceDown
            } else if z < -0.875 {
                deviceOrientation = .faceUp
            } else {
                switch deviceOrientation {
                case .landscapeLeft:
                    if angle < -1.07 {
                        deviceOrientation = .portrait
                    }
                    if angle > 1.08 {
                        deviceOrientation = .portraitUpsideDown
                    }
                case .landscapeRight:
                    if angle < 0 && angle > -2.05 {
                        deviceOrientation = .portrait
                    }
                    if angle > 0 && angle < 2.05 {
                        deviceOrientation = .portraitUpsideDown
                    }
                case .portraitUpsideDown:
                    if angle > 2.66 {
                        deviceOrientation = .landscapeRight
                    }
                    if angle < 0.48 {
                        deviceOrientation = .landscapeLeft
                    }
                case .portrait:
                    if angle > -0.47 {
                        deviceOrientation = .landscapeLeft
                    }
                    if angle < -2.64 {
                        deviceOrientation = .landscapeRight
                    }
                default:
                    if angle > -0.47 {
                        deviceOrientation = .landscapeLeft
                    }
                    if angle < -2.64 {
                        deviceOrientation = .landscapeRight
                    }
                }
            }
        }
        if strongSelf.deviceOrientation != deviceOrientation {
            strongSelf.deviceOrientation = deviceOrientation
            strongSelf.delegate?.didChange(deviceOrientation: deviceOrientation)
        }
    }
  }

  func stopMeasuring() {
    motionManager.stopAccelerometerUpdates()
  }

  func currentInterfaceOrientation() -> AVCaptureVideoOrientation {
    switch deviceOrientation {
    case .portrait:
        return .portrait
    case .landscapeRight:
        return .landscapeLeft
    case .landscapeLeft:
        return .landscapeRight
    case .portraitUpsideDown:
        return .portraitUpsideDown
    default:
        return .portrait
    }
  }
}

字符串
在您的文件中有相机代码:

let orientationHandler = OrientationHandler()


当摄像机处于活动状态时,开始测量方向。

orientationHandler.delegate = self
orientationHandler.startMeasuring()


不使用摄像机时停止测量方向。

orientationHandler.stopMeasuring()
orientationHandler.delegate = nil


最后,在调用capturePhoto之前添加一行代码(使用:设置,委派:self)

//Need to correct image orientation before moving further
    if let photoOutputConnection = photoOutput?.connection(with: .video) {
        photoOutputConnection.videoOrientation = orientationHandler.currentInterfaceOrientation()
    }
    photoOutput?.capturePhoto(with: settings, delegate: self)

qnyhuwrf

qnyhuwrf3#

let deviceOrientation : UIDeviceOrientation =
UIDevice.current.orientation

var avcaptureOrientation : AVCaptureVideoOrientation = .landscapeRight

if (deviceOrientation == .landscapeLeft) {
    
    avcaptureOrientation = .landscapeRight
    
} else if (deviceOrientation == .landscapeRight ) {
    
    avcaptureOrientation = .landscapeLeft
    
} else if (deviceOrientation == .portrait) {
    
    avcaptureOrientation = .portrait
    
} else if (deviceOrientation == .portraitUpsideDown) {
    
    avcaptureOrientation = .portraitUpsideDown
    
}

self.previewLayer?.connection?.videoOrientation = avcaptureOrientation

self.photoOutput.connection(with: .video)?.videoOrientation = avcaptureOrientation

字符串

相关问题