SDK

Adding the Scanner SDK to your project

To add our SDK to your own application, you should add it to the build process of your application. Currently we support doing this using CocoaPods or Carthage.

To add the repository to your project, open the Podfile, if it does not exists, first run pod init in the root of your project with Xcode closed.
Edit the target part of your application in the Podfile, so that it contains the following, making sure it includes your credentials:

                    
pod 'Klippa-Scanner', podspec: 'https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/latest.podspec'
                    
                

The full Podfile might look like this now:

                    
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'TestScanner' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for TestScanner
  pod 'Klippa-Scanner', podspec: 'https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/latest.podspec'

end
                    
                

When you run pod install now, it should download our library as dependency, and with that all dependencies of our library.
Note: this code always uses the latest version, you can also use a specific version to make sure the SDK won't update without your knowledge.

To add the repository to your project, open the Cartfile, if it does not exists, create a Cartfile alongside your .xcodeproj or .xcworkspace.
Add the following to your Cartfile, making sure it includes your credentials:

                    
binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json"
                    
                

When you run carthage update now, it should download our library as dependency, and with that all dependencies of our library.
Note: this code always uses the latest version, you can also use a specific version to make sure the SDK won't update without your knowledge.

Starting the Klippa Scanner

As of KlippaScanner SDK Version 1.0.0 the implementation has changed. If you are using an 0.5.4 or earlier use the button below to switch to the original documentation.

To start the scanner, import our package:

                    
// Add to the top of your file
import KlippaScanner
                    
                

In the controller that you want to launch the scanner, implement the KlippaScannerDelegate.

                    
// Add to the top of your file
import KlippaScanner

// Your class definition should look like this.
final class ExampleScannerViewController: UIViewController, KlippaScannerDelegate {

    // ... Rest of your controller code.

    // Call this from a button
    func startKlippaScanner() {
        let license = "{your-license}"

        let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        builder.startScanner(parent: self)

        //        Or
        //        let viewController = builder.build()
        //        present(viewController, animated: true)
    }

    func klippaScannerDidFailWithError(error: Error) {
        switch error {
        case let licenseError as KlippaScannerLicenseError:
            print("Got licensing error from SDK: \(licenseError.localizedDescription)")
        default:
            print(error)
        }
    }

    func klippaScannerDidFinishScanningWithResult(result: KlippaScannerResult) {
        // Handle scan results here.
        print("didFinishScanningWithResult")
        print("Scanned \(result.images.count) images")
    }

    func klippaScannerDidCancel() {
        print("Scanner canceled")
    }

    // ... Rest of your controller code.
}
                    
                

In the place where you want to start the scanner, for example after a button click, call the startKlippaScanner method:

                    
startKlippaScanner()
                    
                
                    
// Add to the top of your file
import KlippaScanner
                    
                

Then init the scanner options inside your launch method, the license is the only required option:

                    
KlippaScanner.setup.license = "replace-with-received-license"
                    
                

In the controller that you want to launch the scanner, implement the ImageScannerControllerDelegate:

                    
// Add to the top of your file
import KlippaScanner

// Your class definition should look like this.
final class ExampleScannerViewController: UIViewController, ImageScannerControllerDelegate {

    // ... Rest of your controller code.

    func startScanner() {
        let scannerViewController = ImageScannerController()
        scannerViewController.imageScannerDelegate = self
        scannerViewController.modalPresentationStyle = .fullScreen
        present(scannerViewController, animated: false)
    }

    func imageScannerController(_ scanner: ImageScannerController, didFailWithError error: Error) {
        switch error {
        case let licenseError as LicenseError:
            print("Got licensing error from SDK: \(licenseError.localizedDescription)")
        default:
            print(error)
        }
    }

    func imageScannerController(_ scanner: ImageScannerController, didFinishScanningWithResult result: ImageScannerResult) {
        // Handle scan results here.
        print("didFinishScanningWithResult");
        print("multipleDocumentsModeEnabled \(result.multipleDocumentsModeEnabled)")
        print("Scanned \(result.images.count) images")
    }

    func imageScannerControllerDidCancel(_ scanner: ImageScannerController) {
        scanner.dismiss(animated: true, completion: nil)
    }

    // ... Rest of your controller code.
}
                    
                

