Skip to main content

Camera Theme Customization

The Paper Receipt camera scanning screen — its capture, retake, finish, confirm, cancel, and torch buttons, the scanning tooltips, the progress bar, and the receipt-edge guideline hints — is fully themeable through standard Android XML styles. You define a style that extends the SDK's BlinkRecognizerStyle, override only the brand colors and icons you care about, and hand that style to the camera through CameraCharacteristics.

Internally, the SDK reads your XML theme attributes and maps them onto a BlinkRecognizerStyle model that drives the Compose-based camera UI. That model is an SDK-internal type — you never construct it yourself. XML styling is the supported and only customization path.


Table of Contents

  1. How It Works
  2. Setup (Host App)
  3. The BlinkRecognizerStyle Model
  4. Theme Attribute Reference
  5. Full Example
  6. Tips and Pitfalls

1. How It Works

StageWhat happens
Your styleYou add a style to res/values/styles.xml that uses BlinkRecognizerStyle as its parent and overrides the attributes you want to brand.
CameraCharacteristicsYou pass the style's resource ID via CameraCharacteristics.Builder().style(...). If you omit it, the SDK uses its default style (R.style.BlinkRecognizerStyle).
SDK themingThe SDK applies your style to the camera screen and wraps the Compose context in it.
Attribute resolutionThe SDK resolves each theme attribute and builds the internal BlinkRecognizerStyle model that the camera UI renders from.

2. Setup (Host App)

Step 1 — Define your brand colors

In res/values/colors.xml, declare the colors you want the camera UI to use:

<resources>
<color name="brand_primary">#0B5FFF</color>
<color name="brand_primary_tapped">#0846BF</color>
<color name="brand_secondary">#EEF1F6</color>
<color name="brand_secondary_tapped">#C7CDD6</color>
</resources>

Step 2 — Extend BlinkRecognizerStyle

In res/values/styles.xml, create a style whose parent is the SDK's BlinkRecognizerStyle. Use dot-notation, which implies inheritance — BlinkRecognizerStyle.YourBrand automatically inherits everything from BlinkRecognizerStyle, so you only declare the attributes you want to change. Anything you leave out keeps the SDK default.

<style name="BlinkRecognizerStyle.YourBrand">
<!-- Material color roles cascade into the buttons, tooltip, and hints -->
<item name="colorPrimary">@color/brand_primary</item>
<item name="colorPrimaryVariant">@color/brand_primary_tapped</item>
<item name="colorSecondary">@color/brand_secondary</item>
<item name="colorSecondaryVariant">@color/brand_secondary_tapped</item>
<item name="colorOnPrimary">@android:color/white</item>

<!-- Camera-specific colors -->
<item name="guidelineHintViewBackground">?attr/colorPrimary</item>
<item name="progressBarColor">?attr/colorPrimary</item>
</style>
tip

Most apps only need to override the five Material color roles. The tooltip, progress bar, guideline hints, and all six buttons derive their colors from colorPrimary / colorSecondary / colorOnPrimary, so setting those alone re-skins the entire camera screen. Override the per-component styles (next section) only when you need finer control over individual icons or buttons.

Step 3 — Pass the style to the camera

When you launch the camera through CameraRecognizerContract, set your style on the CameraCharacteristics:

import com.microblink.camera.ui.CameraCharacteristics
import com.microblink.camera.ui.CameraRecognizerContract
import com.microblink.camera.ui.CameraRecognizerOptions
import com.microblink.camera.ui.CameraRecognizerResults

val launcher = rememberLauncherForActivityResult(
contract = CameraRecognizerContract(),
) { result ->
when (result) {
is CameraRecognizerResults.Success -> scanResults = result.results
is CameraRecognizerResults.Exception -> Log.e("Scan", "Error: ${result.exception}")
CameraRecognizerResults.Cancelled -> { /* User cancelled */ }
}
}

launcher.launch(
CameraRecognizerOptions.Builder()
.options(scanOptions)
.characteristics(
CameraCharacteristics.Builder()
// Style name "BlinkRecognizerStyle.YourBrand" is referenced
// in code with the dot replaced by an underscore.
.style(R.style.BlinkRecognizerStyle_YourBrand)
.build()
)
.build()
)
note

A style named BlinkRecognizerStyle.YourBrand in XML is referenced from Kotlin/Java as R.style.BlinkRecognizerStyle_YourBrand — the resource compiler replaces dots with underscores. If you don't call .style(...), the camera falls back to R.style.BlinkRecognizerStyle, the SDK default.


3. The BlinkRecognizerStyle Model

Each theme attribute you set in XML maps to one property of the internal BlinkRecognizerStyle model. You don't interact with this model directly, but understanding it explains what each attribute controls:

