相机仅在人像模式下快速拍照

Posted

技术标签:

【中文标题】相机仅在人像模式下快速拍照【英文标题】:Camera only takes pictures in portrait mode swift 【发布时间】:2016-08-02 12:33:37 【问题描述】:

如何将相机设置为横向模式?每次我拍照时,图像都会保存为肖像图像。当设备处于横向模式时,照片看起来不错,但如果我在相机胶卷中看到它,它仍然是纵向模式。 这是我的拍照功能:

// take a photo
@IBAction func takePhoto(sender: AnyObject) 
self.fullScreenView.hidden = false
self.recordButton.enabled = false
self.takephoto.enabled = false
self.recordButton.hidden = true
self.takephoto.hidden = true

session.startRunning()

// customize the quality level or bitrate of the output photo
session.sessionPreset = AVCaptureSessionPresetPhoto

// add the AVCaptureVideoPreviewLayer to the view and set the view in fullscreen
fullScreenView.frame = view.bounds
videoPreviewLayer.frame = fullScreenView.bounds
fullScreenView.layer.addSublayer(videoPreviewLayer)

// add action to fullScreenView
gestureFullScreenView = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhoto(_:)))
self.fullScreenView.addGestureRecognizer(gestureFullScreenView)

// add action to myView
gestureView = UITapGestureRecognizer(target: self, action: #selector(ViewController.setFrontpage(_:)))
self.view.addGestureRecognizer(gestureView)

if (preview == true) 
    if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) 
        // code for photo capture goes here...

        stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler:  (sampleBuffer, error) -> Void in
            // process the image data (sampleBuffer) here to get an image file we can put in our view

            if (sampleBuffer != nil) 
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let image = UIImage(data: imageData, scale: 1.0)

                self.fullScreenView.hidden = true
                self.fullScreenView.gestureRecognizers?.forEach(self.fullScreenView.removeGestureRecognizer)
                self.session.stopRunning()

                // save image to the library
                UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)

                self.imageViewBackground = UIImageView(frame: self.view.bounds)
                self.imageViewBackground.image = image
                self.imageViewBackground.tag = self.key

                self.view.addSubview(self.imageViewBackground)
            
        )
    

else 
    preview = true


我的预览看起来像这样,没关系:

http://img5.fotos-hochladen.net/uploads/bildschirmfotom4s7diaehy.png

但最终看起来是这样的:

http://img5.fotos-hochladen.net/uploads/bildschirmfoto3c2rlwtevf.png

提前致谢!

【问题讨论】:

【参考方案1】:

因为无论您的设备是纵向还是横向,您的 videoConnection 的方向 始终是纵向的。所以你应该在拍摄静态照片之前将 videoConnection 的方向调整到正确的方向

添加如下方法获取当前deviceOrientation的videoOrientation

func videoOrientation(for deviceOrientation: UIDeviceOrientation) -> AVCaptureVideoOrientation 
    switch deviceOrientation 
    case UIDeviceOrientation.portrait:
        return AVCaptureVideoOrientation.portrait
    case UIDeviceOrientation.landscapeLeft:
        return AVCaptureVideoOrientation.landscapeRight
    case UIDeviceOrientation.landscapeRight:
        return AVCaptureVideoOrientation.landscapeLeft
    case UIDeviceOrientation.portraitUpsideDown:
        return AVCaptureVideoOrientation.portraitUpsideDown
    default:
        return AVCaptureVideoOrientation.portrait
    

就在下面一行

if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) 

添加以下行

videoConnection.videoOrientation = videoOrientation(for: UIDevice.current.orientation)

注意:如果您的应用仅支持纵向或横向模式,此问题仍然会发生,因为UIDevice.current.orientation 将始终返回支持的方向。为了克服这个问题,您可以使用CoreMotion 来检测设备方向,然后将其传递给videoOrientation(for:) 方法。

希望这会有所帮助:)

【讨论】:

对于当前的 swift 版本,我做了一些小改动,但效果很好,我把它放在我的拍照功能中【参考方案2】:

我从@Yodagama 得到了答案,但他没有添加如何检测方向

if let photoOutputConnection = self.photoOutput.connection(with: .video) 

                            // USE the below function HERE
    photoOutputConnection.videoOrientation = videoOrientation()

    
photoOutput.capturePhoto(with: settings, delegate: self)

检测设备方向的功能:

