├── .gitignore ├── .swift-version ├── Example ├── Podfile ├── Podfile.lock ├── Pods │ ├── CropView │ │ ├── LICENSE │ │ ├── Pod │ │ │ └── Classes │ │ │ │ ├── Array+shift.swift │ │ │ │ ├── CGPoint+geometry.swift │ │ │ │ ├── SEAreaView.swift │ │ │ │ ├── SECornerView.swift │ │ │ │ ├── SECropError.swift │ │ │ │ ├── SECropView.swift │ │ │ │ ├── SEQuadrangleHelper.swift │ │ │ │ └── UIView+globalCoordinates.swift │ │ └── README.md │ ├── Local Podspecs │ │ └── SwiftDocumentScanner.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ └── Target Support Files │ │ ├── CropView │ │ ├── CropView-Info.plist │ │ ├── CropView-dummy.m │ │ ├── CropView-prefix.pch │ │ ├── CropView-umbrella.h │ │ ├── CropView.modulemap │ │ └── CropView.xcconfig │ │ ├── Pods-SwiftDocumentScanner_Example │ │ ├── Pods-SwiftDocumentScanner_Example-Info.plist │ │ ├── Pods-SwiftDocumentScanner_Example-acknowledgements.markdown │ │ ├── Pods-SwiftDocumentScanner_Example-acknowledgements.plist │ │ ├── Pods-SwiftDocumentScanner_Example-dummy.m │ │ ├── Pods-SwiftDocumentScanner_Example-frameworks.sh │ │ ├── Pods-SwiftDocumentScanner_Example-umbrella.h │ │ ├── Pods-SwiftDocumentScanner_Example.debug.xcconfig │ │ ├── Pods-SwiftDocumentScanner_Example.modulemap │ │ └── Pods-SwiftDocumentScanner_Example.release.xcconfig │ │ └── SwiftDocumentScanner │ │ ├── SwiftDocumentScanner-Info.plist │ │ ├── SwiftDocumentScanner-dummy.m │ │ ├── SwiftDocumentScanner-prefix.pch │ │ ├── SwiftDocumentScanner-umbrella.h │ │ ├── SwiftDocumentScanner.modulemap │ │ └── SwiftDocumentScanner.xcconfig ├── SwiftDocumentScanner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── SwiftDocumentScanner-Example.xcscheme ├── SwiftDocumentScanner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── SwiftDocumentScanner │ ├── Resources │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ └── Info.plist │ └── Sources │ ├── Controllers │ ├── CropController.swift │ ├── ResultController.swift │ └── ScannerController.swift │ └── Helpers │ └── AppDelegate.swift ├── LICENSE ├── README.md ├── SwiftDocumentScanner.podspec ├── SwiftDocumentScanner ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Controllers │ ├── CameraViewController.swift │ ├── DocumentCropViewController.swift │ └── DocumentScannerViewController.swift │ ├── Detectors │ ├── AutoDetector.swift │ ├── CIImageRectangleDetector.swift │ ├── NoSequenceRectangleDetector.swift │ ├── RectangleImageDetector.swift │ ├── SequenceRectangleDetector.swift │ ├── VisionImageRectangleDetector.swift │ └── VisionSequenceRectangleDetector.swift │ ├── Extensions │ ├── Array+extension.swift │ ├── CGPoint+Extension.swift │ ├── CGrect+Extension.swift │ └── UIImage+Extension.swift │ ├── Helpers │ └── CropHelper.swift │ ├── Models │ ├── Observation.swift │ ├── Quad.swift │ └── Result.swift │ └── Views │ └── TrackView.swift └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | # Pods/ 38 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.2 2 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'SwiftDocumentScanner_Example' do 4 | pod 'SwiftDocumentScanner', :path => '../' 5 | end 6 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CropView (0.1.6) 3 | - SwiftDocumentScanner (0.1.2): 4 | - CropView (= 0.1.6) 5 | 6 | DEPENDENCIES: 7 | - SwiftDocumentScanner (from `../`) 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - CropView 12 | 13 | EXTERNAL SOURCES: 14 | SwiftDocumentScanner: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | CropView: 2fad8340e54f433fd68a112a27007a4be4f580d0 19 | SwiftDocumentScanner: 038c994209ca6e583884550a654f0f9c500c8d13 20 | 21 | PODFILE CHECKSUM: 9b231fa4d40eac987db64f6e849f0e8775a035ba 22 | 23 | COCOAPODS: 1.6.0.beta.2 24 | -------------------------------------------------------------------------------- /Example/Pods/CropView/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Nikita Razumnuy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/Array+shift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Array+shift.swift 3 | // CropView 4 | // 5 | // Created by Никита Разумный on 2/3/18. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Array { 11 | func shifted(by shiftAmount: Int) -> Array { 12 | guard self.count > 0, (shiftAmount % self.count) != 0 else { return self } 13 | let moduloShiftAmount = shiftAmount % self.count 14 | 15 | let negativeShift = shiftAmount < 0 16 | let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount 17 | let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount } 18 | 19 | return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/CGPoint+geometry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPoint+geometry.swift 3 | // CropView 4 | // 5 | // Created by Никита Разумный on 2/3/18. 6 | // 7 | 8 | import UIKit 9 | 10 | extension CGPoint { 11 | func cartesian(for size: CGSize) -> CGPoint { 12 | return CGPoint(x: x, y: size.height - y) 13 | } 14 | static func cross(a: CGPoint, b: CGPoint) -> CGFloat { 15 | return a.x * b.y - a.y * b.x 16 | } 17 | func normalized(size: CGSize) -> CGPoint { 18 | return CGPoint(x: max(min(x, size.width), 0), y: max(min(y, size.height), 0)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/SEAreaView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AreaView.swift 3 | // CropViewController 4 | // 5 | // Created by Никита Разумный on 11/5/17. 6 | // Copyright © 2017 resquare. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SEAreaView: UIView { 12 | 13 | var cropView : SECropView? 14 | var isPathValid = true 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: frame) 18 | contentMode = .redraw 19 | 20 | CATransaction.begin() 21 | CATransaction.setDisableActions(true) 22 | CATransaction.commit() 23 | } 24 | 25 | required init?(coder aDecoder: NSCoder) { 26 | super.init(coder: aDecoder) 27 | contentMode = .redraw 28 | 29 | CATransaction.begin() 30 | CATransaction.setDisableActions(true) 31 | CATransaction.commit() 32 | } 33 | 34 | override func draw(_ rect: CGRect) { 35 | super.draw(rect) 36 | 37 | guard let path = cropView?.path else { return } 38 | 39 | let context = UIGraphicsGetCurrentContext() 40 | context?.setAllowsAntialiasing(true) 41 | context?.clip(to: rect) 42 | 43 | context?.addPath(path) 44 | context?.setLineWidth(1) 45 | context?.setLineCap(.round) 46 | context?.setLineJoin(.round) 47 | 48 | 49 | context?.setStrokeColor((isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor).cgColor) 50 | context?.strokePath() 51 | 52 | context?.saveGState() 53 | context?.addRect(bounds) 54 | context?.addPath(path) 55 | 56 | context?.setFillColor(UIColor(white: 0.3, alpha: 0.2).cgColor) 57 | context?.drawPath(using: .eoFill) 58 | 59 | context?.restoreGState() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/SECornerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CornerView.swift 3 | // CropViewController 4 | // 5 | // Created by Никита Разумный on 11/5/17. 6 | // Copyright © 2017 resquare. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SECornerView: UIView { 12 | 13 | override init(frame: CGRect) { 14 | super.init(frame: frame) 15 | layer.cornerRadius = frame.size.width / 2.0 16 | layer.borderWidth = 1.0 17 | layer.masksToBounds = true 18 | backgroundColor = UIColor.clear 19 | } 20 | 21 | required init?(coder aDecoder: NSCoder) { 22 | super.init(coder: aDecoder) 23 | } 24 | 25 | override func draw(_ rect: CGRect) { 26 | super.draw(rect) 27 | let position = superview!.convert(self.frame, to: nil) 28 | let touchPoint = position.origin 29 | 30 | let context = UIGraphicsGetCurrentContext()! 31 | 32 | context.translateBy(x: -(position.size.width / 2 - SECropView.cornerSize / 2), 33 | y: -(position.size.width / 2 - SECropView.cornerSize / 2)) 34 | 35 | context.translateBy(x: -touchPoint.x, 36 | y: -touchPoint.y) 37 | 38 | /* TODO: faster rendering 39 | isHidden = true 40 | (superview as! SECropView).areaQuadrangle.isHidden = true 41 | self.superview?.superview?.superview?.layer.render(in: context) 42 | (superview as! SECropView).areaQuadrangle.isHidden = false 43 | isHidden = false 44 | */ 45 | } 46 | 47 | func scaleUp() { 48 | UIView.animate(withDuration: 0.15, animations: { 49 | self.layer.borderWidth = 0.5 50 | self.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2) 51 | }) { (_) in 52 | self.setNeedsDisplay() 53 | } 54 | } 55 | 56 | func scaleDown() { 57 | UIView.animate(withDuration: 0.15, animations: { 58 | self.layer.borderWidth = 1 59 | self.transform = CGAffineTransform.identity 60 | }) { (_) in 61 | self.setNeedsDisplay() 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/SECropError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SECropError.swift 3 | // CropView 4 | // 5 | // Created by Никита Разумный on 2/3/18. 6 | // 7 | 8 | import UIKit 9 | 10 | public enum SECropError: Error { 11 | case missingSuperview 12 | case missingImageOnImageView 13 | case invalidNumberOfCorners 14 | case nonConvexRect 15 | case missingImageWhileCropping 16 | case unknown 17 | } 18 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/SECropView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CropView.swift 3 | // CropViewController 4 | // 5 | // Created by Никита Разумный on 11/5/17. 6 | // Copyright © 2017 resquare. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | public class SECropView: UIView { 13 | 14 | // MARK: properties 15 | public static var goodAreaColor = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1) 16 | public static var badAreaColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1) 17 | 18 | public static var cornerSize : CGFloat = 25.0 19 | 20 | var areaQuadrangle = SEAreaView() 21 | 22 | fileprivate var corners = Array() 23 | fileprivate var cornerOnTouch = -1 24 | fileprivate var imageView : UIImageView? 25 | 26 | var isPathvalid: Bool { 27 | return areaQuadrangle.isPathValid 28 | } 29 | 30 | public private(set) var cornerLocations : [CGPoint]? 31 | 32 | var path : CGMutablePath { 33 | let path = CGMutablePath() 34 | guard let firstPt = corners.first else { return CGMutablePath() } 35 | 36 | let initPt = CGPoint(x: firstPt.center.x - areaQuadrangle.frame.origin.x, 37 | y: firstPt.center.y - areaQuadrangle.frame.origin.y) 38 | path.move(to: initPt) 39 | for i in 0 ..< corners.count - 1 { 40 | let pt = CGPoint(x: corners[(i + 1) % corners.count].center.x - areaQuadrangle.frame.origin.x, 41 | y: corners[(i + 1) % corners.count].center.y - areaQuadrangle.frame.origin.y) 42 | path.addLine(to: pt) 43 | 44 | } 45 | path.closeSubpath() 46 | return path 47 | } 48 | 49 | var cornersScale : CGPoint? { 50 | guard let imageView = imageView else { return nil } 51 | guard let image = imageView.image else { return nil } 52 | 53 | let imageSizeAspectFit = AVMakeRect(aspectRatio: image.size, insideRect: imageView.bounds).size 54 | 55 | return CGPoint(x: imageSizeAspectFit.width / (image.size.width * image.scale), 56 | y: imageSizeAspectFit.height / (image.size.height * image.scale)) 57 | } 58 | 59 | public var cornersLocationOnView : [CGPoint]? { 60 | guard let imageSize = imageView?.image?.size else { return nil } 61 | guard let scale = cornersScale else { return nil } 62 | guard let imageViewFrame = imageView?.bounds else { return nil } 63 | guard let imageViewOrigin = imageView?.globalPoint else { return nil } 64 | guard let cropViewOrigin = self.globalPoint else { return nil } 65 | guard let cornersOnImage = cornerLocations else { return nil } 66 | 67 | let imageOrigin = AVMakeRect(aspectRatio: imageSize, insideRect: imageViewFrame).origin 68 | let shift = CGPoint(x: -cropViewOrigin.x + imageViewOrigin.x + imageOrigin.x + SECropView.cornerSize / 2.0, 69 | y: -cropViewOrigin.y + imageViewOrigin.y + imageOrigin.y + SECropView.cornerSize / 2.0) 70 | 71 | return cornersOnImage.map { 72 | CGPoint(x: $0.x * scale.x + shift.x, y: $0.y * scale.y + shift.y) 73 | } 74 | } 75 | 76 | // MARK: initialization 77 | 78 | override init(frame: CGRect) { 79 | super.init(frame: frame) 80 | internalInit() 81 | } 82 | 83 | required public init?(coder aDecoder: NSCoder) { 84 | super.init(coder: aDecoder) 85 | internalInit() 86 | } 87 | 88 | fileprivate func internalInit() { 89 | backgroundColor = UIColor.clear 90 | clipsToBounds = true 91 | autoresizingMask = [.flexibleWidth, .flexibleHeight] 92 | } 93 | 94 | // MARK: layout 95 | 96 | fileprivate func pairPositionsAndViews() { 97 | DispatchQueue.main.async { 98 | 99 | if let cornerPositions = self.cornersLocationOnView { 100 | for i in 0 ..< self.corners.count { 101 | self.corners[i].center = CGPoint(x: cornerPositions[i].x - SECropView.cornerSize / 2.0, 102 | y: cornerPositions[i].y - SECropView.cornerSize / 2.0) 103 | self.corners[i].setNeedsDisplay() 104 | } 105 | } 106 | self.areaQuadrangle.setNeedsDisplay() 107 | } 108 | } 109 | 110 | public override func layoutMarginsDidChange() { 111 | super.layoutMarginsDidChange() 112 | layoutSubviews() 113 | } 114 | 115 | public override func layoutSubviews() { 116 | super.layoutSubviews() 117 | print(#function) 118 | if let imgsize = imageView?.image?.size, let imageBounds = imageView?.bounds { 119 | let imageOrigin = AVMakeRect(aspectRatio: imgsize, insideRect: imageBounds) 120 | frame = imageOrigin 121 | areaQuadrangle.frame = AVMakeRect(aspectRatio: imgsize, insideRect: bounds) 122 | } 123 | self.pairPositionsAndViews() 124 | self.update(scale: 0) 125 | setNeedsDisplay() 126 | } 127 | 128 | public func configureWithCorners(corners : Array, on imageView: UIImageView) { 129 | self.cornerLocations = corners 130 | self.imageView = imageView 131 | self.imageView?.isUserInteractionEnabled = true 132 | imageView.addSubview(self) 133 | 134 | for subview in subviews { 135 | if subview is SECornerView { 136 | subview.removeFromSuperview() 137 | } 138 | } 139 | 140 | for _ in 0 ..< 4 { 141 | let corner = SECornerView(frame: CGRect(x: 0, y: 0, width: SECropView.cornerSize, height: SECropView.cornerSize)) 142 | addSubview(corner) 143 | self.corners.append(corner) 144 | } 145 | 146 | areaQuadrangle.autoresizingMask = [.flexibleWidth, .flexibleHeight] 147 | areaQuadrangle.frame = bounds 148 | areaQuadrangle.backgroundColor = .clear 149 | areaQuadrangle.cropView = self 150 | 151 | areaQuadrangle.isPathValid = SEQuadrangleHelper.checkConvex(corners: corners) 152 | addSubview(areaQuadrangle) 153 | for corner in self.corners { 154 | corner.layer.borderColor = (areaQuadrangle.isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor ).cgColor 155 | corner.scaleDown() 156 | } 157 | areaQuadrangle.setNeedsDisplay() 158 | layoutSubviews() 159 | } 160 | 161 | public func setCorners(newCorners: [CGPoint]) { 162 | areaQuadrangle.isPathValid = SEQuadrangleHelper.checkConvex(corners: newCorners) 163 | for i in 0 ..< corners.count { 164 | cornerLocations?[i] = newCorners[i] 165 | corners[i].layer.borderColor = (areaQuadrangle.isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor ).cgColor 166 | } 167 | pairPositionsAndViews() 168 | setNeedsDisplay() 169 | } 170 | 171 | fileprivate func update(scale : Int) { 172 | guard self.cornerOnTouch != -1 else { return } 173 | switch scale { 174 | case +1: 175 | self.corners[self.cornerOnTouch].scaleUp() 176 | self.bringSubviewToFront(self.corners[self.cornerOnTouch]) 177 | self.bringSubviewToFront(self.areaQuadrangle) 178 | case -1: 179 | self.corners[self.cornerOnTouch].scaleDown() 180 | default: break 181 | } 182 | 183 | self.corners[self.cornerOnTouch].setNeedsDisplay() 184 | self.areaQuadrangle.isPathValid = SEQuadrangleHelper.checkConvex(corners: self.corners.map{ $0.center }) 185 | for corner in self.corners { 186 | corner.layer.borderColor = (self.areaQuadrangle.isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor).cgColor 187 | } 188 | } 189 | 190 | // MARK: touches handling 191 | 192 | override public func touchesBegan(_ touches: Set, with event: UIEvent?) { 193 | super.touchesBegan(touches, with: event) 194 | 195 | guard touches.count == 1 && corners.count > 2 else { 196 | return 197 | } 198 | let point = touches.first!.location(in: self) 199 | 200 | var bestDistance : CGFloat = 1000.0 * 1000.0 * 1000.0 201 | 202 | for i in 0 ..< corners.count { 203 | let tmpPoint = corners[i].center 204 | let distance : CGFloat = 205 | (point.x - tmpPoint.x) * (point.x - tmpPoint.x) + 206 | (point.y - tmpPoint.y) * (point.y - tmpPoint.y) 207 | if distance < bestDistance { 208 | bestDistance = distance 209 | cornerOnTouch = i 210 | } 211 | } 212 | update(scale: +1) 213 | } 214 | 215 | override public func touchesMoved(_ touches: Set, with event: UIEvent?) { 216 | super.touchesMoved(touches, with: event) 217 | guard cornerOnTouch != -1 && touches.count == 1 else { 218 | return 219 | } 220 | 221 | let from = touches.first!.previousLocation(in: self) 222 | let to = touches.first!.location(in: self) 223 | 224 | let derivative = CGPoint(x: to.x - from.x, y: to.y - from.y) 225 | 226 | update(scale: 0) 227 | 228 | guard let scale = cornersScale else { return } 229 | guard let cornerLocations = cornerLocations else { return } 230 | guard let img = imageView?.image else { return } 231 | let newCenterOnImage = CGPoint(x: cornerLocations[cornerOnTouch].x + derivative.x / scale.x, 232 | y: cornerLocations[cornerOnTouch].y + derivative.y / scale.y).normalized(size: CGSize(width: img.size.width * img.scale, 233 | height: img.size.height * img.scale)) 234 | self.cornerLocations?[cornerOnTouch] = newCenterOnImage 235 | print(newCenterOnImage) 236 | 237 | pairPositionsAndViews() 238 | areaQuadrangle.setNeedsDisplay() 239 | } 240 | 241 | override public func touchesEnded(_ touches: Set, with event: UIEvent?) { 242 | super.touchesEnded(touches, with: event) 243 | 244 | guard cornerOnTouch != -1 && touches.count == 1 else { 245 | return 246 | } 247 | update(scale: -1) 248 | cornerOnTouch = -1 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/SEQuadrangleHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SEQuadrangleHelper.swift 3 | // CropView 4 | // 5 | // Created by Никита Разумный on 2/3/18. 6 | // 7 | 8 | import UIKit 9 | import Foundation 10 | import AVFoundation 11 | 12 | public class SEQuadrangleHelper { 13 | 14 | static internal func orderPointsInQuadrangle(quad: [CGPoint]) throws -> [CGPoint] { 15 | func orderArrayClockwise(quad: [CGPoint]) -> [CGPoint] { 16 | // oriented area of quadrangle: cloclwise if it > 0 17 | var square : CGFloat = 0.0 18 | for i in 0 ..< quad.count - 1 { 19 | square += CGPoint.cross(a: CGPoint(x: quad[i].x - quad[0].x, y: quad[i].y - quad[0].y), 20 | b: CGPoint(x: quad[i + 1].x - quad[0].x, y: quad[i + 1].y - quad[0].y)) 21 | } 22 | return square > 0 ? quad : quad.reversed() 23 | } 24 | 25 | func findTopLeftPointIndex(quad: [CGPoint]) throws -> Int { 26 | var topLeftPointIdx : Int = -1 27 | var topLeftShiftValue : CGFloat = 1000.0 * 1000.0 * 1000.0 28 | 29 | for i in 0 ..< quad.count { 30 | let shiftValue = quad[i].y + quad[i].x 31 | if shiftValue < topLeftShiftValue { 32 | topLeftPointIdx = i 33 | topLeftShiftValue = shiftValue 34 | } 35 | } 36 | guard topLeftPointIdx != -1 else { throw SECropError.unknown } 37 | return topLeftPointIdx 38 | } 39 | 40 | guard quad.count == 4 else { throw SECropError.invalidNumberOfCorners } 41 | guard checkConvex(corners: quad) else { throw SECropError.nonConvexRect } 42 | 43 | let orderedQuad = orderArrayClockwise(quad: quad) 44 | let topLeftIdx = try findTopLeftPointIndex(quad: orderedQuad) 45 | return orderedQuad.shifted(by: orderedQuad.count - topLeftIdx) 46 | } 47 | 48 | static public func cropImage(with image: UIImage, quad: [CGPoint]) throws -> UIImage { 49 | 50 | let ciImage = CIImage(image: image) 51 | 52 | let perspectiveCorrection = CIFilter(name: "CIPerspectiveCorrection") 53 | let imgSize = CGSize(width: image.size.width * image.scale, 54 | height: image.size.height * image.scale) 55 | 56 | let orderedQuad = try orderPointsInQuadrangle(quad: quad) 57 | let context = CIContext(options: nil) 58 | print("ordered quad: ", orderedQuad) 59 | 60 | guard let transform = perspectiveCorrection else { throw SECropError.unknown } 61 | transform.setValue(CIVector(cgPoint: orderedQuad[0].cartesian(for: imgSize)), 62 | forKey: "inputTopLeft") 63 | transform.setValue(CIVector(cgPoint: orderedQuad[1].cartesian(for: imgSize)), 64 | forKey: "inputTopRight") 65 | transform.setValue(CIVector(cgPoint: orderedQuad[2].cartesian(for: imgSize)), 66 | forKey: "inputBottomRight") 67 | transform.setValue(CIVector(cgPoint: orderedQuad[3].cartesian(for: imgSize)), 68 | forKey: "inputBottomLeft") 69 | transform.setValue(ciImage, forKey: kCIInputImageKey) 70 | 71 | guard let perspectiveCorrectedImg = transform.outputImage, let cgImage = context.createCGImage(perspectiveCorrectedImg, from: perspectiveCorrectedImg.extent) else { throw SECropError.unknown } 72 | 73 | return UIImage(cgImage: cgImage) 74 | } 75 | 76 | static internal func checkConvex(corners: [CGPoint]) -> Bool { 77 | guard corners.count > 2 else { 78 | return false 79 | } 80 | var positiveCount = 0 81 | var negativeCount = 0 82 | for i in 0 ..< corners.count { 83 | let p0 = corners[i] 84 | let p1 = corners[(i + 1) % corners.count] 85 | let p2 = corners[(i + 2) % corners.count] 86 | 87 | let cross = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x); 88 | if cross > 0 { 89 | positiveCount += 1 90 | } else if cross < 0 { 91 | negativeCount += 1 92 | } 93 | } 94 | return positiveCount == corners.count || negativeCount == corners.count 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Example/Pods/CropView/Pod/Classes/UIView+globalCoordinates.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+globalCoordinates.swift 3 | // CropView 4 | // 5 | // Created by Никита Разумный on 2/3/18. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIView { 11 | var globalPoint :CGPoint? { 12 | return self.superview?.convert(self.frame.origin, to: nil) 13 | } 14 | var globalFrame :CGRect? { 15 | return self.superview?.convert(self.frame, to: nil) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Pods/CropView/README.md: -------------------------------------------------------------------------------- 1 | # CropView 2 | Quadrangle view and image cropper like a Notes App 3 | 4 | 5 | 6 | # Demo 7 | ![Screenshot](https://github.com/rzmn/CropView/blob/master/sample.gif) 8 | 9 | # Usage 10 | ### Initialization 11 | Set initial coordinates in points 12 | ``` swift 13 | cropView.configureWithCorners(corners: [CGPoint(x: 120, y: 100), 14 | CGPoint(x: 270, y: 170), 15 | CGPoint(x: 280, y: 450), 16 | CGPoint(x: 120, y: 400)], on: imageView) 17 | ``` 18 | ### Customisation 19 | Customize color of your corners/contour and corners size 20 | ``` swift 21 | // SECornerView.swift 22 | static var cornerSize : CGFloat = 50.0 23 | ``` 24 | ``` swift 25 | // SECropView.swift 26 | static var goodAreaColor = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1) 27 | static var badAreaColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1) 28 | ``` 29 | ### Geometry 30 | ``` swift 31 | // SEQuadrangleHelper.swift 32 | 33 | // Crop image by quadrangle points in pixels 34 | static public func cropImage(with image: UIImage, quad: [CGPoint]) throws -> UIImage 35 | // get image frame in UIImageView and convert quadrangle coordinates into image pixels 36 | static public func getCoordinatesOnImageWithoutScale(on imageView: UIImageView, with cropView: SECropView) throws -> Array 37 | // get quadrangle coordinates, related by UIImageView frame in pixels 38 | static public func getCoordinatesOnImageView(on imageView: UIImageView, with cropView: SECropView) throws -> Array 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/SwiftDocumentScanner.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SwiftDocumentScanner", 3 | "version": "0.1.2", 4 | "summary": "Documentscanner app like Notes.", 5 | "homepage": "https://github.com/jonasbeckers/SwiftDocumentScanner", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "jonasbeckers": "jonas.beckers1996@gmail.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/jonasbeckers/SwiftDocumentScanner.git", 15 | "tag": "0.1.2" 16 | }, 17 | "platforms": { 18 | "ios": "10.0" 19 | }, 20 | "source_files": "SwiftDocumentScanner/Classes/**/*.swift", 21 | "dependencies": { 22 | "CropView": [ 23 | "0.1.6" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CropView (0.1.6) 3 | - SwiftDocumentScanner (0.1.2): 4 | - CropView (= 0.1.6) 5 | 6 | DEPENDENCIES: 7 | - SwiftDocumentScanner (from `../`) 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - CropView 12 | 13 | EXTERNAL SOURCES: 14 | SwiftDocumentScanner: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | CropView: 2fad8340e54f433fd68a112a27007a4be4f580d0 19 | SwiftDocumentScanner: 038c994209ca6e583884550a654f0f9c500c8d13 20 | 21 | PODFILE CHECKSUM: 9b231fa4d40eac987db64f6e849f0e8775a035ba 22 | 23 | COCOAPODS: 1.6.0.beta.2 24 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 021151AC01E28027E54461185DF463B6 /* UIView+globalCoordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A1FB796EF74E8169C3DB64236EE32F /* UIView+globalCoordinates.swift */; }; 11 | 048CD251168A67B1C534E12BFACA8382 /* DocumentScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3E5BB43FE5C5EBCA1D4CCD13CF479F /* DocumentScannerViewController.swift */; }; 12 | 0618D95CA6960BEE80B077004938BF50 /* SEQuadrangleHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 747013BA3A3D61698516C9A0968E7538 /* SEQuadrangleHelper.swift */; }; 13 | 0FF92826D3C1AA467233AD254C11C38A /* Observation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFAF7B88510469F2009C618240158417 /* Observation.swift */; }; 14 | 1062C418718A21FBBE9CF3D74392D1D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B294BC0E8D3950458000FF14B8023B7 /* Foundation.framework */; }; 15 | 18A1EE9A98ECC0F4201941760286D138 /* CropView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE128A8160011B1A7E7A7FDFE9BECAFA /* CropView.framework */; }; 16 | 1D76654CE9CEAF377AAEB5880255E1DB /* SequenceRectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B760E3245DBA04562547DB549A54D84 /* SequenceRectangleDetector.swift */; }; 17 | 282F1F2C217BD3004D366582691239FA /* Quad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E3277A6D1053342808409A24FF4BA63 /* Quad.swift */; }; 18 | 2993F972E255A071255DFFE3224A86E0 /* SwiftDocumentScanner-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 28C3C4749C96D72A66C276E247445811 /* SwiftDocumentScanner-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | 2E432CBAC724A6CE6833F678104B09F2 /* RectangleImageDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE7A5DB102268B4ABD0A07B957B3C66A /* RectangleImageDetector.swift */; }; 20 | 377351608FA2DCE2210C872972045E53 /* VisionImageRectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DE887BA76DA805C28B80DB1EB48417 /* VisionImageRectangleDetector.swift */; }; 21 | 3B70C7E7896CE5156B6959763C2A5A4D /* CGPoint+geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4709D6F6AA82B0E492E8C38EF419C648 /* CGPoint+geometry.swift */; }; 22 | 3E4A4B6BBEBD758DEFE14B052D24E6C0 /* Pods-SwiftDocumentScanner_Example-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F6D47494005FFCAB0EA06B52CEE83630 /* Pods-SwiftDocumentScanner_Example-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | 3F105367BB179BC2C1F1ADC35E8CFA48 /* SEAreaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0E47C0D8568CBB7AB2D96C48AC5036 /* SEAreaView.swift */; }; 24 | 418ABC001C9C855C7AA3F53E447C31DA /* SECropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41D1121B8B89AA4986D6838961D26900 /* SECropView.swift */; }; 25 | 47F43FBBED9E1923D8C1AC71535FB083 /* VisionSequenceRectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE88BF39D700C70D683C3DE10CA21461 /* VisionSequenceRectangleDetector.swift */; }; 26 | 4D87DCB98FABD2286F6724B9C3A32260 /* SECornerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C73016A1923B4882AF7C0A1CBCAC4038 /* SECornerView.swift */; }; 27 | 5CFD7534EA92DBEF9F73F17030619616 /* DocumentCropViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1997C626B40DE33BB0925603FDC1C162 /* DocumentCropViewController.swift */; }; 28 | 6303806A75845AB1B9F236A0E03C0AAC /* CropView-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 194DAE1E1A63CC1E7066FC8E23F997AC /* CropView-dummy.m */; }; 29 | 642CB116EA50C980E2F8CBC66E0ACDE8 /* CropView-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FF549ECC8DAC39B5D968175A7E17F9D /* CropView-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30 | 64F993F365C1D84A468F4A89CA9B8AB3 /* CIImageRectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85ED32A3D97A550624C00C5F732347FD /* CIImageRectangleDetector.swift */; }; 31 | 6FB03805BCED64C0D2C127C4C0954796 /* Array+extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AB8A2497D7BBE3BCAED6EBEC8C9F8 /* Array+extension.swift */; }; 32 | 77A92DD23BA0DCF64381798F7D46BC74 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B294BC0E8D3950458000FF14B8023B7 /* Foundation.framework */; }; 33 | 78654CB21116C916589FA6104EA2E0D9 /* CropHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB279458E9358A73A232B4C250D8BCB /* CropHelper.swift */; }; 34 | 7DAC98CB3522FC109676A6D5C6118D1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B294BC0E8D3950458000FF14B8023B7 /* Foundation.framework */; }; 35 | 93BD7F4C2472F3F15586FE6F4F2EC93E /* AutoDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324FF090280E15B38FB46E6E627CDF6A /* AutoDetector.swift */; }; 36 | 9E08504BBFB68B76A4BBC78E0281E415 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FB2CE2782B2580B23BCA63CA6D0575 /* CameraViewController.swift */; }; 37 | A872B440ABCDE26985033460A2133A87 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08E8C7E9750B71FDC4E138D8034D7616 /* UIImage+Extension.swift */; }; 38 | A9111988B7C835099D0F9CCF8FB7C229 /* NoSequenceRectangleDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70710B1ED2117F843B27D85389F50C3 /* NoSequenceRectangleDetector.swift */; }; 39 | A9B92CED5D4D0F1991E559B90BD7968F /* Pods-SwiftDocumentScanner_Example-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B1664154B9CAACA3F87D7F8C5C249FBB /* Pods-SwiftDocumentScanner_Example-dummy.m */; }; 40 | B2F8B67B9B87FE6868466A71055E717D /* CGrect+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CD92DF151902CF5CDC6ED36111BDBA4 /* CGrect+Extension.swift */; }; 41 | DF25FD13101C019C9508FAF66517C5F2 /* Array+shift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691DC8BE5C51878426D4ADBB0C29982C /* Array+shift.swift */; }; 42 | E16254BC6F99ADBCACA0F8E22796DF25 /* CGPoint+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD865DDDB61391D2ABEF8DBAFF109D3B /* CGPoint+Extension.swift */; }; 43 | E72597DA1CDF941851EE8C152BCB89D1 /* SECropError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B975987E0A603593146E7F3333CD76 /* SECropError.swift */; }; 44 | F38185C6574E965ABBAB430601B8B280 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53F24CFCFA5BEE6F1E445A4314BF0E2 /* Result.swift */; }; 45 | F92D2A8BC47711EFF9716233865FA02E /* TrackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BBC25041650470E0AED1DC2ADA92DE /* TrackView.swift */; }; 46 | FA1D199118E9E3F259E34D4A6E8E333C /* SwiftDocumentScanner-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C655E9D7C4B0C14D1474CA8AD5A85C58 /* SwiftDocumentScanner-dummy.m */; }; 47 | /* End PBXBuildFile section */ 48 | 49 | /* Begin PBXContainerItemProxy section */ 50 | 62591E4A52ECC5F46410BE025D463B1F /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 53 | proxyType = 1; 54 | remoteGlobalIDString = 06F2BCA0BD9BD5F19DDB60767CB1699A; 55 | remoteInfo = SwiftDocumentScanner; 56 | }; 57 | 9007E7A62771BEFDBC39AE816AAD3543 /* PBXContainerItemProxy */ = { 58 | isa = PBXContainerItemProxy; 59 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 60 | proxyType = 1; 61 | remoteGlobalIDString = 3A2394B6AB9D530370C5B30548DEDC03; 62 | remoteInfo = CropView; 63 | }; 64 | DC896ABF1F71C9627B89C9FC96E4A6C0 /* PBXContainerItemProxy */ = { 65 | isa = PBXContainerItemProxy; 66 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 67 | proxyType = 1; 68 | remoteGlobalIDString = 3A2394B6AB9D530370C5B30548DEDC03; 69 | remoteInfo = CropView; 70 | }; 71 | /* End PBXContainerItemProxy section */ 72 | 73 | /* Begin PBXFileReference section */ 74 | 05707D8F752E8DB045DF7B158549AF17 /* Pods-SwiftDocumentScanner_Example-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-SwiftDocumentScanner_Example-acknowledgements.markdown"; sourceTree = ""; }; 75 | 06045D4A56AF0A131C77461E701C411C /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SwiftDocumentScanner_Example.debug.xcconfig"; sourceTree = ""; }; 76 | 08E8C7E9750B71FDC4E138D8034D7616 /* UIImage+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; 77 | 08F048B0267875217430880E805F6D11 /* Pods-SwiftDocumentScanner_Example-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SwiftDocumentScanner_Example-Info.plist"; sourceTree = ""; }; 78 | 0AAAAD2E9E4D3499276B6669A8240012 /* SwiftDocumentScanner.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SwiftDocumentScanner.modulemap; sourceTree = ""; }; 79 | 0D4D13472FE364FBE9069FB3E9D05505 /* SwiftDocumentScanner.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = SwiftDocumentScanner.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 80 | 13D1C1BB3B6D5B00322EA4AE66FF889C /* SwiftDocumentScanner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SwiftDocumentScanner.framework; path = SwiftDocumentScanner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 194DAE1E1A63CC1E7066FC8E23F997AC /* CropView-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "CropView-dummy.m"; sourceTree = ""; }; 82 | 1997C626B40DE33BB0925603FDC1C162 /* DocumentCropViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DocumentCropViewController.swift; sourceTree = ""; }; 83 | 1B760E3245DBA04562547DB549A54D84 /* SequenceRectangleDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SequenceRectangleDetector.swift; sourceTree = ""; }; 84 | 22DE887BA76DA805C28B80DB1EB48417 /* VisionImageRectangleDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = VisionImageRectangleDetector.swift; sourceTree = ""; }; 85 | 28C3C4749C96D72A66C276E247445811 /* SwiftDocumentScanner-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftDocumentScanner-umbrella.h"; sourceTree = ""; }; 86 | 2A1F2AF4B76549BCF05131C5A18C4EB8 /* Pods-SwiftDocumentScanner_Example-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SwiftDocumentScanner_Example-acknowledgements.plist"; sourceTree = ""; }; 87 | 2D3E5BB43FE5C5EBCA1D4CCD13CF479F /* DocumentScannerViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DocumentScannerViewController.swift; sourceTree = ""; }; 88 | 2E3277A6D1053342808409A24FF4BA63 /* Quad.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Quad.swift; sourceTree = ""; }; 89 | 324FF090280E15B38FB46E6E627CDF6A /* AutoDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AutoDetector.swift; sourceTree = ""; }; 90 | 3C0C55E0242BEEDB4DD88C302CBDD44F /* CropView.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = CropView.xcconfig; sourceTree = ""; }; 91 | 3CD92DF151902CF5CDC6ED36111BDBA4 /* CGrect+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "CGrect+Extension.swift"; sourceTree = ""; }; 92 | 41A4D08B6E0354EB7B73B852BB9396C2 /* Pods-SwiftDocumentScanner_Example-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-SwiftDocumentScanner_Example-frameworks.sh"; sourceTree = ""; }; 93 | 41D1121B8B89AA4986D6838961D26900 /* SECropView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SECropView.swift; path = Pod/Classes/SECropView.swift; sourceTree = ""; }; 94 | 4709D6F6AA82B0E492E8C38EF419C648 /* CGPoint+geometry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CGPoint+geometry.swift"; path = "Pod/Classes/CGPoint+geometry.swift"; sourceTree = ""; }; 95 | 48CADED91075EB825A10D22938C04F8C /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE; sourceTree = ""; }; 96 | 4FF549ECC8DAC39B5D968175A7E17F9D /* CropView-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "CropView-umbrella.h"; sourceTree = ""; }; 97 | 573E5C03168BB8A2394E993651201880 /* SwiftDocumentScanner.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftDocumentScanner.xcconfig; sourceTree = ""; }; 98 | 60ACE3E5D3DF5542459912D03E3705BD /* CropView-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "CropView-prefix.pch"; sourceTree = ""; }; 99 | 638A61BC664CD6643DC4A2CC944EA782 /* CropView.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = CropView.modulemap; sourceTree = ""; }; 100 | 68B3839A9DE0035F162D102884A8A6F5 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; 101 | 691DC8BE5C51878426D4ADBB0C29982C /* Array+shift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Array+shift.swift"; path = "Pod/Classes/Array+shift.swift"; sourceTree = ""; }; 102 | 6C0E47C0D8568CBB7AB2D96C48AC5036 /* SEAreaView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SEAreaView.swift; path = Pod/Classes/SEAreaView.swift; sourceTree = ""; }; 103 | 6DB279458E9358A73A232B4C250D8BCB /* CropHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CropHelper.swift; sourceTree = ""; }; 104 | 72B64CEABB6B1535FBBCF1AE881E465B /* CropView-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "CropView-Info.plist"; sourceTree = ""; }; 105 | 747013BA3A3D61698516C9A0968E7538 /* SEQuadrangleHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SEQuadrangleHelper.swift; path = Pod/Classes/SEQuadrangleHelper.swift; sourceTree = ""; }; 106 | 764C366158E24C9C8F58E029B3E83E34 /* SwiftDocumentScanner-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftDocumentScanner-prefix.pch"; sourceTree = ""; }; 107 | 7B294BC0E8D3950458000FF14B8023B7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 108 | 85B975987E0A603593146E7F3333CD76 /* SECropError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SECropError.swift; path = Pod/Classes/SECropError.swift; sourceTree = ""; }; 109 | 85ED32A3D97A550624C00C5F732347FD /* CIImageRectangleDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CIImageRectangleDetector.swift; sourceTree = ""; }; 110 | 87BBC25041650470E0AED1DC2ADA92DE /* TrackView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TrackView.swift; sourceTree = ""; }; 111 | 95FB2CE2782B2580B23BCA63CA6D0575 /* CameraViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = ""; }; 112 | B1664154B9CAACA3F87D7F8C5C249FBB /* Pods-SwiftDocumentScanner_Example-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-SwiftDocumentScanner_Example-dummy.m"; sourceTree = ""; }; 113 | B36AB396275697EEE1A5B13BA8A38FE3 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 114 | BC31DDA618EDEEF19AD0413D3C372056 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SwiftDocumentScanner_Example.release.xcconfig"; sourceTree = ""; }; 115 | BE55654290146630B6B51BFD161DC476 /* Pods_SwiftDocumentScanner_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_SwiftDocumentScanner_Example.framework; path = "Pods-SwiftDocumentScanner_Example.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 116 | C1A1FB796EF74E8169C3DB64236EE32F /* UIView+globalCoordinates.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIView+globalCoordinates.swift"; path = "Pod/Classes/UIView+globalCoordinates.swift"; sourceTree = ""; }; 117 | C2935E39B5096BECC90368B454BEC4A3 /* CropView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = CropView.framework; path = CropView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 118 | C655E9D7C4B0C14D1474CA8AD5A85C58 /* SwiftDocumentScanner-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftDocumentScanner-dummy.m"; sourceTree = ""; }; 119 | C73016A1923B4882AF7C0A1CBCAC4038 /* SECornerView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SECornerView.swift; path = Pod/Classes/SECornerView.swift; sourceTree = ""; }; 120 | CC9C749554AF9C85072138456A0BF68C /* SwiftDocumentScanner-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftDocumentScanner-Info.plist"; sourceTree = ""; }; 121 | CE128A8160011B1A7E7A7FDFE9BECAFA /* CropView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CropView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 122 | CFAF7B88510469F2009C618240158417 /* Observation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Observation.swift; sourceTree = ""; }; 123 | D53F24CFCFA5BEE6F1E445A4314BF0E2 /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; 124 | DB0AB8A2497D7BBE3BCAED6EBEC8C9F8 /* Array+extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "Array+extension.swift"; sourceTree = ""; }; 125 | DE88BF39D700C70D683C3DE10CA21461 /* VisionSequenceRectangleDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = VisionSequenceRectangleDetector.swift; sourceTree = ""; }; 126 | F6D47494005FFCAB0EA06B52CEE83630 /* Pods-SwiftDocumentScanner_Example-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-SwiftDocumentScanner_Example-umbrella.h"; sourceTree = ""; }; 127 | F70710B1ED2117F843B27D85389F50C3 /* NoSequenceRectangleDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NoSequenceRectangleDetector.swift; sourceTree = ""; }; 128 | FC517C8846F3926C2083CDA61338AE4B /* Pods-SwiftDocumentScanner_Example.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-SwiftDocumentScanner_Example.modulemap"; sourceTree = ""; }; 129 | FD865DDDB61391D2ABEF8DBAFF109D3B /* CGPoint+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extension.swift"; sourceTree = ""; }; 130 | FE7A5DB102268B4ABD0A07B957B3C66A /* RectangleImageDetector.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = RectangleImageDetector.swift; sourceTree = ""; }; 131 | /* End PBXFileReference section */ 132 | 133 | /* Begin PBXFrameworksBuildPhase section */ 134 | 2E4E412E92F19B3134F4E95E12A80F77 /* Frameworks */ = { 135 | isa = PBXFrameworksBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 18A1EE9A98ECC0F4201941760286D138 /* CropView.framework in Frameworks */, 139 | 77A92DD23BA0DCF64381798F7D46BC74 /* Foundation.framework in Frameworks */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | 2FA4B33D4CB1B7E40FED6FEE78503A81 /* Frameworks */ = { 144 | isa = PBXFrameworksBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | 7DAC98CB3522FC109676A6D5C6118D1E /* Foundation.framework in Frameworks */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | 9300891651073C88FF81F6881A059367 /* Frameworks */ = { 152 | isa = PBXFrameworksBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | 1062C418718A21FBBE9CF3D74392D1D2 /* Foundation.framework in Frameworks */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXFrameworksBuildPhase section */ 160 | 161 | /* Begin PBXGroup section */ 162 | 1D2D65ED5EAEA9ADE45E3368B684CBC1 /* Support Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 0AAAAD2E9E4D3499276B6669A8240012 /* SwiftDocumentScanner.modulemap */, 166 | 573E5C03168BB8A2394E993651201880 /* SwiftDocumentScanner.xcconfig */, 167 | C655E9D7C4B0C14D1474CA8AD5A85C58 /* SwiftDocumentScanner-dummy.m */, 168 | CC9C749554AF9C85072138456A0BF68C /* SwiftDocumentScanner-Info.plist */, 169 | 764C366158E24C9C8F58E029B3E83E34 /* SwiftDocumentScanner-prefix.pch */, 170 | 28C3C4749C96D72A66C276E247445811 /* SwiftDocumentScanner-umbrella.h */, 171 | ); 172 | name = "Support Files"; 173 | path = "Example/Pods/Target Support Files/SwiftDocumentScanner"; 174 | sourceTree = ""; 175 | }; 176 | 5AB9DE00B893E38F220BE0571134783A /* iOS */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 7B294BC0E8D3950458000FF14B8023B7 /* Foundation.framework */, 180 | ); 181 | name = iOS; 182 | sourceTree = ""; 183 | }; 184 | 5AF5E1AB31877163A2539E184B63FE96 /* Pods-SwiftDocumentScanner_Example */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | FC517C8846F3926C2083CDA61338AE4B /* Pods-SwiftDocumentScanner_Example.modulemap */, 188 | 05707D8F752E8DB045DF7B158549AF17 /* Pods-SwiftDocumentScanner_Example-acknowledgements.markdown */, 189 | 2A1F2AF4B76549BCF05131C5A18C4EB8 /* Pods-SwiftDocumentScanner_Example-acknowledgements.plist */, 190 | B1664154B9CAACA3F87D7F8C5C249FBB /* Pods-SwiftDocumentScanner_Example-dummy.m */, 191 | 41A4D08B6E0354EB7B73B852BB9396C2 /* Pods-SwiftDocumentScanner_Example-frameworks.sh */, 192 | 08F048B0267875217430880E805F6D11 /* Pods-SwiftDocumentScanner_Example-Info.plist */, 193 | F6D47494005FFCAB0EA06B52CEE83630 /* Pods-SwiftDocumentScanner_Example-umbrella.h */, 194 | 06045D4A56AF0A131C77461E701C411C /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */, 195 | BC31DDA618EDEEF19AD0413D3C372056 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */, 196 | ); 197 | name = "Pods-SwiftDocumentScanner_Example"; 198 | path = "Target Support Files/Pods-SwiftDocumentScanner_Example"; 199 | sourceTree = ""; 200 | }; 201 | 6E6DCD42D7FA3AC945E3608B5181F096 /* CropView */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 691DC8BE5C51878426D4ADBB0C29982C /* Array+shift.swift */, 205 | 4709D6F6AA82B0E492E8C38EF419C648 /* CGPoint+geometry.swift */, 206 | 6C0E47C0D8568CBB7AB2D96C48AC5036 /* SEAreaView.swift */, 207 | C73016A1923B4882AF7C0A1CBCAC4038 /* SECornerView.swift */, 208 | 85B975987E0A603593146E7F3333CD76 /* SECropError.swift */, 209 | 41D1121B8B89AA4986D6838961D26900 /* SECropView.swift */, 210 | 747013BA3A3D61698516C9A0968E7538 /* SEQuadrangleHelper.swift */, 211 | C1A1FB796EF74E8169C3DB64236EE32F /* UIView+globalCoordinates.swift */, 212 | 8A08A8DD2F5D1E519FDC826A5103F188 /* Support Files */, 213 | ); 214 | name = CropView; 215 | path = CropView; 216 | sourceTree = ""; 217 | }; 218 | 7DB346D0F39D3F0E887471402A8071AB = { 219 | isa = PBXGroup; 220 | children = ( 221 | B36AB396275697EEE1A5B13BA8A38FE3 /* Podfile */, 222 | F4D6D9477630742F353087551880A366 /* Development Pods */, 223 | EC0C242E9AE1BF7A252E42DB7000F0BC /* Frameworks */, 224 | F80F08CEC06A468B6F457729E89364B8 /* Pods */, 225 | C4AFDEA98CEE236A2796B0DC4AAA5E31 /* Products */, 226 | D81CC094DA7A9999B8192705EB80033D /* Targets Support Files */, 227 | ); 228 | sourceTree = ""; 229 | }; 230 | 88CBAF17A909F136AF5586E569A3D425 /* SwiftDocumentScanner */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | D46AFB32A31D02AE80A56CB038196C63 /* Controllers */, 234 | DB1F064DCD99EC605B3C30DDBBFD7C76 /* Detectors */, 235 | FE628A397AD7544AB402976D384D1F53 /* Extensions */, 236 | 8FE6BF360694700D541A25D198672BE1 /* Helpers */, 237 | E617701313E08E65055E558717325030 /* Models */, 238 | E3130FFA25E3B070789FAAF294AFCDA0 /* Pod */, 239 | 1D2D65ED5EAEA9ADE45E3368B684CBC1 /* Support Files */, 240 | EDE0B23BD7B8363501DB8E0619FDEB6C /* Views */, 241 | ); 242 | name = SwiftDocumentScanner; 243 | path = ../..; 244 | sourceTree = ""; 245 | }; 246 | 8A08A8DD2F5D1E519FDC826A5103F188 /* Support Files */ = { 247 | isa = PBXGroup; 248 | children = ( 249 | 638A61BC664CD6643DC4A2CC944EA782 /* CropView.modulemap */, 250 | 3C0C55E0242BEEDB4DD88C302CBDD44F /* CropView.xcconfig */, 251 | 194DAE1E1A63CC1E7066FC8E23F997AC /* CropView-dummy.m */, 252 | 72B64CEABB6B1535FBBCF1AE881E465B /* CropView-Info.plist */, 253 | 60ACE3E5D3DF5542459912D03E3705BD /* CropView-prefix.pch */, 254 | 4FF549ECC8DAC39B5D968175A7E17F9D /* CropView-umbrella.h */, 255 | ); 256 | name = "Support Files"; 257 | path = "../Target Support Files/CropView"; 258 | sourceTree = ""; 259 | }; 260 | 8FE6BF360694700D541A25D198672BE1 /* Helpers */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 6DB279458E9358A73A232B4C250D8BCB /* CropHelper.swift */, 264 | ); 265 | name = Helpers; 266 | path = SwiftDocumentScanner/Classes/Helpers; 267 | sourceTree = ""; 268 | }; 269 | C4AFDEA98CEE236A2796B0DC4AAA5E31 /* Products */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | C2935E39B5096BECC90368B454BEC4A3 /* CropView.framework */, 273 | BE55654290146630B6B51BFD161DC476 /* Pods_SwiftDocumentScanner_Example.framework */, 274 | 13D1C1BB3B6D5B00322EA4AE66FF889C /* SwiftDocumentScanner.framework */, 275 | ); 276 | name = Products; 277 | sourceTree = ""; 278 | }; 279 | D46AFB32A31D02AE80A56CB038196C63 /* Controllers */ = { 280 | isa = PBXGroup; 281 | children = ( 282 | 95FB2CE2782B2580B23BCA63CA6D0575 /* CameraViewController.swift */, 283 | 1997C626B40DE33BB0925603FDC1C162 /* DocumentCropViewController.swift */, 284 | 2D3E5BB43FE5C5EBCA1D4CCD13CF479F /* DocumentScannerViewController.swift */, 285 | ); 286 | name = Controllers; 287 | path = SwiftDocumentScanner/Classes/Controllers; 288 | sourceTree = ""; 289 | }; 290 | D81CC094DA7A9999B8192705EB80033D /* Targets Support Files */ = { 291 | isa = PBXGroup; 292 | children = ( 293 | 5AF5E1AB31877163A2539E184B63FE96 /* Pods-SwiftDocumentScanner_Example */, 294 | ); 295 | name = "Targets Support Files"; 296 | sourceTree = ""; 297 | }; 298 | DB1F064DCD99EC605B3C30DDBBFD7C76 /* Detectors */ = { 299 | isa = PBXGroup; 300 | children = ( 301 | 324FF090280E15B38FB46E6E627CDF6A /* AutoDetector.swift */, 302 | 85ED32A3D97A550624C00C5F732347FD /* CIImageRectangleDetector.swift */, 303 | F70710B1ED2117F843B27D85389F50C3 /* NoSequenceRectangleDetector.swift */, 304 | FE7A5DB102268B4ABD0A07B957B3C66A /* RectangleImageDetector.swift */, 305 | 1B760E3245DBA04562547DB549A54D84 /* SequenceRectangleDetector.swift */, 306 | 22DE887BA76DA805C28B80DB1EB48417 /* VisionImageRectangleDetector.swift */, 307 | DE88BF39D700C70D683C3DE10CA21461 /* VisionSequenceRectangleDetector.swift */, 308 | ); 309 | name = Detectors; 310 | path = SwiftDocumentScanner/Classes/Detectors; 311 | sourceTree = ""; 312 | }; 313 | E3130FFA25E3B070789FAAF294AFCDA0 /* Pod */ = { 314 | isa = PBXGroup; 315 | children = ( 316 | 48CADED91075EB825A10D22938C04F8C /* LICENSE */, 317 | 68B3839A9DE0035F162D102884A8A6F5 /* README.md */, 318 | 0D4D13472FE364FBE9069FB3E9D05505 /* SwiftDocumentScanner.podspec */, 319 | ); 320 | name = Pod; 321 | sourceTree = ""; 322 | }; 323 | E617701313E08E65055E558717325030 /* Models */ = { 324 | isa = PBXGroup; 325 | children = ( 326 | CFAF7B88510469F2009C618240158417 /* Observation.swift */, 327 | 2E3277A6D1053342808409A24FF4BA63 /* Quad.swift */, 328 | D53F24CFCFA5BEE6F1E445A4314BF0E2 /* Result.swift */, 329 | ); 330 | name = Models; 331 | path = SwiftDocumentScanner/Classes/Models; 332 | sourceTree = ""; 333 | }; 334 | EC0C242E9AE1BF7A252E42DB7000F0BC /* Frameworks */ = { 335 | isa = PBXGroup; 336 | children = ( 337 | CE128A8160011B1A7E7A7FDFE9BECAFA /* CropView.framework */, 338 | 5AB9DE00B893E38F220BE0571134783A /* iOS */, 339 | ); 340 | name = Frameworks; 341 | sourceTree = ""; 342 | }; 343 | EDE0B23BD7B8363501DB8E0619FDEB6C /* Views */ = { 344 | isa = PBXGroup; 345 | children = ( 346 | 87BBC25041650470E0AED1DC2ADA92DE /* TrackView.swift */, 347 | ); 348 | name = Views; 349 | path = SwiftDocumentScanner/Classes/Views; 350 | sourceTree = ""; 351 | }; 352 | F4D6D9477630742F353087551880A366 /* Development Pods */ = { 353 | isa = PBXGroup; 354 | children = ( 355 | 88CBAF17A909F136AF5586E569A3D425 /* SwiftDocumentScanner */, 356 | ); 357 | name = "Development Pods"; 358 | sourceTree = ""; 359 | }; 360 | F80F08CEC06A468B6F457729E89364B8 /* Pods */ = { 361 | isa = PBXGroup; 362 | children = ( 363 | 6E6DCD42D7FA3AC945E3608B5181F096 /* CropView */, 364 | ); 365 | name = Pods; 366 | sourceTree = ""; 367 | }; 368 | FE628A397AD7544AB402976D384D1F53 /* Extensions */ = { 369 | isa = PBXGroup; 370 | children = ( 371 | DB0AB8A2497D7BBE3BCAED6EBEC8C9F8 /* Array+extension.swift */, 372 | FD865DDDB61391D2ABEF8DBAFF109D3B /* CGPoint+Extension.swift */, 373 | 3CD92DF151902CF5CDC6ED36111BDBA4 /* CGrect+Extension.swift */, 374 | 08E8C7E9750B71FDC4E138D8034D7616 /* UIImage+Extension.swift */, 375 | ); 376 | name = Extensions; 377 | path = SwiftDocumentScanner/Classes/Extensions; 378 | sourceTree = ""; 379 | }; 380 | /* End PBXGroup section */ 381 | 382 | /* Begin PBXHeadersBuildPhase section */ 383 | 08975B1A3A31EBE2D75BF6619A955F3B /* Headers */ = { 384 | isa = PBXHeadersBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | 3E4A4B6BBEBD758DEFE14B052D24E6C0 /* Pods-SwiftDocumentScanner_Example-umbrella.h in Headers */, 388 | ); 389 | runOnlyForDeploymentPostprocessing = 0; 390 | }; 391 | 5BD16D456E16CC07857A72F0E1AB16DD /* Headers */ = { 392 | isa = PBXHeadersBuildPhase; 393 | buildActionMask = 2147483647; 394 | files = ( 395 | 2993F972E255A071255DFFE3224A86E0 /* SwiftDocumentScanner-umbrella.h in Headers */, 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | }; 399 | 96DDB25A29577A36E17CEA705F501B2C /* Headers */ = { 400 | isa = PBXHeadersBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | 642CB116EA50C980E2F8CBC66E0ACDE8 /* CropView-umbrella.h in Headers */, 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | }; 407 | /* End PBXHeadersBuildPhase section */ 408 | 409 | /* Begin PBXNativeTarget section */ 410 | 06F2BCA0BD9BD5F19DDB60767CB1699A /* SwiftDocumentScanner */ = { 411 | isa = PBXNativeTarget; 412 | buildConfigurationList = 3814F3A991CBF6C550053D037AFAE836 /* Build configuration list for PBXNativeTarget "SwiftDocumentScanner" */; 413 | buildPhases = ( 414 | 5BD16D456E16CC07857A72F0E1AB16DD /* Headers */, 415 | A872B652B33B193E197332E00C405ECB /* Sources */, 416 | 2E4E412E92F19B3134F4E95E12A80F77 /* Frameworks */, 417 | BBDC5EF1103C61216FFE6B872CD47759 /* Resources */, 418 | ); 419 | buildRules = ( 420 | ); 421 | dependencies = ( 422 | 7E3D4EEF8241D74BEAF8DE711E77465E /* PBXTargetDependency */, 423 | ); 424 | name = SwiftDocumentScanner; 425 | productName = SwiftDocumentScanner; 426 | productReference = 13D1C1BB3B6D5B00322EA4AE66FF889C /* SwiftDocumentScanner.framework */; 427 | productType = "com.apple.product-type.framework"; 428 | }; 429 | 3A2394B6AB9D530370C5B30548DEDC03 /* CropView */ = { 430 | isa = PBXNativeTarget; 431 | buildConfigurationList = 66CA8114BB8F9D611BD0C1C0D846BA1D /* Build configuration list for PBXNativeTarget "CropView" */; 432 | buildPhases = ( 433 | 96DDB25A29577A36E17CEA705F501B2C /* Headers */, 434 | 2252BD7BCAA9B6BEDE41B8764794D9A5 /* Sources */, 435 | 9300891651073C88FF81F6881A059367 /* Frameworks */, 436 | 814D4B3E014FC0E6C0907C946DAF4436 /* Resources */, 437 | ); 438 | buildRules = ( 439 | ); 440 | dependencies = ( 441 | ); 442 | name = CropView; 443 | productName = CropView; 444 | productReference = C2935E39B5096BECC90368B454BEC4A3 /* CropView.framework */; 445 | productType = "com.apple.product-type.framework"; 446 | }; 447 | FF0E20A0919419A17742103A819E798D /* Pods-SwiftDocumentScanner_Example */ = { 448 | isa = PBXNativeTarget; 449 | buildConfigurationList = C31ACEE04942503DD9AA28544367672A /* Build configuration list for PBXNativeTarget "Pods-SwiftDocumentScanner_Example" */; 450 | buildPhases = ( 451 | 08975B1A3A31EBE2D75BF6619A955F3B /* Headers */, 452 | 99363060EAF1B18EF8A70C4B08629338 /* Sources */, 453 | 2FA4B33D4CB1B7E40FED6FEE78503A81 /* Frameworks */, 454 | 0A4FB8A4D78EA277492547E913253A59 /* Resources */, 455 | ); 456 | buildRules = ( 457 | ); 458 | dependencies = ( 459 | EC4580A69E9A1C05FB8270ABAFBC77C9 /* PBXTargetDependency */, 460 | D3B506B58CFD44D34CA2FB04B5E3A490 /* PBXTargetDependency */, 461 | ); 462 | name = "Pods-SwiftDocumentScanner_Example"; 463 | productName = "Pods-SwiftDocumentScanner_Example"; 464 | productReference = BE55654290146630B6B51BFD161DC476 /* Pods_SwiftDocumentScanner_Example.framework */; 465 | productType = "com.apple.product-type.framework"; 466 | }; 467 | /* End PBXNativeTarget section */ 468 | 469 | /* Begin PBXProject section */ 470 | D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { 471 | isa = PBXProject; 472 | attributes = { 473 | LastSwiftUpdateCheck = 0930; 474 | LastUpgradeCheck = 0930; 475 | }; 476 | buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; 477 | compatibilityVersion = "Xcode 3.2"; 478 | developmentRegion = English; 479 | hasScannedForEncodings = 0; 480 | knownRegions = ( 481 | en, 482 | ); 483 | mainGroup = 7DB346D0F39D3F0E887471402A8071AB; 484 | productRefGroup = C4AFDEA98CEE236A2796B0DC4AAA5E31 /* Products */; 485 | projectDirPath = ""; 486 | projectRoot = ""; 487 | targets = ( 488 | 3A2394B6AB9D530370C5B30548DEDC03 /* CropView */, 489 | FF0E20A0919419A17742103A819E798D /* Pods-SwiftDocumentScanner_Example */, 490 | 06F2BCA0BD9BD5F19DDB60767CB1699A /* SwiftDocumentScanner */, 491 | ); 492 | }; 493 | /* End PBXProject section */ 494 | 495 | /* Begin PBXResourcesBuildPhase section */ 496 | 0A4FB8A4D78EA277492547E913253A59 /* Resources */ = { 497 | isa = PBXResourcesBuildPhase; 498 | buildActionMask = 2147483647; 499 | files = ( 500 | ); 501 | runOnlyForDeploymentPostprocessing = 0; 502 | }; 503 | 814D4B3E014FC0E6C0907C946DAF4436 /* Resources */ = { 504 | isa = PBXResourcesBuildPhase; 505 | buildActionMask = 2147483647; 506 | files = ( 507 | ); 508 | runOnlyForDeploymentPostprocessing = 0; 509 | }; 510 | BBDC5EF1103C61216FFE6B872CD47759 /* Resources */ = { 511 | isa = PBXResourcesBuildPhase; 512 | buildActionMask = 2147483647; 513 | files = ( 514 | ); 515 | runOnlyForDeploymentPostprocessing = 0; 516 | }; 517 | /* End PBXResourcesBuildPhase section */ 518 | 519 | /* Begin PBXSourcesBuildPhase section */ 520 | 2252BD7BCAA9B6BEDE41B8764794D9A5 /* Sources */ = { 521 | isa = PBXSourcesBuildPhase; 522 | buildActionMask = 2147483647; 523 | files = ( 524 | DF25FD13101C019C9508FAF66517C5F2 /* Array+shift.swift in Sources */, 525 | 3B70C7E7896CE5156B6959763C2A5A4D /* CGPoint+geometry.swift in Sources */, 526 | 6303806A75845AB1B9F236A0E03C0AAC /* CropView-dummy.m in Sources */, 527 | 3F105367BB179BC2C1F1ADC35E8CFA48 /* SEAreaView.swift in Sources */, 528 | 4D87DCB98FABD2286F6724B9C3A32260 /* SECornerView.swift in Sources */, 529 | E72597DA1CDF941851EE8C152BCB89D1 /* SECropError.swift in Sources */, 530 | 418ABC001C9C855C7AA3F53E447C31DA /* SECropView.swift in Sources */, 531 | 0618D95CA6960BEE80B077004938BF50 /* SEQuadrangleHelper.swift in Sources */, 532 | 021151AC01E28027E54461185DF463B6 /* UIView+globalCoordinates.swift in Sources */, 533 | ); 534 | runOnlyForDeploymentPostprocessing = 0; 535 | }; 536 | 99363060EAF1B18EF8A70C4B08629338 /* Sources */ = { 537 | isa = PBXSourcesBuildPhase; 538 | buildActionMask = 2147483647; 539 | files = ( 540 | A9B92CED5D4D0F1991E559B90BD7968F /* Pods-SwiftDocumentScanner_Example-dummy.m in Sources */, 541 | ); 542 | runOnlyForDeploymentPostprocessing = 0; 543 | }; 544 | A872B652B33B193E197332E00C405ECB /* Sources */ = { 545 | isa = PBXSourcesBuildPhase; 546 | buildActionMask = 2147483647; 547 | files = ( 548 | 6FB03805BCED64C0D2C127C4C0954796 /* Array+extension.swift in Sources */, 549 | 93BD7F4C2472F3F15586FE6F4F2EC93E /* AutoDetector.swift in Sources */, 550 | 9E08504BBFB68B76A4BBC78E0281E415 /* CameraViewController.swift in Sources */, 551 | E16254BC6F99ADBCACA0F8E22796DF25 /* CGPoint+Extension.swift in Sources */, 552 | B2F8B67B9B87FE6868466A71055E717D /* CGrect+Extension.swift in Sources */, 553 | 64F993F365C1D84A468F4A89CA9B8AB3 /* CIImageRectangleDetector.swift in Sources */, 554 | 78654CB21116C916589FA6104EA2E0D9 /* CropHelper.swift in Sources */, 555 | 5CFD7534EA92DBEF9F73F17030619616 /* DocumentCropViewController.swift in Sources */, 556 | 048CD251168A67B1C534E12BFACA8382 /* DocumentScannerViewController.swift in Sources */, 557 | A9111988B7C835099D0F9CCF8FB7C229 /* NoSequenceRectangleDetector.swift in Sources */, 558 | 0FF92826D3C1AA467233AD254C11C38A /* Observation.swift in Sources */, 559 | 282F1F2C217BD3004D366582691239FA /* Quad.swift in Sources */, 560 | 2E432CBAC724A6CE6833F678104B09F2 /* RectangleImageDetector.swift in Sources */, 561 | F38185C6574E965ABBAB430601B8B280 /* Result.swift in Sources */, 562 | 1D76654CE9CEAF377AAEB5880255E1DB /* SequenceRectangleDetector.swift in Sources */, 563 | FA1D199118E9E3F259E34D4A6E8E333C /* SwiftDocumentScanner-dummy.m in Sources */, 564 | F92D2A8BC47711EFF9716233865FA02E /* TrackView.swift in Sources */, 565 | A872B440ABCDE26985033460A2133A87 /* UIImage+Extension.swift in Sources */, 566 | 377351608FA2DCE2210C872972045E53 /* VisionImageRectangleDetector.swift in Sources */, 567 | 47F43FBBED9E1923D8C1AC71535FB083 /* VisionSequenceRectangleDetector.swift in Sources */, 568 | ); 569 | runOnlyForDeploymentPostprocessing = 0; 570 | }; 571 | /* End PBXSourcesBuildPhase section */ 572 | 573 | /* Begin PBXTargetDependency section */ 574 | 7E3D4EEF8241D74BEAF8DE711E77465E /* PBXTargetDependency */ = { 575 | isa = PBXTargetDependency; 576 | name = CropView; 577 | target = 3A2394B6AB9D530370C5B30548DEDC03 /* CropView */; 578 | targetProxy = DC896ABF1F71C9627B89C9FC96E4A6C0 /* PBXContainerItemProxy */; 579 | }; 580 | D3B506B58CFD44D34CA2FB04B5E3A490 /* PBXTargetDependency */ = { 581 | isa = PBXTargetDependency; 582 | name = SwiftDocumentScanner; 583 | target = 06F2BCA0BD9BD5F19DDB60767CB1699A /* SwiftDocumentScanner */; 584 | targetProxy = 62591E4A52ECC5F46410BE025D463B1F /* PBXContainerItemProxy */; 585 | }; 586 | EC4580A69E9A1C05FB8270ABAFBC77C9 /* PBXTargetDependency */ = { 587 | isa = PBXTargetDependency; 588 | name = CropView; 589 | target = 3A2394B6AB9D530370C5B30548DEDC03 /* CropView */; 590 | targetProxy = 9007E7A62771BEFDBC39AE816AAD3543 /* PBXContainerItemProxy */; 591 | }; 592 | /* End PBXTargetDependency section */ 593 | 594 | /* Begin XCBuildConfiguration section */ 595 | 11D027BD8219E71225D197BACF78F7C1 /* Debug */ = { 596 | isa = XCBuildConfiguration; 597 | buildSettings = { 598 | ALWAYS_SEARCH_USER_PATHS = NO; 599 | CLANG_ANALYZER_NONNULL = YES; 600 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 601 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 602 | CLANG_CXX_LIBRARY = "libc++"; 603 | CLANG_ENABLE_MODULES = YES; 604 | CLANG_ENABLE_OBJC_ARC = YES; 605 | CLANG_ENABLE_OBJC_WEAK = YES; 606 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 607 | CLANG_WARN_BOOL_CONVERSION = YES; 608 | CLANG_WARN_COMMA = YES; 609 | CLANG_WARN_CONSTANT_CONVERSION = YES; 610 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 611 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 612 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 613 | CLANG_WARN_EMPTY_BODY = YES; 614 | CLANG_WARN_ENUM_CONVERSION = YES; 615 | CLANG_WARN_INFINITE_RECURSION = YES; 616 | CLANG_WARN_INT_CONVERSION = YES; 617 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 618 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 619 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 620 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 621 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 622 | CLANG_WARN_STRICT_PROTOTYPES = YES; 623 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 624 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 625 | CLANG_WARN_UNREACHABLE_CODE = YES; 626 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 627 | COPY_PHASE_STRIP = NO; 628 | DEBUG_INFORMATION_FORMAT = dwarf; 629 | ENABLE_STRICT_OBJC_MSGSEND = YES; 630 | ENABLE_TESTABILITY = YES; 631 | GCC_C_LANGUAGE_STANDARD = gnu11; 632 | GCC_DYNAMIC_NO_PIC = NO; 633 | GCC_NO_COMMON_BLOCKS = YES; 634 | GCC_OPTIMIZATION_LEVEL = 0; 635 | GCC_PREPROCESSOR_DEFINITIONS = ( 636 | "POD_CONFIGURATION_DEBUG=1", 637 | "DEBUG=1", 638 | "$(inherited)", 639 | ); 640 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 641 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 642 | GCC_WARN_UNDECLARED_SELECTOR = YES; 643 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 644 | GCC_WARN_UNUSED_FUNCTION = YES; 645 | GCC_WARN_UNUSED_VARIABLE = YES; 646 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 647 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 648 | MTL_FAST_MATH = YES; 649 | ONLY_ACTIVE_ARCH = YES; 650 | PRODUCT_NAME = "$(TARGET_NAME)"; 651 | STRIP_INSTALLED_PRODUCT = NO; 652 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 653 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 654 | SWIFT_VERSION = 4.2; 655 | SYMROOT = "${SRCROOT}/../build"; 656 | }; 657 | name = Debug; 658 | }; 659 | 586BFA7ECB2A69A60B1C250C5589F19F /* Debug */ = { 660 | isa = XCBuildConfiguration; 661 | baseConfigurationReference = 06045D4A56AF0A131C77461E701C411C /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */; 662 | buildSettings = { 663 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 664 | CLANG_ENABLE_OBJC_WEAK = NO; 665 | CODE_SIGN_IDENTITY = ""; 666 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 667 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 668 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 669 | CURRENT_PROJECT_VERSION = 1; 670 | DEFINES_MODULE = YES; 671 | DYLIB_COMPATIBILITY_VERSION = 1; 672 | DYLIB_CURRENT_VERSION = 1; 673 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 674 | INFOPLIST_FILE = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-Info.plist"; 675 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 676 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 677 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 678 | MACH_O_TYPE = staticlib; 679 | MODULEMAP_FILE = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.modulemap"; 680 | OTHER_LDFLAGS = ""; 681 | OTHER_LIBTOOLFLAGS = ""; 682 | PODS_ROOT = "$(SRCROOT)"; 683 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 684 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 685 | SDKROOT = iphoneos; 686 | SKIP_INSTALL = YES; 687 | TARGETED_DEVICE_FAMILY = "1,2"; 688 | VERSIONING_SYSTEM = "apple-generic"; 689 | VERSION_INFO_PREFIX = ""; 690 | }; 691 | name = Debug; 692 | }; 693 | 78B4954889058F8A198D71EA74981AF0 /* Release */ = { 694 | isa = XCBuildConfiguration; 695 | baseConfigurationReference = BC31DDA618EDEEF19AD0413D3C372056 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */; 696 | buildSettings = { 697 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 698 | CLANG_ENABLE_OBJC_WEAK = NO; 699 | CODE_SIGN_IDENTITY = ""; 700 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 701 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 702 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 703 | CURRENT_PROJECT_VERSION = 1; 704 | DEFINES_MODULE = YES; 705 | DYLIB_COMPATIBILITY_VERSION = 1; 706 | DYLIB_CURRENT_VERSION = 1; 707 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 708 | INFOPLIST_FILE = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-Info.plist"; 709 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 710 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 711 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 712 | MACH_O_TYPE = staticlib; 713 | MODULEMAP_FILE = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.modulemap"; 714 | OTHER_LDFLAGS = ""; 715 | OTHER_LIBTOOLFLAGS = ""; 716 | PODS_ROOT = "$(SRCROOT)"; 717 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 718 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 719 | SDKROOT = iphoneos; 720 | SKIP_INSTALL = YES; 721 | TARGETED_DEVICE_FAMILY = "1,2"; 722 | VALIDATE_PRODUCT = YES; 723 | VERSIONING_SYSTEM = "apple-generic"; 724 | VERSION_INFO_PREFIX = ""; 725 | }; 726 | name = Release; 727 | }; 728 | 8FB57296A2B59949708C2B492C4646D5 /* Release */ = { 729 | isa = XCBuildConfiguration; 730 | buildSettings = { 731 | ALWAYS_SEARCH_USER_PATHS = NO; 732 | CLANG_ANALYZER_NONNULL = YES; 733 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 734 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 735 | CLANG_CXX_LIBRARY = "libc++"; 736 | CLANG_ENABLE_MODULES = YES; 737 | CLANG_ENABLE_OBJC_ARC = YES; 738 | CLANG_ENABLE_OBJC_WEAK = YES; 739 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 740 | CLANG_WARN_BOOL_CONVERSION = YES; 741 | CLANG_WARN_COMMA = YES; 742 | CLANG_WARN_CONSTANT_CONVERSION = YES; 743 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 744 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 745 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 746 | CLANG_WARN_EMPTY_BODY = YES; 747 | CLANG_WARN_ENUM_CONVERSION = YES; 748 | CLANG_WARN_INFINITE_RECURSION = YES; 749 | CLANG_WARN_INT_CONVERSION = YES; 750 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 751 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 752 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 753 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 754 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 755 | CLANG_WARN_STRICT_PROTOTYPES = YES; 756 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 757 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 758 | CLANG_WARN_UNREACHABLE_CODE = YES; 759 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 760 | COPY_PHASE_STRIP = NO; 761 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 762 | ENABLE_NS_ASSERTIONS = NO; 763 | ENABLE_STRICT_OBJC_MSGSEND = YES; 764 | GCC_C_LANGUAGE_STANDARD = gnu11; 765 | GCC_NO_COMMON_BLOCKS = YES; 766 | GCC_PREPROCESSOR_DEFINITIONS = ( 767 | "POD_CONFIGURATION_RELEASE=1", 768 | "$(inherited)", 769 | ); 770 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 771 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 772 | GCC_WARN_UNDECLARED_SELECTOR = YES; 773 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 774 | GCC_WARN_UNUSED_FUNCTION = YES; 775 | GCC_WARN_UNUSED_VARIABLE = YES; 776 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 777 | MTL_ENABLE_DEBUG_INFO = NO; 778 | MTL_FAST_MATH = YES; 779 | PRODUCT_NAME = "$(TARGET_NAME)"; 780 | STRIP_INSTALLED_PRODUCT = NO; 781 | SWIFT_COMPILATION_MODE = wholemodule; 782 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 783 | SWIFT_VERSION = 4.2; 784 | SYMROOT = "${SRCROOT}/../build"; 785 | }; 786 | name = Release; 787 | }; 788 | 996EBAF65D9ABDE331AF19560E5CCF6A /* Debug */ = { 789 | isa = XCBuildConfiguration; 790 | baseConfigurationReference = 3C0C55E0242BEEDB4DD88C302CBDD44F /* CropView.xcconfig */; 791 | buildSettings = { 792 | CODE_SIGN_IDENTITY = ""; 793 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 794 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 795 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 796 | CURRENT_PROJECT_VERSION = 1; 797 | DEFINES_MODULE = YES; 798 | DYLIB_COMPATIBILITY_VERSION = 1; 799 | DYLIB_CURRENT_VERSION = 1; 800 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 801 | GCC_PREFIX_HEADER = "Target Support Files/CropView/CropView-prefix.pch"; 802 | INFOPLIST_FILE = "Target Support Files/CropView/CropView-Info.plist"; 803 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 804 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 805 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 806 | MODULEMAP_FILE = "Target Support Files/CropView/CropView.modulemap"; 807 | PRODUCT_MODULE_NAME = CropView; 808 | PRODUCT_NAME = CropView; 809 | SDKROOT = iphoneos; 810 | SKIP_INSTALL = YES; 811 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 812 | SWIFT_VERSION = 4.2; 813 | TARGETED_DEVICE_FAMILY = "1,2"; 814 | VERSIONING_SYSTEM = "apple-generic"; 815 | VERSION_INFO_PREFIX = ""; 816 | }; 817 | name = Debug; 818 | }; 819 | D423BEC2B11A8774CD029FC001532E14 /* Debug */ = { 820 | isa = XCBuildConfiguration; 821 | baseConfigurationReference = 573E5C03168BB8A2394E993651201880 /* SwiftDocumentScanner.xcconfig */; 822 | buildSettings = { 823 | CLANG_ENABLE_OBJC_WEAK = NO; 824 | CODE_SIGN_IDENTITY = ""; 825 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 826 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 827 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 828 | CURRENT_PROJECT_VERSION = 1; 829 | DEFINES_MODULE = YES; 830 | DYLIB_COMPATIBILITY_VERSION = 1; 831 | DYLIB_CURRENT_VERSION = 1; 832 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 833 | GCC_PREFIX_HEADER = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-prefix.pch"; 834 | INFOPLIST_FILE = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-Info.plist"; 835 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 836 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 837 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 838 | MODULEMAP_FILE = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner.modulemap"; 839 | PRODUCT_MODULE_NAME = SwiftDocumentScanner; 840 | PRODUCT_NAME = SwiftDocumentScanner; 841 | SDKROOT = iphoneos; 842 | SKIP_INSTALL = YES; 843 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 844 | SWIFT_VERSION = 4.2; 845 | TARGETED_DEVICE_FAMILY = "1,2"; 846 | VERSIONING_SYSTEM = "apple-generic"; 847 | VERSION_INFO_PREFIX = ""; 848 | }; 849 | name = Debug; 850 | }; 851 | D44F227E8EB840CFB4A75DFFBAFCF28F /* Release */ = { 852 | isa = XCBuildConfiguration; 853 | baseConfigurationReference = 573E5C03168BB8A2394E993651201880 /* SwiftDocumentScanner.xcconfig */; 854 | buildSettings = { 855 | CLANG_ENABLE_OBJC_WEAK = NO; 856 | CODE_SIGN_IDENTITY = ""; 857 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 858 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 859 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 860 | CURRENT_PROJECT_VERSION = 1; 861 | DEFINES_MODULE = YES; 862 | DYLIB_COMPATIBILITY_VERSION = 1; 863 | DYLIB_CURRENT_VERSION = 1; 864 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 865 | GCC_PREFIX_HEADER = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-prefix.pch"; 866 | INFOPLIST_FILE = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-Info.plist"; 867 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 868 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 869 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 870 | MODULEMAP_FILE = "Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner.modulemap"; 871 | PRODUCT_MODULE_NAME = SwiftDocumentScanner; 872 | PRODUCT_NAME = SwiftDocumentScanner; 873 | SDKROOT = iphoneos; 874 | SKIP_INSTALL = YES; 875 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 876 | SWIFT_VERSION = 4.2; 877 | TARGETED_DEVICE_FAMILY = "1,2"; 878 | VALIDATE_PRODUCT = YES; 879 | VERSIONING_SYSTEM = "apple-generic"; 880 | VERSION_INFO_PREFIX = ""; 881 | }; 882 | name = Release; 883 | }; 884 | D9FED85A7A6F2EBE8949B9072012B917 /* Release */ = { 885 | isa = XCBuildConfiguration; 886 | baseConfigurationReference = 3C0C55E0242BEEDB4DD88C302CBDD44F /* CropView.xcconfig */; 887 | buildSettings = { 888 | CODE_SIGN_IDENTITY = ""; 889 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 890 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 891 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 892 | CURRENT_PROJECT_VERSION = 1; 893 | DEFINES_MODULE = YES; 894 | DYLIB_COMPATIBILITY_VERSION = 1; 895 | DYLIB_CURRENT_VERSION = 1; 896 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 897 | GCC_PREFIX_HEADER = "Target Support Files/CropView/CropView-prefix.pch"; 898 | INFOPLIST_FILE = "Target Support Files/CropView/CropView-Info.plist"; 899 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 900 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 901 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 902 | MODULEMAP_FILE = "Target Support Files/CropView/CropView.modulemap"; 903 | PRODUCT_MODULE_NAME = CropView; 904 | PRODUCT_NAME = CropView; 905 | SDKROOT = iphoneos; 906 | SKIP_INSTALL = YES; 907 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 908 | SWIFT_VERSION = 4.2; 909 | TARGETED_DEVICE_FAMILY = "1,2"; 910 | VALIDATE_PRODUCT = YES; 911 | VERSIONING_SYSTEM = "apple-generic"; 912 | VERSION_INFO_PREFIX = ""; 913 | }; 914 | name = Release; 915 | }; 916 | /* End XCBuildConfiguration section */ 917 | 918 | /* Begin XCConfigurationList section */ 919 | 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { 920 | isa = XCConfigurationList; 921 | buildConfigurations = ( 922 | 11D027BD8219E71225D197BACF78F7C1 /* Debug */, 923 | 8FB57296A2B59949708C2B492C4646D5 /* Release */, 924 | ); 925 | defaultConfigurationIsVisible = 0; 926 | defaultConfigurationName = Release; 927 | }; 928 | 3814F3A991CBF6C550053D037AFAE836 /* Build configuration list for PBXNativeTarget "SwiftDocumentScanner" */ = { 929 | isa = XCConfigurationList; 930 | buildConfigurations = ( 931 | D423BEC2B11A8774CD029FC001532E14 /* Debug */, 932 | D44F227E8EB840CFB4A75DFFBAFCF28F /* Release */, 933 | ); 934 | defaultConfigurationIsVisible = 0; 935 | defaultConfigurationName = Release; 936 | }; 937 | 66CA8114BB8F9D611BD0C1C0D846BA1D /* Build configuration list for PBXNativeTarget "CropView" */ = { 938 | isa = XCConfigurationList; 939 | buildConfigurations = ( 940 | 996EBAF65D9ABDE331AF19560E5CCF6A /* Debug */, 941 | D9FED85A7A6F2EBE8949B9072012B917 /* Release */, 942 | ); 943 | defaultConfigurationIsVisible = 0; 944 | defaultConfigurationName = Release; 945 | }; 946 | C31ACEE04942503DD9AA28544367672A /* Build configuration list for PBXNativeTarget "Pods-SwiftDocumentScanner_Example" */ = { 947 | isa = XCConfigurationList; 948 | buildConfigurations = ( 949 | 586BFA7ECB2A69A60B1C250C5589F19F /* Debug */, 950 | 78B4954889058F8A198D71EA74981AF0 /* Release */, 951 | ); 952 | defaultConfigurationIsVisible = 0; 953 | defaultConfigurationName = Release; 954 | }; 955 | /* End XCConfigurationList section */ 956 | }; 957 | rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 958 | } 959 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.6 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_CropView : NSObject 3 | @end 4 | @implementation PodsDummy_CropView 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double CropViewVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char CropViewVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView.modulemap: -------------------------------------------------------------------------------- 1 | framework module CropView { 2 | umbrella header "CropView-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/CropView/CropView.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/CropView 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/CropView 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## CropView 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2017 Nikita Razumnuy 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | ## SwiftDocumentScanner 29 | 30 | Copyright (c) 2018 jonasbeckers 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in 40 | all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | THE SOFTWARE. 49 | 50 | Generated by CocoaPods - https://cocoapods.org 51 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2017 Nikita Razumnuy 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | License 39 | MIT 40 | Title 41 | CropView 42 | Type 43 | PSGroupSpecifier 44 | 45 | 46 | FooterText 47 | Copyright (c) 2018 jonasbeckers <jonas.beckers1996@gmail.com> 48 | 49 | Permission is hereby granted, free of charge, to any person obtaining a copy 50 | of this software and associated documentation files (the "Software"), to deal 51 | in the Software without restriction, including without limitation the rights 52 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 53 | copies of the Software, and to permit persons to whom the Software is 54 | furnished to do so, subject to the following conditions: 55 | 56 | The above copyright notice and this permission notice shall be included in 57 | all copies or substantial portions of the Software. 58 | 59 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 60 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 61 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 62 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 63 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 64 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 65 | THE SOFTWARE. 66 | 67 | License 68 | MIT 69 | Title 70 | SwiftDocumentScanner 71 | Type 72 | PSGroupSpecifier 73 | 74 | 75 | FooterText 76 | Generated by CocoaPods - https://cocoapods.org 77 | Title 78 | 79 | Type 80 | PSGroupSpecifier 81 | 82 | 83 | StringsTable 84 | Acknowledgements 85 | Title 86 | Acknowledgements 87 | 88 | 89 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_SwiftDocumentScanner_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_SwiftDocumentScanner_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | if [ -r "$source" ]; then 88 | # Copy the dSYM into a the targets temp dir. 89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 91 | 92 | local basename 93 | basename="$(basename -s .framework.dSYM "$source")" 94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 95 | 96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 97 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 98 | strip_invalid_archs "$binary" 99 | fi 100 | 101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 102 | # Move the stripped file into its final destination. 103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 105 | else 106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 108 | fi 109 | fi 110 | } 111 | 112 | # Signs a framework with the provided identity 113 | code_sign_if_enabled() { 114 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 115 | # Use the current code_sign_identity 116 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 117 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 118 | 119 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 120 | code_sign_cmd="$code_sign_cmd &" 121 | fi 122 | echo "$code_sign_cmd" 123 | eval "$code_sign_cmd" 124 | fi 125 | } 126 | 127 | # Strip invalid architectures 128 | strip_invalid_archs() { 129 | binary="$1" 130 | # Get architectures for current target binary 131 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 132 | # Intersect them with the architectures we are building for 133 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 134 | # If there are no archs supported by this binary then warn the user 135 | if [[ -z "$intersected_archs" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | STRIP_BINARY_RETVAL=0 138 | return 139 | fi 140 | stripped="" 141 | for arch in $binary_archs; do 142 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 143 | # Strip non-valid architectures in-place 144 | lipo -remove "$arch" -output "$binary" "$binary" 145 | stripped="$stripped $arch" 146 | fi 147 | done 148 | if [[ "$stripped" ]]; then 149 | echo "Stripped $binary of architectures:$stripped" 150 | fi 151 | STRIP_BINARY_RETVAL=1 152 | } 153 | 154 | 155 | if [[ "$CONFIGURATION" == "Debug" ]]; then 156 | install_framework "${BUILT_PRODUCTS_DIR}/CropView/CropView.framework" 157 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftDocumentScanner/SwiftDocumentScanner.framework" 158 | fi 159 | if [[ "$CONFIGURATION" == "Release" ]]; then 160 | install_framework "${BUILT_PRODUCTS_DIR}/CropView/CropView.framework" 161 | install_framework "${BUILT_PRODUCTS_DIR}/SwiftDocumentScanner/SwiftDocumentScanner.framework" 162 | fi 163 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 164 | wait 165 | fi 166 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_SwiftDocumentScanner_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_SwiftDocumentScanner_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CropView" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDocumentScanner" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CropView/CropView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDocumentScanner/SwiftDocumentScanner.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "CropView" -framework "SwiftDocumentScanner" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_SwiftDocumentScanner_Example { 2 | umbrella header "Pods-SwiftDocumentScanner_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CropView" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDocumentScanner" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CropView/CropView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDocumentScanner/SwiftDocumentScanner.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "CropView" -framework "SwiftDocumentScanner" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SwiftDocumentScanner : NSObject 3 | @end 4 | @implementation PodsDummy_SwiftDocumentScanner 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SwiftDocumentScannerVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SwiftDocumentScannerVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner.modulemap: -------------------------------------------------------------------------------- 1 | framework module SwiftDocumentScanner { 2 | umbrella header "SwiftDocumentScanner-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SwiftDocumentScanner/SwiftDocumentScanner.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftDocumentScanner 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CropView" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_LDFLAGS = $(inherited) -framework "CropView" 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DDC8CB3A204764860070E650 /* ResultController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8CB30204764850070E650 /* ResultController.swift */; }; 11 | DDC8CB3B204764860070E650 /* ScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8CB31204764850070E650 /* ScannerController.swift */; }; 12 | DDC8CB3C204764860070E650 /* CropController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8CB32204764850070E650 /* CropController.swift */; }; 13 | DDC8CB3D204764860070E650 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC8CB34204764850070E650 /* AppDelegate.swift */; }; 14 | DDC8CB3E204764860070E650 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC8CB36204764860070E650 /* Assets.xcassets */; }; 15 | DDC8CB3F204764860070E650 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DDC8CB37204764860070E650 /* Main.storyboard */; }; 16 | E153BD351C72811B1C2BB911 /* Pods_SwiftDocumentScanner_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD262C684DD1ACF5F0969906 /* Pods_SwiftDocumentScanner_Example.framework */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 17393690A235B5EDE0A5469F /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDocumentScanner_Example.debug.xcconfig"; path = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.debug.xcconfig"; sourceTree = ""; }; 21 | 25AAA1B038B530D859A32658 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 22 | 607FACD01AFB9204008FA782 /* SwiftDocumentScanner_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftDocumentScanner_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 65A6506577B9416A68E6C836 /* SwiftDocumentScanner.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = SwiftDocumentScanner.podspec; path = ../SwiftDocumentScanner.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 24 | BC1D1EEE4C244C7073ACD71B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 25 | CF4B6BF51CA10F98D7384049 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDocumentScanner_Example.release.xcconfig"; path = "Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example.release.xcconfig"; sourceTree = ""; }; 26 | DDC8CB30204764850070E650 /* ResultController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultController.swift; sourceTree = ""; }; 27 | DDC8CB31204764850070E650 /* ScannerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScannerController.swift; sourceTree = ""; }; 28 | DDC8CB32204764850070E650 /* CropController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropController.swift; sourceTree = ""; }; 29 | DDC8CB34204764850070E650 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 30 | DDC8CB36204764860070E650 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | DDC8CB38204764860070E650 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 32 | DDC8CB39204764860070E650 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | FD262C684DD1ACF5F0969906 /* Pods_SwiftDocumentScanner_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftDocumentScanner_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | 607FACCD1AFB9204008FA782 /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | E153BD351C72811B1C2BB911 /* Pods_SwiftDocumentScanner_Example.framework in Frameworks */, 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 00D6E2BF42B1E50416DC3755 /* Pods */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 17393690A235B5EDE0A5469F /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */, 52 | CF4B6BF51CA10F98D7384049 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */, 53 | ); 54 | path = Pods; 55 | sourceTree = ""; 56 | }; 57 | 3BE8A74343A58886B7A555C9 /* Frameworks */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | FD262C684DD1ACF5F0969906 /* Pods_SwiftDocumentScanner_Example.framework */, 61 | ); 62 | name = Frameworks; 63 | sourceTree = ""; 64 | }; 65 | 607FACC71AFB9204008FA782 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 607FACF51AFB993E008FA782 /* Podspec Metadata */, 69 | 607FACD21AFB9204008FA782 /* Example for SwiftDocumentScanner */, 70 | 607FACD11AFB9204008FA782 /* Products */, 71 | 00D6E2BF42B1E50416DC3755 /* Pods */, 72 | 3BE8A74343A58886B7A555C9 /* Frameworks */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 607FACD11AFB9204008FA782 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 607FACD01AFB9204008FA782 /* SwiftDocumentScanner_Example.app */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 607FACD21AFB9204008FA782 /* Example for SwiftDocumentScanner */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | DDC8CB35204764860070E650 /* Resources */, 88 | DDC8CB2E204764850070E650 /* Sources */, 89 | ); 90 | name = "Example for SwiftDocumentScanner"; 91 | path = SwiftDocumentScanner; 92 | sourceTree = ""; 93 | }; 94 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 65A6506577B9416A68E6C836 /* SwiftDocumentScanner.podspec */, 98 | BC1D1EEE4C244C7073ACD71B /* README.md */, 99 | 25AAA1B038B530D859A32658 /* LICENSE */, 100 | ); 101 | name = "Podspec Metadata"; 102 | sourceTree = ""; 103 | }; 104 | DDC8CB2E204764850070E650 /* Sources */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | DDC8CB2F204764850070E650 /* Controllers */, 108 | DDC8CB33204764850070E650 /* Helpers */, 109 | ); 110 | path = Sources; 111 | sourceTree = ""; 112 | }; 113 | DDC8CB2F204764850070E650 /* Controllers */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | DDC8CB30204764850070E650 /* ResultController.swift */, 117 | DDC8CB31204764850070E650 /* ScannerController.swift */, 118 | DDC8CB32204764850070E650 /* CropController.swift */, 119 | ); 120 | path = Controllers; 121 | sourceTree = ""; 122 | }; 123 | DDC8CB33204764850070E650 /* Helpers */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | DDC8CB34204764850070E650 /* AppDelegate.swift */, 127 | ); 128 | path = Helpers; 129 | sourceTree = ""; 130 | }; 131 | DDC8CB35204764860070E650 /* Resources */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | DDC8CB36204764860070E650 /* Assets.xcassets */, 135 | DDC8CB37204764860070E650 /* Main.storyboard */, 136 | DDC8CB39204764860070E650 /* Info.plist */, 137 | ); 138 | path = Resources; 139 | sourceTree = ""; 140 | }; 141 | /* End PBXGroup section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | 607FACCF1AFB9204008FA782 /* SwiftDocumentScanner_Example */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftDocumentScanner_Example" */; 147 | buildPhases = ( 148 | 8DEC171A0A2123D3647427D1 /* [CP] Check Pods Manifest.lock */, 149 | 607FACCC1AFB9204008FA782 /* Sources */, 150 | 607FACCD1AFB9204008FA782 /* Frameworks */, 151 | 607FACCE1AFB9204008FA782 /* Resources */, 152 | 8E3556C17BCC8EE510C65FD6 /* [CP] Embed Pods Frameworks */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = SwiftDocumentScanner_Example; 159 | productName = SwiftDocumentScanner; 160 | productReference = 607FACD01AFB9204008FA782 /* SwiftDocumentScanner_Example.app */; 161 | productType = "com.apple.product-type.application"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | 607FACC81AFB9204008FA782 /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | LastSwiftUpdateCheck = 0830; 170 | LastUpgradeCheck = 1000; 171 | ORGANIZATIONNAME = CocoaPods; 172 | TargetAttributes = { 173 | 607FACCF1AFB9204008FA782 = { 174 | CreatedOnToolsVersion = 6.3.1; 175 | DevelopmentTeam = 5BTSXG27WA; 176 | LastSwiftMigration = 0900; 177 | }; 178 | }; 179 | }; 180 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "SwiftDocumentScanner" */; 181 | compatibilityVersion = "Xcode 3.2"; 182 | developmentRegion = English; 183 | hasScannedForEncodings = 0; 184 | knownRegions = ( 185 | en, 186 | Base, 187 | ); 188 | mainGroup = 607FACC71AFB9204008FA782; 189 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 190 | projectDirPath = ""; 191 | projectRoot = ""; 192 | targets = ( 193 | 607FACCF1AFB9204008FA782 /* SwiftDocumentScanner_Example */, 194 | ); 195 | }; 196 | /* End PBXProject section */ 197 | 198 | /* Begin PBXResourcesBuildPhase section */ 199 | 607FACCE1AFB9204008FA782 /* Resources */ = { 200 | isa = PBXResourcesBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | DDC8CB3E204764860070E650 /* Assets.xcassets in Resources */, 204 | DDC8CB3F204764860070E650 /* Main.storyboard in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXShellScriptBuildPhase section */ 211 | 8DEC171A0A2123D3647427D1 /* [CP] Check Pods Manifest.lock */ = { 212 | isa = PBXShellScriptBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | ); 216 | inputFileListPaths = ( 217 | ); 218 | inputPaths = ( 219 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 220 | "${PODS_ROOT}/Manifest.lock", 221 | ); 222 | name = "[CP] Check Pods Manifest.lock"; 223 | outputFileListPaths = ( 224 | ); 225 | outputPaths = ( 226 | "$(DERIVED_FILE_DIR)/Pods-SwiftDocumentScanner_Example-checkManifestLockResult.txt", 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | shellPath = /bin/sh; 230 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 231 | showEnvVarsInLog = 0; 232 | }; 233 | 8E3556C17BCC8EE510C65FD6 /* [CP] Embed Pods Frameworks */ = { 234 | isa = PBXShellScriptBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | inputFileListPaths = ( 239 | ); 240 | inputPaths = ( 241 | "${PODS_ROOT}/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-frameworks.sh", 242 | "${BUILT_PRODUCTS_DIR}/CropView/CropView.framework", 243 | "${BUILT_PRODUCTS_DIR}/SwiftDocumentScanner/SwiftDocumentScanner.framework", 244 | ); 245 | name = "[CP] Embed Pods Frameworks"; 246 | outputFileListPaths = ( 247 | ); 248 | outputPaths = ( 249 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CropView.framework", 250 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftDocumentScanner.framework", 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | shellPath = /bin/sh; 254 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwiftDocumentScanner_Example/Pods-SwiftDocumentScanner_Example-frameworks.sh\"\n"; 255 | showEnvVarsInLog = 0; 256 | }; 257 | /* End PBXShellScriptBuildPhase section */ 258 | 259 | /* Begin PBXSourcesBuildPhase section */ 260 | 607FACCC1AFB9204008FA782 /* Sources */ = { 261 | isa = PBXSourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | DDC8CB3D204764860070E650 /* AppDelegate.swift in Sources */, 265 | DDC8CB3B204764860070E650 /* ScannerController.swift in Sources */, 266 | DDC8CB3C204764860070E650 /* CropController.swift in Sources */, 267 | DDC8CB3A204764860070E650 /* ResultController.swift in Sources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | /* End PBXSourcesBuildPhase section */ 272 | 273 | /* Begin PBXVariantGroup section */ 274 | DDC8CB37204764860070E650 /* Main.storyboard */ = { 275 | isa = PBXVariantGroup; 276 | children = ( 277 | DDC8CB38204764860070E650 /* Base */, 278 | ); 279 | name = Main.storyboard; 280 | sourceTree = ""; 281 | }; 282 | /* End PBXVariantGroup section */ 283 | 284 | /* Begin XCBuildConfiguration section */ 285 | 607FACED1AFB9204008FA782 /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 294 | CLANG_WARN_BOOL_CONVERSION = YES; 295 | CLANG_WARN_COMMA = YES; 296 | CLANG_WARN_CONSTANT_CONVERSION = YES; 297 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 298 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 299 | CLANG_WARN_EMPTY_BODY = YES; 300 | CLANG_WARN_ENUM_CONVERSION = YES; 301 | CLANG_WARN_INFINITE_RECURSION = YES; 302 | CLANG_WARN_INT_CONVERSION = YES; 303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 308 | CLANG_WARN_STRICT_PROTOTYPES = YES; 309 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 310 | CLANG_WARN_UNREACHABLE_CODE = YES; 311 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 312 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 313 | COPY_PHASE_STRIP = NO; 314 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 315 | ENABLE_STRICT_OBJC_MSGSEND = YES; 316 | ENABLE_TESTABILITY = YES; 317 | GCC_C_LANGUAGE_STANDARD = gnu99; 318 | GCC_DYNAMIC_NO_PIC = NO; 319 | GCC_NO_COMMON_BLOCKS = YES; 320 | GCC_OPTIMIZATION_LEVEL = 0; 321 | GCC_PREPROCESSOR_DEFINITIONS = ( 322 | "DEBUG=1", 323 | "$(inherited)", 324 | ); 325 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 333 | MTL_ENABLE_DEBUG_INFO = YES; 334 | ONLY_ACTIVE_ARCH = YES; 335 | SDKROOT = iphoneos; 336 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 337 | }; 338 | name = Debug; 339 | }; 340 | 607FACEE1AFB9204008FA782 /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 345 | CLANG_CXX_LIBRARY = "libc++"; 346 | CLANG_ENABLE_MODULES = YES; 347 | CLANG_ENABLE_OBJC_ARC = YES; 348 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 349 | CLANG_WARN_BOOL_CONVERSION = YES; 350 | CLANG_WARN_COMMA = YES; 351 | CLANG_WARN_CONSTANT_CONVERSION = YES; 352 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INFINITE_RECURSION = YES; 357 | CLANG_WARN_INT_CONVERSION = YES; 358 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 359 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 360 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 361 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 363 | CLANG_WARN_STRICT_PROTOTYPES = YES; 364 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 365 | CLANG_WARN_UNREACHABLE_CODE = YES; 366 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 367 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 368 | COPY_PHASE_STRIP = NO; 369 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 370 | ENABLE_NS_ASSERTIONS = NO; 371 | ENABLE_STRICT_OBJC_MSGSEND = YES; 372 | GCC_C_LANGUAGE_STANDARD = gnu99; 373 | GCC_NO_COMMON_BLOCKS = YES; 374 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 375 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 376 | GCC_WARN_UNDECLARED_SELECTOR = YES; 377 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 378 | GCC_WARN_UNUSED_FUNCTION = YES; 379 | GCC_WARN_UNUSED_VARIABLE = YES; 380 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 381 | MTL_ENABLE_DEBUG_INFO = NO; 382 | SDKROOT = iphoneos; 383 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 384 | VALIDATE_PRODUCT = YES; 385 | }; 386 | name = Release; 387 | }; 388 | 607FACF01AFB9204008FA782 /* Debug */ = { 389 | isa = XCBuildConfiguration; 390 | baseConfigurationReference = 17393690A235B5EDE0A5469F /* Pods-SwiftDocumentScanner_Example.debug.xcconfig */; 391 | buildSettings = { 392 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 393 | DEVELOPMENT_TEAM = 5BTSXG27WA; 394 | INFOPLIST_FILE = "$(SRCROOT)/SwiftDocumentScanner/Resources/Info.plist"; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 396 | MODULE_NAME = ExampleApp; 397 | PRODUCT_BUNDLE_IDENTIFIER = com.jonasbeckers.test; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 400 | SWIFT_VERSION = 4.2; 401 | }; 402 | name = Debug; 403 | }; 404 | 607FACF11AFB9204008FA782 /* Release */ = { 405 | isa = XCBuildConfiguration; 406 | baseConfigurationReference = CF4B6BF51CA10F98D7384049 /* Pods-SwiftDocumentScanner_Example.release.xcconfig */; 407 | buildSettings = { 408 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 409 | DEVELOPMENT_TEAM = 5BTSXG27WA; 410 | INFOPLIST_FILE = "$(SRCROOT)/SwiftDocumentScanner/Resources/Info.plist"; 411 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 412 | MODULE_NAME = ExampleApp; 413 | PRODUCT_BUNDLE_IDENTIFIER = com.jonasbeckers.test; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 416 | SWIFT_VERSION = 4.2; 417 | }; 418 | name = Release; 419 | }; 420 | /* End XCBuildConfiguration section */ 421 | 422 | /* Begin XCConfigurationList section */ 423 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "SwiftDocumentScanner" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 607FACED1AFB9204008FA782 /* Debug */, 427 | 607FACEE1AFB9204008FA782 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "SwiftDocumentScanner_Example" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | 607FACF01AFB9204008FA782 /* Debug */, 436 | 607FACF11AFB9204008FA782 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | /* End XCConfigurationList section */ 442 | }; 443 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 444 | } 445 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner.xcodeproj/xcshareddata/xcschemes/SwiftDocumentScanner-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Resources/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | We need access to the camera. 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Sources/Controllers/CropController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CropController.swift 3 | // DocumentScanner_Example 4 | // 5 | // Created by Jonas Beckers on 28/02/18. 6 | // Copyright © 2018 CocoaPods. All rights reserved. 7 | // 8 | 9 | import SwiftDocumentScanner 10 | import UIKit 11 | 12 | class CropController: DocumentCropViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | cropDelegate = self 18 | } 19 | @IBAction func cropImage(_ sender: Any) { 20 | crop() 21 | } 22 | 23 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 24 | if let vc = segue.destination as? ResultController { 25 | vc.image = sender as? UIImage 26 | } 27 | } 28 | 29 | } 30 | 31 | extension CropController: DocumentCropViewControllerDelegate { 32 | 33 | func documentCropViewController(result: Result) { 34 | performSegue(withIdentifier: "Result", sender: result.cropped) 35 | } 36 | 37 | func documentCropViewController(failed: Error) { 38 | print(failed) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Sources/Controllers/ResultController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResultController.swift 3 | // DocumentScanner_Example 4 | // 5 | // Created by Jonas Beckers on 28/02/18. 6 | // Copyright © 2018 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ResultController: UIViewController { 12 | 13 | @IBOutlet weak var imageView: UIImageView! 14 | var image: UIImage? 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | imageView.image = image 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Sources/Controllers/ScannerController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScannerController.swift 3 | // DocumentScanner 4 | // 5 | // Created by jonasbeckers on 02/28/2018. 6 | // Copyright (c) 2018 jonasbeckers. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | import SwiftDocumentScanner 11 | import UIKit 12 | 13 | class ScannerController: DocumentScannerViewController { 14 | 15 | @IBOutlet weak var captureButton: UIButton! 16 | 17 | override func viewDidLoad() { 18 | TrackView.fillColor = UIColor.blue.withAlphaComponent(0.4) 19 | TrackView.lineColor = UIColor.blue 20 | 21 | tapToFocus = true 22 | lowLightBoost = false 23 | cameraPosition = .back 24 | flashMode = .off 25 | preset = .hd4K3840x2160 26 | 27 | cameraDelegate = self 28 | scannerDelegate = self 29 | 30 | super.viewDidLoad() 31 | 32 | view.bringSubviewToFront(captureButton) 33 | } 34 | 35 | @IBAction func takePicture(_ sender: Any) { 36 | takePhoto() 37 | } 38 | 39 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 40 | if let vc = segue.destination as? CropController { 41 | vc.image = sender as? UIImage 42 | } else if let vc = segue.destination as? ResultController { 43 | vc.image = sender as? UIImage 44 | } 45 | } 46 | } 47 | 48 | extension ScannerController: DocumentScannerViewControllerDelegate { 49 | 50 | func documentScanner(result: Result) { 51 | performSegue(withIdentifier: "Result", sender: result.cropped) 52 | } 53 | 54 | } 55 | 56 | extension ScannerController: CameraViewControllerDelegate { 57 | 58 | func cameraViewController(didFocus point: CGPoint) { 59 | print("focused point: \(point)") 60 | } 61 | 62 | func cameraViewController(update status: AVAuthorizationStatus) { 63 | print("status changed") 64 | } 65 | 66 | func cameraViewController(captured image: UIImage) { 67 | performSegue(withIdentifier: "Crop", sender: image) 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Example/SwiftDocumentScanner/Sources/Helpers/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DocumentScanner 4 | // 5 | // Created by jonasbeckers on 02/28/2018. 6 | // Copyright (c) 2018 jonasbeckers. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | return true 18 | } 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 jonasbeckers 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftDocumentScanner 2 | 3 | [![CI Status](http://img.shields.io/travis/jonasbeckers/SwiftDocumentScanner.svg?style=flat)](https://travis-ci.org/jonasbeckers/SwiftDocumentScanner) 4 | [![Version](https://img.shields.io/cocoapods/v/SwiftDocumentScanner.svg?style=flat)](http://cocoapods.org/pods/SwiftDocumentScanner) 5 | [![License](https://img.shields.io/cocoapods/l/SwiftDocumentScanner.svg?style=flat)](http://cocoapods.org/pods/SwiftDocumentScanner) 6 | [![Platform](https://img.shields.io/cocoapods/p/SwiftDocumentScanner.svg?style=flat)](http://cocoapods.org/pods/SwiftDocumentScanner) 7 | 8 | ## Example 9 | 10 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 11 | 12 | ## Requirements 13 | 14 | ## Installation 15 | 16 | SwiftDocumentScanner is available through [CocoaPods](http://cocoapods.org). To install 17 | it, simply add the following line to your Podfile: 18 | 19 | ```ruby 20 | pod 'SwiftDocumentScanner' 21 | ``` 22 | 23 | ## Author 24 | 25 | jonasbeckers, jonas.beckers1996@gmail.com 26 | 27 | ## License 28 | 29 | SwiftDocumentScanner is available under the MIT license. See the LICENSE file for more info. 30 | -------------------------------------------------------------------------------- /SwiftDocumentScanner.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SwiftDocumentScanner' 3 | s.version = '0.1.2' 4 | s.summary = 'Documentscanner app like Notes.' 5 | s.homepage = 'https://github.com/jonasbeckers/SwiftDocumentScanner' 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { 'jonasbeckers' => 'jonas.beckers1996@gmail.com' } 8 | s.source = { :git => 'https://github.com/jonasbeckers/SwiftDocumentScanner.git', :tag => s.version.to_s } 9 | s.ios.deployment_target = '10.0' 10 | s.source_files = 'SwiftDocumentScanner/Classes/**/*.swift' 11 | s.dependency 'CropView', '0.1.6' 12 | end 13 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasbeckers/SwiftDocumentScanner/718761a7a0657bd4f8c564e93f6b96eb82a2f76c/SwiftDocumentScanner/Assets/.gitkeep -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasbeckers/SwiftDocumentScanner/718761a7a0657bd4f8c564e93f6b96eb82a2f76c/SwiftDocumentScanner/Classes/.gitkeep -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Controllers/CameraViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CameraViewController.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import AVFoundation 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol CameraViewControllerDelegate: class { 13 | 14 | func cameraViewController(didFocus point: CGPoint) 15 | func cameraViewController(update status: AVAuthorizationStatus) 16 | func cameraViewController(captured image: UIImage) 17 | 18 | } 19 | 20 | open class CameraViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate { 21 | 22 | public var preset: AVCaptureSession.Preset = .high 23 | public var videoGravity: AVLayerVideoGravity = .resizeAspectFill 24 | public var lowLightBoost: Bool = false 25 | 26 | public var tapToFocus: Bool = false 27 | public var flashMode: AVCaptureDevice.FlashMode = .off 28 | 29 | public var cameraPosition: AVCaptureDevice.Position = .back { 30 | didSet { 31 | reconfigureSession() 32 | } 33 | } 34 | 35 | private var queue = DispatchQueue(label: "com.jonasbeckers.camera") 36 | 37 | private(set) var session: AVCaptureSession = AVCaptureSession() 38 | private(set) var previewLayer: AVCaptureVideoPreviewLayer? 39 | 40 | private var captureDevice: AVCaptureDevice? 41 | private var captureDeviceInput: AVCaptureDeviceInput? 42 | private var capturePhotoOutput: AVCapturePhotoOutput? 43 | private var captureVideoOutput: AVCaptureVideoDataOutput? 44 | 45 | public weak var cameraDelegate: CameraViewControllerDelegate? 46 | 47 | open override func viewDidLoad() { 48 | super.viewDidLoad() 49 | 50 | let previewLayer = AVCaptureVideoPreviewLayer(session: session) 51 | previewLayer.videoGravity = videoGravity 52 | previewLayer.connection?.videoOrientation = .portrait 53 | view.layer.insertSublayer(previewLayer, at: 0) 54 | self.previewLayer = previewLayer 55 | 56 | let status = AVCaptureDevice.authorizationStatus(for: .video) 57 | switch status { 58 | case .authorized: 59 | configureSession() 60 | cameraDelegate?.cameraViewController(update: status) 61 | case .notDetermined: 62 | AVCaptureDevice.requestAccess(for: .video) { [unowned self] granted in 63 | let newStatus = AVCaptureDevice.authorizationStatus(for: .video) 64 | if granted { 65 | self.configureSession() 66 | } 67 | self.cameraDelegate?.cameraViewController(update: newStatus) 68 | } 69 | default: 70 | cameraDelegate?.cameraViewController(update: status) 71 | } 72 | } 73 | 74 | open override func viewDidDisappear(_ animated: Bool) { 75 | super.viewDidDisappear(animated) 76 | 77 | queue.async { 78 | guard self.session.isRunning else { return } 79 | self.session.stopRunning() 80 | } 81 | } 82 | 83 | open override func viewDidAppear(_ animated: Bool) { 84 | super.viewDidAppear(animated) 85 | 86 | queue.async { 87 | guard !self.session.isRunning else { return } 88 | self.session.startRunning() 89 | } 90 | } 91 | 92 | open override func viewDidLayoutSubviews() { 93 | super.viewDidLayoutSubviews() 94 | 95 | previewLayer?.frame = view.bounds 96 | previewLayer?.videoGravity = videoGravity 97 | previewLayer?.connection?.videoOrientation = .portrait 98 | } 99 | 100 | public func takePhoto() { 101 | guard let output = capturePhotoOutput, session.isRunning else { return } 102 | 103 | let settings = AVCapturePhotoSettings() 104 | settings.flashMode = flashMode 105 | settings.isHighResolutionPhotoEnabled = true 106 | settings.isAutoStillImageStabilizationEnabled = true 107 | 108 | let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first ?? 0 109 | let previewFormat = [ 110 | kCVPixelBufferPixelFormatTypeKey as String: previewPixelType, 111 | kCVPixelBufferWidthKey as String: 160, 112 | kCVPixelBufferHeightKey as String: 160 113 | ] 114 | 115 | settings.previewPhotoFormat = previewFormat 116 | 117 | output.capturePhoto(with: settings, delegate: self) 118 | } 119 | 120 | open override func touchesBegan(_ touches: Set, with event: UIEvent?) { 121 | guard tapToFocus, let touch = touches.first else { return } 122 | 123 | let location = touch.preciseLocation(in: view) 124 | let size = view.bounds.size 125 | let focusPoint = CGPoint(x: location.x / size.height, y: 1 - location.x / size.width) 126 | 127 | guard let captureDevice = captureDevice else { return } 128 | do { 129 | try captureDevice.lockForConfiguration() 130 | if captureDevice.isFocusPointOfInterestSupported { 131 | captureDevice.focusPointOfInterest = focusPoint 132 | captureDevice.focusMode = .autoFocus 133 | } 134 | if captureDevice.isExposurePointOfInterestSupported { 135 | captureDevice.exposurePointOfInterest = focusPoint 136 | captureDevice.exposureMode = .continuousAutoExposure 137 | } 138 | captureDevice.unlockForConfiguration() 139 | cameraDelegate?.cameraViewController(didFocus: location) 140 | } catch { 141 | print(error) 142 | } 143 | } 144 | 145 | public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 146 | } 147 | 148 | public func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 149 | } 150 | 151 | } 152 | 153 | extension CameraViewController { 154 | 155 | private func reconfigureSession() { 156 | queue.async { 157 | let inputs = self.session.inputs 158 | inputs.forEach { self.session.removeInput($0) } 159 | 160 | self.captureDevice = nil 161 | self.captureDeviceInput = nil 162 | 163 | self.configureCaptureDevice() 164 | self.configureCaptureDeviceInput() 165 | } 166 | } 167 | 168 | private func configureSession() { 169 | queue.async { 170 | self.session.beginConfiguration() 171 | 172 | if self.session.canSetSessionPreset(self.preset) { 173 | self.session.sessionPreset = self.preset 174 | } else { 175 | self.session.sessionPreset = .high 176 | } 177 | 178 | self.configureCaptureDevice() 179 | self.configureCaptureDeviceInput() 180 | self.configureCapturePhotoOutput() 181 | self.configureCaptureVideoOutput() 182 | 183 | self.session.commitConfiguration() 184 | self.session.startRunning() 185 | } 186 | } 187 | 188 | private func configureCaptureDevice() { 189 | let device = captureDevice(for: cameraPosition) 190 | guard let captureDevice = device else { return } 191 | 192 | do { 193 | try captureDevice.lockForConfiguration() 194 | 195 | if captureDevice.isFocusModeSupported(.continuousAutoFocus) { 196 | captureDevice.focusMode = .continuousAutoFocus 197 | } 198 | 199 | if captureDevice.isSmoothAutoFocusSupported { 200 | captureDevice.isSmoothAutoFocusEnabled = true 201 | } 202 | 203 | if captureDevice.isExposureModeSupported(.continuousAutoExposure) { 204 | captureDevice.exposureMode = .continuousAutoExposure 205 | } 206 | 207 | if captureDevice.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) { 208 | captureDevice.whiteBalanceMode = .continuousAutoWhiteBalance 209 | } 210 | 211 | if captureDevice.isLowLightBoostSupported && lowLightBoost { 212 | captureDevice.automaticallyEnablesLowLightBoostWhenAvailable = true 213 | } 214 | 215 | captureDevice.unlockForConfiguration() 216 | } catch { 217 | print(error) 218 | } 219 | 220 | self.captureDevice = captureDevice 221 | } 222 | 223 | private func configureCaptureDeviceInput() { 224 | do { 225 | guard let captureDevice = captureDevice else { return } 226 | let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice) 227 | 228 | if session.canAddInput(captureDeviceInput) { 229 | session.addInput(captureDeviceInput) 230 | } 231 | 232 | self.captureDeviceInput = captureDeviceInput 233 | } catch { 234 | print(error) 235 | } 236 | } 237 | 238 | private func configureCapturePhotoOutput() { 239 | let capturePhotoOutput = AVCapturePhotoOutput() 240 | capturePhotoOutput.isHighResolutionCaptureEnabled = true 241 | 242 | if #available(iOS 11.0, *) { 243 | if capturePhotoOutput.isDualCameraDualPhotoDeliverySupported { 244 | capturePhotoOutput.isDualCameraDualPhotoDeliveryEnabled = true 245 | } 246 | } 247 | 248 | if session.canAddOutput(capturePhotoOutput) { 249 | session.addOutput(capturePhotoOutput) 250 | } 251 | 252 | self.capturePhotoOutput = capturePhotoOutput 253 | } 254 | 255 | private func configureCaptureVideoOutput() { 256 | let captureVideoOutput = AVCaptureVideoDataOutput() 257 | captureVideoOutput.alwaysDiscardsLateVideoFrames = true 258 | captureVideoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "CameraViewControllerQueue")) 259 | 260 | if session.canAddOutput(captureVideoOutput) { 261 | session.addOutput(captureVideoOutput) 262 | } 263 | 264 | self.captureVideoOutput = captureVideoOutput 265 | } 266 | 267 | private func captureDevice(for position: AVCaptureDevice.Position) -> AVCaptureDevice? { 268 | let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: position) 269 | let devices = session.devices 270 | let wideAngle = devices.first { $0.position == position } 271 | return wideAngle 272 | } 273 | } 274 | 275 | extension CameraViewController: AVCapturePhotoCaptureDelegate { 276 | 277 | @available(iOS 11.0, *) 278 | public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 279 | DispatchQueue.global(qos: .userInitiated).async { 280 | guard let data = photo.fileDataRepresentation(), let image = UIImage(data: data) else { return } 281 | DispatchQueue.main.async { [weak self] in 282 | self?.cameraDelegate?.cameraViewController(captured: image) 283 | } 284 | } 285 | } 286 | 287 | public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) { 288 | if #available(iOS 11.0, *) { } else { 289 | DispatchQueue.global(qos: .userInitiated).async { 290 | guard let sampleBuffer = photoSampleBuffer, let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: nil), let image = UIImage(data: data) else { return } 291 | DispatchQueue.main.async { [weak self] in 292 | self?.cameraDelegate?.cameraViewController(captured: image) 293 | } 294 | } 295 | } 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Controllers/DocumentCropViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentCropViewController.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CropView 9 | import UIKit 10 | import Vision 11 | 12 | public protocol DocumentCropViewControllerDelegate: class { 13 | 14 | func documentCropViewController(result: Result) 15 | func documentCropViewController(failed: Error) 16 | 17 | } 18 | 19 | open class DocumentCropViewController: UIViewController { 20 | 21 | @IBOutlet public var imageView: UIImageView! 22 | public private(set) var cropView = SECropView() 23 | 24 | private var points: [CGPoint] = [] { 25 | didSet { 26 | updateCropview() 27 | } 28 | } 29 | 30 | private var configuredCropView: Bool = false 31 | private var rectangleDetector: ImageRectangleDetector = CIImageRectangleDetector() 32 | 33 | public var image: UIImage? { 34 | didSet { 35 | image = image?.fixOrientation() 36 | } 37 | } 38 | public weak var cropDelegate: DocumentCropViewControllerDelegate? 39 | 40 | open override func viewDidLoad() { 41 | super.viewDidLoad() 42 | 43 | if #available(iOS 11.0, *) { 44 | rectangleDetector = VisionImageRectangleDetector() 45 | } 46 | 47 | SECropView.goodAreaColor = .white 48 | SECropView.badAreaColor = .red 49 | 50 | configure() 51 | } 52 | 53 | open override func viewDidLayoutSubviews() { 54 | super.viewDidLayoutSubviews() 55 | 56 | cropView.frame = view.bounds 57 | cropView.layoutSubviews() 58 | 59 | updateCropview() 60 | } 61 | 62 | public func configure() { 63 | image = image?.fixOrientation() 64 | imageView.transform = CGAffineTransform.identity 65 | imageView.image = image 66 | imageView.contentMode = .scaleAspectFit 67 | points = defaultCropViewCorners() 68 | 69 | guard let image = image else { return } 70 | rectangleDetector.detect(image: image, completion: handleDetection) 71 | } 72 | 73 | private func updateCropview() { 74 | let size = image?.size ?? .zero 75 | let width = Int(size.width) 76 | let height = Int(size.height) 77 | 78 | let converted: [CGPoint] 79 | 80 | if #available(iOS 11, *) { 81 | converted = points.map { VNImagePointForNormalizedPoint($0, width, height) } 82 | } else { 83 | converted = points.map { $0.scaledAbsolute(size: size) } 84 | } 85 | 86 | updateCorners(points: converted.map { $0.cartesian(height: size.height) }) 87 | } 88 | 89 | private func updateCorners(points: [CGPoint]) { 90 | if configuredCropView { 91 | cropView.setCorners(newCorners: points) 92 | } else { 93 | cropView.configureWithCorners(corners: points, on: imageView) 94 | configuredCropView = true 95 | } 96 | } 97 | 98 | private func handleDetection(quad: Quad?) { 99 | if let quad = quad { 100 | points = quad.points 101 | } else { 102 | points = defaultCropViewCorners() 103 | } 104 | } 105 | 106 | private func defaultCropViewCorners() -> [CGPoint] { 107 | return [CGPoint(x: 0.2, y: 0.2), CGPoint(x: 0.2, y: 0.8), CGPoint(x: 0.8, y: 0.8), CGPoint(x: 0.8, y: 0.2)] 108 | } 109 | 110 | public func crop() { 111 | guard let image = image, let points = cropView.cornerLocations else { return } 112 | 113 | DispatchQueue.global(qos: .userInitiated).async { 114 | do { 115 | let croppedImage = try SEQuadrangleHelper.cropImage(with: image, quad: points) 116 | let result = Result(original: image, cropped: croppedImage, quad: Quad(clockwise: points)) 117 | 118 | DispatchQueue.main.async { [weak self] in 119 | self?.cropDelegate?.documentCropViewController(result: result) 120 | } 121 | } catch { 122 | DispatchQueue.main.async { [weak self] in 123 | self?.cropDelegate?.documentCropViewController(failed: error) 124 | } 125 | } 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Controllers/DocumentScannerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentScannerViewController.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import AVFoundation 9 | import UIKit 10 | import Vision 11 | 12 | public protocol DocumentScannerViewControllerDelegate: class { 13 | 14 | func documentScanner(result: Result) 15 | 16 | } 17 | 18 | @available(iOS 10.0, *) 19 | open class DocumentScannerViewController: CameraViewController { 20 | 21 | private var trackView = TrackView() 22 | 23 | public var autoDetector = AutoDetector() { 24 | didSet { 25 | autoDetector.delegate = self 26 | } 27 | } 28 | 29 | public var rectangleDetector: SequenceRectangleDetector = NoSequenceRectangleDetector() { 30 | didSet { 31 | configureDetector() 32 | } 33 | } 34 | 35 | public weak var scannerDelegate: DocumentScannerViewControllerDelegate? 36 | 37 | open override func viewDidLoad() { 38 | super.viewDidLoad() 39 | 40 | if #available(iOS 11.0, *) { 41 | rectangleDetector = VisionSequenceRectangleDetector() 42 | } 43 | 44 | view.addSubview(trackView) 45 | autoDetector.delegate = self 46 | } 47 | 48 | open override func viewWillDisappear(_ animated: Bool) { 49 | super.viewDidDisappear(animated) 50 | 51 | autoDetector.reset() 52 | trackView.update(path: nil) 53 | } 54 | 55 | open override func viewWillAppear(_ animated: Bool) { 56 | super.viewWillAppear(animated) 57 | 58 | autoDetector.reset() 59 | trackView.update(path: nil) 60 | } 61 | 62 | private func configureDetector() { 63 | rectangleDetector.update = { [weak self] observation in 64 | guard let strongSelf = self else { return } 65 | strongSelf.autoDetector.feed(observation: observation) 66 | } 67 | } 68 | 69 | open override func viewDidLayoutSubviews() { 70 | super.viewDidLayoutSubviews() 71 | 72 | trackView.frame = view.bounds 73 | trackView.layoutSubviews() 74 | } 75 | 76 | public override func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 77 | guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } 78 | rectangleDetector.detect(on: pixelBuffer) 79 | } 80 | 81 | } 82 | 83 | @available(iOS 10.0, *) 84 | extension DocumentScannerViewController: AutoDetectorDelegate { 85 | 86 | public func detector(update: Observation) { 87 | guard let points = update.quad?.mirrorUp()?.points else { return } 88 | let converted = points.compactMap { previewLayer?.layerPointConverted(fromCaptureDevicePoint: $0) } 89 | let path = converted.quadPath 90 | trackView.update(path: path) 91 | } 92 | 93 | public func detector(success: Observation) { 94 | guard let quad = success.quad, let mirrored = quad.mirrorUp() else { return } 95 | 96 | CropHelper.crop(buffer: success.buffer, quad: mirrored) { result in 97 | self.scannerDelegate?.documentScanner(result: result) 98 | } 99 | } 100 | 101 | public func detector(failed: Observation) { 102 | trackView.update(path: nil) 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/AutoDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutoDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | import CoreGraphics 10 | 11 | public protocol AutoDetectorDelegate: class { 12 | 13 | func detector(update: Observation) 14 | func detector(success: Observation) 15 | func detector(failed: Observation) 16 | 17 | } 18 | 19 | public final class AutoDetector { 20 | 21 | public struct Config { 22 | 23 | public var minCorrectFrames: Int // minimum correct frames before update 24 | public var maxDroppedFrames: Int // maximum frames that can be dropped before tracking is lost 25 | public var frameBufferSize: Int // frames needed to autodetect 26 | 27 | public var threshold: CGFloat // maximum deviation of points 28 | 29 | public static var `default` = Config(minCorrectFrames: 8, maxDroppedFrames: 5, frameBufferSize: 64, threshold: 0.05) 30 | } 31 | 32 | public weak var delegate: AutoDetectorDelegate? 33 | 34 | private(set) var finished: Bool = false 35 | private var droppedFrames: Int = 0 36 | private var queue = DispatchQueue(label: "AutoDetectionQueue") 37 | 38 | private var quads: [Quad] = [] 39 | private var config: Config 40 | 41 | public init(config: Config = Config.default) { 42 | self.config = config 43 | } 44 | 45 | public func feed(observation: Observation) { 46 | guard !finished else { return } 47 | 48 | queue.async { [weak self] in 49 | guard let strongSelf = self else { return } 50 | strongSelf.execute(observation: observation) 51 | } 52 | } 53 | 54 | public func reset() { 55 | droppedFrames = 0 56 | quads = [] 57 | finished = false 58 | } 59 | 60 | private func execute(observation: Observation) { 61 | if let newQuad = observation.quad { 62 | if quads.count < 1 { quads.append(newQuad); return; } 63 | 64 | let averageQuad = calculateWeightedAverage() 65 | if newQuad.isInRange(other: averageQuad, threshold: config.threshold) { 66 | quads.append(newQuad) 67 | if quads.count > config.frameBufferSize { quads.removeFirst() } 68 | guard quads.count >= config.minCorrectFrames else { return } 69 | 70 | DispatchQueue.main.async { 71 | self.delegate?.detector(update: observation) 72 | } 73 | 74 | guard quads.count >= config.frameBufferSize else { return } 75 | finished = true 76 | 77 | DispatchQueue.main.async { 78 | self.delegate?.detector(success: observation) 79 | } 80 | } else { 81 | droppedFrames = 0 82 | quads = [] 83 | 84 | DispatchQueue.main.async { 85 | self.delegate?.detector(failed: observation) 86 | } 87 | } 88 | } else { 89 | droppedFrames += 1 90 | guard droppedFrames >= config.maxDroppedFrames else { return } 91 | droppedFrames = 0 92 | quads = [] 93 | 94 | DispatchQueue.main.async { 95 | self.delegate?.detector(failed: observation) 96 | } 97 | } 98 | } 99 | 100 | private func calculateWeightedAverage() -> Quad { 101 | let count = quads.count 102 | let fixedWeights: [CGFloat] = [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20].reversed() 103 | let weights = fixedWeights + Array(repeating: 1, count: max(count - fixedWeights.count, 0)) 104 | let totalWeight = weights[0 ..< count].reduce(0, +) 105 | 106 | let combined = zip(quads.reversed(), weights).map { $0.multiply(value: $1).divide(value: totalWeight) } 107 | let averagePoint = combined.reduce(Quad(), +) 108 | 109 | return averagePoint 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/CIImageRectangleDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIImageRectangleDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | import UIKit 10 | 11 | public final class CIImageRectangleDetector: ImageRectangleDetector { 12 | 13 | public func detect(image: UIImage, completion: @escaping Completion) { 14 | DispatchQueue.global().async { 15 | guard let ciImage = CIImage(image: image) else { return } 16 | 17 | guard let detector = CIDetector(ofType: CIDetectorTypeRectangle, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]) else { return } 18 | 19 | let results = detector.features(in: ciImage) 20 | let sortedBySize = results.sorted { $0.bounds.area > $1.bounds.area } 21 | 22 | if let feature = sortedBySize.first as? CIRectangleFeature { 23 | let size = ciImage.extent.size 24 | let points = [feature.topLeft, feature.topRight, feature.bottomRight, feature.bottomLeft] 25 | let normalized = points.map { $0.scaledRelative(size: size) } 26 | 27 | let quad = Quad(clockwise: normalized) 28 | 29 | DispatchQueue.main.async { 30 | completion(quad) 31 | } 32 | } else { 33 | DispatchQueue.main.async { 34 | completion(nil) 35 | } 36 | } 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/NoSequenceRectangleDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoSequenceRectangleDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | 10 | public final class NoSequenceRectangleDetector: SequenceRectangleDetector { 11 | 12 | public var update: SequenceRectangleDetector.Update? 13 | public func detect(on pixelBuffer: CVPixelBuffer) { } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/RectangleImageDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RectangleImageDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | import UIKit 10 | import Vision 11 | 12 | public protocol ImageRectangleDetector: class { 13 | 14 | typealias Completion = (Quad?) -> Void 15 | 16 | func detect(image: UIImage, completion: @escaping Completion) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/SequenceRectangleDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SequenceRectangleDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import AVFoundation 9 | import Foundation 10 | import Vision 11 | 12 | public protocol SequenceRectangleDetector: class { 13 | 14 | typealias Update = (Observation) -> Void 15 | 16 | var update: Update? { get set } 17 | func detect(on pixelBuffer: CVPixelBuffer) 18 | 19 | } 20 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/VisionImageRectangleDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VisionImageRectangleDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import Foundation 9 | 10 | import UIKit 11 | import Vision 12 | 13 | @available(iOS 11.0, *) 14 | public final class VisionImageRectangleDetector: ImageRectangleDetector { 15 | 16 | private var completionHandler: Completion? 17 | 18 | public func detect(image: UIImage, completion: @escaping Completion) { 19 | guard let cgImage = image.cgImage else { return } 20 | 21 | let request = VNDetectRectanglesRequest(completionHandler: handleRequest) 22 | request.minimumAspectRatio = 0 23 | request.quadratureTolerance = 45 24 | request.preferBackgroundProcessing = true 25 | 26 | let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) 27 | 28 | do { 29 | completionHandler = completion 30 | try handler.perform([request]) 31 | } catch { 32 | print(error) 33 | } 34 | } 35 | 36 | @available(iOS 11.0, *) 37 | private func handleRequest(request: VNRequest, error: Error?) { 38 | guard let observations = request.results as? [VNRectangleObservation] else { return } 39 | let sortedByConfidence = observations.sorted { $0.confidence > $1.confidence } 40 | 41 | if let observation = sortedByConfidence.first { 42 | let quad = Quad(obvservation: observation) 43 | 44 | DispatchQueue.main.async { [weak self] in 45 | self?.completionHandler?(quad) 46 | } 47 | } else { 48 | DispatchQueue.main.async { [weak self] in 49 | self?.completionHandler?(nil) 50 | } 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Detectors/VisionSequenceRectangleDetector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VisionSequenceRectangleDetector.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | import CoreImage 12 | import Vision 13 | 14 | @available(iOS 11.0, *) 15 | public final class VisionSequenceRectangleDetector: SequenceRectangleDetector { 16 | private var data: [NSObject: CVPixelBuffer] = [:] 17 | public var update: Update? 18 | 19 | private lazy var visionRequestHandler = VNSequenceRequestHandler() 20 | 21 | public func detect(on pixelBuffer: CVPixelBuffer) { 22 | let request = VNDetectRectanglesRequest(completionHandler: handle) 23 | request.minimumConfidence = 0.5 24 | request.maximumObservations = 4 25 | request.minimumSize = 0.2 26 | request.minimumAspectRatio = 0.2 27 | request.maximumAspectRatio = 1 28 | request.quadratureTolerance = 45 29 | request.preferBackgroundProcessing = true 30 | 31 | execute(request: request, buffer: pixelBuffer) 32 | } 33 | 34 | private func execute(request: VNRequest, buffer: CVPixelBuffer) { 35 | do { 36 | data[request] = buffer 37 | try visionRequestHandler.perform([request], on: buffer) 38 | } catch { 39 | complete(buffer: buffer) 40 | } 41 | } 42 | 43 | private func handle(request: VNRequest, error: Error?) { 44 | guard let buffer = data.removeValue(forKey: request) else { return } 45 | guard let observations = request.results as? [VNRectangleObservation] else { return } 46 | let sorted = observations.sorted { $0.confidence > $1.confidence } 47 | 48 | if let result = sorted.first { 49 | complete(observation: result, buffer: buffer) 50 | } else { 51 | complete(buffer: buffer) 52 | } 53 | } 54 | 55 | private func complete(observation: VNRectangleObservation? = nil, buffer: CVPixelBuffer) { 56 | let result: Observation 57 | if let observation = observation { 58 | result = Observation(quad: Quad(obvservation: observation), buffer: buffer) 59 | } else { 60 | result = Observation(quad: nil, buffer: buffer) 61 | } 62 | 63 | DispatchQueue.main.async { [weak self] in 64 | self?.update?(result) 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Extensions/Array+extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Array+extension.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import UIKit 9 | 10 | public extension Array where Element == CGPoint { 11 | 12 | public var quadPath: UIBezierPath { 13 | let path = UIBezierPath() 14 | 15 | guard count == 4 else { return path } 16 | path.move(to: self[0]) 17 | 18 | for i in 1 ..< 4 { 19 | path.addLine(to: self[i]) 20 | } 21 | path.close() 22 | 23 | return path 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Extensions/CGPoint+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPoint+Extension.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreGraphics 9 | 10 | extension CGPoint { 11 | 12 | public func cartesian(height: CGFloat) -> CGPoint { 13 | return CGPoint(x: x, y: height - y) 14 | } 15 | 16 | public func scaledRelative(size: CGSize) -> CGPoint { 17 | return CGPoint(x: x / size.width, y: y / size.height) 18 | } 19 | 20 | public func scaledAbsolute(size: CGSize) -> CGPoint { 21 | return CGPoint(x: x * size.width, y: y * size.height) 22 | } 23 | 24 | func isInRange(other: CGPoint, theshold: CGFloat) -> Bool { 25 | return x - other.x < theshold && y - other.y < theshold 26 | } 27 | 28 | func multiply(value: CGFloat) -> CGPoint { 29 | return CGPoint(x: x * value, y: y * value) 30 | } 31 | 32 | func divide(value: CGFloat) -> CGPoint { 33 | return CGPoint(x: x / value, y: y / value) 34 | } 35 | 36 | public static func +(lhs: CGPoint, rhs: CGPoint) -> CGPoint { 37 | return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Extensions/CGrect+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGrect+Extension.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreGraphics 9 | 10 | extension CGRect { 11 | 12 | public var area: CGFloat { 13 | return width * height 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Extensions/UIImage+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extension.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import UIKit 9 | 10 | public extension UIImage { 11 | 12 | public func fixOrientation(orientation: UIImage.Orientation? = nil) -> UIImage { 13 | guard orientation == nil && imageOrientation != .up else { return self } 14 | 15 | var transform = CGAffineTransform.identity 16 | let orientation = orientation ?? imageOrientation 17 | 18 | switch orientation { 19 | case .down, .downMirrored: 20 | transform = transform.translatedBy(x: size.width, y: size.height) 21 | transform = transform.rotated(by: CGFloat.pi) 22 | case .left, .leftMirrored: 23 | transform = transform.translatedBy(x: size.width, y: 0) 24 | transform = transform.rotated(by: CGFloat.pi / 2) 25 | case .right, .rightMirrored: 26 | transform = transform.translatedBy(x: 0, y: size.height) 27 | transform = transform.rotated(by: -(CGFloat.pi / 2)) 28 | default: 29 | break 30 | } 31 | 32 | switch orientation { 33 | case .upMirrored, .downMirrored: 34 | transform.translatedBy(x: size.width, y: 0) 35 | transform.scaledBy(x: -1, y: 1) 36 | case .leftMirrored, .rightMirrored: 37 | transform.translatedBy(x: size.height, y: 0) 38 | transform.scaledBy(x: -1, y: 1) 39 | default: 40 | break 41 | } 42 | 43 | guard let bitsPerComponent = self.cgImage?.bitsPerComponent, let colorSpace = self.cgImage?.colorSpace, let ctx: CGContext = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return self } 44 | ctx.concatenate(transform) 45 | 46 | guard let cgImage = self.cgImage else { return self } 47 | switch orientation { 48 | case .left, .leftMirrored, .right, .rightMirrored: 49 | ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) 50 | default: 51 | ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) 52 | break 53 | } 54 | 55 | guard let image: CGImage = ctx.makeImage() else { return self } 56 | return UIImage(cgImage: image) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Helpers/CropHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CropHelper.swift 3 | // CropView 4 | // 5 | // Created by Jonas Beckers on 28/02/18. 6 | // 7 | 8 | import CoreImage 9 | import Vision 10 | 11 | public struct CropHelper { 12 | 13 | public typealias Completion = (Result) -> Void 14 | 15 | static func crop(buffer: CVPixelBuffer, quad: Quad, completion: @escaping Completion) { 16 | DispatchQueue.global(qos: .userInteractive).async { 17 | let ciImage = CIImage(cvPixelBuffer: buffer) 18 | let context = CIContext() 19 | 20 | guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return } 21 | let image = UIImage(cgImage: cgImage, scale: 1, orientation: .right).fixOrientation() 22 | 23 | let size = ciImage.extent.size 24 | let width = Int(size.width) 25 | let height = Int(size.height) 26 | 27 | let points: [CGPoint] 28 | if #available(iOS 11.0, *) { 29 | points = quad.points.map { VNImagePointForNormalizedPoint($0, width, height) } 30 | } else { 31 | points = quad.points.map { $0.scaledAbsolute(size: size) } 32 | } 33 | let converted = points.map { $0.cartesian(height: size.height) } 34 | 35 | let result: Result 36 | if let quad = Quad(clockwise: converted), let cropped = applyPersperpectiveCorrection(ciImage: ciImage, quad: quad) { 37 | result = Result(original: image, cropped: cropped, quad: quad) 38 | } else { 39 | result = Result(original: image, cropped: nil, quad: nil) 40 | } 41 | 42 | DispatchQueue.main.async { 43 | completion(result) 44 | } 45 | } 46 | } 47 | 48 | private static func applyPersperpectiveCorrection(ciImage: CIImage, quad: Quad) -> UIImage? { 49 | guard let filter = CIFilter(name: "CIPerspectiveCorrection") else { return nil } 50 | let context = CIContext(options: nil) 51 | 52 | filter.setValue(CIVector(cgPoint: quad.topLeft), forKey: "inputTopLeft") 53 | filter.setValue(CIVector(cgPoint: quad.topRight), forKey: "inputTopRight") 54 | filter.setValue(CIVector(cgPoint: quad.bottomLeft), forKey: "inputBottomLeft") 55 | filter.setValue(CIVector(cgPoint: quad.bottomRight), forKey: "inputBottomRight") 56 | filter.setValue(ciImage, forKey: kCIInputImageKey) 57 | 58 | guard let correctedImage = filter.outputImage, let cgImage = context.createCGImage(correctedImage, from: correctedImage.extent) else { return nil } 59 | return UIImage(cgImage: cgImage, scale: 1, orientation: .right) 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Models/Observation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observation.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | 10 | public struct Observation { 11 | 12 | public init(quad: Quad?, buffer: CVPixelBuffer) { 13 | self.quad = quad 14 | self.buffer = buffer 15 | } 16 | 17 | public let quad: Quad? 18 | public let buffer: CVPixelBuffer 19 | 20 | } 21 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Models/Quad.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quad.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import CoreImage 9 | import Vision 10 | import UIKit 11 | 12 | public struct Quad { 13 | 14 | public var topLeft: CGPoint 15 | public var topRight: CGPoint 16 | public var bottomLeft: CGPoint 17 | public var bottomRight: CGPoint 18 | 19 | public init(topLeft: CGPoint, topRight: CGPoint, bottomLeft: CGPoint, bottomRight: CGPoint) { 20 | self.topLeft = topLeft 21 | self.topRight = topRight 22 | self.bottomLeft = bottomLeft 23 | self.bottomRight = bottomRight 24 | } 25 | 26 | public init() { 27 | self.init(topLeft: .zero, topRight: .zero, bottomLeft: .zero, bottomRight: .zero) 28 | } 29 | 30 | public init?(clockwise points: [CGPoint]) { 31 | guard points.count == 4 else { return nil } 32 | self.init(topLeft: points[0], topRight: points[1], bottomLeft: points[3], bottomRight: points[2]) 33 | } 34 | 35 | @available(iOS 11.0, *) 36 | public init(obvservation: VNRectangleObservation) { 37 | self.init(topLeft: obvservation.topLeft, topRight: obvservation.topRight, bottomLeft: obvservation.bottomLeft, bottomRight: obvservation.bottomRight) 38 | } 39 | } 40 | 41 | extension Quad { 42 | 43 | public var isEmpty: Bool { 44 | return topLeft == .zero && topRight == .zero && bottomRight == .zero && bottomLeft == .zero 45 | } 46 | 47 | public var points: [CGPoint] { 48 | return [topLeft, topRight, bottomRight, bottomLeft] 49 | } 50 | 51 | } 52 | 53 | extension Quad { 54 | 55 | func absolute(size: CGSize) -> Quad { 56 | return Quad(topLeft: topLeft.scaledAbsolute(size: size), topRight: topLeft.scaledAbsolute(size: size), bottomLeft: bottomLeft.scaledAbsolute(size: size), bottomRight: bottomRight.scaledAbsolute(size: size)) 57 | } 58 | 59 | func mirrorUp() -> Quad? { 60 | let converted = points.map { CGPoint(x: $0.x, y: 1 - $0.y) } 61 | return Quad(clockwise: converted) 62 | } 63 | 64 | func multiply(value: CGFloat) -> Quad { 65 | return Quad(topLeft: topRight.multiply(value: value), topRight: topRight.multiply(value: value), bottomLeft: bottomRight.multiply(value: value), bottomRight: bottomRight.multiply(value: value)) 66 | } 67 | 68 | func divide(value: CGFloat) -> Quad { 69 | return Quad(topLeft: topRight.divide(value: value), topRight: topRight.divide(value: value), bottomLeft: bottomRight.divide(value: value), bottomRight: bottomRight.divide(value: value)) 70 | } 71 | 72 | func isInRange(other: Quad, threshold: CGFloat) -> Bool { 73 | return topRight.isInRange(other: other.topRight, theshold: threshold) && topLeft.isInRange(other: other.topLeft, theshold: threshold) && bottomRight.isInRange(other: other.bottomRight, theshold: threshold) && bottomLeft.isInRange(other: other.bottomLeft, theshold: threshold) 74 | } 75 | 76 | static func +(lhs: Quad, rhs: Quad) -> Quad { 77 | return Quad(topLeft: lhs.topLeft + rhs.topLeft, topRight: lhs.topRight + rhs.topRight, bottomLeft: lhs.bottomLeft + rhs.bottomLeft, bottomRight: lhs.bottomRight + rhs.bottomRight) 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Models/Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Result.swift 3 | // CropView 4 | // 5 | // Created by Jonas Beckers on 28/02/18. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Result { 11 | 12 | public let original: UIImage 13 | public let cropped: UIImage? 14 | public let quad: Quad? 15 | 16 | } 17 | -------------------------------------------------------------------------------- /SwiftDocumentScanner/Classes/Views/TrackView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrackView.swift 3 | // DocumentScanner 4 | // 5 | // Created by Jonas Beckers on 25/02/18. 6 | // 7 | 8 | import UIKit 9 | 10 | public final class TrackView: UIView { 11 | 12 | public static var lineColor: UIColor = .green 13 | public static var fillColor: UIColor = UIColor.green.withAlphaComponent(0.5) 14 | public static var lineWidth: CGFloat = 2 15 | 16 | private var shape = CAShapeLayer() 17 | private var updated: Double = 0 18 | 19 | override init(frame: CGRect) { 20 | super.init(frame: frame) 21 | 22 | setup() 23 | } 24 | 25 | required public init?(coder aDecoder: NSCoder) { 26 | super.init(coder: aDecoder) 27 | 28 | setup() 29 | } 30 | 31 | private func setup() { 32 | shape.strokeColor = TrackView.lineColor.cgColor 33 | shape.fillColor = TrackView.fillColor.cgColor 34 | shape.lineWidth = TrackView.lineWidth 35 | 36 | layer.addSublayer(shape) 37 | } 38 | 39 | override public func layoutSubviews() { 40 | super.layoutSubviews() 41 | 42 | shape.frame = bounds 43 | shape.strokeColor = TrackView.lineColor.cgColor 44 | shape.fillColor = TrackView.fillColor.cgColor 45 | shape.lineWidth = TrackView.lineWidth 46 | } 47 | 48 | func update(path: UIBezierPath?) { 49 | if let path = path { 50 | shape.path = path.cgPath 51 | } else { 52 | shape.path = nil 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------