Настройка вида камеры - PullRequest
       30

Настройка вида камеры

0 голосов
/ 09 апреля 2020

Я не слишком разбираюсь в Swift или Xcode, поэтому любая помощь будет признательна!

Я сделал отдельный файл .swift для моего контроллера QR / Camera. Я нашел это онлайн-руководство о том, как сделать QR Code Reader, и я набрал предоставленный код, и все в порядке, за исключением того, что изображение с камеры не отображается должным образом на экране (с использованием iPhone 8). Как настроить вид видео?

Код:

import UIKit
import AVFoundation

class CameraController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVCapturePhotoCaptureDelegate, AVCaptureMetadataOutputObjectsDelegate {

    @IBOutlet weak var previewView: UIView!
    @IBOutlet weak var lblOutput: UILabel!

    var imageOrientation: AVCaptureVideoOrientation?
    var captureSession: AVCaptureSession?
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    var capturePhotoOutput: AVCapturePhotoOutput?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get an instance of the AVCaptureDevice class to initialize a
        // device object and provide the video as the media type parameter
        guard let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) else {
            fatalError("No video device found")
        }
        // handler chiamato quando viene cambiato orientamento
        self.imageOrientation = AVCaptureVideoOrientation.portrait

        do {
            // Get an instance of the AVCaptureDeviceInput class using the previous deivce object
            let input = try AVCaptureDeviceInput(device: captureDevice)

            // Initialize the captureSession object
            captureSession = AVCaptureSession()

            // Set the input device on the capture session
            captureSession?.addInput(input)

            // Get an instance of ACCapturePhotoOutput class
            capturePhotoOutput = AVCapturePhotoOutput()
            capturePhotoOutput?.isHighResolutionCaptureEnabled = true

            // Set the output on the capture session
            captureSession?.addOutput(capturePhotoOutput!)
            captureSession?.sessionPreset = .high

            // Initialize a AVCaptureMetadataOutput object and set it as the input device
            let captureMetadataOutput = AVCaptureMetadataOutput()
            captureSession?.addOutput(captureMetadataOutput)

            // Set delegate and use the default dispatch queue to execute the call back
            captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]

            //Initialise the video preview layer and add it as a sublayer to the viewPreview view's layer
            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
            videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
            videoPreviewLayer?.frame = view.layer.bounds
            previewView.layer.addSublayer(videoPreviewLayer!)

            //start video capture
            captureSession?.startRunning()

        } catch {
            //If any error occurs, simply print it out
            print(error)
            return
        }

    }

    override func viewWillAppear(_ animated: Bool) {
        navigationController?.setNavigationBarHidden(true, animated: false)
        self.captureSession?.startRunning()
    }

    // Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
    func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
        let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
        for device in discoverySession.devices {
            if device.position == position {
                return device
            }
        }

        return nil
    }

    func metadataOutput(_ captureOutput: AVCaptureMetadataOutput,
                        didOutput metadataObjects: [AVMetadataObject],
                        from connection: AVCaptureConnection) {
        // Check if the metadataObjects array is contains at least one object.
        if metadataObjects.count == 0 {
            return
        }

        //self.captureSession?.stopRunning()

        // Get the metadata object.
        let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject

        if metadataObj.type == AVMetadataObject.ObjectType.qr {
            if let outputString = metadataObj.stringValue {
                DispatchQueue.main.async {
                    print(outputString)
                    self.lblOutput.text = outputString
                }
            }
        }

    }

}

Изображение текущего вида: enter image description here

Подсвеченный белый прямоугольник - UIView

enter image description here

Ответы [ 4 ]

2 голосов
/ 09 апреля 2020

Ошибка в том, что вы используете frame из view, но добавляете videoPreviewLayer к previewView, который меньше (как вы показали на раскадровке).

Замените строку на viewPreviewLayer frame конфигурация.

        //Initialise the video preview layer and add it as a sublayer to the viewPreview view's layer
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
        videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        videoPreviewLayer?.frame = view.layer.bounds
        previewView.layer.addSublayer(videoPreviewLayer!)

эта строка

        videoPreviewLayer?.frame = view.layer.bounds

до

        videoPreviewLayer?.frame = previewView.layer.bounds
1 голос
/ 09 апреля 2020

Я ожидаю, что произойдет одно из следующих событий: - Вы не настроили свои ограничения должным образом - Ваше представление изменяет размеры - Вы использовали неправильное представление для установки размера вашего слоя

Настройка ограничений практически невозможно объяснить написав это. Есть много способов их настройки, поэтому я сделал очень короткое видео, которое объясняет один или два способа о настройке ограничений.

Второй и третий могут быть объяснены в этом фрагменте :

override func viewDidLoad() {
    super.viewDidLoad()

        ...

    videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
    videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    previewView.layer.addSublayer(videoPreviewLayer!)
    updatePreviewLayerFrame()

        ...
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    updatePreviewLayerFrame()
}

private func updatePreviewLayerFrame() {
    videoPreviewLayer?.frame = previewView.bounds
}

Переопределение viewDidLayoutSubviews должно изменить размер вашего слоя, так как этот метод вызывается всякий раз, когда контроллер вида "изменяет размеры". Он также вызывается вскоре после viewDidLoad. Также обратите внимание, что previewView используется для определения кадра: videoPreviewLayer?.frame = previewView.bounds.

1 голос
/ 09 апреля 2020

Слои автоматически не изменяют размер с их родительского представления. Это означает, что ваш videoPreviewLayer получает кадр из оригинала (еще не выложенного) previewView и никогда не меняет его. Чтобы обновить слой, вы можете переопределить этот метод:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    // you need to keep a reference for that
    self.videoPreviewLayer.frame = self.previewView.bounds
}

В качестве альтернативы, и я думаю, что лучше, вы можете проверить, как реализован предварительный просмотр в примере приложения Apple AVCam . Изменение размера будет обрабатываться Auto Layout при использовании их подхода.

0 голосов
/ 09 апреля 2020

Вы должны использовать NSLayoutConstraint из раскадровки.

Шаг # 1

это ваше текущее состояние this is your current state

шаг # 2

добавить ограничение сверху, снизу, сверху и снизу add top, leading, trailing and bottom constraint

шаг # 3

окончательный результат final result

...