SDK

Adding the 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 only support doing this using Gradle.
Adding the SDK to your gradle build file consist of two steps:

Adding the repository

To add the repository to your project, open the settings.gradle file in your application.
Edit the repositories part of your settings.gradle, so that it contains the following:

                        
maven {
    credentials {
        username 'ExampleUsername'
        password 'ExamplePassword'
    }
    url "https://custom-ocr.klippa.com/sdk/android/maven"
}
maven { url "https://jitpack.io" }
                        
                    
                        
maven {
    credentials {
        username = "ExampleUsername"
        password = "ExamplePassword"
    }
    setUrl("https://custom-ocr.klippa.com/sdk/android/maven")
}
maven { setUrl("https://jitpack.io") }
                        
                    

We add jitpack.io because some of our dependencies are hosted there. If your settings.gradle already contains jitpack.io, don't add it.
The full repositories section of your settings.gradle might look like this now:

                        
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        maven {
            credentials {
                username 'ExampleUsername'
                password 'ExamplePassword'
            }
            url "https://custom-ocr.klippa.com/sdk/android/maven"
        }
        maven { url "https://jitpack.io" }
    }
}
                        
                    
                        
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven {
            credentials {
                username = "ExampleUsername"
                password = "ExamplePassword"
            }
            setUrl("https://custom-ocr.klippa.com/sdk/android/maven")
        }
        maven { setUrl("https://jitpack.io") }
    }
}
                        
                    

Adding the dependency

Edit the dependencies part of your app/build.gradle, so that it contains the following:

                        
implementation 'com.klippa:scanner:4.0.6'
                        
                    
                        
implementation("com.klippa:scanner:4.0.6")
                        
                    

The full dependencies section of your build.gradle might look like this now:

                        
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    implementation 'com.klippa:scanner:4.0.6'
}
                        
                    
                        
dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.2.1")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
    implementation("com.klippa:scanner:4.0.6")
}
                        
                    

Starting the Klippa Scanner

As of KlippaScanner SDK Version 4.0.0 the implementation has changed. If you are using an 3.1.11 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 com.klippa.scanner.ScannerSession
import com.klippa.scanner.ScannerSessionResult
import com.klippa.scanner.StartScannerSession
                                    
                                
                                    
// Add to the top of your file
import com.klippa.scanner.ScannerSession;
import com.klippa.scanner.ScannerSessionResult;
import com.klippa.scanner.StartScannerSession;
                                    
                                

Then start our Scanner Activity from your own Activity, be sure that you implemented registerForActivityResult(StartScannerSession()).

                                    
class MainActivity : AppCompatActivity() {

    private val startScannerSession = registerForActivityResult(StartScannerSession()) { sessionCode ->
        when (sessionCode) {
            is ScannerSessionResult.FinishedWithError -> klippaScannerDidFailWithError(error = sessionCode.error)
            is ScannerSessionResult.FinishedWithResult -> klippaScannerDidFinishScanningWithResult(result = sessionCode.result)
            ScannerSessionResult.UserCanceled, ScannerSessionResult.Unknown -> klippaScannerDidCancel()
        }
    }

    // Call this method from a button press
    private fun startKlippaScanner() {
        // Launch the Klippa Scanner
        val license = "{your-license}"
        val scannerSession = ScannerSession(license = license)
        startScannerSession.launch(scannerSession)
    }

    private fun klippaScannerDidFinishScanningWithResult(result: KlippaScannerResult) {
        Log.w("KlippaScanner", "Finished with image count" + result.images.size)
    }

    private fun klippaScannerDidCancel() {
        Log.w("KlippaScanner", "canceled")
    }

    private fun klippaScannerDidFailWithError(error: KlippaError) {
        Log.e("KlippaScanner", "Failed with error: ${error.message}")
    }
}
                                    
                                
                
public class MainActivity extends AppCompatActivity {

    private final ActivityResultLauncher startScannerSession = registerForActivityResult(
        new StartScannerSession(),
        sessionCode -> {
            if (sessionCode instanceof ScannerSessionResult.FinishedWithError) {
                klippaScannerDidFailWithException(((ScannerSessionResult.FinishedWithError) sessionCode).getError());
            } else if (sessionCode instanceof ScannerSessionResult.FinishedWithResult) {
                klippaScannerDidFinishScanningWithResult(((ScannerSessionResult.FinishedWithResult) sessionCode).getResult());
            } else if (sessionCode instanceof ScannerSessionResult.Unknown) {
                Log.i("ExampleActivity", "FAILED UNKNOWN");
            } else if (sessionCode instanceof ScannerSessionResult.UserCanceled) {
                klippaScannerDidCancel();
            }
        });

    // Call this method from a button press
    private void startKlippaScanner() {
        // Launch the Klippa Scanner
        String license = "{your-license}";
        ScannerSession scannerSession = new ScannerSession(license);
        startScannerSession.launch(scannerSession);
    }

    private void klippaScannerDidFinishScanningWithResult(@NonNull KlippaScannerResult result) {
        Log.w("KlippaScanner", "Finished with image count" + result.getImages().size());
    }

    private void klippaScannerDidCancel() {
        Log.w("KlippaScanner", "canceled");
    }
    
    private void klippaScannerDidFailWithError(@NonNull KlippaError error) {
        Log.e("KlippaScanner", "Failed with error: " + error.getMessage());
    }
}
                
            
                                    
// Add to the top of your file
import com.klippa.scanner.KlippaScannerBuilder
import com.klippa.scanner.KlippaScannerListener
import com.klippa.scanner.model.KlippaScannerResult
                                    
                                
                                    
// Add to the top of your file
import com.klippa.scanner.KlippaScannerBuilder;
import com.klippa.scanner.KlippaScannerListener;
import com.klippa.scanner.model.KlippaScannerResult;
                                    
                                

Then start our scanner Activity from your own Activity, be sure that you implemented KlippaScannerListener.

                                    
class MainActivity : AppCompatActivity(), KlippaScannerListener {
    // Call this method from a button press
    private fun startKlippaScanner() {
        // Launch the Klippa Scanner
        val license = "{your-license}"
        KlippaScannerBuilder(this, license)
            .startScanner(this)
    }

    override fun klippaScannerDidFinishScanningWithResult(result: KlippaScannerResult) {
        Log.w("KlippaScanner", "Finished with image count" + result.images.size)
    }