In the place where you want to start the scanner, for example after a button click, call the startScanner method:

                    
startScanner()
                    
                

Customizing the scanner

The SDK has a few customizing settings, the following methods are available:

Customizing the colors

Note: when setting the colors the values should be a UIColor.

                    
let colors = KlippaColors(
    // The primary color of the interface. This is used for the app bar.
    primaryColor: .green,
    // The accent color of the interface. This is used for control elements.
    accentColor: .orange,
    // The overlay color (when using document detection).
    overlayColor: .gray,
    // The color of the background of the warning message.
    warningBackgroundColor: .red,
    // The color of the text of the warning message.
    warningTextColor: .white,
    // The overlay color (when using document detection).
    overlayColorAlpha: 0.75,
    // The color of the menu icons when they are enabled.
    iconEnabledColor: .white,
    // The color of the menu icons when they are disabled.
    iconDisabledColor: .gray,
    // The color of the menu icons of the screen where you can review/edit the images.
    reviewIconColor: .white,
    // What the default color conversion will be (grayscale, original, enhanced).
    defaultImageColor: .original)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaColors(colors)
    builder.startScanner(parent: self)
}
                    
                
    
// The primary color of the interface, should be a UIColor.
KlippaScanner.setup.primaryColor = UIColor(red: 0.153, green: 0.733, blue: 0.373, alpha: 1.00)

// The accent color of the interface, should be a UIColor.
KlippaScanner.setup.accentColor = UIColor(red: 0.153, green: 0.733, blue: 0.373, alpha: 1.00)

// The overlay color (when using document detection), should be a UIColor.
KlippaScanner.setup.overlayColor = UIColor(red: 0.17, green: 0.77, blue: 0.41, alpha: 1.00)

// The amount of opacity for the overlay, should be a float.
KlippaScanner.setup.overlayColorAlpha = 0.75

// The color of the background of the warning message, should be a UIColor.
KlippaScanner.setup.warningBackgroundColor = .red

// The color of the text of the warning message, should be a UIColor.
KlippaScanner.setup.warningTextColor = .white

// The color of the menu icons when they are enabled, should be a UIColor.
KlippaScanner.setup.iconEnabledColor = .white

// The color of the menu icons when they are disabled, should be a UIColor.
KlippaScanner.setup.iconDisabledColor = .gray

// The color of the menu icons of the screen where you can review/edit the images, should be a UIColor.
KlippaScanner.setup.reviewIconColor = .white
    

Customizing the messages

    
let messages = KlippaMessages(
    // The warning message when someone should move closer to a document.
    moveCloserMessage: "Move closer to the document",
    // The warning message when the camera result is too bright.
    imageTooBrightMessage: "The image is too bright",
    // The warning message when the camera result is too dark.
    imageTooDarkMessage: "The image is too dark",
    // The warning message when the camera preview has too much motion to be able to automatically take a photo.
    imageMovingMessage: "Camera is moving too much",
    // The message to display when the limit has been reached.
    imageLimitReachedMessage: "You have reached the limit",
    // The warning message when device is held in landscape mode.
    orientationWarningMessage: "Hold your phone in portrait mode",
    // After capture, show a checkmark preview with this success message, instead of a preview of the image.
    successMessage: "success",
    // The confirmation message shown when the cancel button is pressed on the review screen.
    cancelConfirmationMessage: "Delete photos and exit scanner?")

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaMessages(messages)
    builder.startScanner(parent: self)
}
    
    
// The warning message when someone should move closer to a document, should be a string.
KlippaScanner.setup.moveCloserMessage = "Move closer to the document"

// The warning message when the camera preview has too much motion to be able to automatically take a photo.
KlippaScanner.setup.imageMovingMessage = "Too much movement"

// The warning message when the camera result is too bright.
KlippaScanner.setup.imageTooBrightMessage = "The image is too bright"

// The warning message when the camera result is too dark.
KlippaScanner.setup.imageTooDarkMessage = "The image is too dark"

// Users receive an orientation warning when device is not held in portrait mode, text can be set with:
KlippaScanner.setup.orientationWarningMessage = "Hold your phone in portrait mode"

// Ability to limit amount of pictures that can be taken and set a message once the limit has been reached.
KlippaScanner.setup.set(imageLimitReachedMessage: "Limit reached", imageLimit: 1)

