From 90da40e68f53234f3fb7d45f9cd7ab4ad7eebcb7 Mon Sep 17 00:00:00 2001 From: Haik Aslanyan Date: Thu, 5 Mar 2020 17:57:43 +0400 Subject: [PATCH] added CVPixel cropping --- Sources/Public/RCCameraViewController.swift | 94 +++++++++++++-------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/Sources/Public/RCCameraViewController.swift b/Sources/Public/RCCameraViewController.swift index 89e32bc..6c9b46c 100644 --- a/Sources/Public/RCCameraViewController.swift +++ b/Sources/Public/RCCameraViewController.swift @@ -23,12 +23,21 @@ import UIKit import AVFoundation -public class RCCameraViewController: UIViewController, UIImagePickerControllerDelegate { +public final class RCCameraViewController: UIViewController, UIImagePickerControllerDelegate { //MARK: Public properties public weak var delegate: RCCameraViewControllerDelegate? - public var cancelButtonTitle = "Cancel" + public var configuration = RCCoderConfiguration.defaultConfiguration + override public var supportedInterfaceOrientations: UIInterfaceOrientationMask { + .portrait + } + public override var prefersStatusBarHidden: Bool { + true + } //Private properties + private lazy var coder: RCCoder = { + RCCoder(configuration: self.configuration) + }() private var captureSession = AVCaptureSession() private var videoPreviewLayer: AVCaptureVideoPreviewLayer? private var maskLayer = CAShapeLayer() @@ -44,6 +53,7 @@ public class RCCameraViewController: UIViewController, UIImagePickerControllerDe return cameraView }() + //MARK: Inits public required init?(coder: NSCoder) { super.init(coder: coder) @@ -97,39 +107,27 @@ extension RCCameraViewController { //MARK: Private methods extension RCCameraViewController { - func configureCancelButton() { - let topView = UIView() - let topContainerView = UIView() - view.addSubview(topView) - topView.addSubview(topContainerView) - [topView, topContainerView].forEach { view in - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = .clear - view.leadingAnchor.constraint(equalTo: view.superview!.leadingAnchor).isActive = true - view.trailingAnchor.constraint(equalTo: view.superview!.trailingAnchor).isActive = true + private func configureCancelButton() { + let cancelButton = UIButton(type: .custom) + cancelButton.addTarget(self, action: #selector(cancelPressed), for: .touchUpInside) + cancelButton.setImage(UIImage(systemName: "xmark"), for: .normal) + cancelButton.tintColor = .white + view.addSubview(cancelButton) + cancelButton.translatesAutoresizingMaskIntoConstraints = false + view.trailingAnchor.constraint(equalTo: cancelButton.trailingAnchor, constant: 30).isActive = true + cancelButton.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor, constant: 20).isActive = true + } + + @objc private func cancelPressed() { + dismiss(animated: true) { + self.delegate?.cameraViewControllerDidCancel(self) } - topView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true - topContainerView.heightAnchor.constraint(equalToConstant: 40).isActive = true - topContainerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor).isActive = true - topContainerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: 0).isActive = true - let button = UIButton(type: .system) - button.setTitle(cancelButtonTitle, for: .normal) - button.addTarget(self, action: #selector(cancelPressed), for: .touchUpInside) - button.tintColor = .white - topContainerView.addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - topContainerView.trailingAnchor.constraint(equalTo: button.trailingAnchor, constant: 20).isActive = true - button.centerYAnchor.constraint(equalTo: topContainerView.centerYAnchor).isActive = true } - @objc func cancelPressed() { - delegate?.cameraViewControllerDidCancel(self) - } - - func configureMaskLayer() { + private func configureMaskLayer() { let path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 0) - let centerPoint = CGPoint(x: view.bounds.midX, y: view.bounds.midY - 30) - let radius = min(view.bounds.width, view.bounds.height) / 2 - 50 + let centerPoint = CGPoint(x: view.bounds.midX, y: view.bounds.midY) + let radius = min(view.bounds.width, view.bounds.height) * 0.9 / 2 let circlePath = UIBezierPath(arcCenter: centerPoint, radius: radius, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true) path.append(circlePath) path.usesEvenOddFillRule = true @@ -142,12 +140,17 @@ extension RCCameraViewController { circleLayer.fillColor = UIColor.clear.cgColor } - func configureVideoStream() { + private func configureVideoStream() { guard let captureDevice = AVCaptureDevice.default(for: .video) else { return } do { + captureSession.sessionPreset = .hd1280x720 let input = try AVCaptureDeviceInput(device: captureDevice) captureSession.addInput(input) let videoOutput = AVCaptureVideoDataOutput() + if let con = videoOutput.connection(with: .video) { + con.videoOrientation = .portrait + print(123) + } videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .background)) videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)] captureSession.addOutput(videoOutput) @@ -156,7 +159,7 @@ extension RCCameraViewController { } } - func configureVideoPreview(orientation: AVCaptureVideoOrientation = .portrait) { + private func configureVideoPreview(orientation: AVCaptureVideoOrientation = .portrait) { videoPreviewLayer?.removeFromSuperlayer() videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) videoPreviewLayer?.videoGravity = .resizeAspectFill @@ -170,6 +173,29 @@ extension RCCameraViewController { extension RCCameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate { public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { - + connection.videoOrientation = .portrait + guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } + CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly) + let date = Date() + let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) + let bufferHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0) + let bufferWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0) + let size = min(bufferWidth, bufferHeight) + let origin = (max(bufferWidth, bufferHeight) - size) / 2 + let lumaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)?.advanced(by: bytesPerRow * origin) + let lumaCopy = UnsafeMutableRawPointer.allocate(byteCount: bytesPerRow * size, alignment: MemoryLayout.alignment) + lumaCopy.copyMemory(from: lumaBaseAddress!, byteCount: bytesPerRow * size) + let bufferData = UnsafeMutableBufferPointer(start: lumaCopy.bindMemory(to: UInt8.self, capacity: size * bytesPerRow), count: size * bytesPerRow) + if let message = try? coder.decode(bufferData, size: size) { + DispatchQueue.main.async {[weak self] in + guard let weakSelf = self else { return } + weakSelf.dismiss(animated: true) { + weakSelf.delegate?.cameraViewController(weakSelf, didFinishPickingScanning: message) + } + } + } + print(Date().timeIntervalSince(date)) + lumaCopy.deallocate() + CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly) } }