    override fun klippaScannerDidCancel() {
        Log.w("KlippaScanner", "canceled")
    }

    override fun klippaScannerDidFailWithException(exception: Exception) {
        Log.e("KlippaScanner", "Failed with error: " + exception.message)
    }
}
                                    
                                
                
public class MainActivity extends AppCompatActivity implements KlippaScannerListener {
    // Call this method from a button press
    private void startKlippaScanner() {
        // Launch the Klippa Scanner
        String license = "{your-license}";
        new KlippaScannerBuilder(this, license)
                .startScanner(this);
    }

    @Override
    public void klippaScannerDidFinishScanningWithResult(@NonNull KlippaScannerResult klippaScannerResult) {
        Log.w("KlippaScanner", "Finished with image count" + klippaScannerResult.getImages().size());
    }

    @Override
    public void klippaScannerDidCancel() {
        Log.w("KlippaScanner", "canceled");
    }

    @Override
    public void klippaScannerDidFailWithException(@NonNull Exception e) {
        Log.e("KlippaScanner", "Failed with error: " + e.getMessage());
    }
}
                
            

Customizing the Scanner

The SDK has a few customizing settings, each customization can be added to the KlippaScanner(Builder) class using the functions below:

Customizing the colors

Add or edit the file app/src/main/res/values/colors.xml.

                            
<xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="klippa_scanner_sdk_color_primary">#000000</color>
    <color name="klippa_scanner_sdk_color_accent">#ffffff</color>
    <color name="klippa_scanner_sdk_color_secondary">#2dc36a</color>
    <color name="klippa_scanner_sdk_color_warning_background">#BF000000</color>
    <color name="klippa_scanner_sdk_color_warning_text">#ffffff</color>
    <color name="klippa_scanner_sdk_color_icon_disabled">#444</color>
    <color name="klippa_scanner_sdk_color_icon_enabled">#ffffff</color>
    <color name="klippa_scanner_sdk_color_button_with_icon_foreground">#ffffff</color>
    <color name="klippa_scanner_sdk_color_button_with_icon_background">#444444</color>
</resources>
                                                
                            

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

                                    
private val klippaColors = KlippaColors(
    // What the default color conversion will be (grayscale, original, enhanced).
    imageColorMode = KlippaImageColor.ORIGINAL,
    // The primary color of the interface. This is used for the app bar.
    primaryColor = android.R.color.holo_blue_bright,
    // The primary dark color of the interface. This is used for the status bar.
    primaryColorDark = android.R.color.holo_orange_dark,
    // The accent color of the interface. This is used for control elements.
    accentColor = android.R.color.holo_red_dark,
    // The overlay color (when using document detection).
    overlayColor = android.R.color.holo_blue_bright,
    // The color of the background of the warning message.
    warningColor = android.R.color.holo_red_light,
    // The color of the menu icons when they are enabled.
    iconDisabledColor = android.R.color.holo_red_dark,
    // The color of the menu icons when they are disabled.
    iconEnabledColor = android.R.color.darker_gray,
    // The color of the menu icons of the screen where you can review/edit the images.
    reviewIconColor = android.R.color.holo_red_dark)

// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScannerBuilder(this, license)
        .colors(klippaColors)
        .startScanner(this)
}
                                    
                                
        
KlippaColors klippaColors = new KlippaColors(
    // What the default color conversion will be (grayscale, original, enhanced).
    KlippaImageColor.ORIGINAL, // imageColorMode
    // The primary color of the interface. This is used for the app bar.
    android.R.color.holo_blue_bright, // primaryColor
    // The primary dark color of the interface. This is used for the status bar.
    android.R.color.holo_orange_dark, //primaryColorDark
    // The accent color of the interface. This is used for control elements.
    android.R.color.holo_red_dark, // accentColor
    // The overlay color (when using document detection).
    android.R.color.holo_blue_bright, // overlayColor
    // The color of the background of the warning message.
    android.R.color.holo_red_light, // warningColor
    // The color of the menu icons when they are enabled.
    android.R.color.holo_red_dark, // iconEnabledColor
    // The color of the menu icons when they are disabled.
    android.R.color.darker_gray, // iconDisabledColor
    // The color of the menu icons of the screen where you can review/edit the images.
    android.R.color.holo_red_dark // reviewIconColor
    );

// Call this from a button
private void startKlippaScanner() {
// Launch the Klippa Scanner
String license = "{your-license}";
new KlippaScannerBuilder(this, license)
        .colors(klippaColors)
        .startScanner(this);
}
        

                                

Instead of customizing colors through the setup you can also supply them through values. Add or edit the file app/src/main/res/values/colors.xml.

                            
<xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="klippa_scanner_sdk_color_Primary">#2dc36a</color>
    <color name="klippa_scanner_sdk_color_PrimaryDark">#308D53</color>
    <color name="klippa_scanner_sdk_color_Accent">#2dc36a</color>
    <color name="klippa_scanner_sdk_color_Overlay">#2dc36a</color>
    <color name="klippa_scanner_sdk_color_Warning">#BFFF0000</color>
    <color name="klippa_scanner_sdk_color_IconDisabledColor">#80FFFFFF</color>
    <color name="klippa_scanner_sdk_color_IconEnabledColor">#FFFFFFFF</color>
    <color name="klippa_scanner_sdk_color_ReviewIconColor">#FFFFFFFF</color>
</resources>
                                                
                            

Customizing the texts

Add or edit the file app/src/main/res/values/strings.xml

            
<resources>
    <string name="klippa_action_crop">Crop</string>
    <string name="klippa_action_delete">Delete</string>
    <string name="klippa_image_color_original">Original</string>
    <string name="klippa_image_color_grayscale">Grayscale</string>
    <string name="klippa_image_color_enhanced">Enhanced</string>
    <string name="klippa_zoom_message">Move closer to the document</string>
    <string name="klippa_image_limit_reached">You have reached the image limit</string>
    <string name="klippa_images">Images</string>
    <string name="klippa_success_message">Success</string>
    <string name="klippa_image_moving_message">Moving too much</string>
    <string name="klippa_orientation_warning_message">Hold your phone in portrait mode</string>
    <string name="klippa_delete_button_text">Delete</string>
    <string name="klippa_retake_button_text">Retake</string>
    <string name="klippa_cancel_button_text">Cancel</string>
    <string name="klippa_cancel_delete_images">Cancel Scanner</string>
    <string name="klippa_cancel_confirmation">When you close the taken scans will be deleted. Are you sure you want to cancel without saving?</string>
    <string name="klippa_continue_button_text">Continue</string>
    <string name="klippa_auto_capture">Auto-Capture</string>
    <string name="klippa_manual_capture">Manual</string>
    <string name="klippa_action_save">Save</string>
    <string name="klippa_action_expand">Expand</string>
    <string name="klippa_action_filter">Filter</string>
    <string name="klippa_action_rotate">Rotate</string>