Model propertyControlsThemed by
guidelineHintColorBackground of the receipt-edge guideline hint shown over the camera.guidelineHintViewBackground
shutterSurfaceColorSurface that animates like a camera shutter on capture.shutterSurfaceColor
progressBarColorProgress bar shown while a scan is being processed.progressBarColor
tooltipStyleInformational tooltips (e.g. "Image seems blurry").blinkTooltipStyle
torchButtonStyleFlashlight / torch toggle button.torchButtonStyle
cancelButtonStyleCancel (exit) button.cancelButtonStyle
retakeButtonStyleRetake-capture button.retakeButtonStyle
finishButtonStyleFinish / done button.finishButtonStyle
captureButtonStyleMain camera capture (shutter) button.captureButtonStyle
confirmButtonStyleConfirm / "add another photo" button.confirmButtonStyle

4. Theme Attribute Reference

All attributes below are set as <item> entries inside your BlinkRecognizerStyle.YourBrand style (top-level colors) or inside the nested child styles it references (tooltip and buttons). Defaults are the values the SDK's base BlinkRecognizerStyle resolves to.

Top-level colors

Declared directly on your style:

AttributeFormatControlsDefault
colorPrimarycolorPrimary brand color. Drives the tooltip, progress bar, guideline hint, and the "primary" circle of the capture / finish / retake / confirm buttons.SDK blue
colorPrimaryVariantcolorPressed/tapped variant of the primary color.SDK blue (tapped)
colorSecondarycolorSecondary surface color. Drives button container backgrounds (torch, cancel) and the "secondary" circle of action buttons.Light grey
colorSecondaryVariantcolorPressed/ripple variant of the secondary color.Dark grey
colorOnPrimarycolorForeground color used for icon tints on primary surfaces.White
guidelineHintViewBackgroundcolorBackground of the receipt-edge guideline hint.?attr/colorPrimary
progressBarColorcolorColor of the scan progress bar.?attr/colorPrimary
shutterSurfaceColorcolorColor of the capture shutter animation surface.Black

Tooltip — blinkTooltipStyle

blinkTooltipStyle references a child style with these attributes:

AttributeFormatControlsDefault
tooltipColorcolorTooltip background and pointer color.?attr/colorPrimary
tooltipTextColorcolorTooltip text color.?attr/colorOnPrimary
tooltipPointHeightdimensionHeight of the tooltip's triangular pointer.8dp
tooltipBoxRadiusdimensionCorner radius of the tooltip body.6dp

Torch button — torchButtonStyle

AttributeFormatControlsDefault
android:colorAccentcolorButton container (background) color.?attr/colorSecondary
android:colorPressedHighlightcolorRipple color on press.?attr/colorSecondaryVariant
android:paddingdimensionPadding around the icon.0dp
torchOnSrcreferenceDrawable for the torch-on (activated) state.ic_torch_on
torchOffSrcreferenceDrawable for the torch-off (normal) state.ic_torch
torchOnContentDescriptionstringAccessibility text for the torch-on state.
torchOffContentDescriptionstringAccessibility text for the torch-off state.
android:tintcolorIcon tint.White

Cancel button — cancelButtonStyle

AttributeFormatControlsDefault
android:colorAccentcolorButton container (background) color.?attr/colorSecondary
android:colorPressedHighlightcolorRipple color on press.?attr/colorSecondaryVariant
android:paddingdimensionPadding around the icon.12dp
android:srcreferenceButton icon.ic_exit
android:contentDescriptionstringAccessibility text.@null
android:tintcolorIcon tint.White

Action buttons — retakeButtonStyle, finishButtonStyle, captureButtonStyle, confirmButtonStyle

These four buttons share the same attribute shape (each renders as an inner and outer circle):

AttributeFormatControlsDefault
android:colorActivatedHighlightcolorPrimary (outer circle) container color.?attr/colorPrimary
android:colorAccentcolorSecondary (inner circle) container color.?attr/colorSecondary
android:colorPressedHighlightcolorRipple color on press.?attr/colorSecondaryVariant
android:srcreferenceButton icon.ic_retake / ic_confirm / ic_camera_capture / ic_add
android:paddingdimensionPadding around the icon.0dp
android:tintcolorIcon tint.White
android:contentDescriptionstringAccessibility text.@null
Deprecated attributes (BlinkReceipt SDK 1.9.10+)

A few legacy attributes are deprecated and will be ignored in future SDK versions:

  • android:background on the button styles → use android:colorAccent, android:colorPressedHighlight, and android:colorActivatedHighlight instead.
  • android:src on the torch button → use torchOnSrc and torchOffSrc instead.
  • android:statusBarColor / android:navigationBarColor / android:enforceStatusBarContrast / android:enforceNavigationBarContrast are no longer honored.

5. Full Example

This is a complete, working theme — the same one used by the BlinkReceipt sample app. It overrides the Material color roles plus every nested button and tooltip style. Copy it into your res/values/styles.xml, rename it to your brand, and adjust the colors and drawables.