// After capture, show a checkmark preview with this success message, instead of a preview of the image.
KlippaScanner.setup.set(successMessage: "Success!", successPreviewDuration: 0.3)
    

Customizing text in buttons

                    
let buttonTexts = KlippaButtonTexts(
    // The text inside of the delete button.
    deleteButtonText: "Delete",
    // The text inside of the retake button.
    retakeButtonText: "Retake",
    // The text inside of the cancel button.
    cancelButtonText: "Cancel",
    // The text inside of the cancel confirmation alert, confirming to cancel the scanner without a result.
    cancelAndDeleteImagesButtonText: "Delete photos and exit",
    // Tapping on the image color-changing button prompts an alert to confirm your action.
    // Texts can be set with:
    imageColorOriginalText: "Original",
    imageColorGrayscaleText: "Grayscale",
    imageColorEnhancedText: "Enhanced")

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaButtonTexts(buttonTexts)
    builder.startScanner(parent: self)
}
                    
                
    
// Deleting an image prompts an alert to confirm your action. Texts can be set with:
KlippaScanner.setup.set(deleteButtonText: "Delete", retakeButtonText: "Retake", cancelButtonText: "Cancel")

// Ability to cancel the scanner completely on the review screen by pressing cancel, texts can be set with:
KlippaScanner.setup.set(cancelConfirmationMessage: "Delete photos and exit scanner?", cancelAndDeleteImagesButtonText:
"Delete photos & exit")

// Tapping on the image color-changing button prompts an alert to confirm your action. Texts can be set with:
KlippaScanner.setup.set(imageColorOriginalText: "Original", imageColorGrayscaleText: "Grayscale",
imageColorEnhancedText: "Enhanced")
    

Customizing the menu icons

                    
let menu = KlippaMenu(
    // Whether the crop mode (auto edge detection) should be enabled by default.
    isCropEnabled: false,
    // Whether to show the icon to enable "multi-document-mode"
    allowMultipleDocumentsMode: false,
    // Whether the "multi-document-mode" should be enabled by default.
    isMultipleDocumentsModeEnabled: true,
    // If you would like to enable automatic capturing of images.
    isTimerEnabled: false,
    // Whether to show the icon to enable timer
    allowTimer: true,
    // Whether to show the rotate icon in the review screen.
    userCanRotateImage: true,
    // Whether to show the crop icon in the review screen.
    userCanCropManually: true,
    // Whether to show the color adjusting icon in the review screen.
    userCanChangeColorSetting: true,
    // Whether to automatically go to the review screen once the image limit has been reached.
    shouldGoToReviewScreenWhenImageLimitReached: false,
    // Whether the camera has a view finder overlay (a helper grid so the user knows where the document should be), should be a Boolean.
    isViewFinderEnabled: false)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaMenu(menu)
    builder.startScanner(parent: self)
}
                    
                
    
// Whether to show the icon to enable "multi-document-mode"
KlippaScanner.setup.set(allowMultipleDocumentsMode: true)

// Whether the "multi-document-mode" should be enabled by default.
KlippaScanner.setup.set(isMultipleDocumentsModeEnabled: true)

// Whether the crop mode (auto edge detection) should be enabled by default.
KlippaScanner.setup.set(cropEnabled: true)

// Whether going to the review screen automatically once the image limit has been reached. Default false.
KlippaScanner.setup.shouldGoToReviewScreenWhenImageLimitReached = true

// Whether the camera has a view finder overlay (a helper grid so the user knows where the document should be), should
be a Boolean.
KlippaScanner.setup.isViewFinderEnabled = true

// Whether the camera automatically saves the images to the camera roll. Default true. (iOS version 0.4.2 and up only)
KlippaScanner.setup.storeImagesToCameraRoll = true

// Ability to hide timer button.
KlippaScanner.setup.allowTimer = false

// If you would like to enable automatic capturing of images.
KlippaScanner.setup.isTimerEnabled = true


// Ability to hide top navigation bar buttons.
KlippaScanner.setup.set(userCanRotateImage: true, userCanCropManually: true, userCanChangeColorSetting: true)

    