func videoOrientation() -> AVCaptureVideoOrientation 
    
    var videoOrientation: AVCaptureVideoOrientation!
    
    let orientation: UIDeviceOrientation = UIDevice.current.orientation
    
    switch orientation 
        
    case .faceUp, .faceDown, .unknown:
        
        // let interfaceOrientation = UIApplication.shared.statusBarOrientation
        
        if let interfaceOrientation = UIApplication.shared.windows.first(where:  $0.isKeyWindow )?.windowScene?.interfaceOrientation 
            
            switch interfaceOrientation 
                
            case .portrait, .portraitUpsideDown, .unknown:
                videoOrientation = .portrait
            case .landscapeLeft:
                videoOrientation = .landscapeRight
            case .landscapeRight:
                videoOrientation = .landscapeLeft
            @unknown default:
                videoOrientation = .portrait
            
        
        
    case .portrait, .portraitUpsideDown:
        videoOrientation = .portrait
    case .landscapeLeft:
        videoOrientation = .landscapeRight
    case .landscapeRight:
        videoOrientation = .landscapeLeft
    @unknown default:
        videoOrientation = .portrait
    
    
    return videoOrientation

【讨论】:

【参考方案3】:

可能的解决方案:将图像保存为 JPEG 而不是 PNG

这是因为 PNG 不存储方向信息。将照片另存为 JPG,它的方向会正确。

使用此代码在拍摄图像后立即将图像转换为 JPG(第二行是此处的操作):

let image = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
let imageData:NSData = UIImageJPEGRepresentation(image, 0.9)! // 0.9 is compression value: 0.0 is most compressed/lowest quality and 1.0 is least compressed/highest quality

来源+更多信息:https://***.com/a/34796890/5700898


如果这不起作用

我已经在几个地方编辑了你的代码,看看下面的代码现在是否能如你所愿:

// initialize saving photo capabilities
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>) 
        if error == nil 
            print("image saved")
         else 
            print("save error: \(error?.localizedDescription)")
        


// take a photo
@IBAction func takePhoto(sender: AnyObject) 
self.fullScreenView.hidden = false
self.recordButton.enabled = false
self.takephoto.enabled = false
self.recordButton.hidden = true
self.takephoto.hidden = true

session.startRunning()

// customize the quality level or bitrate of the output photo
session.sessionPreset = AVCaptureSessionPresetPhoto

// add the AVCaptureVideoPreviewLayer to the view and set the view in fullscreen
fullScreenView.frame = view.bounds
videoPreviewLayer.frame = fullScreenView.bounds
fullScreenView.layer.addSublayer(videoPreviewLayer)

// add action to fullScreenView
gestureFullScreenView = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhoto(_:)))
self.fullScreenView.addGestureRecognizer(gestureFullScreenView)

// add action to myView
gestureView = UITapGestureRecognizer(target: self, action: #selector(ViewController.setFrontpage(_:)))
self.view.addGestureRecognizer(gestureView)

if (preview == true) 
    if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) 
        // code for photo capture goes here...

        stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler:  (sampleBuffer, error) -> Void in
            // process the image data (sampleBuffer) here to get an image file we can put in our view

            if (sampleBuffer != nil) 
                self.stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
        if let videoConnection = self.stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo)
            videoConnection.videoOrientation = self.interfaceToVideoOrientation()
            self.stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: 
                (sampleBuffer, error) in
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let image = UIImage(data: imageData)

                self.fullScreenView.hidden = true
                self.fullScreenView.gestureRecognizers?.forEach(self.fullScreenView.removeGestureRecognizer)
                self.session.stopRunning()

                // save image to the library
                UIImageWriteToSavedPhotosAlbum(image, self, #selector(ViewController.image(_:didFinishSavingWithError:contextInfo:)), nil)

                self.imageViewBackground = UIImageView(frame: self.view.bounds)
                self.imageViewBackground.image = image
                self.imageViewBackground.tag = self.key

                self.view.addSubview(self.imageViewBackground)
            
        )
    

else 
    preview = true


【讨论】:

我想我把它保存为 JPEG 还是我错了? let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) @mafioso 尝试将您的 imageData 声明更改为我在上面所做的声明,我不确定您的是否有效。如果那不能解决您的问题,我会更深入地研究;)。请告诉我。 好的,我会试试的 ;) 但我仍然不知道为什么它在纵向模式下完美地工作,而不是在横向模式下 我应该如何处理 imageData ? 将项目中的这行代码 (let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)) 替换为我在上面的答案中输入的行,@mafioso。

以上是关于相机仅在人像模式下快速拍照的主要内容,如果未能解决你的问题,请参考以下文章

用相机意图拍照以肖像模式android旋转图片

Android | 教你如何使用HwCameraKit接入相机人像模式

CameraView 中的人像模式

用苹果手机拍照,连这三个功能都不会,你的iPhone白买了

相机参数知识

华为p40手机相机专业模式怎么用?