Skip to main content

Image Cropping | Android Document Scanner

The Scanbot SDK provides the ability to crop, rotate and perform perspective correction on the source images.

The Image cropping functionality is available both as an RTU UI and as a classic component (types of components are explained here).

Integration

Take a look at our Example Apps to see how to integrate Image Cropping.

Add Feature as a Dependency

Image Cropping is available with SDK Package 1. You have to add the following dependency for it:

implementation("io.scanbot:sdk-package-1:$latestSdkVersion")

Initialize the SDK

The Scanbot SDK must be initialized before use. Add the following code snippet to your Application class:

import io.scanbot.sdk.ScanbotSDKInitializer

class ExampleApplication : Application() {

override fun onCreate() {
super.onCreate()

// Initialize the Scanbot Scanner SDK:
ScanbotSDKInitializer().initialize(this)
}
}

Ready-To-Use UI Component

Ready-To-Use UI Component (activity) that is responsible for the Cropping functionality is CroppingActivity.

alt text

Have a look at our end-to-end working example of the RTU components usage here.

Starting and configuring RTU Cropping screen

First of all, you have to add the SDK package and feature dependencies as described here.

Initialize the SDK as described here. More information about the SDK license initialization can be found here.

To use any of the RTU UI components you need to include the corresponding dependency in your build.gradle file:

implementation("io.scanbot:sdk-package-ui:$scanbotSdkVersion")

Get the latest $scanbotSdkVersion from the Changelog.

To start the RTU Cropping screen you only have to start a new activity and be ready to process its result later.

info

Starting from version 1.90.0, the SDK RTU components contain predefined AndroidX Result API contracts. They handle part of the boilerplate for starting the RTU activity component and mapping the result once it finishes.

If your code is bundled with Android's deprecated startActivityForResult API - check the other approach we offer for this case.

val croppingActivityResult: ActivityResultLauncher<CroppingConfiguration>

...

croppingActivityResult =
activity.registerForActivityResultOk(CroppingActivity.ResultContract()) { result ->
val page: Page? = result.result
//TODO: add your logic here to handle the result Page object
}

...

myButton.setOnClickListener {
val croppingConfiguration = CroppingConfiguration()
croppingConfiguration.setPage(page)
croppingActivityResult.launch(croppingConfiguration)
}
info

We offer some syntactic sugar for handling the result from RTU components via AndroidX Result API:

  • every RTU component's activity contains a Result class which, in turn, along with the resultCode value exposes a Boolean resultOk property. This will be true if resultCode equals Activity.RESULT_OK;

  • when you only expect Activity.RESULT_OK result code - you can use the AppCompatActivity.registerForActivityResultOk extension method instead of registerForActivityResult - it will be triggered only when there is a non-nullable result entity present.

caution

Always use the corresponding activity's static newIntent method to create intent when starting the RTU UI activity using deprecated startActivityForResult approach. Creating android.content.Intent object using its constructor (passing the activity's class as a parameter) will lead to the RTU UI component malfunctioning.

An instance of CroppingConfiguration is required for starting the RTU UI activity. It allows configuration changes through methods it exposes:

val croppingConfiguration = CroppingConfiguration()

// mandatory configuration parameter! All other options are optional.
croppingConfiguration.setPage(page)
Important

croppingConfiguration.setPage(page: Page) is a mandatory config parameter. It defines which page will be presented in the CroppingActivity.

Full API references for these methods can be found on this page.

Handling the result

CroppingActivity returns a CroppingActivity.Result object which aggregates the processed (cropped and rotated) Page object. The Scanbot SDK provides a bunch of different page processors. For example, you can use PageProcessor to perform additional image modifications (see more) or use PageFileStorage to extract the Page content as Bitmap or JPG images (see more)

Accessibility customization

CroppingActivity provides an ability to customize the Text resources for the accessibility feature. Users can set a custom configuration CroppingAccessibilityConfiguration in CroppingConfiguration. Here is an example:

val croppingConfiguration = CroppingConfiguration()

croppingConfiguration.setPage(page)

