Skip to content

Commit

Permalink
Expose AVDocumentScanner to be public (#34)
Browse files Browse the repository at this point in the history
* Make stuff public

* Make more stuff public

* SwiftLint

* Add custom UIViewController class

Showing how to use the scanner directly

* Add some documentation
  • Loading branch information
xavierLowmiller authored and fbernutz committed May 5, 2019
1 parent 1a6f22d commit 76ba026
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 28 deletions.
8 changes: 6 additions & 2 deletions Example/YesWeScanExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
229B7B212170D5E700619215 /* Bundle+UserActivityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229B7B202170D5E700619215 /* Bundle+UserActivityIdentifier.swift */; };
4ED16A52227B68ED0020CEB2 /* CustomUIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ED16A51227B68ED0020CEB2 /* CustomUIViewController.swift */; };
AB100DEAC71BE98E3B0188D0 /* Pods_YesWeScanExampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F337E1B4DB2217E8FBAF8016 /* Pods_YesWeScanExampleApp.framework */; };
B23598F32097134700813B39 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B23598F22097134700813B39 /* AppDelegate.swift */; };
B23598F52097134700813B39 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B23598F42097134700813B39 /* ViewController.swift */; };
Expand All @@ -24,6 +25,7 @@
229B7B202170D5E700619215 /* Bundle+UserActivityIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+UserActivityIdentifier.swift"; sourceTree = "<group>"; };
22CF73BE216777DE008C9FEB /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
22D8225221676AE90035206F /* DocumentScannerApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DocumentScannerApp.entitlements; sourceTree = "<group>"; };
4ED16A51227B68ED0020CEB2 /* CustomUIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomUIViewController.swift; sourceTree = "<group>"; };
91CD6F12F8CED7AD02974558 /* Pods-YesWeScanExampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YesWeScanExampleApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-YesWeScanExampleApp/Pods-YesWeScanExampleApp.debug.xcconfig"; sourceTree = "<group>"; };
B23598EF2097134700813B39 /* YesWeScanExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YesWeScanExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
B23598F22097134700813B39 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -95,6 +97,7 @@
B2B60675209715C0005A43D4 /* Views */,
B23598F22097134700813B39 /* AppDelegate.swift */,
B23598F42097134700813B39 /* ViewController.swift */,
4ED16A51227B68ED0020CEB2 /* CustomUIViewController.swift */,
229B7B202170D5E700619215 /* Bundle+UserActivityIdentifier.swift */,
B23598F62097134700813B39 /* Main.storyboard */,
B23598F92097134800813B39 /* Assets.xcassets */,
Expand All @@ -107,10 +110,10 @@
B2B60675209715C0005A43D4 /* Views */ = {
isa = PBXGroup;
children = (
B2B60676209715D6005A43D4 /* LogoView.swift */,
B2B6067A20978DB8005A43D4 /* EditButton.swift */,
B2B6067C20985A3C005A43D4 /* IconButton.swift */,
B2B60676209715D6005A43D4 /* LogoView.swift */,
B2B6067820972343005A43D4 /* ScanButton.swift */,
B2B6067A20978DB8005A43D4 /* EditButton.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -263,6 +266,7 @@
B2B6067920972343005A43D4 /* ScanButton.swift in Sources */,
B23598F52097134700813B39 /* ViewController.swift in Sources */,
229B7B212170D5E700619215 /* Bundle+UserActivityIdentifier.swift in Sources */,
4ED16A52227B68ED0020CEB2 /* CustomUIViewController.swift in Sources */,
B2B60677209715D6005A43D4 /* LogoView.swift in Sources */,
B23598F32097134700813B39 /* AppDelegate.swift in Sources */,
);
Expand Down
64 changes: 64 additions & 0 deletions Example/YesWeScanExampleApp/CustomUIViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// CustomUIViewController.swift
// YesWeScanExampleApp
//
// Created by Xaver Lohmüller on 02.05.19.
// Copyright © 2019 adorsys GmbH & Co KG. All rights reserved.
//

import YesWeScan

final class CustomUIViewController: UIViewController {
private lazy var scanner: DocumentScanner = AVDocumentScanner(delegate: self)

private var detectionLayer: CAShapeLayer = {
let layer = CAShapeLayer()
layer.fillColor = UIColor.red.withAlphaComponent(0.3).cgColor
layer.strokeColor = UIColor.red.withAlphaComponent(0.9).cgColor
layer.lineWidth = 2
layer.contentsGravity = .resizeAspectFill
return layer
}()

override func viewDidLoad() {
super.viewDidLoad()
scanner.previewLayer.frame = UIScreen.main.bounds
view.layer.addSublayer(scanner.previewLayer)
scanner.previewLayer.addSublayer(detectionLayer)
}
}


extension CustomUIViewController: DocumentScannerDelegate {
func didCapture(image: UIImage) {
let imageView = UIImageView(image: image)
imageView.showAnimated(on: view)

scanner.stop()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
imageView.hideAnimated()
self.scanner.start()
}
}

func didRecognize(feature: RectangleFeature?, in image: CIImage) {
detectionLayer.path = feature?.bezierPath.cgPath
}
}

