Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Example/QRCodeReader.swift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@
CE412E9E19D9A1E4000F294E /* QRCodeReader.swiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QRCodeReader.swiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
CE412EA319D9A1E4000F294E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CE412EA419D9A1E4000F294E /* QRCodeReader_swiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeReader_swiftTests.swift; sourceTree = "<group>"; };
CE4E1ED31D81838F00D2AC35 /* QRCodeReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeReader.swift; sourceTree = "<group>"; };
CE4E1ED41D81838F00D2AC35 /* QRCodeReaderResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeReaderResult.swift; sourceTree = "<group>"; };
CE4E1ED31D81838F00D2AC35 /* QRCodeReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = QRCodeReader.swift; sourceTree = "<group>"; };
CE4E1ED41D81838F00D2AC35 /* QRCodeReaderResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = QRCodeReaderResult.swift; sourceTree = "<group>"; };
CE4E1ED51D81838F00D2AC35 /* QRCodeReaderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeReaderViewController.swift; sourceTree = "<group>"; };
CE4E1ED61D81838F00D2AC35 /* QRCodeReaderViewControllerBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeReaderViewControllerBuilder.swift; sourceTree = "<group>"; };
CE4E1ED71D81838F00D2AC35 /* ReaderOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderOverlayView.swift; sourceTree = "<group>"; };
CE4E1ED71D81838F00D2AC35 /* ReaderOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ReaderOverlayView.swift; sourceTree = "<group>"; };
CE4E1ED81D81838F00D2AC35 /* SwitchCameraButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchCameraButton.swift; sourceTree = "<group>"; };
CE4E1ED91D81838F00D2AC35 /* ToggleTorchButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleTorchButton.swift; sourceTree = "<group>"; };
CE8FFED61BAB4E7F00D43F38 /* QRCodeReader.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QRCodeReader.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -142,6 +142,7 @@
CE8FFED71BAB4E7F00D43F38 /* QRCodeReader */,
CE412E8A19D9A1E4000F294E /* Products */,
);
indentWidth = 2;
sourceTree = "<group>";
};
CE412E8A19D9A1E4000F294E /* Products */ = {
Expand Down
70 changes: 42 additions & 28 deletions Example/QRCodeReader.swift/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,61 @@
import UIKit
import AVFoundation

class ViewController: UIViewController, QRCodeReaderViewControllerDelegate {
class ViewController: UIViewController {
lazy var reader = QRCodeReaderViewController(builder: QRCodeReaderViewControllerBuilder {
$0.reader = QRCodeReader(metadataObjectTypes: [AVMetadataObjectTypeQRCode])
$0.showTorchButton = true
})

@IBAction func scanAction(_ sender: AnyObject) {
if QRCodeReader.supportsMetadataObjectTypes() {
reader.modalPresentationStyle = .formSheet
reader.delegate = self

reader.completionBlock = { (result: QRCodeReaderResult?) in
if let result = result {
print("Completion with result: \(result.value) of type \(result.metadataType)")
}
}

present(reader, animated: true, completion: nil)
}
else {

reader.codeReader.buzzWhenCodeIsFound = true

guard QRCodeReader.supportsMetadataObjectTypes() else {
let alert = UIAlertController(title: "Error", message: "Reader not supported by the current device", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))

present(alert, animated: true, completion: nil)
return
}

reader.modalPresentationStyle = .formSheet

reader.showHighlight = false // remove any existing highlight (as QRCodeReaderViewController is reused)
reader.showHighlight = true

// results can be returned in a delegate or a completion block
reader.delegate = self

reader.completionBlock = { (result: QRCodeReaderResult?) in
if let result = result {
print("Completion with result: \(result.value) of type \(result.metadataType)")
}
}

present(reader, animated: true, completion: nil)
}

// MARK: - QRCodeReader Delegate Methods
}

extension ViewController: QRCodeReaderViewControllerDelegate {

func reader(_ reader: QRCodeReaderViewController, didScanResult result: QRCodeReaderResult) {
reader.stopScanning()

dismiss(animated: true) { [weak self] in
let alert = UIAlertController(
title: "QRCodeReader",
message: String (format:"%@ (of type %@)", result.value, result.metadataType),
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))

self?.present(alert, animated: true, completion: nil)
}

// delay dismiss so we can see highlighted QR code

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1, execute: { [weak self] in
self?.dismiss(animated: true) { [weak self] in
let alert = UIAlertController(
title: "QRCodeReader",
message: String (format:"%@ (of type %@)", result.value, result.metadataType),
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))

self?.present(alert, animated: true, completion: nil)
}
})
}