Customizing the image attributes

    
let imageAttributes = KlippaImageAttributes(

    imageLimit: 2,
    // Define the max resolution of the output file.
    // It’s possible to set only one of these values.
    // We will make sure the picture fits in the given resolution.
    // We will also keep the aspect ratio of the image. Default is max resolution of camera.
    imageMaxWidth: 3000,
    imageMaxHeight: 3000,
    // Set the output quality (between 0-100) of the jpg encoder. Default is 100.
    imageMaxQuality: 95,
    // The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 200).
    imageMovingSensitivity: 200,
    // To add extra horizontal and / or vertical padding to the cropped image.
    cropPadding: CGSize(width: 100, height: 100),
    // Whether the camera automatically saves the images to the camera roll. Default true.
    storeImagesToCameraRoll: false)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaImageAttributes(imageAttributes)
    builder.startScanner(parent: self)
}
    
    
// Define the max resolution of the output file. It’s possible to set only one of these values. We will make sure the
picture fits in the given resolution. We will also keep the aspect ratio of the image. Default is max resolution of
camera.
KlippaScanner.setup.imageMaxWidth = 1920
KlippaScanner.setup.imageMaxHeight = 1080

// Set the output quality (between 0-100) of the jpg encoder. Default is 100.
KlippaScanner.setup.imageMaxQuality = 95

// To add extra horizontal and / or vertical padding to the cropped image.
KlippaScanner.setup.set(cropPadding: CGSize(width: 100, height: 100))

// The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 200).
KlippaScanner.setup.imageMovingSensitivity = 200
    

Customizing the shutter button

    
let shutterButton = KlippaShutterButton(
    // Whether to allow the shutter button. (If false the shutter button is greyed out)
    allowShutterButton: true,
    // Whether to hide the shutter button. (Only works if allowShutterButton is false)
    hideShutterButton: false)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaShutterbutton(shutterButton)
    builder.startScanner(parent: self)
}
    
    
// Ability to disable/hide the shutter button (only works when a model is supplied as well).
KlippaScanner.setup.set(allowShutterButton: true, hideShutterButton: false)
    

Customizing the timers

    
let durations = KlippaDurations(
    // The amount of seconds the preview should be visible for, should be a float.
    previewDuration: 2.0,
    // The duration of the timer. (Only works if timer is enabled)
    timerDuration: 1.0,
    // Whether to show a success checkmark and how long.
    successPreviewDuration: 0.5)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaDurations(durations)
    builder.startScanner(parent: self)
}
    
    
// The amount of seconds the preview should be visible for, should be a float.
KlippaScanner.setup.previewDuration = 1.0

//The amount of seconds the timer requires before automatically taking photo.
KlippaScanner.setup.timerDuration = 0.5
    

Customizing the camera modes

The SDK supports three camera modes: KlippaSingleDocumentMode, KlippaMultipleDocumentMode and KlippaSegmentedDocumentMode:

KlippaSingleDocumentMode is used for scanning a single-page document.

KlippaMultipleDocumentMode is used for scanning a document that consists of multiple pages.

KlippaSegmentedDocumentMode is used for scanning a single-page document with multiple photo captures. The photos are stitched together to create a single long document. Suitable for scanning long receipts.

Each comes with its own set of instructions which can be customized and if nil is supplied then no instructions are shown.
The SDK starts with KlippaSingleDocumentMode as default. Not all modes are required, the SDK allows to leave out the undesired camera modes as long as there is a minimum of 1 camera mode.

    
let cameraModes = KlippaCameraModes(
    modes: [
        // The document mode for scanning a single-page document.
        KlippaSingleDocumentMode(
            name: "Single Document",
            instructions: Instructions(
                message: "Single Document Instructions",
                dismissHandler: {
                    print("Single document mode instructions dismissed.")
                })
        ),
        // The document mode for scanning a document which consists of multiple pages.
        KlippaMultipleDocumentMode(
            name: "Multiple Document",
            instructions: Instructions(
                message: "Multiple Document Instructions",
                dismissHandler: {
                    print("Multiple document mode instructions dismissed.")
                })
        ),
        // The document mode for scanning a single-page document with multiple photo captures. Suitable for scanning long receipts.
        KlippaSegmentedDocumentMode(
            name: "Segmented Document",
            instructions: Instructions(
                message: "Segmented Document Instructions",
                dismissHandler: {
                    print("Segmented document mode instructions dismissed.")
                })
        )
    ],
    // The index to set which camera mode will be shown as default.
    startingIndex: 0
)