<resources>

<style name="BlinkRecognizerStyle.BlinkReceiptApp">
<item name="colorPrimary">@android:color/holo_red_dark</item>
<item name="colorPrimaryVariant">@color/colorPrimaryDark</item>
<item name="colorSecondary">@color/colorAccent</item>
<item name="colorSecondaryVariant">@color/greenlight</item>
<item name="colorOnPrimary">@android:color/white</item>
<item name="blinkTooltipStyle">@style/Tooltip.BlinkReceiptAppStyle</item>
<item name="guidelineHintViewBackground">?attr/colorPrimary</item>
<item name="progressBarColor">?attr/colorPrimary</item>
<item name="torchButtonStyle">@style/Widget.AppCompat.ImageButton.TorchButtonStyle.BlinkReceiptAppStyle</item>
<item name="cancelButtonStyle">@style/Widget.AppCompat.ImageButton.CancelButtonStyle.BlinkReceiptAppStyle</item>
<item name="retakeButtonStyle">@style/Widget.AppCompat.ImageButton.RetakeButtonStyle.BlinkReceiptAppStyle</item>
<item name="finishButtonStyle">@style/Widget.AppCompat.ImageButton.FinishButtonStyle.BlinkReceiptAppStyle</item>
<item name="captureButtonStyle">@style/Widget.AppCompat.ImageButton.CaptureButtonStyle.BlinkReceiptAppStyle</item>
<item name="confirmButtonStyle">@style/Widget.AppCompat.ImageButton.ConfirmButtonStyle.BlinkReceiptAppStyle</item>
</style>

<style name="Tooltip.BlinkReceiptAppStyle">
<item name="tooltipPointHeight">8dp</item>
<item name="tooltipBoxRadius">6dp</item>
<item name="tooltipColor">?attr/colorPrimary</item>
<item name="tooltipTextColor">?attr/colorOnPrimary</item>
</style>

<style name="Widget.AppCompat.ImageButton.TorchButtonStyle.BlinkReceiptAppStyle">
<item name="torchOnSrc">@drawable/ic_chip_completed</item>
<item name="torchOffSrc">@drawable/ic_chip_not_found</item>
<item name="tint">@android:color/holo_orange_dark</item>
</style>

<style name="Widget.AppCompat.ImageButton.CancelButtonStyle.BlinkReceiptAppStyle">
<item name="android:contentDescription">@null</item>
<item name="android:padding">12dp</item>
<item name="android:src">@drawable/ic_exit</item>
<item name="tint">@android:color/holo_blue_bright</item>
</style>

<style name="Widget.AppCompat.ImageButton.FinishButtonStyle.BlinkReceiptAppStyle">
<item name="android:src">@drawable/ic_confirm</item>
<item name="tint">@android:color/holo_blue_dark</item>
</style>

<style name="Widget.AppCompat.ImageButton.RetakeButtonStyle.BlinkReceiptAppStyle">
<item name="android:src">@drawable/ic_retake</item>
<item name="tint">@android:color/white</item>
</style>

<style name="Widget.AppCompat.ImageButton.CaptureButtonStyle.BlinkReceiptAppStyle">
<item name="android:src">@drawable/ic_camera_capture</item>
<item name="tint">@android:color/white</item>
</style>

<style name="Widget.AppCompat.ImageButton.ConfirmButtonStyle.BlinkReceiptAppStyle">
<item name="android:src">@drawable/ic_add</item>
<item name="tint">@android:color/white</item>
</style>
</resources>

Each nested button and tooltip style also uses dot-notation inheritance, so it inherits from the SDK's base button styles and only needs to declare the icons/colors you override.

Launch the camera with this theme:

CameraCharacteristics.Builder()
.style(R.style.BlinkRecognizerStyle_BlinkReceiptApp)
.build()

6. Tips and Pitfalls

Extend the base style. Always use BlinkRecognizerStyle (or one of its Widget.AppCompat.ImageButton.* button styles / the Tooltip style) as a parent. Inheritance via dot-notation means unset attributes fall back to SDK defaults, so a missing icon or color never leaves a button blank.

Override only what you need. Setting the five Material color roles is enough to re-skin the whole screen. Reach for the per-button nested styles only when you want custom icons or per-button colors.

Dots become underscores in code. The XML style BlinkRecognizerStyle.YourBrand is R.style.BlinkRecognizerStyle_YourBrand in Kotlin/Java.

Pass the style every launch. The theme is read from CameraCharacteristics when the camera starts. There is no global "set once" call — include .style(...) on every launch you want branded. Omitting it uses the SDK default.

Avoid the deprecated attributes. As of SDK 1.9.10, use android:colorAccent / android:colorPressedHighlight / android:colorActivatedHighlight instead of android:background, and torchOnSrc / torchOffSrc instead of android:src on the torch button. See the warning above.