</resources>
            
        

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

// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .messages(messages)
        .startScanner(this)
}
                
            
            
KlippaMessages messages = new KlippaMessages(
    // The warning message when someone should move closer to a document.
    "Move closer to the document", // moveCloserMessage
    // The message to display when the limit has been reached.
    "You have reached the limit", // imageLimitReached
    // After capture, show a checkmark preview with this success message, instead of a preview of the image.
    "Success", // successMessage
    // The warning message when the camera preview has to much motion to be able to automatically take a photo.
    "Camera is moving too much", // imageMovingMessage
    // The confirmation message shown when the cancel button is pressed on the review screen.
    "Delete photos and exit scanner?", // cancelConfirmationMessage
    // The warning message when device is held in landscape mode.
    "Hold your phone in portrait mode" // orientationWarningMessage
);

// Call this from a button
private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .messages(messages)
        .startScanner(this);
}
            
        

Instead of customizing messages through the setup you can also supply them through values. Add or edit the file app/src/main/res/values/strings.xml

            
<resources>
    <string name="klippa_zoom_message">Move closer to the document</string>
    <string name="klippa_image_limit_reached">You have reached the image limit</string>
    <string name="klippa_success_message">Success</string>
    <string name="klippa_image_moving_message">Moving too much</string>
    <string name="klippa_orientation_warning_message">Hold your phone in portrait mode</string>
    <string name="klippa_cancel_confirmation">Delete photos and exit scanner?</string>
</resources>
            
        

Customizing the menu icons

                                    
private val klippaMenu = KlippaMenu(
    // Whether the crop mode (auto edge detection) should be enabled by default.
    isCropEnabled = true,
    // Whether to show the icon to enable the timer.
    allowTimer = true,
    // Whether the timer (auto take photo) should be enabled by default.
    isTimerEnabled = false,
    // Whether to show the rotate icon in the review screen.
    userCanRotateImage = false,
    // Whether to show the crop icon in the review screen.
    userCanCropManually = false,
    // Whether to show the color adjusting icon in the review screen.
    userCanChangeColorSetting = false,
    // Whether to automatically go to the review screen once the image limit has been reached.
    shouldGoToReviewScreenWhenImageLimitReached = false,
    // Whether to allow users to select media from their device (Shows a media button bottom left on the scanner screen).
    userCanPickMediaFromStorage = true,
    // Whether the next button in the bottom right of the scanner screen goes to the review screen instead of finishing the session.
    shouldGoToReviewScreenOnFinishPressed = true
)

// Call this from a button
private fun startKlippaScanner() {
    val license = "{your-license}"

    val scannerSession = ScannerSession(
        license = license
    ).apply {
        menu = klippaMenu
    }

    startScannerSession.launch(scannerSession)
}
                                    
                                
                                    
KlippaMenu menu = new KlippaMenu(
    // Whether the crop mode (auto edge detection) should be enabled by default.
    true, // isCropEnabled
    // Whether to show the icon to enable the timer.
    true, // allowTimer
    // Whether the timer (auto take photo) should be enabled by default.
    false, // isTimerEnabled
    // Whether to show the rotate icon in the review screen.
    false, // userCanRotateImage
    // Whether to show the crop icon in the review screen.
    false, // userCanCropManually
    // Whether to show the color adjusting icon in the review screen.
    false, // userCanChangeColorSetting
    // Whether to automatically go to the review screen once the image limit has been reached.
    false, // shouldGoToReviewScreenWhenImageLimitReached
    // Whether to allow users to select media from their device (Shows a media button bottom left on the scanner screen).
    false, // userCanPickMediaFromStorage
    // Whether the next button in the bottom right of the scanner screen goes to the review screen instead of finishing the session.
    false // shouldGoToReviewScreenOnFinishPressed
);

private void startKlippaScanner() {
    String license = "{your-license}";

    ScannerSession scannerSession = new ScannerSession(license);
    scannerSession.setMenu(menu);
    startScannerSession.launch(scannerSession);
}
                                    
                                

                                    
private val menu = KlippaMenu(
    // Whether the crop mode (auto edge detection) should be enabled by default.
    isCropEnabled = true,
    // Whether to show the icon to enable "multi-document-mode"
    allowMultiDocumentsMode = true,
    // Whether the "multi-document-mode" should be enabled by default.
    isMultiDocumentsModeEnabled = true,
    // Whether to show the icon to enable the timer.
    allowTimer = true,
    // Whether the timer (auto take photo) should be enabled by default.
    isTimerEnabled = false,
    // Whether to show the rotate icon in the review screen.
    userCanRotateImage = false,
    // Whether to show the crop icon in the review screen.
    userCanCropManually = false,
    // Whether to show the color adjusting icon in the review screen.
    userCanChangeColorSetting = false,
    // Whether to automatically go to the review screen once the image limit has been reached.
    shouldGoToReviewScreenWhenImageLimitReached = false
)

// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .menu(menu)
        .startScanner(this)
}
                                    
                                
                                    
KlippaMenu menu = new KlippaMenu(
    // Whether the crop mode (auto edge detection) should be enabled by default.
    true, // isCropEnabled
    // Whether to show the icon to enable "multi-document-mode"
    true, // allowMultiDocumentsMode
    // Whether to show the icon to enable the timer.
    true, // allowTimer
    // Whether the timer (auto take photo) should be enabled by default.
    false, // isTimerEnabled
    // Whether to show the rotate icon in the review screen.
    false, // userCanRotateImage
    // Whether to show the crop icon in the review screen.
    false, // userCanCropManually
    // Whether to show the color adjusting icon in the review screen.
    false, // userCanChangeColorSetting
    // Whether to automatically go to the review screen once the image limit has been reached.
    false // shouldGoToReviewScreenWhenImageLimitReached
);

private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .menu(menu)
        .startScanner(this);
}
                                    
                                