private extension UIView {
func showAnimated(on view: UIView, duration: TimeInterval = 0.5) {
frame = view.frame
alpha = 0
view.addSubview(self)
UIView.animate(withDuration: duration) {
self.alpha = 1
}
}

func hideAnimated(duration: TimeInterval = 0.5) {
UIView.animate(withDuration: duration,
animations: { self.alpha = 0 },
completion: { _ in self.removeFromSuperview() })
}
}
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This pod contains a ready to use view controller for document scanning. Yes we s
- [UI Configuration](#ui-configuration)
- [Performance hint](#performance-hint)
- [Siri Shortcuts](#siri-shortcuts)
- [Using the scanner directly](#using-the-scanner-directly)
- [License](#license)

## Requirements
Expand Down Expand Up @@ -201,6 +202,15 @@ func application(_ application: UIApplication, continue userActivity: NSUserActi
}
```

### Using the scanner directly

It's also possible to use the scanner class without the `ScannerViewController`
class (that is part of this pod) directly.

As an example how to do this, take a look at the [`CustomUIViewController`][custom VC] class.

[custom VC]: https://github.com/adorsys/YesWeScan/blob/master/Example/YesWeScanExampleApp/CustomUIViewController.swift

## License

YesWeScan is released under the **Apache 2.0 License**. Please see the [LICENSE](https://github.com/adorsys/YesWeScan/blob/master/LICENSE) file for more information.
8 changes: 4 additions & 4 deletions Sources/Classes/Maths/RectangleFeature.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import UIKit

struct RectangleFeature {
public struct RectangleFeature {
let topLeft: CGPoint
let topRight: CGPoint
let bottomLeft: CGPoint
Expand Down Expand Up @@ -60,7 +60,7 @@ extension RectangleFeature {
)
}

var bezierPath: UIBezierPath {
public var bezierPath: UIBezierPath {

let path = UIBezierPath()
path.move(to: topLeft)
Expand Down Expand Up @@ -92,11 +92,11 @@ extension RectangleFeature {
}

extension RectangleFeature: Comparable {
static func < (lhs: RectangleFeature, rhs: RectangleFeature) -> Bool {
public static func < (lhs: RectangleFeature, rhs: RectangleFeature) -> Bool {
return lhs.areaQualifier < rhs.areaQualifier
}

static func == (lhs: RectangleFeature, rhs: RectangleFeature) -> Bool {
public static func == (lhs: RectangleFeature, rhs: RectangleFeature) -> Bool {
return lhs.topLeft == rhs.topLeft
&& lhs.topRight == rhs.topRight
&& lhs.bottomLeft == rhs.bottomLeft
Expand Down
34 changes: 17 additions & 17 deletions Sources/Classes/Scanner/AVDocumentScanner.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import AVFoundation
import UIKit

final class AVDocumentScanner: NSObject {
public final class AVDocumentScanner: NSObject {
var lastTorchLevel: Float = 0
var desiredJitter: CGFloat = 100 {
public var desiredJitter: CGFloat = 100 {
didSet { progress.completedUnitCount = Int64(desiredJitter) }
}
var featuresRequired: Int = 7
public var featuresRequired: Int = 7

let progress = Progress()
public let progress = Progress()

lazy var previewLayer: CALayer = {
public lazy var previewLayer: CALayer = {
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
layer.videoGravity = .resizeAspectFill
return layer
Expand Down Expand Up @@ -46,8 +46,8 @@ final class AVDocumentScanner: NSObject {
output.setSampleBufferDelegate(self, queue: imageQueue)
}

convenience init(sessionPreset: AVCaptureSession.Preset = .photo,
delegate: DocumentScannerDelegate) {
public convenience init(sessionPreset: AVCaptureSession.Preset = .photo,
delegate: DocumentScannerDelegate) {
self.init(sessionPreset: sessionPreset)
self.delegate = delegate
}
Expand All @@ -64,8 +64,8 @@ final class AVDocumentScanner: NSObject {
deviceTypes: [.builtInWideAngleCamera],
mediaType: .video,
position: .back
).devices
.first { $0.hasTorch }
).devices
.first { $0.hasTorch }
}()

private lazy var output: AVCaptureVideoDataOutput = {
Expand All @@ -84,13 +84,13 @@ final class AVDocumentScanner: NSObject {
CIDetectorMaxFeatureCount: 10

// swiftlint:disable:next force_unwrapping
])!
])!
}

extension AVDocumentScanner: AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from _: AVCaptureConnection) {
public func captureOutput(_: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from _: AVCaptureConnection) {

guard isStopped == false,
CMSampleBufferIsValid(sampleBuffer),
Expand Down Expand Up @@ -137,20 +137,20 @@ extension AVDocumentScanner: AVCaptureVideoDataOutputSampleBufferDelegate {
}

extension AVDocumentScanner: DocumentScanner {
func captureImage(in bounds: RectangleFeature?, completion: @escaping (UIImage) -> Void) {
public func captureImage(in bounds: RectangleFeature?, completion: @escaping (UIImage) -> Void) {
imageCapturer.captureImage(in: bounds, completion: completion)
}
func start() {
public func start() {
guard !captureSession.isRunning else {
return
}
captureSession.startRunning()
isStopped = false
}
func pause() {
public func pause() {
isStopped = true
}
func stop() {
public func stop() {
guard captureSession.isRunning else {
return
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Classes/Scanner/DocumentScanner.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import AVFoundation
import UIKit

protocol DocumentScanner {
public protocol DocumentScanner {

/// Jitter of automatic capture. Higher values will capture images faster,
/// but will reduce quality. Default value is 100.
Expand Down
15 changes: 13 additions & 2 deletions Sources/Classes/Scanner/DocumentScannerDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import UIKit
import CoreImage

protocol DocumentScannerDelegate: AnyObject {
// Always called on main queue
// Methods are always called on main queue
public protocol DocumentScannerDelegate: AnyObject {

/// Called when the scanner successfully found an image
///
/// - Parameter image: The image that was found
func didCapture(image: UIImage)

/// Use this method to display a preview border of the image that is about
/// to be recognized
///
/// - Parameters:
/// - feature: The extent of the image that is being recognized
/// - image: The image that contains the image to be recognized
func didRecognize(feature: RectangleFeature?, in image: CIImage)
}
4 changes: 2 additions & 2 deletions Sources/Classes/ViewController/ScannerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,14 @@ extension ScannerViewController {
}

extension ScannerViewController: DocumentScannerDelegate {
func didCapture(image: UIImage) {
public func didCapture(image: UIImage) {
if let delegate = delegate {
scanner.pause()
delegate.scanner(self, didCaptureImage: image)
}
}

func didRecognize(feature: RectangleFeature?, in image: CIImage) {
public func didRecognize(feature: RectangleFeature?, in image: CIImage) {
guard let feature = feature else { detectionLayer.path = nil; return }

detectionLayer.path = feature.bezierPath.cgPath
Expand Down

0 comments on commit 76ba026

Please sign in to comment.