// Call this from a button
func startKlippaScanner() {
    let license = "{your-license}"
    let builder = KlippaScannerBuilder(builderDelegate: self, license: license)
        .klippaCameraModes(cameraModes)
    builder.startScanner(parent: self)
}
    

Calling the OCR API

It's possible to use the results of the scanner with the OCR API.

For instructions, please visit the documentation page.

SDK size

The dependency download size itself is 15.2MB when extracted, but it contains builds for multiple architectures, it depends on the architecture of the phone how much the SDK is going to add to the app size:

  • arm64: 4.5MB
  • x86_64-simulator: 10.7MB

Requesting Authorization for Media Capture and Image Saving

Include the NSCameraUsageDescription key in your app's Info.plist file.

Name
 Privacy - Camera Usage Description

                
<key>NSCameraUsageDescription</key>
<string>In order to scan documents, we need access to your camera.</string>
                
            

Saving scans to the user's photo library, include the NSPhotoLibraryAddUsageDescription key in your app's Info.plist file.

Name
 Privacy - Photo Library Additions Usage Description

                
<key>NSPhotoLibraryAddUsageDescription</key>
<string>In order to save scans we need access to your photos.</string>
                
            

Troubleshooting

Sandbox Issue

In case you encounter issues related to the Sandbox, you can disable the ENABLE_USER_SCRIPT_SANDBOXING by following these steps:

  1. In Xcode select your App project
  2. With your app as the target, go to Build Settings.
  3. In the Build Options group, change User Script Sandboxing to NO.

Versions

The following versions are available:

Version Podspec include URL Cartfile dependency Binary download
1.2.1 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/1.2.1.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 1.2.1 Fat framework (.xcarchive) | XCFramework
1.2.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/1.2.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 1.2.0 Fat framework (.xcarchive) | XCFramework
1.1.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/1.1.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 1.1.0 Fat framework (.xcarchive) | XCFramework
1.0.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/1.0.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 1.0.0 Fat framework (.xcarchive) | XCFramework
0.5.4 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.5.4.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.5.4 Fat framework (.xcarchive) | XCFramework
0.5.3 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.5.3.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.5.3 Fat framework (.xcarchive) | XCFramework
0.5.2 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.5.2.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.5.2 Fat framework (.xcarchive) | XCFramework
0.5.1 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.5.1.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.5.1 Fat framework (.xcarchive) | XCFramework
0.5.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.5.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.5.0 Fat framework (.xcarchive) | XCFramework
0.4.12 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.12.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.12 Fat framework (.xcarchive) | XCFramework
0.4.11 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.11.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.11 Fat framework (.xcarchive) | XCFramework
0.4.10 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.10.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.10 Fat framework (.xcarchive) | XCFramework
0.4.9 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.9.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.9 Fat framework (.xcarchive) | XCFramework
0.4.8 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.8.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.8 Fat framework (.xcarchive) | XCFramework
0.4.7 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.7.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.7 Fat framework (.xcarchive) | XCFramework
0.4.6 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.6.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.6 Fat framework (.xcarchive) | XCFramework
0.4.5 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.5.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.5 Fat framework (.xcarchive) | XCFramework
0.4.4 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.4.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.4 Fat framework (.xcarchive) | XCFramework
0.4.3 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.3.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.3 Fat framework (.xcarchive) | XCFramework
0.4.2 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.4.2.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.4.2 Fat framework (.xcarchive) | XCFramework
0.3.4 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.3.4.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.3.4 Fat framework (.xcarchive) | XCFramework
0.3.3 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.3.3.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.3.3 Fat framework (.xcarchive) | XCFramework
0.3.2 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.3.2.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.3.2 Fat framework (.xcarchive) | XCFramework
0.3.1 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.3.1.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.3.1 Fat framework (.xcarchive) | XCFramework
0.3.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.3.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.3.0 Fat framework (.xcarchive) | XCFramework
0.2.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.2.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.2.0 Fat framework (.xcarchive) | XCFramework
0.1.4 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.1.4.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.1.4 Fat framework (.xcarchive) | XCFramework
0.1.3 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.1.3.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.1.3 Fat framework (.xcarchive) | XCFramework
0.1.2 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.1.2.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.1.2 Fat framework (.xcarchive) | XCFramework
0.1.1 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.1.1.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.1.1 Fat framework (.xcarchive) | XCFramework
0.1.0 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.1.0.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.1.0 Fat framework (.xcarchive) | XCFramework
0.0.14 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.14.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.14 Fat framework (.xcarchive) | XCFramework
0.0.13 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.13.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.13 Fat framework (.xcarchive) | XCFramework
0.0.12 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.12.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.12 Fat framework (.xcarchive) | XCFramework
0.0.11 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.11.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.11 Fat framework (.xcarchive) | XCFramework
0.0.10 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.10.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.10 Fat framework (.xcarchive) | XCFramework
0.0.8 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.8.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.8 Fat framework (.xcarchive) | XCFramework
0.0.7 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.7.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.7 Fat framework (.xcarchive) | XCFramework
0.0.6 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.6.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.6 Fat framework (.xcarchive) | XCFramework
0.0.5 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.5.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.5 Fat framework (.xcarchive) | XCFramework
0.0.4 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.4.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.4 Fat framework (.xcarchive) | XCFramework
0.0.2 https://custom-ocr.klippa.com/sdk/ios/specrepo/ExampleUsername/ExamplePassword/KlippaScanner/0.0.2.podspec binary "https://custom-ocr.klippa.com/sdk/ios/carthage/ExampleUsername/ExamplePassword/KlippaScanner.json" == 0.0.2 Fat framework (.xcarchive) | XCFramework