Customizing the image attributes

                                    
private val klippaImageAttributes = KlippaImageAttributes(
    // Define the max resolution of the output file.
    // It’s possible to set only one (width or height max resolution).
    // 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.
    resolutionMaxWidth = 3000,
    resolutionMaxHeight = 3000,
    // Set the output quality (between 0-100) of the jpg encoder. Default is 100.
    outputQuality = 95,
    // Where to put the image results.
    outputDirectory = "/sdcard/scanner",
    // The filename to use for the output images, supports replacement tokens %dateTime% and %randomUUID%.
    outputFileName= "KlippaScannerExample-%dateTime%-%randomUUID%",
    // To limit the amount of images that can be taken.
    imageLimit = 5,
    // To add extra horizontal and / or vertical padding to the cropped image.
    cropPadding = KlippaSize(100, 100),
    // The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 50).
    imageMovingSensitivity = 50,
    // Whether to store the taken images to the phones gallery.
    storeImagesToGallery = true,
    // Whether to perform OCR (on device) on the images taken.
    performOnDeviceOCR = false,
    // The default color mode in which the photos are taken.
    imageColorMode = KlippaImageColor.ORIGINAL
)

// Call this from a button
private fun startKlippaScanner() {
    val license = "{your-license}"

    val scannerSession = ScannerSession(
        license = license
    ).apply {
        imageAttributes = klippaImageAttributes
    }

    startScannerSession.launch(scannerSession)
}
                                    
                                
                                    
KlippaImageAttributes klippaImageAttributes = new KlippaImageAttributes(
    // Define the max resolution of the output file.
    // It’s possible to set only one (width or height max resolution).
    // 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.
    3000, // resolutionMaxWidth
    3000, // resolutionMaxHeight
    // Set the output quality (between 0-100) of the jpg encoder. Default is 100.
    95, // outputQuality
    // Where to put the image results.
    "/sdcard/scanner", // outputDirectory
    // The filename to use for the output images, supports replacement tokens %dateTime% and %randomUUID%.
    "KlippaScannerExample-%dateTime%-%randomUUID%", // outputFileName
    // To limit the amount of images that can be taken.
    5, // imageLimit
    // To add extra horizontal and / or vertical padding to the cropped image.
    new KlippaSize(100, 100), // cropPadding
    // The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 50).
    50, // imageMovingSensitivity
    // Whether to store the taken images to the phones gallery.
    true, // storeImagesToGallery,
    // Whether to perform OCR (on device) on the images taken.
    false, // performOnDeviceOCR
    // The default color mode in which the photos are taken.
    KlippaImageColor.ORIGINAL // imageColorMode
);

// Call this from a button
private void startKlippaScanner() {
    String license = "{your-license}";

    ScannerSession scannerSession = new ScannerSession(license);
    scannerSession.setImageAttributes(klippaImageAttributes);
    startScannerSession.launch(scannerSession);
}
                                    
                                

                                    
private val imageAttributes = KlippaImageAttributes(
    // Define the max resolution of the output file.
    // It’s possible to set only one (width or height max resolution).
    // 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.
    resolutionMaxWidth = 3000,
    resolutionMaxHeight = 3000,
    // Set the output quality (between 0-100) of the jpg encoder. Default is 100.
    outputQuality = 95,
    // Where to put the image results.
    outputDirectory = "/sdcard/scanner",
    // The filename to use for the output images, supports replacement tokens %dateTime% and %randomUUID%.
    outputFileName= "KlippaScannerExample-%dateTime%-%randomUUID%",
    // To limit the amount of images that can be taken.
    imageLimit = 5,
    // To add extra horizontal and / or vertical padding to the cropped image.
    cropPadding = Size(100, 100),
    // The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 50).
    imageMovingSensitivity = 50,
    // Whether to store the taken images to the phones gallery.
    storeImagesToGallery = true
)

// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .imageAttributes(imageAttributes)
        .startScanner(this)
}
                                    
                                
                                    
KlippaImageAttributes imageAttributes = new KlippaImageAttributes(
    // Define the max resolution of the output file.
    // It’s possible to set only one (width or height max resolution).
    // 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.
    3000, // resolutionMaxWidth
    3000, // resolutionMaxHeight
    // Set the output quality (between 0-100) of the jpg encoder. Default is 100.
    95, // outputQuality
    // Where to put the image results.
    "/sdcard/scanner", // outputDirectory
    // The filename to use for the output images, supports replacement tokens %dateTime% and %randomUUID%.
    "KlippaScannerExample-%dateTime%-%randomUUID%", // outputFileName
    // To limit the amount of images that can be taken.
    5, // imageLimit
    // To add extra horizontal and / or vertical padding to the cropped image.
    new Size(100, 100), // cropPadding
    // The threshold sensitive the motion detection is. (lower value is higher sensitivity, default 50).
    50, // imageMovingSensitivity
    // Whether to store the taken images to the phones gallery.
    true // storeImagesToGallery
);

private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .imageAttributes(imageAttributes)
        .startScanner(this);
}
                                    
                                

Customizing the shutter button

                
private val klippaShutterButton = 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
private fun startKlippaScanner() {
    val license = "{your-license}"

    val scannerSession = ScannerSession(
        license = license
    ).apply {
        shutterButton = klippaShutterButton
    }

    startScannerSession.launch(scannerSession)
}
                
            
                                    
KlippaShutterButton klippaShutterButton = new KlippaShutterButton(
        // Whether to allow the shutter button. (If false the shutter button is greyed out)
        true, // allowShutterButton
        // Whether to hide the shutter button. (Only works if allowShutterButton is false)
        false // hideShutterButton
);

// Call this from a button
private void startKlippaScanner() {
    String license = "{your-license}";

    ScannerSession scannerSession = new ScannerSession(license);
    scannerSession.setShutterButton(klippaShutterButton);
    startScannerSession.launch(scannerSession);
}
                                    
                                

                
private val 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
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .shutterButton(shutterButton)
        .startScanner(this)
}
                
            
                                    
KlippaShutterButton shutterButton = new KlippaShutterButton(
    // Whether to allow the shutter button. (If false the shutter button is greyed out)
    true, // allowShutterButton
    // Whether to hide the shutter button. (Only works if allowShutterButton is false)
    false // hideShutterButton
);

private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .shutterButton(shutterButton)
        .startScanner(this);
}
                                    
                                

