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:
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") }
}
}
Edit the dependencies part of your app/build.gradle
, so that it contains the following:
implementation 'com.klippa:scanner:4.0.5'
implementation("com.klippa:scanner:4.0.5")
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.5'
}
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.5")
}
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());
}
}
The SDK has a few customizing settings, each customization can be added to the
KlippaScanner(Builder)
class using the functions below:
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>
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>
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);
}
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);
}
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);
}
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);
}
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);
}
It's possible to use the results of the scanner with the OCR API.
For instructions, please visit the documentation
page.
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:
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.
The JavaDoc of the latest version is available for download here.
The following versions are available:
Version | Gradle dependency | JavaDoc |
---|---|---|
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 |
imageLimit
to 1
would crash the SDK.MediaPicker
and setting imageLimit
to 0
we try to use getPickImagesMaxLimit()
(Api 33+), if this is unavailable it will set it to 5.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.imageLimit
in KlippaImageAttributes
was not being respected.ScannerSessionResult
was not included in the bundle.NOTE: This version introduces breaking changes, please see our documentation for the new implementation.
minSdkVersion
21 -> 25.imageColorMode
from KlippaColors
to KlippaImageAttributes
.cropPadding
in KlippaImageAttributes
now uses com.klippa.scanner.model.KlippaSize
instead of android.util.Size
.klippa_scanner_sdk_color_Primary
to klippa_scanner_sdk_color_primary
.klippa_scanner_sdk_color_Accent
to klippa_scanner_sdk_color_accent
.klippa_scanner_sdk_color_Overlay
to klippa_scanner_sdk_color_secondary
.klippa_scanner_sdk_color_Warning
to klippa_scanner_sdk_color_warning_background
.klippa_scanner_sdk_color_WarningTextColor
to klippa_scanner_sdk_color_warning_text
.klippa_scanner_sdk_color_IconDisabledColor
to klippa_scanner_sdk_color_icon_disabled
.klippa_scanner_sdk_color_IconEnabledColor
to klippa_scanner_sdk_color_icon_enabled
.klippa_scanner_sdk_color_ReviewIconColor
to klippa_scanner_sdk_color_button_with_icon_foreground
and klippa_scanner_sdk_color_button_with_icon_background
.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.klippa_images
.klippa_auto_capture
.klippa_manual_capture
.klippa_action_filter
.KlippaScannerBuilder
please use ScannerSession
instead.KlippaScannerListener
please use StartScannerSession
instead.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.klippa_scanner_sdk_color_PrimaryDark
.klippa_action_color
.lateinit attrs
could throw RuntimeException
for not being initialized.tflite
model.ModePicker
did not hide correctly.name
and instructions
are now mutable directly inside of their corresponding KlippaDocumentMode
.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.KlippaSingleDocumentMode
, KlippaMultipleDocumentMode
, KlippaSegmentedDocumentMode
.groupId
to KlippaImage
; KlippaSingleDocumentMode
adds the same groupId
for each photo, KlippaMultipleDocumentMode
and KlippaSegmentedDocumentMode
add a unique groupId
for each photo.name
.Instructions
.klippaCameraModes
to KlippaScannerBuilder
, which can be used to setup different KlippaCameraModes
.build(context: Context)
now returns Result<Intent, Exception>
instead of only Intent
..kt
files were not being de-compiled correctly.deleteButtonText
or klippa_delete_button_text
did not update the UI.NOTE: This version introduces breaking changes, please see our documentation for new implementation.
KlippaScannerBuilder
.KlippaScannerListener
.DEFAULT_COLOR
to KlippaScanner.DefaultColor.ENHANCED
. This setting adds additional enhancements to the taken image.previewDuration
.orientationWarningMessage
.deleteButtonText
, retakeButtonText
, cancelButtonText
, cancelAndDeleteImagesButtonText
and cancelConfirmationMessage
.FloatingActionButton
size was not being set correctly.AlertDialog
theme was not set correctly.shouldGoToReviewScreenWhenImageLimitReached
(default false).userCanRotateImage
, userCanCropManually
, userCanChangeColorSetting
accordingly (each default true).klippa_delete_button_text
, klippa_retake_button_text
, klippa_cancel_button_text
in your strings.xml.klippa_cancel_delete_images
, klippa_cancel_confirmation
in your strings.xml.1000
to 3000
.imageMovingMessage
only shows when we have detected an object.STORE_IMAGES_TO_GALLERY
.ALLOW_TIMER
TIMER_ENABLED
OUTPUT_DIRECTORY
would not be set correctly.DEFAULT_COLOR
.ALLOW_SHUTTER_BUTTON
and HIDE_SHUTTER_BUTTON
IMAGE_MOVING_SENSITIVITY
KlippaScanner.Setup.*
, setting up with Intent still works like before. Please see this for more information.KlippaScanner.PREVIEW_DURATION
.ICON_ENABLED_COLOR, ICON_DISABLED_COLOR, REVIEW_ICON
KlippaScanner.IMAGE_MOVING_MESSAGE
org.tensorflow:tensorflow-lite
version 2.4.0
instead of 0.0.0-nightly
org.tensorflow:tensorflow-lite-metadata
version 0.1.0
instead of 0.0.0-nightly
SUCCESS_PREVIEW_DURATION
and TIMER_DURATION
KlippaScanner.MODEL_NAME
and KlippaScanner.MODEL_LABELS_NAME
KlippaScanner.TIMER_ENABLED
and KlippaScanner.TIMER_DURATION
KlippaScanner.SUCCESS_MESSAGE
and KlippaScanner.SUCCESS_PREVIEW_DURATION
KlippaScanner.CROP_PADDING_WIDTH
and KlippaScanner.CROP_PADDING_HEIGHT
minSdkVersion
is now 14
.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%
.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
.KlippaScanner.PRIMARY_DARK_COLOR
to set the colorPrimaryDark (the color in the status bar)KlippaScanner.PRIMARY_DARK_COLOR
is used for the status bar, KlippaScanner.PRIMARY_COLOR
for the app bar and KlippaScanner.ACCENT_COLOR
for the controls.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.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.