Changelog

1.2.1

Added

  • klippaScanner View which can be used to call the KlippaScanner SDK from SwiftUI.
  • Privacy manifest.

Fixed

  • Issue where ghost image on segmented documents could hide ui elements on devices with a notch.
  • Issue where some bounding boxes were not saved correctly after rotating an image.
  • Issue where users might get stuck if taking a photo fails.

1.2.0

Added

  • KlippaCameraModes which is used to setup what camera modes the user can pick from, optionally supply it with an startingIndex to preselect a camera mode.
  • Supported camera modes: KlippaSingleDocumentMode, KlippaMultipleDocumentMode, KlippaSegmentedDocumentMode.
  • groupId to KlippaImage; KlippaSingleDocumentMode adds the same groupId for each photo, KlippaMultipleDocumentMode and KlippaSegmentedDocumentMode add a unique groupId for each photo.
  • The ability to change/localize the name of each camera mode by setting it’s name.
  • The ability to show instructions for each camera mode by supplying it with Instructions.
  • klippaCameraModes to KlippaScannerBuilder, which can be used to setup different KlippaCameraModes.
  • Animations and other UX improvements.

Changed

  • startScanner(context: UIViewController) has become deprecated; please use startScanner(parent: UIViewController) instead.
  • build() now returns Result<UIViewController, KlippaError> instead of only UIViewController.
  • rawStrings in KlippaImage has become deprecated; please use detectedText instead.

Fixed

  • Limitations to editing bounding box, it should now be harder to create non rectangular shapes.

1.1.0

Fixed

  • Issue where saving an image with insufficient storage could cause a black screen, now gracefully end scanner with KlippaScannerControllerError.capture.

Changed

  • Removed redundant noAllowedPackageNames error message.

1.0.0

NOTE: This version introduces breaking changes, please see our documentation for new implementation.

Changed

  • Scanner setup requires KlippaScannerBuilder.
  • Scanner results are only sent through KlippaScannerDelegate.

0.5.4

Fixed

  • Issue where scanner could start from incorrect thread.

Changed

  • Deployment target from 10.0 to 11.0.
  • Deployment target in Podspec from 10.0 to 11.0.

0.5.3

Added

  • Ability to convert image to grayscale.
  • Ability to start scanner with a default image color which can be set with imageColorMode. Possible options are: .original, .grayscale, .enhanced.
  • Tapping on the image color-changing button now prompts an alert to confirm your action. Texts can be set with: imageColorOriginalText, imageColorGrayscaleText, imageColorEnhancedText.

Fixed

  • Issue where cropped image could have the incorrect color state.

Changed

  • Removed doesUserPreferEnhancedScan you can use imageColorMode instead.