func reader(_ reader: QRCodeReaderViewController, didSwitchCamera newCaptureDevice: AVCaptureDeviceInput) {
Expand All @@ -79,7 +92,8 @@ class ViewController: UIViewController, QRCodeReaderViewControllerDelegate {

func readerDidCancel(_ reader: QRCodeReaderViewController) {
reader.stopScanning()

dismiss(animated: true, completion: nil)
}

}
33 changes: 29 additions & 4 deletions Sources/QRCodeReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,19 @@ public final class QRCodeReader: NSObject, AVCaptureMetadataOutputObjectsDelegat

// MARK: - Managing the Code Discovery

/// Flag to know whether the scanner should stop scanning when a code is found.
public var stopScanningWhenCodeIsFound: Bool = true
/// Flag to know whether the scanner should stop scanning when a code is found. (default: true)
public var stopScanningWhenCodeIsFound = true

/// Block is executed when a metadata object is found.
/// Flag to buzz when a code is found (default: false)
public var buzzWhenCodeIsFound = false

/// Block to execute when a metadata object is found.
public var didFindCode: ((QRCodeReaderResult) -> Void)?

/// Block to execute when corners are found
public var didFindCorners: (([CGPoint]) -> Void)?

// MARK: - Creating the Code Reade
// MARK: - Creating the Code Reader

/**
Initializes the code reader with the QRCode metadata type object.
Expand Down Expand Up @@ -340,7 +346,26 @@ public final class QRCodeReader: NSObject, AVCaptureMetadataOutputObjectsDelegat
if stopScanningWhenCodeIsFound {
stopScanning()
}

if buzzWhenCodeIsFound {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
}

// convert corners coordinates to our view
if let meta = previewLayer.transformedMetadataObject(for: _readableCodeObject) as? AVMetadataMachineReadableCodeObject {
var points:[CGPoint] = []
if let corners = meta.corners {
points = corners.map {
let dict = $0 as! CFDictionary
return CGPoint(dictionaryRepresentation: dict)!
}
DispatchQueue.main.async(execute: { [weak self] in
self?.didFindCorners?(points)
})
}

}

let scannedResult = QRCodeReaderResult(value: _readableCodeObject.stringValue, metadataType:_readableCodeObject.type)

DispatchQueue.main.async(execute: { [weak self] in
Expand Down
36 changes: 33 additions & 3 deletions Sources/QRCodeReaderViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,33 @@ import AVFoundation
public class QRCodeReaderViewController: UIViewController {
/// The code reader object used to scan the bar code.
public let codeReader: QRCodeReader

/// highlight a found QR code (default: true)
public var showHighlight:Bool {
get { return codeReader.didFindCorners != nil }
set(highlight) {

if highlight {

codeReader.didFindCorners = { [weak self] corners in
if let overlayView = self?.readerView.displayable.overlayView as? ReaderOverlayView {
overlayView.showHighlight(corners)
}
}

} else {
codeReader.didFindCorners = nil
// remove any existing highlight
if let overlayView = readerView.displayable.overlayView as? ReaderOverlayView {
overlayView.showHighlight([])
}

}

}

}

let readerView: QRCodeReaderContainer
let startScanningAtLoad: Bool
let showCancelButton: Bool
Expand Down Expand Up @@ -73,16 +99,19 @@ public class QRCodeReaderViewController: UIViewController {

view.backgroundColor = .black

showHighlight = true

codeReader.didFindCode = { [weak self] resultAsObject in
if let weakSelf = self {
weakSelf.completionBlock?(resultAsObject)
weakSelf.delegate?.reader(weakSelf, didScanResult: resultAsObject)
weakSelf.completionBlock?(resultAsObject)
weakSelf.delegate?.reader(weakSelf, didScanResult: resultAsObject)
}
}

setupUIComponentsWithCancelButtonTitle(builder.cancelButtonTitle)

NotificationCenter.default.addObserver(self, selector: #selector(orientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

}

required public init?(coder aDecoder: NSCoder) {
Expand All @@ -93,8 +122,9 @@ public class QRCodeReaderViewController: UIViewController {
showTorchButton = false
showSwitchCameraButton = false
showOverlayView = false

super.init(coder: aDecoder)

}

// MARK: - Responding to View Events
Expand Down
3 changes: 1 addition & 2 deletions Sources/QRCodeReaderViewControllerBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ public final class QRCodeReaderViewControllerBuilder {
Flag to display the guide view.
*/
public var showOverlayView = true



// MARK: - Initializing a Flap View

/**
Expand Down
23 changes: 22 additions & 1 deletion Sources/ReaderOverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import UIKit

/// Overlay over the camera view to display the area (a square) where to scan the code.
public final class ReaderOverlayView: UIView {

/// color to highlight the QR code
public var highlightColor = UIColor.orange.withAlphaComponent(0.5)

private var overlay: CAShapeLayer = {
var overlay = CAShapeLayer()
overlay.backgroundColor = UIColor.clear.cgColor
Expand All @@ -39,7 +43,13 @@ public final class ReaderOverlayView: UIView {

return overlay
}()


lazy var highlight: CAShapeLayer = {
var layer = CAShapeLayer()
layer.fillColor = self.highlightColor.cgColor
return layer
}()

override init(frame: CGRect) {
super.init(frame: frame)

Expand All @@ -54,6 +64,17 @@ public final class ReaderOverlayView: UIView {

private func setupOverlay() {
layer.addSublayer(overlay)
layer.addSublayer(highlight)
}

public func showHighlight(_ corners: [CGPoint]) {

let path = UIBezierPath()
for (index,point) in corners.enumerated() {
index == 0 ? path.move(to: point) : path.addLine(to: point)
}

self.highlight.path = path.cgPath
}

public override func draw(_ rect: CGRect) {
Expand Down