Skip to main content

Modules in Detail | iOS Document Scanner

Detectors#

Document Scanner#

The Scanbot SDK comes with a view controller subclass that handles all the camera and detection implementation details for you. It provides a UI for document scanning guidance as well as a UI and functionality and a UI for manual and automatic shutter release.

The view controller's delegate can customize the appearance and behavior of the guidance UI. Further SBSDKScannerViewController gives it's delegate control over how and when frames are analyzed and, most important, it delivers the scanned (and perspective corrected, cropped document) images to it's delegate.

See SBSDKScannerViewControllerDelegate for customization of UI and behavior.

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKScannerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
class DocumentScannerSwiftViewController: UIViewController {
    // The instance of the scanner view controller.    var scannerViewController: SBSDKScannerViewController?
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the SBSDKScannerViewController instance.        self.scannerViewController = SBSDKScannerViewController(parentViewController: self, imageStorage: nil)    }
}
extension DocumentScannerSwiftViewController: SBSDKScannerViewControllerDelegate {    func scannerController(_ controller: SBSDKScannerViewController,                           didDetect polygon: SBSDKPolygon?,                            with status: SBSDKDocumentDetectionStatus) {        // Process the detected document.    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIDocumentScannerViewController.

Usually this view controller is used as a separate screen for scanning documents. It returns results wrapped in an SBSDKUIDocument instance.

While you don't have direct control of the actual scanner view controller, you can use the SBSDKUIDocumentScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class DocumentScannerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIDocumentScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable multi page mode to scan several documents before processing the result.        configuration.behaviorConfiguration.isMultiPageEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsActiveColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Present the recognizer view controller modally on this view controller.        SBSDKUIDocumentScannerViewController.present(on: self,                                                     with: configuration,                                                     andDelegate: self)    }}
extension DocumentScannerUISwiftViewController: SBSDKUIDocumentScannerViewControllerDelegate {    func scanningViewController(_ viewController: SBSDKUIDocumentScannerViewController,                                didFinishWith document: SBSDKUIDocument) {        // Process the scanned document.    }}

Multiple Objects Scanner#

The ScanbotSDK provides the ability to detect multiple non-overlapping rectangular objects in a UIImage or SampleBufferRef. Results of scanning are stored in an image storage (more about Image storage).

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKMultipleObjectScannerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import Foundationimport ScanbotSDK
// This is a simple, empty view controller which acts as a container and delegate for the SBSDKMultipleObjectScannerViewController.class MultipleObjectsScannerSwiftViewController: UIViewController {
    // The instance of the recognition view controller.    var recognizerController: SBSDKMultipleObjectScannerViewController?
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the SBSDKMultipleObjectScannerViewController instance        // and let it embed into this view controller's view.        self.recognizerController = SBSDKMultipleObjectScannerViewController(parentViewController: self,                                                                             parentView: self.view)
        // Set the delegate to this view controller.        self.recognizerController?.delegate = self
        // Turn on/off the shutter button.        self.recognizerController?.shutterButtonHidden = false    }}
extension MultipleObjectsScannerSwiftViewController: SBSDKMultipleObjectScannerViewControllerDelegate {    func scannerController(_ controller: SBSDKMultipleObjectScannerViewController,                           didCaptureObjectImagesInStorage imageStorage: SBSDKImageStoring) {        // Process detected images in storage.    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIMultipleObjectScannerViewController.

Usually this view controller is used as a separate screen for scanning multiple rectangular objects, e.g. business cards. It returns results wrapped in an SBSDKUIDocument instance.

While you don't have direct control of the actual scanner view controller, you can use the SBSDKUIMultipleObjectScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import Foundationimport ScanbotSDK
class MultipleObjectsScannerUISwiftViewController: UIViewController {    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    private func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIMultipleObjectScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable batch mode.        configuration.behaviorConfiguration.isBatchModeEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsActiveColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.batchButtonTitle = "Batch Mode"        configuration.textConfiguration.flashButtonTitle = "Flash"
        // Present the recognizer view controller modally on this view controller.        SBSDKUIMultipleObjectScannerViewController.present(on: self, with: configuration, andDelegate: self)    }}
extension MultipleObjectsScannerUISwiftViewController: SBSDKUIMultipleObjectScannerViewControllerDelegate {    func multipleObjectScannerViewController(_ viewController: SBSDKUIMultipleObjectScannerViewController,                                             didFinishWith document: SBSDKUIDocument) {        // Process the recognized document.    }}

Barcode and QR-Code Scanner#

The Scanbot SDK provides the ability to search and decode multiple types of barcodes in a UIImage or SampleBufferRef. The result is incapsulated in an array of SBSDKBarcodeScannerResult instances. The Scanbot SDK supports the following types of barcodes:

1D barcodes:

  • EAN_13
  • EAN_8
  • UPC_E
  • CODE_39
  • CODE_93
  • CODE_128
  • ITF (Interleaved 2 of 5)

2D barcodes:

  • QR_CODE
  • DATA_MATRIX
  • AZTEC
  • PDF_417

To provide better detection results Scanbot SDK supports the ability to accumulate multiple frames before running detection. In this case, the barcode scanner will return empty results until the frames have been called a given number of times. Then the barcode scanner will perform detection on the frame with the least amount of blur. This feature is intended for use with live detection.

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKBarcodeScannerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
// This is a simple, empty view controller which acts as a container and delegate for the SBSDKBarcodeScannerViewController.class BarcodeScannerSwiftViewController: UIViewController {
    // The instance of the scanner view controller.    var scannerViewController: SBSDKBarcodeScannerViewController?
    // The variable to indicate whether you want the scanner to detect barcodes or not.    var shouldDetectBarcodes = false
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the SBSDKBarcodeScannerViewController instance.        self.scannerViewController = SBSDKBarcodeScannerViewController(parentViewController: self,                                                                       parentView: self.view)
        // Define a finder view:        // set the color and width of the finder line,        self.scannerViewController?.viewFinderLineColor = UIColor.green        self.scannerViewController?.viewFinderLineWidth = 5
        // set the finder's aspect ratio,        self.scannerViewController?.finderAspectRatio = SBSDKAspectRatio(width: 1, andHeight: 0.5)
        // set the finder's minimum insets,        self.scannerViewController?.finderMinimumInset = UIEdgeInsets(top: 100, left: 50, bottom: 100, right: 50)
        // enable the finder view.        self.scannerViewController?.shouldUseFinderFrame = true
        // Set detection rate.        self.scannerViewController?.detectionRate = 5
        // Define and set barcode types that should be accepted by the scanner.        let commonTypes = SBSDKBarcodeType.commonTypes()        self.scannerViewController?.acceptedBarcodeTypes = commonTypes    }
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start detecting barcodes when the screen is visible.        self.shouldDetectBarcodes = true    }
    override func viewWillDisappear(_ animated: Bool) {        super.viewWillDisappear(animated)
        // Stop detecting barcodes when the screen is not visible.        self.shouldDetectBarcodes = false    }
}
// The implementation of SBSDKBarcodeScannerViewControllerDelegate.extension BarcodeScannerSwiftViewController: SBSDKBarcodeScannerViewControllerDelegate {
    // Implement this function to process detected barcodes.    func barcodeScannerController(_ controller: SBSDKBarcodeScannerViewController,                                  didDetectBarcodes codes: [SBSDKBarcodeScannerResult]) {        // Process the detected barcodes.    }
    // Implement this function when you need to pause the detection (e.g. when showing the results).    func barcodeScannerControllerShouldDetectBarcodes(_ controller: SBSDKBarcodeScannerViewController) -> Bool {        return self.shouldDetectBarcodes    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIBarcodeScannerViewController.

Usually this view controller is used as a separate screen for scanning multiple barcodes in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIBarcodeScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class BarcodeScannerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIBarcodeScannerConfiguration.default()
        // Behavior configuration:        // e.g. set minimum text length.        // **NOTE:** Currently works for ITF barcodes only.        configuration.behaviorConfiguration.additionalParameters.minimumTextLength = 3
        // UI Configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsColor = UIColor.white
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Create an array of accepted barcode types.        let acceptedMachineCodeTypes = SBSDKUIMachineCodesCollection.twoDimensionalBarcodes()
        // Present the recognizer view controller modally on this view controller.        SBSDKUIBarcodeScannerViewController.present(on: self,                                                    withAcceptedMachineCodeTypes: acceptedMachineCodeTypes,                                                    configuration: configuration,                                                    andDelegate: self)    }}
extension BarcodeScannerUISwiftViewController: SBSDKUIBarcodeScannerViewControllerDelegate {    func qrBarcodeDetectionViewController(_ viewController: SBSDKUIBarcodeScannerViewController,                                          didDetect barcodeResults: [SBSDKBarcodeScannerResult]) {        // Process the detected results.    }}

Barcodes Batch Scanner#

The Scanbot SDK provides the ability to search and decode multiple instances of different types of barcodes in a UIImage or SampleBufferRef. Result is encapsulated in an array of SBSDKBarcodeScannerResult instances.

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKBarcodeScannerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
// This is a simple, empty view controller which acts as a container and delegate for the SBSDKBarcodeScannerViewController.class BarcodesBatchSwiftViewController: UIViewController {
    // The instance of the scanner view controller.    var scannerViewController: SBSDKBarcodeScannerViewController?
    // Property to indicate whether you want the scanner to detect barcodes or not.    var shouldDetectBarcodes = false
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the SBSDKBarcodeScannerViewController instance        self.scannerViewController = SBSDKBarcodeScannerViewController(parentViewController: self,                                                                       parentView: self.view)
        // Define a finder view:        // Set the color and width of the finder line,        self.scannerViewController?.viewFinderLineColor = UIColor.green        self.scannerViewController?.viewFinderLineWidth = 5
        // set the finder's aspect ratio,        self.scannerViewController?.finderAspectRatio = SBSDKAspectRatio(width: 1, andHeight: 0.5)
        // set the finder's minimum insets,        self.scannerViewController?.finderMinimumInset = UIEdgeInsets(top: 100, left: 50, bottom: 100, right: 50)
        // enable the finder view.        self.scannerViewController?.shouldUseFinderFrame = true
        // Set detection rate.        self.scannerViewController?.detectionRate = 5
        // Define and set barcode types that should be accepted by the scanner.        let commonTypes = SBSDKBarcodeType.commonTypes()        self.scannerViewController?.acceptedBarcodeTypes = commonTypes    }
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start detecting barcodes when the screen is visible.        self.shouldDetectBarcodes = true    }
    override func viewWillDisappear(_ animated: Bool) {        super.viewWillDisappear(animated)
        // Stop detecting barcodes when the screen is not visible.        self.shouldDetectBarcodes = false    }}
// The implementation of the SBSDKBarcodeScannerViewControllerDelegate.extension BarcodesBatchSwiftViewController: SBSDKBarcodeScannerViewControllerDelegate {
    // Implement this function to process detected barcodes.    func barcodeScannerController(_ controller: SBSDKBarcodeScannerViewController,                                  didDetectBarcodes codes: [SBSDKBarcodeScannerResult]) {        // Process the detected barcodes.    }
    // Implement this function when you need to pause the detection (e.g. when showing the results).    func barcodeScannerControllerShouldDetectBarcodes(_ controller: SBSDKBarcodeScannerViewController) -> Bool {        return self.shouldDetectBarcodes    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIBarcodesBatchScannerViewController.

Usually this view controller is used as a separate screen for scanning multiple barcodes in a UIImage or SampleBufferRef. It displays the recognition results in an expandable table view. Once you are happy with the results, press the submit button and the recognizer view controller is dismissed and passes the results to it's delegate.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIBarcodesBatchScannerConfiguration to customize it in a wide variety, such as colors, texts and behavior.

import Foundationimport ScanbotSDK
// This is a simple, empty view controller which acts as a container and delegate for the SBSDKBarcodeScannerViewController.class BarcodesBatchScannerUISwiftViewController: UIViewController {    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIBarcodesBatchScannerConfiguration.default()
        // Behavior configuration:        // e.g. set minimum text length.        // **NOTE:** Currently works for ITF barcodes only.        configuration.behaviorConfiguration.additionalDetectionParameters.minimumTextLength = 3
        // UI Configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Create an array of accepted barcode types.        let acceptedMachineCodeTypes = SBSDKUIMachineCodesCollection.oneDimensionalBarcodes()
        // Present the recognizer view controller modally on this view controller.        SBSDKUIBarcodesBatchScannerViewController.present(on: self,                                                          withAcceptedMachineCodeTypes: acceptedMachineCodeTypes,                                                          configuration: configuration,                                                          andDelegate: self)    }}
extension BarcodesBatchScannerUISwiftViewController: SBSDKUIBarcodesBatchScannerViewControllerDelegate {    func barcodesBatchScannerViewController(_ viewController: SBSDKUIBarcodesBatchScannerViewController,                                            didFinishWith barcodeResults: [SBSDKUIBarcodeMappedResult]) {        // Process the detected results.    }}

MRZ Scanner#

The Scanbot SDK provides the ability to recognize machine-readable zones in a UIImage or SampleBufferRef. Result is encapsulated in SBSDKMRZRecognizerResult instance.

NOTE: In order to operate, this class requires tesseract languages and trained data to be present in application bundle

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIMRZScannerViewController.

Usually this view controller is used as a separate screen for scanning machine readable zones in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIMRZScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class MRZScannerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIMRZScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable beep sound on successful detection.        configuration.behaviorConfiguration.isSuccessBeepEnabled = true
        // UI configuration:        // e.g. configure various colors and finder aspect ratio.        configuration.uiConfiguration.topBarButtonsColor = UIColor.white        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.finderAspectRatio = SBSDKAspectRatio(width: 1, andHeight: 0.25)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"        configuration.textConfiguration.flashButtonTitle = "Flash"
        // Present the recognizer view controller modally on this view controller.        SBSDKUIMRZScannerViewController.present(on: self, with: configuration, andDelegate: self)    }}
extension MRZScannerUISwiftViewController: SBSDKUIMRZScannerViewControllerDelegate {    func mrzDetectionViewController(_ viewController: SBSDKUIMRZScannerViewController, didDetect zone: SBSDKMachineReadableZoneRecognizerResult) {        // Process the detected result.    }}

License Plate Scanner#

A class to scan a vehicle's license plate in a UIImage or SampleBufferRef and run a validation on the result. Ideally you use an instance of this class on subsequent video frames. Each scanned frame will raise the confidence of the scan.

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKLicensePlateScannerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
class LicensePlateScannerSwiftViewController: UIViewController {
    // The instance of the scanner view controller.    var scannerViewController: SBSDKLicensePlateScannerViewController?
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the SBSDKLicensePlateScannerConfiguration object.        let configuration = SBSDKLicensePlateScannerConfiguration()
        // Set the maximum number of accumulated frames before starting recognition.        configuration.maximumNumberOfAccumulatedFrames = 5
        // Create the SBSDKLicensePlateScannerViewController instance.        self.scannerViewController = SBSDKLicensePlateScannerViewController(parentViewController: self,                                                                            parentView: self.view,                                                                            delegate: self,                                                                            configuration: configuration)    }
}
extension LicensePlateScannerSwiftViewController: SBSDKLicensePlateScannerViewControllerDelegate {    func licensePlateScannerViewController(_ controller: SBSDKLicensePlateScannerViewController,                                           didRecognizeLicensePlate licensePlateResult: SBSDKLicensePlateScannerResult,                                           on image: UIImage) {        // Process the recognized result.    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUILicensePlateScannerViewController.

Usually this view controller is used as a separate screen for scanning license plates in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUILicensePlateScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class LicensePlateScannerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUILicensePlateScannerConfiguration.default()
        // Behavior configuration:        // e.g. set the maximum number of accumulated frames before starting recognition.        configuration.behaviorConfiguration.maximumNumberOfAccumulatedFrames = 5
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Present the recognizer view controller modally on this view controller.        SBSDKUILicensePlateScannerViewController.present(on: self,                                                         configuration: configuration,                                                         andDelegate: self)    }}
extension LicensePlateScannerUISwiftViewController: SBSDKUILicensePlateScannerViewControllerDelegate {    func licensePlateScanner(_ controller: SBSDKUILicensePlateScannerViewController,                             didRecognizeLicensePlate result: SBSDKLicensePlateScannerResult) {        // Process the scanned result.    }}

Generic Text line Recognizer#

The Scanbot SDK comes with separate scanners for many specific use cases. Use cases that are not covered by any of these specialized scanners can be tackled with the Data Scanner module. This modules main class is SBSDKGenericTextLineRecognizer. You can configure it's behaviour using the SBSDKGenericTextLineRecognizerConfiguration class.

Within a user-defined rectangular area of interest in consecutive video frames the Data Scanner recognizes text (OCR). A customizable block lets you clean up the raw string by filtering it against unwanted characters and OCR noise. Additionally, you can validate the result using pattern-matching or another block.

The Data Scanner returns a SBSDKGenericTextLineRecognizerResult object when it recognizes text. This result contains the cleaned-up string as well as a boolean flag that informs you whether the validation was successful or not.

Use cases for the Data Scanner module are the recognition of single-line text like IBAN numbers, insurance numbers, dates and other textual data fields that can be easily validated resp. pattern-matched.

How is the Data Scanner different to regular OCR? In short, it is more reliable and robust, with a higher confidence in text recognition because it accumulates the results of multiple video frames as well as your input from the raw text clean up block.

To make the integration painless for you, Scanbot SDK provides a simple-to-use plugin-viewcontroller named SBSDKGenericTextLineRecognizerViewController that takes over the camera handling, displays the area-of-interest and runs the Data Scanner. The scanner's results are passed to a delegate.

There are two ways to integrate the component into the application:

Usage of the Classical UI component:#

The main class of the classical UI component is SBSDKGenericTextLineRecognizerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
class GenericTextLineRecognizerSwiftViewController: UIViewController {
    // The instance of the scanner view controller.    var recognizerController: SBSDKGenericTextLineRecognizerViewController?
    override func viewDidLoad() {        super.viewDidLoad()
        // Create the default SBSDKGenericTextLineRecognizerConfiguration object.        let configuration = SBSDKGenericTextLineRecognizerConfiguration.default()
        // Create the SBSDKGenericTextLineRecognizerViewController instance.        self.recognizerController = SBSDKGenericTextLineRecognizerViewController(parentViewController: self,                                                                                 parentView: self.view,                                                                                 configuration: configuration,                                                                                 delegate: self)    }}
extension GenericTextLineRecognizerSwiftViewController: SBSDKGenericTextLineRecognizerViewControllerDelegate {    func textLineRecognizerViewController(_ controller: SBSDKGenericTextLineRecognizerViewController,                                          didValidate result: SBSDKGenericTextLineRecognizerResult) {        // Process the recognized result.    }}

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUITextDataScannerViewController.

Usually this view controller is used as a separate screen for scanning one line texts in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUITextDataScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class GenericTextLineRecognizerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUITextDataScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable highlighting of the detected word boxes.        configuration.behaviorConfiguration.wordBoxHighlightEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsColor = UIColor.white
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Create the data scanner step.        let step = SBSDKUITextDataScannerStep()
        // Set finder's unzoomed height.        step.unzoomedFinderHeight = 100
        // Set the aspect ratio.        step.aspectRatio = SBSDKAspectRatio(width: 4.0, andHeight: 1.0)
        // Set the filter strategy.        step.textFilterStrategy = .document
        // Set the guidance text.        step.guidanceText = "Scan a document"
        // Present the recognizer view controller modally on this view controller.        SBSDKUITextDataScannerViewController.present(on: self,                                                     configuration: configuration,                                                     recognitionStep: step,                                                     andDelegate: self)    }}
extension GenericTextLineRecognizerUISwiftViewController: SBSDKUITextDataScannerViewControllerDelegate {    func textLineRecognizerViewController(_ viewController: SBSDKUITextDataScannerViewController,                                          didFinish step: SBSDKUITextDataScannerStep,                                          with result: SBSDKUITextDataScannerStepResult) {        // Process the recognized result.    }}

Generic Document Recognizer#

The Scanbot SDK provides the ability to detect various types of documents on the image, crop them and recognize fields data via Generic Document Recognizer.

Currently, Generic Document Recognizer supports the following types of documents:

  • German ID Card
  • German Passport
  • German Driver's license

As a result of scanning, the user gets the SBSDKGenericDocument object, if the result of the scanning was successful. SBSDKGenericDocument is a hierarchical structured type, that contains the document's type, eventually a list of child documents, a total recognition confidence and a list of the documents fields. Each field is represented by the SBSDKGenericDocumentField class, holding the field's type, a cropped image of the field, the recognized text and the field's recognition confidence.

For convenience and user interface related tasks the SBSDKGenericDocument can either be flattened, using the functions -[SBSDKGenericDocument flatDocumentIncludingEmptyChildren:includingEmptyFields:] and -[SBSDKGenericDocument allFieldsIncludingEmptyFields:], or wrapped into a document's type specific subclass of SBSDKGenericDocumentWrapper using the function -[SBSDKGenericDocument wrap]. Currently the following document wrappers exist:

  • SBSDKGenericDocumentDeIdCardFront - German ID card front side
  • SBSDKGenericDocumentDeIdCardBack - German ID card back side
  • SBSDKGenericDocumentDePassport - German passport
  • SBSDKGenericDocumentDeDriverLicenseFront - German driver's license front side
  • SBSDKGenericDocumentDeDriverLicenseBack - German driver's license back side

There are two ways to integrate the component into the application:

Usage of the Classical UI component#

The main class of the classical UI component is SBSDKGenericDocumentRecognizerViewController.

Usually this view controller is embedded as a child view controller into another view controller, the parent view controller. The parent view controller usually acts as the delegate and processes the recognition results. You still have full control over the UI elements and can add additional views and buttons to your view controller. The classical component does not display results, instead it just forwards them to the delegate.

import UIKitimport ScanbotSDK
// This is a simple, empty view controller which acts as a container and delegate for the SBSDKGenericDocumentRecognizerViewController.class GenericDocumentViewController: UIViewController, SBSDKGenericDocumentRecognizerViewControllerDelegate {
    // The instance of the recognition view controller.    var recognizerController: SBSDKGenericDocumentRecognizerViewController!
    override func viewDidLoad() {        super.viewDidLoad()
        // Define the types of documents that should be recognized.        // Recognize all supported document types.        let allTypes: [SBSDKGenericDocumentRootType] = SBSDKGenericDocumentRootType.allDocumentTypes()
        // Recognize German ID cards only. Front and/or back side.        let idCardTypes: [SBSDKGenericDocumentRootType] = [            SBSDKGenericDocumentRootType.deIdCardFront(),            SBSDKGenericDocumentRootType.deIdCardBack()        ]
        // Recognize German passports. Front side only.        let passportTypes: [SBSDKGenericDocumentRootType] = [            SBSDKGenericDocumentRootType.dePassport()        ]
        // Recognize German driver's licenses only. Front and/or back side.        let driverLicenseTypes: [SBSDKGenericDocumentRootType] = [            SBSDKGenericDocumentRootType.deDriverLicenseFront(),            SBSDKGenericDocumentRootType.deDriverLicenseBack()        ];
        // Create the SBSDKGenericDocumentRecognizerViewController instance        // and let it embed into this view controller's view.        self.recognizerController            = SBSDKGenericDocumentRecognizerViewController(parentViewController: self,                                                           //Embed the recognizer in this view controller's view.                                                           parentView: self.view,                                                           // Pass the above types here as required.                                                           acceptedDocumentTypes: allTypes,                                                           // Set the delegate to this view controller.                                                           delegate: self)

        // Set additional configuration of the the recognizer view controller.
        // e.g. turn on/off camera light on start.        self.recognizerController.flashLightEnabled = false
        // Turn on/off the viewfinder.        self.recognizerController.showViewFinder = true
        // Configure the finder view colors.        self.recognizerController.viewFinderLineColor = UIColor.red        self.recognizerController.viewFinderBackgroundColor = UIColor.red.withAlphaComponent(0.1)    }

    // The delegate implementation of SBSDKGenericDocumentViewController.    func documentRecognizerViewController(_ controller: SBSDKGenericDocumentRecognizerViewController,                                          didRecognizeDocument document: SBSDKGenericDocument,                                          on image: UIImage) {
        // Access the documents fields directly by iterating over the documents fields.        for field in document.fields {            // Print field type name, field text and field confidence to the console.            print("\(field.type.name) = \(field.value?.text ?? "") (Confidence: \(field.value?.confidence ?? 0.0)")        }

        // Or get a field by it's name.        if let nameField = document.field(byTypeName: "Surname") {            // Access various properties of the field.            let fieldTypeName = nameField.type.name            let fieldValue = nameField.value?.text            let confidence = nameField.value?.confidence        }

        // Or create a wrapper for the document if needed.        // You must cast it to the specific wrapper subclass.        if let wrapper = document.wrap() as? SBSDKGenericDocumentDeIdCardFront {            // Access the documents fields easily through the wrapper.            let fieldTypeName = wrapper.surname.type.name            let fieldValue = wrapper.surname.value?.text            let confidence = wrapper.surname.value?.confidence        }    }}

Usage of the Ready to use UI component#

The main class of the ready to use UI component is SBSDKUIGenericDocumentRecognizerViewController.

Usually this view controller is used as a separate screen for recognizing generic documents. It displays the recognition results in an expandable tableview while the recognizer continues to recognize the document to further improve the result. SBSDKUIGenericDocumentRecognizerViewController even allows you to scan two sides of a document, e.g. an ID card with front and back side, in a single screen. Once happy with the results, press the submit button and the recognizer view controller is dismissed and passes the results to it's delegate.

While you don't have direct control of the actual recognition view controller you can use the SBSDKUIGenericDocumentRecognizerConfiguration to customize it in a wide variety, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
// The view controller that presents the document recognizer screen.class GenericDocumentUIViewController: UIViewController, SBSDKUIGenericDocumentRecognizerViewControllerDelegate {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIGenericDocumentRecognizerConfiguration.default()
        // And customize behaviour, user interface and text.
        // Behaviour configuration:        // Select one of the following document types:        // German ID card. Front and/or backside.        configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.idCardFrontBackDE()
        // Or German driver's license. Front and/or backside.        // configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.driverLicenseFrontBackDE()
        // Or German passport. Single sided.        // configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.passportDE()
        // e.g. turn on/off camera light on start.        configuration.behaviorConfiguration.isFlashEnabled = false

        // UI configuration:        // configure various colors.        configuration.uiConfiguration.detailsBackgroundColor = UIColor.darkGray        configuration.uiConfiguration.detailsSectionHeaderBackgroundColor = UIColor.darkGray
        // Customize the visibility of certain fields in the recognized fields list.        // Print the field type visibilities, if needed.        // print("\(configuration.uiConfiguration.fieldTypeVisibilities)")
        // Always show the eye-color field in the recognized fields list.        configuration.uiConfiguration.fieldTypeVisibilities["DeIdCardBack.EyeColor"]            = SBSDKGenericDocumentFieldDisplayStateAlwaysVisible        // Show the categories field in the recognized fields list if the field has a value. Otherwise it is hidden.        configuration.uiConfiguration.fieldTypeVisibilities["DeDriverLicenseFront.LicenseCategories"]            = SBSDKGenericDocumentFieldDisplayStateVisibleIfNotEmpty

        // Text configuration:        // customize UI element's texts.        configuration.textConfiguration.cancelButtonTitle = "Abort"        configuration.textConfiguration.clearButtonTitle = "Reset"
        // Customize document type and field type names. Used also for internationalisation.        // Print the document type texts if needed.        // print("\(configuration.textConfiguration.documentTypeDisplayTexts)")
        // Change/localize the display text for the front side of a German ID card.        configuration.textConfiguration.documentTypeDisplayTexts["DeIdCardFront"] = "Personalausweis (Vorderseite)"
        // Print the field type texts if needed.        // print("\(configuration.textConfiguration.fieldTypeDisplayTexts)")        // Change/localize the display text for the surname field on the front side of a German ID card.        configuration.textConfiguration.fieldTypeDisplayTexts["DeDriverLicenseFront.Surname"] = "Nachname"
        // Present the recognizer view controller modally on this view controller.        SBSDKUIGenericDocumentRecognizerViewController.present(on: self,                                                               // Pass the configuration.                                                               configuration: configuration,                                                               //Set the delegate                                                               andDelegate: self)    }
    // The delegate function implementation.    func genericDocumentRecognizerViewController(_ viewController: SBSDKUIGenericDocumentRecognizerViewController,                                                 didFinishWith documents: [SBSDKGenericDocument]) {
        // Get the first document. In case of multiple documents, e.g. front side and back side you need to        // handle all of them.        guard let document = documents.first else {            return        }
        // Access the documents fields directly by iterating over the documents fields.        for field in document.fields {            // Print field type name, field text and field confidence to the console.            print("\(field.type.name) = \(field.value?.text ?? "") (Confidence: \(field.value?.confidence ?? 0.0)")        }

        // Or get a field by it's name.        if let nameField = document.field(byTypeName: "Surname") {            // Access various properties of the field.            let fieldTypeName = nameField.type.name            let fieldValue = nameField.value?.text            let confidence = nameField.value?.confidence        }

        // Or create a wrapper for the document if needed.        // You must cast it to the specific wrapper subclass.        if let wrapper = document.wrap() as? SBSDKGenericDocumentDeIdCardFront {            // Access the documents fields easily through the wrapper.            let fieldTypeName = wrapper.surname.type.name            let fieldValue = wrapper.surname.value?.text            let confidence = wrapper.surname.value?.confidence        }    }}

NFC Passport Reader#

The Scanbot SDK provides Near Field Communication(NFC) scanner for reading data from passport's NFC chip. To use it you should follow these steps:

  • device you launch your app on should have iOS 13 or higher
  • your app needs to add "Near Field Communication Tag Reading"
  • your app's info.plist needs to provide "Privacy - NFC Scan Usage Description"
  • your app's info.plist needs to define the passport nfc application ID. To do so add the following entry: "com.apple.developer.nfc.readersession.iso7816.select-identifiers" and as the first element add the passport application ID "A0000002471001"

To check if NFC passport reading is available on the system you can call SBSDKNFCPassportReader's class method isPassportReadingAvailable.

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUINFCPassportReaderViewController.

Usually this view controller is used as a separate screen for reading data from passport's NFC cards in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUINFCPassportReaderConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class NFCPassportReaderUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUINFCPassportReaderConfiguration.default()
        // Behavior configuration:        // e.g. enable beep sound on successful detection.        configuration.behaviorConfiguration.isSuccessBeepEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Present the recognizer view controller modally on this view controller.        SBSDKUINFCPassportReaderViewController.present(on: self,                                                       with: configuration, andDelegate: self)    }}
extension NFCPassportReaderUISwiftViewController: SBSDKUINFCPassportReaderViewControllerDelegate {    func nfcPassportReaderViewController(_ viewController: SBSDKUINFCPassportReaderViewController,                                         didFinishWith result: SBSDKUINFCPassportReaderResult) {        // Process the readout result.    }}

Payform Recognizer#

The SBSDKPayFormScanner class provides functionality to detect and recognize SEPA payforms. It extracts relevant information fields by performing optical text recognition on certain areas of the image, e.g. IBAN, BIC, receiver, amount of money and reference.

This module needs the german language package. See SBSDKOpticalTextRecognizer for language addition.

For performance reasons the scanner is divided into two parts: detection and recognition. The detection only tests whether the scanned image contains a payform or not. The recognizer performs the text extraction and fills the fields.

The common usage is to configure the iPhones camera for full HD video capturing and run the detection part on each incoming frame synchronously in the video capture queue. When the detector returns a positive result the recognizing part runs on the same full HD frame in the same video capture queue and returns the recognizers result.

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIWorkflowScannerViewController.

Usually this view controller is used as a separate screen for scanning various scanning scenarios e.g. Payform scanning.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIWorkflowScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class PayformScanWorkflowUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIWorkflowScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable beep sound on successful detection.        configuration.behaviorConfiguration.isSuccessBeepEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsActiveColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Create a workflow step for payform scan.        let workflowStep = SBSDKUIScanPayFormWorkflowStep(title: "Scan payform",                                                          message: "Please scan your payform",                                                          wantsCapturedPage: false) { result in            // Process the result of the workflow step.            if let payform = result.payformResult, payform.recognitionSuccessful {
                // Return nil if a payform was found and recognized.                return nil            }
            // Handle the error if no payform was found or recognized.            return NSError(domain: "PayformErrorDomain",                           code: 2,                           userInfo: [NSLocalizedDescriptionKey: "This does not seem to be a valid payform."])        }
        // Create a workflow using a payform workflow step.        let workflow = SBSDKUIWorkflow(steps: [workflowStep],                                       name: "Payform",                                       validationHandler: nil)
        // Present the recognizer view controller modally on this view controller.        SBSDKUIWorkflowScannerViewController.present(on: self,                                                     workflow: workflow!,                                                     configuration: configuration,                                                     delegate: self)    }}
extension PayformScanWorkflowUISwiftViewController: SBSDKUIWorkflowScannerViewControllerDelegate {    func workflowScanViewController(_ viewController: SBSDKUIWorkflowScannerViewController,                                    didFinish workflow: SBSDKUIWorkflow,                                    with results: [SBSDKUIWorkflowStepResult]) {        // Process the result of the workflow.    }}

Health Insurance Card Scanner#

The Scanbot SDK provides the ability to recognize European health insurance cards (EHIC), a.k.a. elektronische Gesundheitkarten(eGK).

NOTE: In order to operate, this class requires tesseract languages and trained data to be present in the application bundle.

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIHealthInsuranceCardScannerViewController.

Usually this view controller is used as a separate screen for scanning European health insuranse cards in a UIImage or SampleBufferRef. It returns the recognition results in a delegate method.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIHealthInsuranceCardScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class EHICScannerUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIHealthInsuranceCardScannerConfiguration.default()
        //Behavior configuration:        // e.g. turn on/off camera light on start.        configuration.behaviorConfiguration.isFlashEnabled = true
        //UI configuration:        //e.g. configure various colors        configuration.uiConfiguration.topBarButtonsColor = UIColor.white        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red
        //Text configuration:        //e.g. customize UI element's text        configuration.textConfiguration.flashButtonTitle = "Flash"        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        //Present the recognizer view controller modally on this view controller.        SBSDKUIHealthInsuranceCardScannerViewController.present(on: self,                                                                with: configuration,                                                                andDelegate: self)    }}
extension EHICScannerUISwiftViewController: SBSDKUIHealthInsuranceCardScannerViewControllerDelegate {    func healthInsuranceCardDetectionViewController(_ viewController: SBSDKUIHealthInsuranceCardScannerViewController,                                                    didDetectCard card: SBSDKHealthInsuranceCardRecognitionResult) {        //Process detected card    }}

Disability Certificate Recognizer#

The Scanbot SDK provides the ability to recognize disability certificates in a UIImage or CMSampleBufferRef. Result is encapsulated in SBSDKDisabilityCertificatesRecognizerResult instance.

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready to use UI component is SBSDKUIWorkflowScannerViewController.

Usually this view controller is used as a separate screen for scanning various scanning scenarios e.g. Disability Certificate scanning.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIWorkflowScannerConfiguration to customize it in a variety of ways, such as colors, texts and behavior.

import UIKitimport ScanbotSDK
class DisabilityCertificateScanWorkflowUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIWorkflowScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable beep sound on successful detection.        configuration.behaviorConfiguration.isSuccessBeepEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsActiveColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Create an array with the accepted aspect ratios        // e.g. aspect ratios used for German disability certificates.        let ratios = [SBSDKAspectRatio(width: 1.0, andHeight: 1.414),                      SBSDKAspectRatio(width: 1.414, andHeight: 1.0),                      SBSDKAspectRatio(width: 1.0, andHeight: 1.5715)]
        // Create a workflow step using the accepted aspect ratios.        let workflowStep = SBSDKUIScanDisabilityCertificateWorkflowStep(title: "Scan Disability Certificate",                                                                        message: "Please scan your disability certificate.",                                                                        requiredAspectRatios: ratios,                                                                        wantsCapturedPage: true) { result in            // Process the result of the workflow step.            if let dcCertificate = result.disabilityCertificateResult, dcCertificate.recognitionSuccessful {
                // Return nil if a disability certificate was found and recognized.                return nil            }
            // Handle the error if no disability certificate was found or recognized.            return NSError(domain: "DCCertificateErrorDomain",                           code: 2,                           userInfo: [NSLocalizedDescriptionKey: "This does not seem to be a valid certificate."])        }
        // Create a workflow using a disability certificate workflow step.        let workflow = SBSDKUIWorkflow(steps: [workflowStep],                                       name: "Disability Certificate",                                       validationHandler: nil)
        // Present the recognizer view controller modally on this view controller.        SBSDKUIWorkflowScannerViewController.present(on: self,                                                     workflow: workflow!,                                                     configuration: configuration,                                                     delegate: self)    }}
extension DisabilityCertificateScanWorkflowUISwiftViewController: SBSDKUIWorkflowScannerViewControllerDelegate {    func workflowScanViewController(_ viewController: SBSDKUIWorkflowScannerViewController,                                    didFinish workflow: SBSDKUIWorkflow,                                    with results: [SBSDKUIWorkflowStepResult]) {        // Process the result of the workflow.    }}

Cheque Recognizer#

The Scanbot SDK provides the ability to recognize U.S. cheques in a UIImage or CMSampleBufferRef. After successful detection, it runs a recognition operation to extract the data fields of the detected cheque. Result is encapsulated in SBSDKChequeRecognizerResult instance.

Usage of the cheque recognizer#

import UIKitimport ScanbotSDK
class ChequeScannerViewController: UIViewController {
    // Create the instance of the cheque recognizer.    private let recognizer: SBSDKChequeRecognizer = SBSDKChequeRecognizer()
    // Create the instance of the camera session.    private let cameraSession: SBSDKCameraSession = SBSDKCameraSession(for: FeatureCheque)
    override func viewDidLoad() {        super.viewDidLoad()
        // Set the video delegate to this view controller.        self.cameraSession.videoDelegate = self    }}
extension ChequeScannerViewController: SBSDKCameraSessionDelegate {    func captureOutput(_ output: AVCaptureOutput,                       didOutput sampleBuffer: CMSampleBuffer,                       from connection: AVCaptureConnection) {        // Run recognition of CMSampleBufferRef.        if let result = self.recognizer.recognizeCheque(on: sampleBuffer,                                                        orientation: self.cameraSession.videoOrientation) {            DispatchQueue.main.async {                // Process the recognized result            }        }    }}

Utilities#

Scanning Workflow#

The Scanbot SDK can process and combine various scanning scenarios via the Scanning Workflow component. It is represented by SBSDKUIWorkflow which can combine document scanning with QR code detection or machine-readable zone recognition. Many steps can be run in a UIImage or CMSampleBufferRef, so a step can either be a live-detection or a still-image capturing step. You can validate each workflow step separately in a SBSDKUIWorkflowStepValidationHandler block or in the end when all steps finished in a single SBSDKUIWorkflowValidationHandler block and restart the whole workflow if the validation fails.

The creation of custom steps is possible by subclassing the SBSDKUIWorkflowStep.

You can integrate the component into the application using:

Usage of the Ready to use UI component:#

The main class of the ready-to-use UI component is SBSDKUIWorkflowScannerViewController.

Usually, this view controller is used as a separate screen for processing SBSDKUIWorkflow.

While you don't have direct control of the actual scanner view controller you can use the SBSDKUIWorkflowScannerConfiguration to customize it in a variety of ways, such as colors, texts, and behavior.

import UIKitimport ScanbotSDK;
class ScanningWorkflowUISwiftViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {        super.viewDidAppear(animated)
        // Start scanning here. Usually this is an action triggered by some button or menu.        self.startScanning()    }
    func startScanning() {
        // Create the default configuration object.        let configuration = SBSDKUIWorkflowScannerConfiguration.default()
        // Behavior configuration:        // e.g. enable beep sound on successful detection.        configuration.behaviorConfiguration.isSuccessBeepEnabled = true
        // UI configuration:        // e.g. configure various colors.        configuration.uiConfiguration.topBarBackgroundColor = UIColor.red        configuration.uiConfiguration.topBarButtonsActiveColor = UIColor.white        configuration.uiConfiguration.topBarButtonsInactiveColor = UIColor.white.withAlphaComponent(0.3)
        // Text configuration:        // e.g. customize UI element's text.        configuration.textConfiguration.cancelButtonTitle = "Cancel"
        // Create an array with the accepted aspect ratios        // e.g. aspect ratios for a portrait/landscape A4 page.        let portraitRatios = [SBSDKAspectRatio(width: 1.0, andHeight: 1.414)]        let landscapeRatios = [SBSDKAspectRatio(width: 1.414, andHeight: 1.0)]
        // Create a document workflow step using the portrait aspect ratio.        let portraitStep = SBSDKUIScanDocumentPageWorkflowStep(title: "Black & White Document 1/2",                                                               message: "Please scan a PORTRAIT A4 document.",                                                               requiredAspectRatios: portraitRatios,                                                               pagePostProcessing: { page in                                                                // Apply the Black & White filter to the document.                                                                page.filter = SBSDKImageFilterTypeBlackAndWhite                                                               }, resultValidation: nil)
        // Create a document workflow step using the landscape aspect ratio.        let landscapeStep = SBSDKUIScanDocumentPageWorkflowStep(title: "Black & White Document 2/2",                                                               message: "Please scan a LANDSCAPE A4 document.",                                                               requiredAspectRatios: landscapeRatios,                                                               pagePostProcessing: { page in                                                                // Apply the Black & White filter to the document.                                                                page.filter = SBSDKImageFilterTypeBlackAndWhite                                                               }, resultValidation: nil)
        // Create a workflow using the document workflow steps.        let workflow = SBSDKUIWorkflow(steps: [portraitStep, landscapeStep],                                       name: "2-page, black and white document",                                       validationHandler: nil)
        // Present the recognizer view controller modally on this view controller.        SBSDKUIWorkflowScannerViewController.present(on: self,                                                     workflow: workflow!,                                                     configuration: configuration,                                                     delegate: self)    }}
extension ScanningWorkflowUISwiftViewController: SBSDKUIWorkflowScannerViewControllerDelegate {    func workflowScanViewController(_ viewController: SBSDKUIWorkflowScannerViewController,                                    didFinish workflow: SBSDKUIWorkflow,                                    with results: [SBSDKUIWorkflowStepResult]) {        // Process the results of the workflow.    }}

Image Processing#

See SBSDKImageProcessor.

Digital image processing is a core part of Scanbot SDK. Basically there are three operations on images:

  • Rotation
  • Image filtering
  • Image warping (perspective correction and cropping) into a 4-sided polygons shape

All of these image operations can be called either synchronously in any thread or queue or asynchronously on a special serial image processing queue. When working with large images it is highly recommended to make use of the asynchronous API as here no parallel processing of images is possible. Processing large images concurrently easily causes memory warnings and crashes.

Synchronous API can be found in the UIImageSBSDK class extension.

The asynchronous API is implemented as static class SBSDKImageProcessor. Additionally to the three standard operations SBSDKImageProcessor provides a method to apply custom image processing by specifying an SBSDKImageProcessingHandler block. Execution is also dispatched to the image processing queue. The operations completion handlers are called in main thread.

Each call into the asynchronous API returns a SBSDKProgress object to you. This NSProgress subclass can be used to observe the progress of the operation but also it can be used to cancel the operation via the -(void)cancel method.

Example code for custom asynchronous image filter#

// Specify the file URL for the input imageguard let inputImageURL = URL(string: "...") else { return }
// Specify the file URL the output image is written to. Set to nil, if you don't want to save the output imagelet outputImageURL = URL(string: "...")
// Create the image processing closurelet processingHandler: SBSDKImageProcessingHandler = { sourceImage, outError in    // Apply a color filter to the input image,    let filteredImage = sourceImage.sbsdk_imageFiltered(by: SBSDKImageFilterTypeColor)
    // and return the filtered image.    return filteredImage}let progress = SBSDKImageProcessor.customFilterImage(inputImageURL,                                                     processingBlock: processingHandler,                                                     outputImageURL: outputImageURL) { isFinished, error, resultInfo in    let outputImage = resultInfo?[SBSDKResultInfoDestinationImageKey] as? UIImage}

Example code for detecting and applying a polygon to an image:#

// Specify the file URL for the input imageguard let inputImageURL = URL(string: "...") else { return }
// Load image from the specified pathguard let inputImage = UIImage(contentsOfFile: inputImageURL.path) else { return }
// Specify the file URL the output image is written to. Set to nil, if you don't want to save the output imagelet outputImageURL = URL(string: "...")
// Create a document detector.let detector = SBSDKDocumentDetector()
// Let the document detector run on our input image.let result = detector.detectDocumentPolygon(on: inputImage,                                            visibleImageRect: .zero,                                            smoothingEnabled: false,                                            useLiveDetectionParameters: false)
// Check the result.if result.status == SBSDKDocumentDetectionStatusOK, let polygon = result.polygon {
    // If the result is an acceptable polygon, we warp the image into the polygon asynchronously.    // When warping is done we check the result and on success we pick up the output image.    // Then do whatever you want with the warped image.    SBSDKImageProcessor.warpImage(inputImageURL,                                  polygon: polygon,                                  outputImageURL: outputImageURL) { isFinished, error, resultInfo in        if isFinished && error == nil {            let outputImage = resultInfo?[SBSDKResultInfoDestinationImageKey] as? UIImage        }    }} else {    // No acceptable polygon found.}

PDF Creation#

The SBSDKPDFRenderer static class takes an image storage and renders them into a PDF. For each image a page is generated. The generated pages have sizes that correspond to DIN A4, US Letter or Custom. As the images are embedded unscaled the resolution for each page depends on its image. When rendering into a DIN A4 or US Letter format the orientation of the page; landscape or portrait; is derived from the image's aspect ratio.

PDFs can be encrypted using SBSDKAESEncrypter or your custom written encryption classes. The PDF's data is encrypted in memory before it is written to disk. To decrpyt the PDF you need to run proper decryption in your backend or clients.

NOTE: The ScanbotSDK does not lock the PDF with the password, but rather encrypts the actual file. This provides the best level of protection. To decrypt the PDF file you can use the key property of SBSDKAESEncrypter or generate the key yourself using salt, password and iterations.

See SBSDKPDFRendererPageSize for further information.

The operations completion handler is called in main thread.

Example code for creating a standard PDF from an image storage:#

// Create an image storage to save the captured document images tolet imagesURL = SBSDKStorageLocation.applicationDocumentsFolderURL().appendingPathComponent("Images")let imagesLocation = SBSDKStorageLocation.init(baseURL: imagesURL)guard let imageStorage = SBSDKIndexedImageStorage(storageLocation: imagesLocation) else { return }
// Define the indices of the images in the image storage you want to render to the PDF, e.g. the first 3.// To include all images you can simply pass nil for the indexSet. The indexSet is validated internally.// You don't need to take care if all indices are valid.let indexSet = IndexSet(integersIn: 0...2)
// Specify the file URL where the PDF will be saved to. Nil here makes no sense.guard let outputPDFURL = URL(string: "outputPDF") else { return }
// In case you want to encrypt your PDF file, create encrypter using a password and an encryption mode.let encrypter = SBSDKAESEncrypter(password: "password_example#42", mode: .AES256)
// Enqueue the operation and store the SBSDKProgress to watch the progress or cancel the operation.// After completion the PDF is stored at the URL specified in outputPDFURL.// You can also extract the image store and the PDF URL from the resultInfo.let progress = SBSDKPDFRenderer.renderImageStorage(imageStorage,                                                   copyImageStorage: true,                                                   indexSet: indexSet,                                                   with: .autoLocale,                                                   encrypter: encrypter,                                                   output: outputPDFURL) { isFinished, error, resultInfo in    if isFinished && error == nil {        let completedImageStore = resultInfo?[SBSDKResultInfoImageStorageKey] as? SBSDKIndexedImageStorage        let completedPDFURL = resultInfo?[SBSDKResultInfoDestinationFileURLKey] as? URL
    }}

Optical Character Recognition#

The Scanbot OCR feature is based on the Tesseract OCR engine with some modifications and enhancements. The Scanbot SDK uses an optimized custom library of the Tesseract OCR under the hood and provides a convenient API.

For each desired OCR language a corresponding .traineddata file (aka. tessdata) must be installed in the optional resource bundle named ScanbotSDKOCRData.bundle. Also the special data file osd.traineddata is required and must be installed. It is used for orientation and script detection.

The ScanbotSDK.framework itself does not contain any OCR language files to keep the framework small in size. The optional bundle ScanbotSDKOCRData.bundle, provided in the ZIP archive of Scanbot SDK, contains the language files for English and German as well as the osd.traineddata as examples. You can replace or complete these language files as needed. Add this bundle to your project and make sure that it is copied along with your resources into your app.

Preconditions to achieve a good OCR result#

Conditions while scanning#

A perfect document for OCR is flat, straight, doesn't show large shadows, folds, or any other objects that could distract it and is in the highest possible resolution. Our UI and algorithms do their best to help you meet these requirements. But as in photography, you can never fully get the image information back that was lost during the shot.

Languages#

You can use multiple languages for OCR. But since the recognition of characters and words is a very complicated process, increasing the number of languages lowers the overall precision. With more languages, there are more results where the detected word could match. We suggest using as few languages as possible. Make sure that the language you're trying to detect is supported by the SDK and added to the project.

Size and position#

Put the document on a flat surface. Take the photo from straight above in parallel to the document to make sure that the perspective correction doesn't need to fix much. The document should fill out the camera frame while still showing all of the text that needs to be recognized. This results in more pixels for each character that needs to be detected and hence, more detail. Skewed pages decrease the recognition quality.

Light and shadows#

More ambient light is always better. The camera takes the shot at a lower ISO value, which results in less grainy photos. You should make sure that there are no visible shadows. If you have large shadows, it's better to take the shot at an angle instead. That's why we also don't recommend to use the flashlight. From this low distance, it creates a light spot at the center of the document, which decreases the quality.

Focus#

The document needs to be properly focused so that the characters are sharp and clear. The auto-focus of the camera works well if you meet the minimum required distance for the lens to be able to focus. Which usually starts at 5-10cm.

Typefaces#

The OCR trained data is optimized for common serif and sans-serif font types. Decorative or script fonts decrease the quality of the detection a lot.

Implementing OCR#

Download OCR files#

You can find a list of all supported OCR languages and download links on this Tesseract wiki page.

⚠️️️ Please choose and download the proper version of the language data files:

OCR API#

The SBSDKOpticalTextRecognizer takes one or more images and performs various text related operations on each of the images:

  • Page layout analysis
  • Text recognizing
  • Creation of searchable PDF documents with selectable text

The page layout analysis returns information about page orientation, an angle the image should be rotated to deskew it, the text writing direction or the text line order.

The text recognizing operations take either a collection of images (SBSDKImageStoring) and optionally create a PDF of it, or a single image. The single image operation also can take a rectangle describing which area of the image should be text-recognized. The results found in the completion handlers resultsDictionary contain information about the found text, where the text was found (boundingBox) and what kind of text it is (word, line, paragraph).

Examples#

All SBSDKOpticalTextRecognizer operations run in a separate serial queue.

The operations completion handlers are called in main thread.

Example code for performing a page layout analysis:#
// The file URL of the image we want to analyse.guard let imageURL = URL(string: "...") else { return }
// Start the page layout analysis and store the returned SBSDKProgress object. This object can be used to cancel// the operation or to observe the progress. See NSProgress.// In completion check if we finished without error and extract the analyzer result from the resultInfo dictionary.let progress = SBSDKOpticalTextRecognizer.analyseImagePageLayout(imageURL) { isFinished, error, resultInfo in    if isFinished && error == nil {        if let result = resultInfo?[SBSDKResultInfoPageAnalyzerResultsKey] as? SBSDKPageAnalyzerResult {            // Now we can work with the result.        }    }}
Example code for performing text recognition on an image:#
// The file URL of the image we want to analyse.guard let imageURL = URL(string: "...") else { return }
// Enqueue the text recognition operation.// We limit detection to the center area of the image leaving margins of 25% on each side.// Only use english language to be recognized.// The returned SBSDKProgress object can be used to cancel the operation or observer the progress.// Upon completion we extract the result from the resultsDictionary and log the whole recognized text.// The we enumerate all words and log them to the console together with their confidence values and bounding boxes.let progress = SBSDKOpticalTextRecognizer.recognizeText(imageURL,                                                        rectangle: CGRect(x: 0.25, y: 0.25, width: 0.5, height: 0.5),                                                        languageString: "eng") { isFinished, error, resultInfo in    if let result = resultInfo?[SBSDKResultInfoOCRResultsKey] as? SBSDKOCRResult {        // Now we can work with the result.    }}

Image Storage#

The ScanbotSDK comes with built-in image storage. You can store scanned images using either keyed or indexed storage. We provide convenient interfaces for this via SBSDKKeyedImageStorage and SBSDKIndexedImageStorage classes.

SBSDKKeyedImageStorage is a simple thread-safe multiple-reader-single-writer key-value fashioned disk image cache class. Manages images in a dictionary-like fashion.

SBSDKIndexedImageStorage is a simple thread-safe multiple-reader-single-writer index based disk image cache class. Manages images in an array-like fashion.

Both classes support PNG and JPEG image file formats represented in SBSDKImageFileFormat Enumeration.

Both classes support encryption, so your data is stored securely. We provide built-in support for AES128 and AES256 encryption. If these algorithms do not meet your requirements you can create your own encrypter by implementing a class conforming to the protocol SBSDKStorageCrypting.

For easier access to device's file system ScanbotSDK provides convenient helper class SBSDKStorageLocation.

Example of creating indexed image storage using SBSDKStorageLocation and built-in AES256 encrypter:#

// Create Url to the directory where you plan to store imageslet imagesDirectoryURL = SBSDKStorageLocation.applicationDocumentsFolderURL().appendingPathComponent("Images")
// Create storage location using Url to images directorylet storageLocation = SBSDKStorageLocation.init(baseURL: imagesDirectoryURL)
// Create encrypter with password and desired encryption modelet encrypter = SBSDKAESEncrypter(password: "password_example#42", mode: .AES256)
// Create indexed image storage using the storage location, image file format and encrypterlet imageStorage = SBSDKIndexedImageStorage(storageLocation: storageLocation,                                            fileFormat: .JPEG,                                            withEncrypter: encrypter)

Examples of some basic operations on Indexed Image storage:#

// In the example we are using temporary image storageguard let imageStorage = SBSDKIndexedImageStorage.temporary() else { return }
// Create imageguard let image = UIImage(named: "testImage") else { return }
// Create indexlet index: UInt = 0
// Get image at indexlet storedImage = imageStorage.image(at: index)
// Add image to storagelet isAdded = imageStorage.add(image)
// Insert image at indexlet isInserted = imageStorage.insert(image, at: index)
// Remove image at indeximageStorage.removeImage(at: index)
// Move image from index to index// Create new index to move image tolet newIndex: UInt = 1let isMoved = imageStorage.moveImage(from: index, to: newIndex)
// Replace image at index with another image// Create image to replace stored oneguard let newImage = UIImage(named: "newTestImage") else { return }let isReplaced = imageStorage.replaceImage(at: index, with: newImage)

Examples of some basic operations on Keyed Image storage:#

// Create image storage using storage location, in example we are using temporary locationlet imageStorage = SBSDKKeyedImageStorage()
// Create imageguard let image = UIImage(named: "testImage") else { return }
// Create keylet key = "testKey"
// Set image for keyimageStorage.setImage(image, forKey: key)
// Get image for keylet storedImage = imageStorage.image(forKey: key)
// Remove image for keyimageStorage.removeImage(forKey: key)
// Remove images for keys matching prefix// Create prefixlet prefix = "test"imageStorage.removeImagesForKeys(matchingPrefix: prefix)