AVCAPTURE图像方向 [英] AVCAPTURE image orientation

查看:117
本文介绍了AVCAPTURE图像方向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个允许用户拍照的视图控制器。我将avcapture边界设置为屏幕上视图的边界。

I have a view controller which allows a user to take a picture. I am setting the avcapture bounds to be the bounds of a view on screen.

在此视图上方,我有一个集合视图。因此,用户可以捕获多张图片,然后将它们添加到上面的集合视图中。

Above this view I have a collection view. So users can capture multiple pictures, they are then added to the collection view above.

我在上面的预览中出现了正确方向的问题。

I am having trouble with the correct orientation appearing in my preview above.

代码如下:

@IBOutlet weak var imagePreviews: UICollectionView!
@IBOutlet weak var imgPreview: UIView!

var session: AVCaptureSession?
var stillImageOutput: AVCaptureStillImageOutput?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var images: [UIImage] = [UIImage]()

var isLandscapeLeft     : Bool = false
var isLandscapeRight    : Bool = false
var isPortrait          : Bool = false
var isPortraitUpsideDown: Bool = false

@IBAction func capture(_ sender: UIButton)
    {
    if let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo)
            {
                stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) in
                    if sampleBuffer != nil {
                        if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer), let dataProvider = CGDataProvider(data: imageData as CFData), let cgImageRef = CGImage(jpegDataProviderSource: dataProvider, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
                        {
                            var image: UIImage

                            if (self.isLandscapeLeft || self.isLandscapeRight)
                            {
                                image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: self.isLandscapeLeft ? UIImageOrientation.left : UIImageOrientation.right)
                            } else {
                                image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: self.isPortrait ? UIImageOrientation.up : UIImageOrientation.down)
                            }

                            image = self.fixOrientation(img: image)
                            self.images.append(image)


                            DispatchQueue.main.async {
                                self.imagePreviews.reloadData()
                            }
                        }
                    }
                })
            }
        }
   } 

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()

    if let connection =  self.videoPreviewLayer?.connection  {

        let currentDevice: UIDevice = UIDevice.current

        let orientation: UIDeviceOrientation = currentDevice.orientation

        let previewLayerConnection : AVCaptureConnection = connection

        if (previewLayerConnection.isVideoOrientationSupported) {

            switch (orientation) {
            case .portrait:

                isLandscapeLeft      = false
                isLandscapeRight     = false
                isPortrait           = true
                isPortraitUpsideDown = false
                updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)
                break

            case .landscapeRight:

                isLandscapeLeft      = false
                isLandscapeRight     = true
                isPortrait           = false
                isPortraitUpsideDown = false
                updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight)
                break

            case .landscapeLeft:

                isLandscapeLeft      = true
                isLandscapeRight     = false
                isPortrait           = false
                isPortraitUpsideDown = false
                updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft)
                break
            case .portraitUpsideDown:

                isLandscapeLeft      = false
                isLandscapeRight     = false
                isPortrait           = false
                isPortraitUpsideDown = true
                updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown)
                break
            default:

                updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait)

                break
            }
        }
    }
}

func fixOrientation(img: UIImage) -> UIImage {
        if (img.imageOrientation == .up) {
            return img
        }

        UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
        let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
        img.draw(in: rect)

        let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return normalizedImage
    }


推荐答案

从纵向设备创建图像时,您应该考虑旋转90度的 UIImage ,例如:

When creating the image from a portrait orientation device, you should consider that a UIImage that has been rotated 90 degrees, e.g.:

switch UIApplication.shared.statusBarOrientation {
case .portrait:
    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .right)
case .landscapeRight:
    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .up)
case .landscapeLeft:
    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .down)
case .portraitUpsideDown:
    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .left)
default:
    fatalError("Unexpected orientation")
}

完整例如,请参阅:

import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var videoPreviewView: UIView!
    var videoPreviewLayer: AVCaptureVideoPreviewLayer!

    var session: AVCaptureSession = AVCaptureSession()
    var stillImageOutput: AVCaptureStillImageOutput = {
        let output = AVCaptureStillImageOutput()
        output.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
        return output
    }()

    var images: [UIImage] = [UIImage]()

    var orientation = UIApplication.shared.statusBarOrientation

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let device = AVCaptureDevice.default(for: .video) else {
            print("Unable to create capture device")
            return
        }

        let input: AVCaptureDeviceInput
        do {
            input = try AVCaptureDeviceInput(device: device)
        } catch {
            print("Unable to create input", error)
            return
        }

        guard session.canAddInput(input) else {
            print("Cannot add input")
            return
        }
        session.addInput(input)

        guard session.canAddOutput(stillImageOutput) else {
            print("Cannot add output")
            return
        }
        session.addOutput(stillImageOutput)

        session.startRunning()
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
        videoPreviewView.layer.addSublayer(videoPreviewLayer)
    }

    @IBAction func didTapCaptureButton(_ sender: Any) {
        if let connection = stillImageOutput.connection(with: .video) {
            stillImageOutput.captureStillImageAsynchronously(from: connection) { sampleBuffer, error in
                guard let sampleBuffer = sampleBuffer, error == nil else {
                    print(error ?? "Unknown error")
                    return
                }

                guard
                    let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer),
                    let dataProvider = CGDataProvider(data: imageData as CFData),
                    let cgImageRef = CGImage(jpegDataProviderSource: dataProvider, decode: nil, shouldInterpolate: true, intent: .defaultIntent) else {
                        print("unable to capture image")
                        return
                }

                var image: UIImage?

                switch self.orientation {
                case .portrait:
                    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .right)
                case .landscapeRight:
                    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .up)
                case .landscapeLeft:
                    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .down)
                case .portraitUpsideDown:
                    image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: .left)
                default:
                    fatalError("Unexpected orientation")
                }

                guard image != nil else {
                    print("unable to create UIImage")
                    return
                }

                DispatchQueue.main.async {
                    self.images.append(image!)
                    self.imageView.image = image
                }
            }

        }
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if let connection =  self.videoPreviewLayer?.connection  {
            orientation = UIApplication.shared.statusBarOrientation

            switch orientation {
            case .portrait:           updatePreviewOrientation(for: connection, to: .portrait)
            case .landscapeRight:     updatePreviewOrientation(for: connection, to: .landscapeRight)
            case .landscapeLeft:      updatePreviewOrientation(for: connection, to: .landscapeLeft)
            case .portraitUpsideDown: updatePreviewOrientation(for: connection, to: .portraitUpsideDown)
            default:                  updatePreviewOrientation(for: connection, to: .portrait)
            }
        }
    }

    private func updatePreviewOrientation(for connection: AVCaptureConnection, to orientation: AVCaptureVideoOrientation) {
        if connection.isVideoOrientationSupported {
            connection.videoOrientation = orientation
        }
        videoPreviewLayer.frame = videoPreviewView.bounds
    }
}

您在中手动转换图像方向fixOrientation 。使用相应的方向 CGImage 创建 UIImage 后,如果你不想要的话,你不必乱搞重建图像。

You are manually converting the image orientation in fixOrientation. Once you create UIImage from CGImage using the appropriate orientation, you don't have to mess around with recreating the image if you don't want.

这篇关于AVCAPTURE图像方向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