Customizing the timers

        
private val klippaDurations = KlippaDurations(
    // The duration of the timer. (Only works if timer is enabled)
    timerDuration = 0.5,
    // Whether to show a success checkmark and how long.
    successPreviewDuration = 0.0,
    // Whether to show a image preview and how long. (Only works if successPreviewDuration is 0.0)
    previewDuration = 1.0
)

// Call this from a button
private fun startKlippaScanner() {
    val license = "{your-license}"

    val scannerSession = ScannerSession(
        license = license
    ).apply {
        durations = klippaDurations
    }

    startScannerSession.launch(scannerSession)
}
                                    
                                
            
KlippaDurations klippaDurations = new KlippaDurations(
        // The duration of the timer. (Only works if timer is enabled)
        0.5, // timerDuration
        // Whether to show a success checkmark and how long.
        0.0, // successPreviewDuration
        // Whether to show a image preview and how long. (Only works if successPreviewDuration is 0.0)
        1.0 // previewDuration
);

// Call this from a button
private void startKlippaScanner() {
    String license = "{your-license}";

    ScannerSession scannerSession = new ScannerSession(license);
    scannerSession.setDurations(klippaDurations);
    startScannerSession.launch(scannerSession);
}
            
        

        
private val durations = KlippaDurations(
    // The duration of the timer. (Only works if timer is enabled)
    timerDuration = 0.5,
    // Whether to show a success checkmark and how long.
    successPreviewDuration = 0.0,
    // Whether to show a image preview and how long. (Only works if successPreviewDuration is 0.0)
    previewDuration = 1.0
)

// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .durations(durations)
        .startScanner(this)
}
                                    
                                
            
KlippaDurations durations = new KlippaDurations(
    // The duration of the timer. (Only works if timer is enabled)
    0.5, // timerDuration
    // Whether to show a success checkmark and how long.
    0.0, // successPreviewDuration
    // Whether to show a image preview and how long. (Only works if successPreviewDuration is 0.0)
    1.0 // previewDuration
);

private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .durations(durations)
        .startScanner(this);
}
            
        

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 null 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.

        
private val klippaCameraModes = KlippaCameraModes(
    listOf(
        // The document mode for scanning a single-page document.
        KlippaSingleDocumentMode(
            name = "Single",
            Instructions(
                title = "Single Document",
                message = "Single Document Instructions"
            )
        ),
        // The document mode for scanning a document which consists of multiple pages.
        KlippaMultipleDocumentMode(
            name = "Multiple",
            Instructions(
                title = "Multiple Document",
                message = "Multiple Document Instructions"
            )
        ),
        // The document mode for scanning a single-page document with multiple photo captures. Suitable for scanning long receipts.
        KlippaSegmentedDocumentMode(
            name = "Segmented",
            Instructions(
                title = "Segmented Document",
                message = "Segmented Document Instructions"
            )
        )
    ),
    // The index to set which camera mode will be shown as default.
    startingIndex = 0
)

// Call this from a button
private fun startKlippaScanner() {
    val license = "{your-license}"

    val scannerSession = ScannerSession(
        license = license
    ).apply {
        cameraModes = klippaCameraModes
    }

    startScannerSession.launch(scannerSession)
}
                                    
                                
            
KlippaCameraModes klippaCameraModes = new KlippaCameraModes(
        Arrays.asList(
                new KlippaSingleDocumentMode(
                        "Single", // name
                        new Instructions(
                                "Single Document", // title
                                "Single Document Instructions" // message
                        )
                ),
                new KlippaMultipleDocumentMode(
                        "Multiple", // name
                        new Instructions(
                                "Multiple Documents", // title
                                "Multiple Documents Instructions" // message
                        )
                ),
                new KlippaSegmentedDocumentMode(
                        "Segmented", // name
                        new Instructions(
                                "Segmented Document", // title
                                "Segmented Document Instructions" // message
                        )
                )
        ),
        0 // starting index
);

// Call this from a button
private void startKlippaScanner() {
    String license = "{your-license}";

    ScannerSession scannerSession = new ScannerSession(license);
    scannerSession.setCameraModes(klippaCameraModes);
    startScannerSession.launch(scannerSession);
}
            
        

To change the image in the instructions navigate to app/src/main/res/drawable/ and add one or more of the following 3 xml files.

  • klippa_camera_mode_single_document.xml
  • klippa_camera_mode_multiple_documents.xml
  • klippa_camera_mode_segmented_document.xml

        
private val cameraModes = KlippaCameraModes(
    listOf(
        // The document mode for scanning a single-page document.
        KlippaSingleDocumentMode(
            name = "Single Document",
            Instructions(
                message = "Single Document Instructions",
                dismissHandler = {
                    Toast.makeText(this, "Single document mode instructions dismissed.", Toast.LENGTH_LONG).show()
                })
        ),
        // The document mode for scanning a document which consists of multiple pages.
        KlippaMultipleDocumentMode(
            name = "Multiple Document",
            Instructions(
                message = "Multiple Document Instructions",
                dismissHandler = {
                    Toast.makeText(this, "Multiple document mode instructions dismissed.", Toast.LENGTH_LONG).show()
                })
        ),
        // The document mode for scanning a single-page document with multiple photo captures. Suitable for scanning long receipts.
        KlippaSegmentedDocumentMode(
            name = "Segmented Document",
            Instructions(
                message = "Segmented Document Instructions",
                dismissHandler = {
                    Toast.makeText(this, "Segmented document mode instructions dismissed.", Toast.LENGTH_LONG).show()
                })
        )
    ),
    // The index to set which camera mode will be shown as default.
    startingIndex = 0
)


// Call this from a button
private fun startKlippaScanner() {
    // Launch the Klippa Scanner
    val license = "{your-license}"
    KlippaScanner(this, license)
        .cameraModes(cameraModes)
        .startScanner(this)
}
                                    
                                
            