croppingConfiguration.setAccessibilityConfiguration(CroppingAccessibilityConfiguration(
cancelButtonAccessibilityLabel = "Cancel button",
cancelButtonAccessibilityHint = "Go back to the previous screen",
doneButtonAccessibilityLabel = "Done button",
doneButtonAccessibilityHint = "Finish the flow",
detectButtonAccessibilityLabel = "Detect the polygon",
detectButtonAccessibilityHint = "Automatically detect the polygon",
resetButtonAccessibilityLabel = "Reset the polygon",
resetButtonAccessibilityHint = "Discard the current polygon",
rotateButtonAccessibilityLabel = "Rotate",
rotateButtonAccessibilityHint = "Rotate the image clockwise"
))

Classic component

The classic component of the cropping functionality is presented by 2 main views - EditPolygonImageView and MagnifierView. They provide the ability to precisely modify the adjustable cropping polygon on the screen.

To integrate the classic component of the Cropping feature you can take a look at our Cropping Example App or check the following step-by-step integration instructions.

Add feature dependencies and initialize the SDK

First of all, you have to add the SDK package and feature dependencies as described here.

Initialize the SDK as described here. More information about the SDK license initialization can be found here.

Add EditPolygonImageView to your layout


<io.scanbot.sdk.ui.EditPolygonImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:edgeColor="#00cea6"
app:cornerImageSrc="@drawable/ui_crop_corner_handle"
app:edgeImageSrc="@drawable/ui_crop_side_handle"
app:editPolygonHandleSize="48dp"
app:magneticLineTreshold="10dp"
app:editPolygonStrokeWidth="3dp"/>

The customizable attributes here are:

  • edgeColor - the color of the polygon line. Default is undefined - meaning no color.
  • cornerImageSrc - the image to be used as the polygon corner handle
  • edgeImageSrc - the image to be used as the edge handle
  • editPolygonHandleSize - defines the touchable area size for the polygon edge and corner handles. Default is 48dp.
  • editPolygonStrokeWidth - the width of the polygon line. Default is 3dp.
  • magneticLineTreshold - the edge should be this close to the magnetic line to snap in place. Default is 10dp.
  • edgeColorOnLine - the color of the edge when it aligns with the detected magnetic line. Default is undefined - meaning no color change.

Set the detected polygon

The default polygon for EditPolygonImageView can be received from ContourDetector. ContourDetector always contains the latest detected contours information like lines and polygons. After the first detection you can set the latest detected contour to EditPolygonImageView.

val detector = ScanbotSDK(context).createContourDetector()
detector.detect(image)
editPolygonView.polygon = detector.polygonF

EditPolygonImageView supports the magnetic lines feature. For this you have to set the detected horizontal and vertical lines:

editPolygonView.setLines(detector.horizontalLines, detector.verticalLines)

Add magnifying glass

EditPolygonImageView supports a magnifying glass feature. To enable it, you should add io.scanbot.sdk.ui.MagnifierView to your custom layout.

<io.scanbot.sdk.ui.MagnifierView
android:id="@+id/magnifier"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:magnifierImageSrc="@drawable/ui_crop_magnifier"
app:magnifierRadius="36dp"
app:magnifierMargin="16dp"
app:magnifierEnableBounding="true"/>

The customizable attributes here are:

  • magnifierImageSrc - the magnifier image. To be used as a mask - make sure it has a transparent section to see the magnified content. No default value.
  • magnifierRadius - the magnifier's size. Default is 36dp.
  • magnifierMargin - the magnifier's margin (distance to the screen border). Default is 16dp.
  • magnifierEnableBounding - bounce the magnifier to the opposite part of screen when editing the polygon's corner. Default is true.
Important

You should set up the MagnifierView every time editPolygonView is set with a new image:

magnifierView.setupMagnifier(editPolygonView)

Get the selected polygon

If you want to get a selected polygon from EditPolygonImageView just call:

val currentPolygon = editPolygonView.polygon

Want to scan longer than one minute?

Generate your free "no-strings-attached" Trial License and properly test the Scanbot SDK.

Get your free Trial License

What do you think of this documentation?