diff --git a/WeScan/ImageScannerController.swift b/WeScan/ImageScannerController.swift index c0cd0ab5..f5746970 100644 --- a/WeScan/ImageScannerController.swift +++ b/WeScan/ImageScannerController.swift @@ -76,29 +76,10 @@ public final class ImageScannerController: UINavigationController { // If an image was passed in by the host app (e.g. picked from the photo library), use it instead of the document scanner. if let image = image { - - var detectedQuad: Quadrilateral? - - // Whether or not we detect a quad, present the edit view controller after attempting to detect a quad. - // *** Vision *requires* a completion block to detect rectangles, but it's instant. - // *** When using Vision, we'll present the normal edit view controller first, then present the updated edit view controller later. - - guard let ciImage = CIImage(image: image) else { return } - let orientation = CGImagePropertyOrientation(image.imageOrientation) - let orientedImage = ciImage.oriented(forExifOrientation: Int32(orientation.rawValue)) - if #available(iOS 11.0, *) { - - // Use the VisionRectangleDetector on iOS 11 to attempt to find a rectangle from the initial image. - VisionRectangleDetector.rectangle(forImage: ciImage, orientation: orientation) { (quad) in - detectedQuad = quad?.toCartesian(withHeight: orientedImage.extent.height) - let editViewController = EditScanViewController(image: image, quad: detectedQuad, rotateImage: false) - self.setViewControllers([editViewController], animated: true) - } - } else { - // Use the CIRectangleDetector on iOS 10 to attempt to find a rectangle from the initial image. - detectedQuad = CIRectangleDetector.rectangle(forImage: ciImage)?.toCartesian(withHeight: orientedImage.extent.height) + detect(image: image) { [weak self] detectedQuad in + guard let self = self else { return } let editViewController = EditScanViewController(image: image, quad: detectedQuad, rotateImage: false) - setViewControllers([editViewController], animated: false) + self.setViewControllers([editViewController], animated: false) } } } @@ -111,6 +92,42 @@ public final class ImageScannerController: UINavigationController { fatalError("init(coder:) has not been implemented") } + private func detect(image: UIImage, completion: @escaping (Quadrilateral?) -> Void) { + // Whether or not we detect a quad, present the edit view controller after attempting to detect a quad. + // *** Vision *requires* a completion block to detect rectangles, but it's instant. + // *** When using Vision, we'll present the normal edit view controller first, then present the updated edit view controller later. + + guard let ciImage = CIImage(image: image) else { return } + let orientation = CGImagePropertyOrientation(image.imageOrientation) + let orientedImage = ciImage.oriented(forExifOrientation: Int32(orientation.rawValue)) + + if #available(iOS 11.0, *) { + // Use the VisionRectangleDetector on iOS 11 to attempt to find a rectangle from the initial image. + VisionRectangleDetector.rectangle(forImage: ciImage, orientation: orientation) { (quad) in + let detectedQuad = quad?.toCartesian(withHeight: orientedImage.extent.height) + completion(detectedQuad) + } + } else { + // Use the CIRectangleDetector on iOS 10 to attempt to find a rectangle from the initial image. + let detectedQuad = CIRectangleDetector.rectangle(forImage: ciImage)?.toCartesian(withHeight: orientedImage.extent.height) + completion(detectedQuad) + } + } + + public func useImage(image: UIImage) { + guard topViewController is ScannerViewController else { return } + + detect(image: image) { [weak self] detectedQuad in + guard let self = self else { return } + let editViewController = EditScanViewController(image: image, quad: detectedQuad, rotateImage: false) + self.setViewControllers([editViewController], animated: true) + } + } + + public func resetScanner() { + setViewControllers([ScannerViewController()], animated: true) + } + private func setupConstraints() { let blackFlashViewConstraints = [ blackFlashView.topAnchor.constraint(equalTo: view.topAnchor), diff --git a/WeScan/Scan/ScannerViewController.swift b/WeScan/Scan/ScannerViewController.swift index 63454daf..d3c74461 100644 --- a/WeScan/Scan/ScannerViewController.swift +++ b/WeScan/Scan/ScannerViewController.swift @@ -10,7 +10,7 @@ import UIKit import AVFoundation /// The `ScannerViewController` offers an interface to give feedback to the user regarding quadrilaterals that are detected. It also gives the user the opportunity to capture an image with a detected rectangle. -final class ScannerViewController: UIViewController { +public final class ScannerViewController: UIViewController { private var captureSessionManager: CaptureSessionManager? private let videoPreviewLayer = AVCaptureVideoPreviewLayer() @@ -67,10 +67,11 @@ final class ScannerViewController: UIViewController { // MARK: - Life Cycle - override func viewDidLoad() { + override public func viewDidLoad() { super.viewDidLoad() title = nil + view.backgroundColor = UIColor.black setupViews() setupNavigationBar() @@ -83,7 +84,7 @@ final class ScannerViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(subjectAreaDidChange), name: Notification.Name.AVCaptureDeviceSubjectAreaDidChange, object: nil) } - override func viewWillAppear(_ animated: Bool) { + override public func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setNeedsStatusBarAppearanceUpdate() @@ -95,13 +96,13 @@ final class ScannerViewController: UIViewController { navigationController?.navigationBar.barStyle = .blackTranslucent } - override func viewDidLayoutSubviews() { + override public func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() videoPreviewLayer.frame = view.layer.bounds } - override func viewWillDisappear(_ animated: Bool) { + override public func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) UIApplication.shared.isIdleTimerDisabled = false @@ -201,7 +202,7 @@ final class ScannerViewController: UIViewController { CaptureSession.current.removeFocusRectangleIfNeeded(focusRectangle, animated: true) } - override func touchesBegan(_ touches: Set, with event: UIEvent?) { + override public func touchesBegan(_ touches: Set, with event: UIEvent?) { super.touchesBegan(touches, with: event) guard let touch = touches.first else { return }