List<KlippaDocumentMode> modes = Arrays.asList(
        // The document mode for scanning a single-page document.
        new KlippaSingleDocumentMode(
                "Single Document",
                new Instructions(
                        "Single Document Instructions",
                        () -> {
                            Toast.makeText(this, "Single document mode instructions dismissed.", Toast.LENGTH_LONG).show();
                            return null;
                        })
        ),
        // The document mode for scanning a document which consists of multiple pages.
        new KlippaMultipleDocumentMode(
                "Multiple Document",
                new Instructions(
                        "Multiple Document Instructions",
                        () -> {
                            Toast.makeText(this, "Multiple document mode instructions dismissed.", Toast.LENGTH_LONG).show();
                            return null;
                        })
        ),
        // The document mode for scanning a single-page document with multiple photo captures. Suitable for scanning long receipts.
        new KlippaSegmentedDocumentMode(
                "Segmented Document",
                new Instructions(
                        "Segmented Document Instructions",
                        () -> {
                            Toast.makeText(this, "Segmented document mode instructions dismissed.", Toast.LENGTH_LONG).show();
                            return null;
                        })
        )
);
// The index to set which camera mode will be shown as default.
int startingIndex = 0;
KlippaCameraModes cameraModes = new KlippaCameraModes(modes, startingIndex);

private void startKlippaScanner() {
    // Launch the Klippa Scanner
    String license = "{your-license}";
    new KlippaScanner(this, license)
        .cameraModes(cameraModes)
        .startScanner(this);
}
            
        

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.

APK size / APK splitting

Because our SDK includes OpenCV, which includes native code which in turn generates a native library (.so file) for every architecture, the APK size can increase quite a bit by using our SDK.
To minimize the impact of the SDK on your app size, you can enable APK splitting in your build.grade, like this:

                
android {
    // Other options
    splits {
       abi {
           enable true
           universalApk false
           reset()
           include 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
       }
    }
    // Other options
}
                
            

In our example app (which contains not much more than the SDK), this resulted in the following APK files:

  • arm64-v8a.apk: 10.5MB
  • armeabi-v7a.apk: 8MB
  • x86_64.apk: 26.7MB
  • x86.apk: 19.6MB

While creating a single APK file creates a file that is 64.8MB, since most phones are ARM, on average APK splitting will result in a 40MB smaller APK, in those cases the SDK will add between 23-26MB to the APK size.

Please note that all APK files should be signed and uploaded to the Play Store to get a release that works on all devices.

JavaDoc

The JavaDoc of the latest version is available for download here.

Versions

The following versions are available:

Version Gradle dependency JavaDoc
4.0.6 implementation 'com.klippa:scanner:4.0.6' Download
4.0.5 implementation 'com.klippa:scanner:4.0.5' Download
4.0.4 implementation 'com.klippa:scanner:4.0.4' Download
4.0.3 implementation 'com.klippa:scanner:4.0.3' Download
3.1.12 implementation 'com.klippa:scanner:3.1.12' Download
4.0.2 implementation 'com.klippa:scanner:4.0.2' Download
4.0.1 implementation 'com.klippa:scanner:4.0.1' Download
4.0.0 implementation 'com.klippa:scanner:4.0.0' Download
3.1.11 implementation 'com.klippa:scanner:3.1.11' Download
3.1.10 implementation 'com.klippa:scanner:3.1.10' Download
3.1.9 implementation 'com.klippa:scanner:3.1.9' Download
3.1.8 implementation 'com.klippa:scanner:3.1.8' Download
3.1.7 implementation 'com.klippa:scanner:3.1.7' Download
3.1.6 implementation 'com.klippa:scanner:3.1.6' Download
3.1.5 implementation 'com.klippa:scanner:3.1.5' Download
3.1.4 implementation 'com.klippa:scanner:3.1.4' Download
3.1.3 implementation 'com.klippa:scanner:3.1.3' Download
3.1.2 implementation 'com.klippa:scanner:3.1.2' Download
3.1.1 implementation 'com.klippa:scanner:3.1.1' Download
3.1.0 implementation 'com.klippa:scanner:3.1.0' Download
3.0.3 implementation 'com.klippa:scanner:3.0.3' Download
3.0.2 implementation 'com.klippa:scanner:3.0.2' Download
3.0.1 implementation 'com.klippa:scanner:3.0.1' Download
3.0.0 implementation 'com.klippa:scanner:3.0.0' Download
2.1.11 implementation 'com.klippa:scanner:2.1.11' Download
2.1.10 implementation 'com.klippa:scanner:2.1.10' Download
2.1.9 implementation 'com.klippa:scanner:2.1.9' Download
2.1.8 implementation 'com.klippa:scanner:2.1.8' Download
2.1.7 implementation 'com.klippa:scanner:2.1.7' Download
2.1.6 implementation 'com.klippa:scanner:2.1.6' Download
2.1.5 implementation 'com.klippa:scanner:2.1.5' Download
2.1.4 implementation 'com.klippa:scanner:2.1.4' Download
2.1.3 implementation 'com.klippa:scanner:2.1.3' Download
2.1.2 implementation 'com.klippa:scanner:2.1.2' Download
2.1.1 implementation 'com.klippa:scanner:2.1.1' Download
2.1.0 implementation 'com.klippa:scanner:2.1.0' Download
2.0.8 implementation 'com.klippa:scanner:2.0.8' Download
2.0.7 implementation 'com.klippa:scanner:2.0.7' Download
2.0.6 implementation 'com.klippa:scanner:2.0.6' Download
2.0.5 implementation 'com.klippa:scanner:2.0.5' Download
2.0.4 implementation 'com.klippa:scanner:2.0.4' Download
2.0.3 implementation 'com.klippa:scanner:2.0.3' Download
2.0.2 implementation 'com.klippa:scanner:2.0.2' Download
2.0.1 implementation 'com.klippa:scanner:2.0.1' Download
2.0.0 implementation 'com.klippa:scanner:2.0.0' Download
1.3.7 implementation 'com.klippa:scanner:1.3.7' Download
1.3.6 implementation 'com.klippa:scanner:1.3.6' Download
1.3.5 implementation 'com.klippa:scanner:1.3.5' Download
1.3.5-rc implementation 'com.klippa:scanner:1.3.5-rc' Download
1.3.4 implementation 'com.klippa:scanner:1.3.4' Download
1.3.3 implementation 'com.klippa:scanner:1.3.3' Download
1.3.2 implementation 'com.klippa:scanner:1.3.2' Download
1.3.0 implementation 'com.klippa:scanner:1.3.0' Download
1.2.0 implementation 'com.klippa:scanner:1.2.0' Download
1.1.6 implementation 'com.klippa:scanner:1.1.6' Download
1.1.5 implementation 'com.klippa:scanner:1.1.5' Download
1.1.4 implementation 'com.klippa:scanner:1.1.4' Download
1.1.3 implementation 'com.klippa:scanner:1.1.3' Download
1.1.2 implementation 'com.klippa:scanner:1.1.2' Download
1.1.1 implementation 'com.klippa:scanner:1.1.1' Download
1.0.9 implementation 'com.klippa:scanner:1.0.9' Download