0.5.2

Added

  • Ability to detect device orientation. Users receive an orientation warning when device is not held in portrait mode, text can be set with: orientationWarningMessage.

0.5.1

Fixed

  • Issue where zoomed image on edit screen had incorrect orientation.

0.5.0

Added

  • Ability to automatically go to the review screen once the image limit has been reached by setting shouldGoToReviewScreenWhenImageLimitReached (default false).
  • Ability to hide top navigation bar buttons by setting: userCanRotateImage, userCanCropManually, userCanChangeColorSetting accordingly (each default true).
  • Deleting an image now prompts an alert to confirm your action. Texts can be set with: deleteButtonText, retakeButtonText, cancelButtonText.
  • Ability to cancel the scanner completely on the review screen by pressing cancel, texts can be set with: cancelAndDeleteImagesButtonText, cancelConfirmationMessage.
  • Users can now complete scan process from the review screen by pressing “>” button.

Fixed

  • Issue where scanner could stop working unexpectedly due to memory running out.

0.4.12

Fixed

  • Issue where users could take more pictures than the specified image limit.

Added

  • Support for longer receipts.

Changed

  • Default max image resolutions from 1000 to 3000.
  • Now imageMovingMessage only shows when we have detected an object.

0.4.11

Fixed

  • Issue where device could run out of memory with high resolution images.

0.4.10

Added

  • Ability to limit amount of pictures that can be taken with imageLimit and set a message once limit has been reached with imageLimitReachedMessage.

Fixed

  • Done button will now automatically use correct localization.

0.4.9

Added

  • Ability to hide timer button by setting KlippaScanner.setup.set(allowTimer: false)

0.4.8

Added

  • arm64 build for simulator to add support for M1 Macs. Please note that this only work in XCFrameworks (CocoaPods), and not in the fat framework, since you can only have one arm64 binary, and the device binaries already come with an arm64 binary.

0.4.7

Fixed

  • When scanning with a model the scanner no longer requires you to supply the Bundle.

0.4.6

Added

  • Ability to disable/hide the shutter button. KlippaScanner.setup.set(allowShutterButton: false, hideShutterButton: false)
  • Ability to adjust the sensitivity of the motion detection, lower values give higher sensitivity. KlippaScanner.setup.set(imageMovingSensitivity: 200)

0.4.5

Fixed

  • Issue where padding was being set incorrectly with document scanning.

Changed

  • Default colors are now default Klippa colors.

0.4.4

Fixed

  • Issue when setting up with Carthage.

0.4.3

Added

  • Functionality when timer is enabled scanner will not automatically take photos if too much movement is detected.
  • Optionally add user indication when movement is detected. KlippaScanner.setup.set(imageMovingMessage: "Too much movement")

0.4.2

Fixed

  • Issue where scanner failed to reinitialize.
  • Issue where storing enhanced images sometimes caused memory to run out.

Added

  • Ability to disable saving to camera roll with following method KlippaScanner.setup.set(storeImagesToCameraRoll: false).

0.4.1

Fixed

  • Issue where images did not load in React Native.
  • Issue where path was not returned correctly from scanner in React Native.

Added

  • Helper method retrieve(path: "pathToImage", from directory: .documents, as type: UIImage.self) to retrieve image from provided path.

0.4.0

Fixed

  • Important: Scanner now only returns a path to image in documents instead of also a UIImage (see next bullet point for reasoning).
  • Taken images are now no longer stored in device memory but in temporary storage.
  • Fixed multiple memory leaks.

0.3.4

Fixed

  • Issue related to implementing the SDK directly in a Swift project.

0.3.3

Fixed

  • Added default extension for model and labelmap file.

0.3.2

Fixed

  • Added default value for crop padding: CGSize(0, 0)

0.3.1

Fixed

  • Fixed the overlay color not being correctly restored.

0.3.0

