Skip to main content

Generic Document Scanner UI Components | iOS Document Scanner

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

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

  • German ID Card
  • German Passport
  • German Driver's License
  • German Residence Permit
  • German Health Insurance Card (front side)
  • European Health Insurance Card

As a result of scanning, the user gets the SBSDKGenericDocument object, if the result of the scanning was successful. SBSDKGenericDocument is a hierarchically structured type that contains the document's type, eventually a list of child documents, total recognition confidence, and a list of the document's 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 flatDocumentIncludeEmptyChildren:includeEmptyFields:] and -[SBSDKGenericDocument allFieldsIncludeEmptyFields:] or wrapped into a document's type-specific subclass of SBSDKGenericDocumentWrapper using the function -[SBSDKGenericDocument wrap].

The Generic Document Recognizer also provides the ability to exclude certain fields from the scanning process altogether. When implemented, these excluded fields will not even be attempted to be recognized. This is useful for security and/or privacy reasons. See the excludedFieldTypes property in SBSDKGenericDocumentRecognizer, SBSDKGenericDocumentRecognizerViewController and SBSDKUIGenericDocumentRecognizerBehaviorConfiguration. excludedFieldTypes is an array of normalized names for the document field types, e.g. SBSDKGenericDocumentDeIdCardFrontPINFieldNormalizedName.

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
  • SBSDKGenericDocumentDeResidencePermitFront - German residence permit front side
  • SBSDKGenericDocumentDeResidencePermitBack - German residence permit back side
  • SBSDKGenericDocumentDeHealthInsuranceCardFront - German health insurance card front side
  • SBSDKGenericDocumentEuropeanHealthInsuranceCard - European health insurance card

The Generic Document Recognizer is based on the OCR feature and thus requires the proper installation of the corresponding OCR language files (e.g. for English please add the file eng.traineddata). For more details on how to set up the OCR language files please refer to the OCR section.

Generic Document Scanner UI

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

danger

Please be aware that processing really large images may lead to out-of-memory crashes on iOS. Since this limit is highly dynamic and untransparent in iOS, depending on the device, your app's current memory usage, the other running apps, the iOS version, the system configuration and many other unknown variables, we did not add a hard limit for image sizes.

As a general rule of thumb, it is quite safe to assume that processing images of the resolution the camera can shoot will most likely not crash your app. On most modern iOS devices this currently translates to 12 megapixels. But even much larger images may work without crashing as well.

Thus we cannot take responsibility for out-of-memory crashes when dealing with very high-resolution images. It is your responsibility, as an app developer, to properly manage the handling of large images and keep the memory footprint of your app as small as possible.

In case you have any questions on this topic, please reach out to our support team.

caution

Please do not use multiple scanners at the same time. For example, do not combine generic document scanner, health insurance scanner, text data scanner, etc. at the same time! Each scanner instance requires a lot of memory, GPU, and processor resources. Using multiple scanners will lead to performance issues for the entire application.

Ready-To-Use UI Component

alt text

The main class of the Ready-To-Use UI (RTU 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 sides, 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 its delegate.

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

import UIKit
import ScanbotSDK

// The view controller that presents the document recognizer screen.
class GenericDocumentUISwiftViewController: 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 = SBSDKUIGenericDocumentRecognizerConfiguration.defaultConfiguration

// Customize the behavior, user interface and text.

// Behavior configuration:
// Select one of the following document types:
// German ID card. Front and/or back side.
configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.idCardFrontBackDE

// Or German driver's license. Front and/or back side.
// configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.driverLicenseFrontBackDE()

// Or German passport. Single sided.
// configuration.behaviorConfiguration.documentType = SBSDKUIDocumentType.passportDE()

// Select the field types that should be excluded from the recognition process.
configuration.behaviorConfiguration.excludedFieldTypes = [SBSDKGenericDocument.mrzGenderFieldNormalizedName,
SBSDKGenericDocument.mrzIssuingAuthorityFieldNormalizedName,
SBSDKGenericDocument.deIdCardFrontNationalityFieldNormalizedName]

// Turn the flashlight on/off.
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"] = .alwaysVisible
// Show the categories field in the recognized fields list if the field has a value, otherwise it is hidden.
configuration.uiConfiguration.fieldTypeVisibilities?["DeDriverLicenseFront.LicenseCategories"] = .visibleIfNotEmpty


// Text configuration:
// customize UI elements' 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
delegate: self)
}
}

extension GenericDocumentUISwiftViewController: SBSDKUIGenericDocumentRecognizerViewControllerDelegate {
// 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 document's fields directly by iterating over the document's 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 its name.
if let nameField = document.field(by: "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 document's fields easily through the wrapper.
let fieldTypeName = wrapper.surname?.type.name
let fieldValue = wrapper.surname?.value?.text
let confidence = wrapper.surname?.value?.confidence
}
}
}

Classic UI Component

The main class of the Classic 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 Classic component does not display results, instead, it just forwards them to the delegate.

import UIKit
import 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 only. 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
];

// Exclude these field types from the recognition process.
let excludedTypes = [SBSDKGenericDocument.mrzGenderFieldNormalizedName,
SBSDKGenericDocument.mrzIssuingAuthorityFieldNormalizedName,
SBSDKGenericDocument.deIdCardFrontNationalityFieldNormalizedName]

// 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,
// Pass the above excluded types here to exclude them from the recognition process
excludedFieldTypes: excludedTypes,
// Set the delegate to this view controller.
delegate: self)


// Define additional configuration of the the recognizer view controller.

// Turn the flashlight on/off.
self.recognizerController.isFlashLightEnabled = false

// Configure the viewfinder.
// Get current view finder configuration object
let config = self.recognizerController.viewFinderConfiguration

// Enable the view finder
config.isViewFinderEnabled = true

// Configure the view finder colors and line properties.
config.lineColor = UIColor.red
config.backgroundColor = UIColor.red.withAlphaComponent(0.1)
config.lineWidth = 2
config.lineCornerRadius = 8

// Set the view finder configuration to apply it.
self.recognizerController.viewFinderConfiguration = config
}

// The delegate implementation of SBSDKGenericDocumentViewController.
func documentRecognizerViewController(_ controller: SBSDKGenericDocumentRecognizerViewController,
didRecognize result: SBSDKGenericDocumentRecognitionResult,
on image: UIImage) {
// Access the document's fields directly by iterating over the document's fields.
result.document?.fields.forEach { field in
// 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 its name.
if let nameField = result.document?.field(by: "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 = result.document?.wrap() as? SBSDKGenericDocumentDeIdCardFront {
// Access the document's fields easily through the wrapper.
let fieldTypeName = wrapper.surname?.type.name
let fieldValue = wrapper.surname?.value?.text
let confidence = wrapper.surname?.value?.confidence
}
}
}

Want to scan longer than one minute?

Generate a free trial license to test the Scanbot SDK thoroughly.

Get your free Trial License

What do you think of this documentation?