Changelog

4.0.6

Added

  • userShouldAcceptResultToContinue to KlippaMenu which when enabled forces users to confirm the photo they took before they can continue.

4.0.5

Fixed

  • Issue where setting imageLimit to 1 would crash the SDK.

Changed

  • When using the MediaPicker and setting imageLimit to 0 we try to use getPickImagesMaxLimit() (Api 33+), if this is unavailable it will set it to 5.

4.0.4

Fixed

  • Issue where SDK could fail to finish with result.

4.0.3

Added

  • userCanPickMediaFromStorage to KlippaMenu which allows users to pick images from storage instead of using the camera.
  • shouldGoToReviewScreenOnFinishPressed to KlippaMenu which allows users to go to the review screen when the finish button is pressed instead of finishing the scanner.

Fixed

  • Issue where imageLimit in KlippaImageAttributes was not being respected.
  • Issue where the SDK could crash on initialization on some devices.

4.0.2

Fixed

  • Issue where ScannerSessionResult was not included in the bundle.

4.0.1

Fixed

  • Issue where not all dependencies were automatically included.

4.0.0

Changed

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

  • Introduced a new UI.
  • Bumped minSdkVersion 21 -> 25.
  • Moved imageColorMode from KlippaColors to KlippaImageAttributes.
  • cropPadding in KlippaImageAttributes now uses com.klippa.scanner.model.KlippaSize instead of android.util.Size.
  • Renamed XML color klippa_scanner_sdk_color_Primary to klippa_scanner_sdk_color_primary.
  • Renamed XML color klippa_scanner_sdk_color_Accent to klippa_scanner_sdk_color_accent.
  • Renamed XML color klippa_scanner_sdk_color_Overlay to klippa_scanner_sdk_color_secondary.
  • Renamed XML color klippa_scanner_sdk_color_Warning to klippa_scanner_sdk_color_warning_background.
  • Renamed XML color klippa_scanner_sdk_color_WarningTextColor to klippa_scanner_sdk_color_warning_text.
  • Renamed XML color klippa_scanner_sdk_color_IconDisabledColor to klippa_scanner_sdk_color_icon_disabled.
  • Renamed XML color klippa_scanner_sdk_color_IconEnabledColor to klippa_scanner_sdk_color_icon_enabled.
  • Renamed XML color klippa_scanner_sdk_color_ReviewIconColor to klippa_scanner_sdk_color_button_with_icon_foreground and klippa_scanner_sdk_color_button_with_icon_background.

Added

  • ScannerSession to setup the session.
  • StartScannerSession to start the scanner session using registerForActivityResult.
  • dismissedInstructions to KlippaScannerResult to keep track of whether the instructions were dismissed.
  • XML text klippa_images.
  • XML text klippa_auto_capture.
  • XML text klippa_manual_capture.
  • XML text klippa_action_filter.

Removed

  • Removed KlippaScannerBuilder please use ScannerSession instead.
  • Removed KlippaScannerListener please use StartScannerSession instead.
  • Removed dismissHandler from Instructions, now dismissed will be set to true instead if the instructions were dismissed.
  • KlippaColors, KlippaButtonTexts and KlippaMessages were removed, now colors, texts and messages must be setup through XML.
  • XML color klippa_scanner_sdk_color_PrimaryDark.
  • XML text klippa_action_color.

Fixed

  • Issue where lateinit attrs could throw RuntimeException for not being initialized.

3.1.12

Changed

  • Bumped the Gradle versions to 8+.

3.1.11

Changed

  • Improved object detection with custom tflite model.

Fixed

  • Issue where scanner would crash when attempting to delete images that were already deleted.

3.1.10

Changed

  • OpenCV dependency to prevent conflicts.

3.1.9

Changed

  • Internal logging for better support.

3.1.8

Fixed

  • Issue where retaking a scan could could cause the scanner to quit unexpectedly.

3.1.7

Changed

  • Improved object detection.

3.1.6

Fixed

  • Issue with shutter button input lag.

3.1.5

Fixed

  • Issue where ModePicker did not hide correctly.

3.1.4

Fixed

  • Issue where navigation graph could cause conflicts.

3.1.3

Changed

  • Reverted kotlin & gradle version bumps as they were not backwards compatible, the next major version will include these changes again.

3.1.2

Fixed

  • Issue where the menu bar icons would not update correctly on API levels 34+.

Changed

  • Improved document detection.

3.1.1

Changed

  • name and instructions are now mutable directly inside of their corresponding KlippaDocumentMode.

3.1.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

  • build(context: Context) now returns Result<Intent, Exception> instead of only Intent.

3.0.3

Fixed

  • Issue where .kt files were not being de-compiled correctly.

3.0.2

Fixed

  • High memory usage during motion detection.
  • Issue where full storage exceptions were not being handled correctly.
  • Issue where scanner might fail to continue after being in the background.

Changed

  • The scanner now always finishes on the main thread.
  • Scanner now ends when there are insufficient permissions to launch.

3.0.1

Fixed

  • Issue where setting deleteButtonText or klippa_delete_button_text did not update the UI.

3.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 KlippaScannerListener.

2.1.11

Fixed

  • Issue where SDK could crash when processing a taken photo and SDK is moved to background.

2.1.10

Fixed

  • Issue where camera could fail to load on Android 13 (API Level 33).

2.1.9

Fixed

  • Issue where some UI components would fail to load.

2.1.8

Fixed

  • Issue where layout and drawable resources could cause conflicts.

2.1.7

Fixed

  • Issue where toolbar icons were not set correctly when editing an image.

Added

  • The ability to set DEFAULT_COLOR to KlippaScanner.DefaultColor.ENHANCED. This setting adds additional enhancements to the taken image.

2.1.6

Fixed

  • Issue where scanner would not restart after returning back from the review screen.

2.1.5

Fixed

  • Issue where thumbnail image was not showing correctly when using previewDuration.
  • Provide users with orientation warning when device is not held in portrait mode, text can be set with: orientationWarningMessage.

2.1.4

Fixed

  • Issue where the torch was flashing while image capturing, even if the environment is bright enough.
  • Issue with JavaDoc.

