This guide describes how an iOS developer can use our technologies to add document recognition functionality to their application.
doc — documentationSamples/Swift/OCRStudioSDKSample.xcodeproj — sample project launch fileOCRStudioSDKCore/lib/*.xcframework — universal static library for iOS devices and
Simulators
OCRStudioSDKCore/wrap — wrapper for the C++ libraryOCRStudioSDKCore/include — C++ header files for Objective-C interfaceOCRStudioSDKCore/config/*.ocr — configuration filesOCRStudioSDK — Objective-C GUI files for interacting with the libraryAll source files can be modified as needed.
The C++ library is delivered as an xcframework, containing binaries for multiple iOS architectures.
Since Swift cannot interact with C++ directly, the library is integrated through an Objective-C
wrapper located in the wrap directory.
When building the project in Xcode, you must specify the paths to the wrapper headers (wrap)
and
library interface headers (include) via Header Search Paths.
The OCRStudioSDK directory contains helper Objective-C files that simplify
interaction with the
library from Swift.
Swift code accesses the public Objective-C interfaces via OCRStudioSDK-Bridging-Header.h, which must also be included in the project.
OCRStudioSDK directory with source files from the SDK to your
project, selecting
Create Groups.
OCRStudioSDKCore/wrap directory with the wrapper, selecting
Create
Groups.
OCRStudioSDKCore/lib/*.xcframework framework in your project under
General ->
Frameworks, Libraries, and Embedded Content -> "+", with Do not embed.
OCRStudioSDKCore/data directory, selecting Create Folder
References.
OCRStudioSDKCore/includeOCRStudioSDKCore/wrap/objcocrstudiosdk/includeOCRStudioSDKCore/wrap/objcocrstudiosdk/include_implOCRStudioSDK/OCRStudioSDK-Bridging-Header.h to the
Objective-C Bridging Header in project settings.
├── config
├── wrap
└── OCRStudioSDK
├── Core
├── Controller
├── Media
└── OCRStudioSDK-Bridging-Header.h
The typical workflow with the library is:
The OCRStudioSDK module fully encapsulates the library logic, offering delegates
and classes for
convenience.
After adding the *-Bridging-Header.h, main classes are available:
OCRStudioSDKViewController and OCRStudioSDKInstance.
To receive recognition results, implement the OCRStudioSDKViewControllerDelegate
protocol and
initialize the wrapper as follows:
// Initialize controller
let ocrController: OCRStudioSDKViewController = {
let ocrController = OCRStudioSDKViewController(lockedOrientation: false, withTorch: false, withBestDevice: true)
return ocrController
}()
override func viewDidLoad() {
super.viewDidLoad()
// Set delegate to receive recognition results
ocrController.ocrDelegate = self
// Initialize engine from the bundle
DispatchQueue.main.async {
let configPaths = Bundle.main.paths(forResourcesOfType: "ocr", inDirectory: "config")
if configPaths.count == 1 {
self.engineInstance.initializeEngine(configPaths[0])
}
}
// Attach engine to controller
self.ocrController.attachEngineInstance(self.engineInstance)
}
func showocrViewController() {
// Setting video_recognition session type
ocrController.sessionParams().setSessionType("video_recognition")
// Specify document types for recognition
ocrController.sessionParams().setTargetGroupType("default")
ocrController.sessionParams().addTargetMask("are.id.*")
// Set session timeout in seconds
ocrController.sessionParams().setOptionWithName("sessionTimeout", to: "5.0")
// Present the recognition screen
present(ocrController, animated: true, completion: {
print("sample: ocrViewController presented")
})
}
func ocrViewControllerDidRecognize(_ result: OBJCOCRStudioSDKResult, from buffer: CMSampleBuffer?) {
let resultRef = result.getRef()
if resultRef.allTargetsFinal() {
// Access text fields
let item_it = target.itemsBegin("string")
let item_end = target.itemsEnd("string")
while !item_it.isEqual(to: item_end) {
print(item_it.item().name(), item_it.item().value())
item_it.step()
}
// Access images
let item_image_it = target.itemsBegin("image")
let item_image_end = target.itemsEnd("image")
while !item_image_it.isEqual(to: item_image_end) {
if item_image_it.item().hasImage() {
let image = item_it.item().image().convertToUIImage()
}
item_image_it.step()
}
// Dismiss recognition screen
dismiss(animated: true, completion: nil)
}
}
func ocrViewControllerDidCancel() {
dismiss(animated: true, completion: nil)
}
func ocrViewControllerDidStop(_ result: OBJCOCRStudioSDKResult) {
// Here you can display fields in the same way as in ocrViewControllerDidRecognize
dismiss(animated: true, completion: nil)
}
iOS runtime does not manage C++ memory. ARC/GC cannot access objects created in C++. Most library classes return pointers to heap-allocated objects. Responsibility for freeing memory lies with the developer.
The OCRStudioSDK module encapsulates memory management for recognition. When using the API directly, developers are responsible for memory cleanup.
The library may throw exceptions of type ocrstudio::OCRStudioSDKException for invalid
input, incorrect calls, or other errors. The OCRStudioSDK module handles exceptions internally; when using the
API directly, developers must implement proper exception handling.
Our SDK implements the process of reading NFC chips from identity documents using the NFCPassportReader library, which uses the open-source OpenSSL library for data decryption and CoreNFC (a UIKit package for NFC reading). Use the example below to embed RFID reading. Our SDK can also be used to parse NFC passports and perform document authentication checks if your product configuration supports parsing such data.
NFCPassportReader
import NFCPassportReader
func readPassport(mrzKey: String) {
let passportReader = PassportReader()
// specify which data groups (Data Groups) from the chip need to be read
let dataGroups : [DataGroupId] = [.COM, .SOD, .DG1, .DG2]
Task {
do {
// mrzKey — is string in format <passport number><passport number checksum><date of birth><date of birth checksum><expiry date><expiry date checksum>
let passportModel = try await passportReader.readPassport(
mrzKey: mrzKey,
tags: dataGroups)
DispatchQueue.main.async {
// successfully read the chip and can now work with the data
debugPrint(passportModel.documentNumber)
}
} catch {
debugPrint(error.localizedDescription)
}
}
}