123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- import UIKit
- import AVFoundation
- @available(iOS 10, *)
- final class EditScanViewController: UIViewController {
-
- lazy private var imageView: UIImageView = {
- let imageView = UIImageView()
- imageView.clipsToBounds = true
- imageView.isOpaque = true
- imageView.image = image
- imageView.backgroundColor = .black
- imageView.contentMode = .scaleAspectFit
- imageView.translatesAutoresizingMaskIntoConstraints = false
- return imageView
- }()
-
- lazy private var quadView: QuadrilateralView = {
- let quadView = QuadrilateralView()
- quadView.editable = true
- quadView.translatesAutoresizingMaskIntoConstraints = false
- return quadView
- }()
-
- lazy private var nextButton: UIBarButtonItem = {
- let title = NSLocalizedString("wescan.edit.button.next", comment: "A generic next button")
- let button = UIBarButtonItem(title: title, style: .plain, target: self, action: #selector(pushReviewController))
- button.tintColor = navigationController?.navigationBar.tintColor
- return button
- }()
-
- private let image: UIImage
-
-
- private var quad: Quadrilateral
-
- private var zoomGestureController: ZoomGestureController!
-
- private var quadViewWidthConstraint = NSLayoutConstraint()
- private var quadViewHeightConstraint = NSLayoutConstraint()
-
-
-
- init(image: UIImage, quad: Quadrilateral?) {
- self.image = image.applyingPortraitOrientation()
- self.quad = quad ?? EditScanViewController.defaultQuad(forImage: image)
- super.init(nibName: nil, bundle: nil)
- }
-
- required init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- setupViews()
- setupConstraints()
- title = NSLocalizedString("wescan.edit.title", comment: "The title of the EditScanViewController")
- navigationItem.rightBarButtonItem = nextButton
-
- zoomGestureController = ZoomGestureController(image: image, quadView: quadView)
-
- let touchDown = UILongPressGestureRecognizer(target:zoomGestureController, action: #selector(zoomGestureController.handle(pan:)))
- touchDown.minimumPressDuration = 0
- view.addGestureRecognizer(touchDown)
- }
-
- override func viewDidLayoutSubviews() {
- super.viewDidLayoutSubviews()
- adjustQuadViewConstraints()
- displayQuad()
- }
-
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
-
-
- navigationController?.navigationBar.tintAdjustmentMode = .normal
- navigationController?.navigationBar.tintAdjustmentMode = .automatic
- }
-
-
-
- private func setupViews() {
- view.addSubview(imageView)
- view.addSubview(quadView)
- }
-
- private func setupConstraints() {
- let imageViewConstraints = [
- imageView.topAnchor.constraint(equalTo: view.topAnchor),
- imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- view.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
- view.leadingAnchor.constraint(equalTo: imageView.leadingAnchor)
- ]
- quadViewWidthConstraint = quadView.widthAnchor.constraint(equalToConstant: 0.0)
- quadViewHeightConstraint = quadView.heightAnchor.constraint(equalToConstant: 0.0)
-
- let quadViewConstraints = [
- quadView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
- quadView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
- quadViewWidthConstraint,
- quadViewHeightConstraint
- ]
-
- NSLayoutConstraint.activate(quadViewConstraints + imageViewConstraints)
- }
-
-
-
- @objc func pushReviewController() {
- guard let quad = quadView.quad,
- let ciImage = CIImage(image: image) else {
- if let imageScannerController = navigationController as? ImageScannerController {
- let error = ImageScannerControllerError.ciImageCreation
- imageScannerController.imageScannerDelegate?.imageScannerController(imageScannerController, didFailWithError: error)
- }
- return
- }
-
- let scaledQuad = quad.scale(quadView.bounds.size, image.size)
- self.quad = scaledQuad
-
- var cartesianScaledQuad = scaledQuad.toCartesian(withHeight: image.size.height)
- cartesianScaledQuad.reorganize()
-
- let filteredImage = ciImage.applyingFilter("CIPerspectiveCorrection", parameters: [
- "inputTopLeft": CIVector(cgPoint: cartesianScaledQuad.bottomLeft),
- "inputTopRight": CIVector(cgPoint: cartesianScaledQuad.bottomRight),
- "inputBottomLeft": CIVector(cgPoint: cartesianScaledQuad.topLeft),
- "inputBottomRight": CIVector(cgPoint: cartesianScaledQuad.topRight)
- ])
-
- var uiImage: UIImage!
-
-
- if let cgImage = CIContext(options: nil).createCGImage(filteredImage, from: filteredImage.extent) {
- uiImage = UIImage(cgImage: cgImage)
- } else {
- uiImage = UIImage(ciImage: filteredImage, scale: 1.0, orientation: .up)
- }
-
- let results = ImageScannerResults(originalImage: image, scannedImage: uiImage, detectedRectangle: scaledQuad)
- let reviewViewController = ReviewViewController(results: results)
-
- navigationController?.pushViewController(reviewViewController, animated: true)
- }
- private func displayQuad() {
- let imageSize = image.size
- let imageFrame = CGRect(x: quadView.frame.origin.x, y: quadView.frame.origin.y, width: quadViewWidthConstraint.constant, height: quadViewHeightConstraint.constant)
-
- let scaleTransform = CGAffineTransform.scaleTransform(forSize: imageSize, aspectFillInSize: imageFrame.size)
- let transforms = [scaleTransform]
- let transformedQuad = quad.applyTransforms(transforms)
-
- quadView.drawQuadrilateral(quad: transformedQuad, animated: false)
- }
-
-
-
- private func adjustQuadViewConstraints() {
- let frame = AVMakeRect(aspectRatio: image.size, insideRect: imageView.bounds)
- quadViewWidthConstraint.constant = frame.size.width
- quadViewHeightConstraint.constant = frame.size.height
- }
-
-
- private static func defaultQuad(forImage image: UIImage) -> Quadrilateral {
- let topLeft = CGPoint(x: image.size.width / 3.0, y: image.size.height / 3.0)
- let topRight = CGPoint(x: 2.0 * image.size.width / 3.0, y: image.size.height / 3.0)
- let bottomRight = CGPoint(x: 2.0 * image.size.width / 3.0, y: 2.0 * image.size.height / 3.0)
- let bottomLeft = CGPoint(x: image.size.width / 3.0, y: 2.0 * image.size.height / 3.0)
-
- let quad = Quadrilateral(topLeft: topLeft, topRight: topRight, bottomRight: bottomRight, bottomLeft: bottomLeft)
-
- return quad
- }
- }
|