Added

  • Ability to set texts for deleteButtonText, retakeButtonText, cancelButtonText, cancelAndDeleteImagesButtonText and cancelConfirmationMessage.

Changed

  • Removed JCenter()

2.1.3

Fixed

  • Issue where SDK could stop responding when tapping the trash icon.

2.1.2

Fixed

  • Issue where FloatingActionButton size was not being set correctly.

2.1.1

Fixed

  • Issue where AlertDialog theme was not set correctly.

2.1.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: klippa_delete_button_text, klippa_retake_button_text, klippa_cancel_button_text in your strings.xml.
  • Ability to cancel the scanner completely on the review screen by pressing cancel, texts can be set with: klippa_cancel_delete_images, klippa_cancel_confirmation in your strings.xml.
  • Users can now complete scan process from the review screen by pressing “>” button.
  • Support for longer receipts.

Changed

  • Image quality is now higher.
  • Default max image resolutions from 1000 to 3000.

2.0.8

Fixed

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

Changed

  • Now imageMovingMessage only shows when we have detected an object.

2.0.7

Added

  • Ability to disable or enable if the taken photos should be stored to the gallery by setting STORE_IMAGES_TO_GALLERY.
  • Support for Android API Level 31.

2.0.6

Added

  • Ability to hide timer button by setting ALLOW_TIMER
  • Returns state of timer button in intent with TIMER_ENABLED

2.0.5

Fixed

  • Issue where OUTPUT_DIRECTORY would not be set correctly.
  • Issue with backwards compatibility with DEFAULT_COLOR.

Changed

  • Images are now aligned with iOS KlippaScanner SDK.

2.0.4

Fixed

  • Issue where license error was not providing correct error in some cases.

2.0.3

Added

  • Ability to disable/hide the shutter button. ALLOW_SHUTTER_BUTTON and HIDE_SHUTTER_BUTTON
  • Ability to adjust the sensitivity of the motion detection, lower values give higher sensitivity. IMAGE_MOVING_SENSITIVITY

2.0.2

Fixed

  • Issue where some properties could not be accessed unexpectedly.

2.0.1

Fixed

  • Issue where some colors would not load correctly
  • Issue where sometimes preview would not disappear.

2.0.0

Changed

  • Now completely rewritten in Kotlin.
  • Supports AndroidX
  • Default color scheme is now Klippa colors.

Added

  • Scanner can now be setup with KlippaScanner.Setup.*, setting up with Intent still works like before. Please see this for more information.
  • Short image preview after taking picture by setting a duration for the preview with: KlippaScanner.PREVIEW_DURATION.
  • Icon colors can now be set with: ICON_ENABLED_COLOR, ICON_DISABLED_COLOR, REVIEW_ICON

1.3.7

Fixed

  • Issue where autofocus was not being called when needed.

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.IMAGE_MOVING_MESSAGE

1.3.6

Fixed

  • Fixed a bug where sorting method could throw exception

1.3.5

Changed

  • Use org.tensorflow:tensorflow-lite version 2.4.0 instead of 0.0.0-nightly
  • Use org.tensorflow:tensorflow-lite-metadata version 0.1.0 instead of 0.0.0-nightly

Fixed

  • The SDK mistakenly included a drawable resources for the launcher icon

1.3.3 and 1.3.4

Fixed

  • Fixed a bug when parsing integers to doubles for SUCCESS_PREVIEW_DURATION and TIMER_DURATION

1.3.2

Changed

  • The minSdkVersion has been changed to 21.
  • 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 options KlippaScanner.MODEL_NAME and KlippaScanner.MODEL_LABELS_NAME
  • A timer has been added, to automatically capture recognized objects after a certain time has elapsed: KlippaScanner.TIMER_ENABLED and KlippaScanner.TIMER_DURATION
  • A success message with checkmark icon can be shown instead of a preview of the captured image using KlippaScanner.SUCCESS_MESSAGE and KlippaScanner.SUCCESS_PREVIEW_DURATION
  • When capturing using a model, padding can be added to the cropped area using KlippaScanner.CROP_PADDING_WIDTH and KlippaScanner.CROP_PADDING_HEIGHT

1.2.0

Changed

  • We upgraded our dependency on the Picasso library to version 2.71828.

1.1.6

Fixed

  • Changed minification to include our package name to prevent duplicate classes.

1.1.4

Fixed

  • Fix bug where you could press the next button when you didn’t create any image yet.

Changed

  • The minSdkVersion is now 14.

1.1.3

Fixed

  • Properly center the warning messages.

1.1.2

Added

  • Added option KlippaScanner.OUTPUT_FILENAME to set the output filename. By default it will be a random UUID string. There are 2 replacements available: %randomUUID% and %dateTime%, so you could do something like this: KlippaScanner-%randomUUID%-%dateTime%.
  • Added option KlippaScanner.IMAGE_LIMIT to set a maximum amount of files to be taken. After reaching the maximum the user will be shown a message that they reached the limit. The message is configured using KlippaScanner.IMAGE_LIMIT_REACHED_MESSAGE.

Changed

  • Shutter now directly shows after pressing the button.

1.1.1

Added

  • Added option KlippaScanner.PRIMARY_DARK_COLOR to set the colorPrimaryDark (the color in the status bar)

Changed

  • Color handling is now changed: KlippaScanner.PRIMARY_DARK_COLOR is used for the status bar, KlippaScanner.PRIMARY_COLOR for the app bar and KlippaScanner.ACCENT_COLOR for the controls.

Fixed

  • Give the camera control some more padding for when the status bar is hidden.

1.1.0

Added

  • Added options KlippaScanner.RESOLUTION_MAX_WIDTH and KlippaScanner.RESOLUTION_MAX_HEIGHT to set 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.
  • Added option KlippaScanner.OUTPUT_QUALITY to set the output quality (between 0-100) of the jpg encoder. You can see what the quality level does to the output quality/size here: https://sirv.sirv.com/Examples/example-coast.jpg?q=80 change the last value to see the quality change.

1.0.9

Changed

  • Upgrade dependency versions.

1.0.8

Fixed

  • Restore correct position in image list after deleting an image.

1.0.7

Added

  • Add next/previous arrows.

1.0.6

Fixed

  • Prevent crash when opening details when taking picture.
  • Fix when amount of images goes above 100.
  • Fix flashlight staying on when returning from SDK.