AVCAPTURE image orientation

青春壹個敷衍的年華 提交于 2019-12-20 02:34:11

问题


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.

Code is as follows:

@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
    }

回答1:


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")
}

For a complete example, see:

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
    }
}

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.



来源:https://stackoverflow.com/questions/46913953/avcapture-image-orientation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!