Changed

  • Added the ability to recognize custom objects (instead of documents) using a trained TensorFlow Lite model. Klippa can train these custom models for whatever you like to capture using the KlippaScanner SDK.
  • Model can be supplied by using the setup method KlippaScanner.setup.set(modelName: "model", modelLabelsName: "labels", modelBundleLocation: ViewController.self)
  • A timer has been added, to automatically capture recognized objects after a certain time has elapsed: KlippaScanner.setup.set(isTimerEnabled: true) and KlippaScanner.setup.set(timerDuration: 0.5)
  • A success message with checkmark icon can be shown instead of a preview of the captured image using KlippaScanner.setup.set(successMessage: "Success!", successPreviewDuration: 0.3)
  • When capturing using a model, padding can be added to the cropped area using KlippaScanner.setup.set(cropPadding: CGSize(width: 200, height: 200)) (this example adds 100px cropping to the left, right, top and bottom of the image).

0.2.0

Changed

  • Build using XCode 12/Swift 5.3

0.1.3

Changed

  • The ImageScannerResult object returned in didFinishScanningWithResult now also contains the cropEnabled variable, indicating the status of the crop button.

0.1.1

Changed

  • A back button has been added in the bottom left corner. It’s visible as long as no photo’s have been taken yet. Pressing the back button dismisses the view controller and calls imageScannerControllerDidCancel on the delegate.

0.1.0

Changed

  • The build system has now been changes to the modern build system, and we now build the library with the option BUILD_LIBRARY_FOR_DISTRIBUTION. We also use XCFrameworks now to package the framework. The Carthage package still links to the traditional fat framework because Carthage does not support XCFramework yet, but the framework is now based on the files from the XCFramework package.

0.0.13

Changed

  • The isMultipleDocumentsModeEnabled option has been added to make a distinction between the multiple documents mode being available at all, and the user toggling the button. allowMultipleDocumentsMode now displays / hides the button whilst isMultipleDocumentsModeEnabled toggles the initial state when the button is visible.

0.0.12

Fixed

  • Fix image preview when cropping pictures that have been taken in landscape.

0.0.11

Changed

  • The primaryColor is now used for the toolbar.
  • The accentColor is used for controls.
  • The overlayColor is used for both the area that will be cropped and the cropping controls.
  • The isAutoScanEnabled and isAutoScanEnabled options have been removed.
  • Reduced the duration of capture animations.
  • The colors for the crop, multiple documents mode and flash toggles have been changed to partially white (disabled state) and fully white (enabled state).

Fixed

  • Pressing the crop-button no longer takes a photo.
  • Fixed inconsistent behavior of isCropEnabled option.
  • Changes to the cropped area were not saved when returning to the camera.
  • The orientation of landscape photos changed to black-white was incorrect.
  • The initial state for allowMultipleDocumentsMode was being ignored.
  • Rotating the photo now also rotates the original picture and not just the cropped area. The cropped area will also be properly rotated.

0.0.10

Added

  • Added default constructor for ImageScannerController.

Changed

  • ImageScannerControllerDelegate now finishes scanning with one object (ImageScannerResult), containing the captured images and the multipleDocumentsModeEnabled property.
  • Added classname to the @objc decorator, to enable Nativescript to discover the correct classes on run time.

0.0.9

Added

  • Added default constructor for ImageScannerController.

Fixed

  • Corrected some typo’s (imageTooDarkMessage, imageTooBrightMessage).

0.0.8

Fixed

  • Combine Swift headers for all archs.

0.0.7

Changed

  • Lower deployment target in Podspec from 11.0 to 10.0.

0.0.6

Changed

  • Lower deployment target from 11.0 to 10.0.

Fixed

  • Minor bugfixes

0.0.5

Fixed

  • Properties of KlippaImage were missing public acccess.

0.0.4

Added

  • Added multiple documents mode (allowMultipleDocumentsMode in KlippaScanner).
  • Added max width, height and quality constraints (imageMaxWidth, imageMaxHeight and imageMaxQuality in KlippaScanner).
  • Added ability to customize the warning text color (warningTextColor in KlippaScanner).

Changed

  • Renamed project from KippaScanner to KlippaScanner.
  • KlippaImage results now also returns the output path (path property in KlippaImage).
  • Lower deployment target from 11.2 to 11.0.

Fixed

  • Clicking the hidden thumbnails button without pictures crashed the camera.
  • Auto scan triggering directly after enabling.

0.0.3

Changed

  • Export more members to Object C for use in projects like NativeScript and React Native.

0.0.2

Changed

  • Updated podspec file to match deployment target.

0.0.1

Fixed

  • Fix UILabel padding extension.