Suntech.KazamCaptureAI
1.0.12
dotnet add package Suntech.KazamCaptureAI --version 1.0.12
NuGet\Install-Package Suntech.KazamCaptureAI -Version 1.0.12
<PackageReference Include="Suntech.KazamCaptureAI" Version="1.0.12" />
<PackageVersion Include="Suntech.KazamCaptureAI" Version="1.0.12" />
<PackageReference Include="Suntech.KazamCaptureAI" />
paket add Suntech.KazamCaptureAI --version 1.0.12
#r "nuget: Suntech.KazamCaptureAI, 1.0.12"
#:package Suntech.KazamCaptureAI@1.0.12
#addin nuget:?package=Suntech.KazamCaptureAI&version=1.0.12
#tool nuget:?package=Suntech.KazamCaptureAI&version=1.0.12
Suntech.KazamCaptureAI
KAZAM CAPTURE AI — Zebra AI DataCapture SDK for .NET MAUI and .NET for Android.
A .NET binding library that exposes barcode decoding and OCR (text recognition) capabilities of Zebra AI DataCapture on Zebra mobile devices.
Table of contents
- Features
- Requirements
- Compatible devices
- Installation
- Android Manifest permissions
- Quick start
- Lifecycle
- API reference
- License management
- Troubleshooting
- Support
Features
- Barcode decoding — 44+ symbologies (1D/2D/postal) via Zebra AI DataCapture SDK
- OCR text recognition — Multi-line, high-accuracy text recognition with stabilization
- Combined mode — Barcode + OCR simultaneously in the same camera preview
- Three selection modes — Automatic, Manual (tap), Accumulate (batch)
- OCR filters — Numeric, alpha, alphanumeric, exact match, starts-with, contains, regex
- Offline JWT license — RSA-SHA256 signed, device-locked, no network calls
- DEMO mode — Full functionality with degraded results (asterisks) for evaluation
- Full-screen overlay UI — Built-in camera preview, torch, settings panel
- Tap-to-focus — Tap any area of the preview to focus at that point
- Inactivity timeout — Auto-closes the scanner after N ms of no detections
Requirements
- .NET 10 or later (
net10.0-android36.0) - .NET MAUI or .NET for Android project
- Zebra mobile device with Zebra AI DataCapture support
- Android API 30+ (Android 11 or later)
- License JWT provided by Suntech, or the string
"DEMO"for evaluation
Compatible devices
| Device | Barcode | OCR | Notes |
|---|---|---|---|
| Zebra TC53 | ✅ | ✅ | Primary target, fully tested |
| Other Zebra AI DataCapture devices | ✅ | ✅ | Requires Zebra AI DataCapture SDK support |
The SDK uses Zebra AI Vision libraries which are only available on Zebra hardware. On non-Zebra devices the callback will receive
ZebraAiErrorwith codeCODE_SDK_NOT_AVAILABLE.
Installation
<PackageReference Include="Suntech.KazamCaptureAI" Version="1.0.12" />
All transitive dependencies (Kotlin stdlib, CameraX, AndroidX, etc.) are declared in the package and resolved automatically by NuGet — no manual package additions required.
Android Manifest permissions
Add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
MAUI note: Request
CAMERApermission at runtime before callingScan(). The SDK internally requests it viaActivityCompat.requestPermissionsif missing, but it is better practice to request it from your app code.
Quick start
Minimal example
using IT.Suntech.Zebraai.Sdk;
// ── 1. Initialize once at app startup ───────────────────────────────────────
// Pass your JWT license, or "DEMO" for evaluation
try
{
ZebraAiScanner.Initialize(context, "DEMO");
}
catch (LicenseException ex)
{
// Invalid JWT, expired license, or unauthorized device
Console.Error.WriteLine(ex.Message);
return;
}
// ── 2. Configure the scanner ─────────────────────────────────────────────────
ZebraAiScanner.Configure(new ZebraAiConfig
{
RecognitionMode = RecognitionMode.Barcode,
SelectionMode = SelectionMode.Automatic,
});
// ── 3. Start a scan ───────────────────────────────────────────────────────────
ZebraAiScanner.Scan(activity, new MyCallback());
// ── 4. Handle the result ──────────────────────────────────────────────────────
class MyCallback : Java.Lang.Object, IZebraAiCallback
{
public void OnResult(ZebraAiResult result)
=> Console.WriteLine($"[{result.Type}] {result.Symbology}: {result.Value}");
public void OnResults(IList<ZebraAiResult> results)
{
foreach (var r in results)
Console.WriteLine($"[{r.Type}] {r.Symbology}: {r.Value}");
}
public void OnError(ZebraAiError error)
=> Console.Error.WriteLine($"Error {error.Code}: {error.Message}");
public void OnCancelled()
=> Console.WriteLine("Scan cancelled by user");
}
Task-based wrapper (recommended for MAUI)
// Wraps the callback in a TaskCompletionSource — await the result directly.
var tcs = new TaskCompletionSource<IList<ZebraAiResult>>();
ZebraAiScanner.Configure(new ZebraAiConfig
{
RecognitionMode = RecognitionMode.Ocr,
SelectionMode = SelectionMode.Accumulate,
OcrFilter = new OcrFilterConfig
{
MinConfidencePercent = 70,
FilterType = OcrFilterType.NumericOnly,
}
});
ZebraAiScanner.Scan(Platform.CurrentActivity, new SimpleCallback(
onResult: r => tcs.TrySetResult(new[] { r }),
onResults: rs => tcs.TrySetResult(rs),
onError: e => tcs.TrySetException(new Exception($"{e.Code}: {e.Message}")),
onCancelled: () => tcs.TrySetCanceled()
));
var results = await tcs.Task;
Lifecycle
App startup
└─ ZebraAiScanner.Initialize(context, licenseJwt) ← once only
│
├─ License verified (offline RSA-SHA256)
├─ Native Zebra libraries loaded
└─ SDK ready
Per-scan
└─ ZebraAiScanner.Configure(config) ← optional, update config
│
└─ ZebraAiScanner.Scan(activity, callback) ← opens full-screen overlay
│
├─ Camera starts, AI decoders initialized
├─ Results detected → callback.OnResult / OnResults
├─ User presses CLOSE → callback.OnCancelled
└─ Overlay closed, scanner ready for next scan
App shutdown
└─ ZebraAiScanner.Dispose() ← releases AI decoders
Initialize()is idempotent — calling it more than once is a no-op.Configure()can be called at any time between scans.
API reference
ZebraAiScanner {#zebraaiscannerclass}
The main entry point of the SDK. All methods are static.
namespace IT.Suntech.Zebraai.Sdk
static class ZebraAiScanner
| Method | Description |
|---|---|
Initialize(Context, string) |
Verifies the JWT license and loads native libraries. Throws LicenseException on failure. Must be called once before any other method. |
Configure(ZebraAiConfig) |
Updates the scanner configuration. Can be called at any time. |
GetConfig() |
Returns the current ZebraAiConfig. |
Scan(Activity, IZebraAiCallback) |
Opens the full-screen camera overlay. Calls the callback on result/error/cancellation. |
Cancel() |
Requests cancellation of an ongoing scan. The callback will receive OnCancelled. |
Dispose() |
Releases AI decoder resources. Call when the app is closing. |
IsInitialized() |
Returns true if the SDK has been successfully initialized. |
IsScanning() |
Returns true if a scan is currently in progress. |
Properties:
| Property | Type | Description |
|---|---|---|
LicenseInfo |
ZebraAiScanner.LicenseInfoData? |
Active license info (customer, expiry, features, device count). null if not initialized. |
ZebraAiConfig
Scanner configuration. All fields have default values — only override what you need.
var config = new ZebraAiConfig
{
RecognitionMode = RecognitionMode.Barcode,
SelectionMode = SelectionMode.Automatic,
InactivityTimeoutMs = 15_000,
ShowSettingsButton = false,
OcrFilter = new OcrFilterConfig { ... }
};
ZebraAiScanner.Configure(config);
Core options
| Field | Type | Default | Description |
|---|---|---|---|
RecognitionMode |
RecognitionMode |
Barcode |
Recognition engine to use. |
SelectionMode |
SelectionMode |
Automatic |
How results are selected and sent. |
InactivityTimeoutMs |
long |
10000 |
Auto-close timeout in ms. 0 = disabled. |
ShowSettingsButton |
bool |
true |
Shows the ⚙ button in the overlay. |
ShowTorchButton |
bool |
true |
Shows the flashlight button. |
EnableTapToFocus |
bool |
true |
Tap empty area → camera focuses there. |
Camera options
| Field | Type | Default | Description |
|---|---|---|---|
CameraResolution |
CameraResolution |
FHD_1080P |
Camera capture resolution. |
ProcessorType |
ProcessorType |
Auto |
AI inference processor (DSP, GPU, CPU, Auto). |
Barcode options
| Field | Type | Default | Description |
|---|---|---|---|
BarcodeModelInput |
int |
1280 |
AI model input size in pixels (640, 1280, 1600). |
EnabledSymbologies |
MutableSet<Symbology> |
Common set | Set of enabled barcode symbologies. |
Inverse1DMode |
int |
2 |
0=Disabled, 1=Enabled, 2=Auto. |
LinearSecurityLevel |
int |
0 |
0–3 (aggressive→safe). |
MarginlessDecodeEffortLevel |
int |
0 |
0–3. |
PoorQualityDecodeEffortLevel |
int |
0 |
0–3. |
DatamatrixInverse |
int |
2 |
0=Regular, 1=InverseOnly, 2=AutoDetect. |
DotCodeInverse |
int |
2 |
0=Disabled, 1=Enabled, 2=Auto. |
GridMatrixMode |
int |
2 |
0=Disabled, 1=Enabled, 2=Auto. |
OCR options
| Field | Type | Default | Description |
|---|---|---|---|
OcrModelInput |
int |
1600 |
AI model input size (640, 1280, 1600, 2560). |
OcrStabilizationFrames |
int |
5 |
Frames for stabilization (1=fast, 15=stable). |
OcrFilter |
OcrFilterConfig |
(see below) | Text filter applied to OCR results. |
OcrFilterConfig
Controls which OCR results are passed to the callback.
var config = new ZebraAiConfig
{
RecognitionMode = RecognitionMode.Ocr,
OcrFilter = new OcrFilterConfig
{
FilterType = OcrFilterType.NumericOnly,
MinConfidencePercent = 80,
MinLength = 6,
MaxLength = 13,
CaseTransform = OcrCaseTransform.Uppercase,
}
};
| Field | Type | Default | Description |
|---|---|---|---|
FilterType |
OcrFilterType |
ShowAll |
Text filter to apply. |
CaseTransform |
OcrCaseTransform |
None |
Output case transformation. |
MinConfidencePercent |
int |
0 |
Minimum OCR confidence (0–100). Lines below this are discarded before stabilization. |
MinLength |
int |
1 |
Minimum character length (for types 1–6). |
MaxLength |
int |
50 |
Maximum character length (for types 1–6). |
ExactMatchList |
string |
"" |
Comma-separated values for ExactMatch. |
StartsWithList |
string |
"" |
Comma-separated prefixes for StartsWith. |
ContainsList |
string |
"" |
Comma-separated substrings for Contains. |
RegexPattern |
string |
"" |
Regular expression for Regex. |
OcrFilterType values:
| Value | Description |
|---|---|
ShowAll |
No filtering — all detected text is shown. |
NumericOnly |
Keeps only lines that are purely numeric (digits). |
AlphaOnly |
Keeps only lines that are purely alphabetic. |
AlphaNumericOnly |
Keeps only lines with letters and digits (no special characters). |
ExactMatch |
Keeps lines that exactly match any value in ExactMatchList. |
StartsWith |
Keeps lines starting with any prefix in StartsWithList. |
Contains |
Keeps lines containing any substring in ContainsList. |
Regex |
Keeps lines matching RegexPattern. |
IZebraAiCallback {#zebraicallback}
Implement this interface to receive scan results. In MAUI you must extend both
Java.Lang.Object and the interface:
class MyCallback : Java.Lang.Object, IZebraAiCallback
{
// Called for AUTOMATIC, MANUAL, or single tap in ACCUMULATE mode
public void OnResult(ZebraAiResult result) { ... }
// Called for ACCUMULATE mode when the user presses "SEND ALL"
public void OnResults(IList<ZebraAiResult> results) { ... }
// Called on any error (see ZebraAiError error codes)
public void OnError(ZebraAiError error) { ... }
// Called when the user closes the scanner without scanning
public void OnCancelled() { ... }
}
Which method is called, by mode:
| SelectionMode | Single result | Multiple results |
|---|---|---|
Automatic |
OnResult |
— |
Manual |
OnResult (user taps a box) |
— |
Accumulate |
OnResult (tap single item from list) |
OnResults ("SEND ALL") |
ZebraAiResult
public class ZebraAiResult
{
public string Value { get; } // Decoded value
public ResultType Type { get; } // BARCODE or OCR
public string? Symbology { get; } // e.g. "Code128", null for OCR
public int SymbologyId { get; } // Zebra SDK numeric ID, -1 for OCR
public float Confidence { get; } // 0.0 – 1.0
public long Timestamp { get; } // Epoch milliseconds
}
ZebraAiError {#zebraierror}
public class ZebraAiError
{
public int Code { get; }
public string Message { get; }
}
Error codes:
| Constant | Code | When |
|---|---|---|
CODE_SDK_NOT_AVAILABLE |
1 | Zebra AI DataCapture not available on this device. |
CODE_CAMERA_PERMISSION_DENIED |
2 | Camera permission was denied by the user. |
CODE_DECODER_INIT_FAILED |
3 | AI decoder failed to initialize. |
CODE_ALREADY_SCANNING |
4 | Scan() called while a scan is already in progress. |
CODE_NOT_INITIALIZED |
5 | Scan() called before Initialize(). |
CODE_INACTIVITY_TIMEOUT |
6 | No detections within InactivityTimeoutMs. |
CODE_UNKNOWN |
99 | Unclassified error. |
Enumerations
RecognitionMode
| Value | Description |
|---|---|
Barcode |
Barcode decoding only. |
Ocr |
Text recognition only. |
Both |
Barcode + OCR simultaneously. |
SelectionMode
| Value | Description |
|---|---|
Automatic |
First decoded result is sent immediately, overlay closes. |
Accumulate |
Results accumulate (✓ button appears). User presses ✓ to confirm. |
Manual |
Green boxes are shown; user taps the one they want. |
CameraResolution
| Value | Resolution | Notes |
|---|---|---|
HD_720P |
1280×720 (1 MP) | Fastest, lower quality. |
FHD_1080P |
1920×1080 (2 MP) | Default. Recommended balance. |
QHD_1512P |
2688×1512 (4 MP) | Better for small/dense barcodes. |
UHD_2160P |
3840×2160 (8 MP) | Highest quality, highest CPU/memory load. |
ProcessorType
| Value | Description |
|---|---|
Auto |
DSP → CPU → GPU (tries fastest available). Default. |
Dsp |
Force DSP. Fastest on Zebra hardware. |
Gpu |
Force GPU. |
Cpu |
Force CPU. Slowest, most compatible. |
Symbology (common subset)
AZTEC, CODE_39, CODE_128, DATA_MATRIX, EAN_8, EAN_13, GS1_DATABAR,
GS1_DATABAR_EXPANDED, MAILMARK, MAXICODE, PDF417, QR_CODE, UPC_A, UPC_E (enabled by default),
plus 30 additional symbologies including all postal codes.
To restrict to a subset:
config.EnabledSymbologies = new HashSet<Symbology> { Symbology.Qr_Code, Symbology.Code_128 };
License management
DEMO mode
Pass "DEMO" as the license JWT to evaluate the SDK without a real license:
ZebraAiScanner.Initialize(context, "DEMO");
- No signature, device serial, or expiry verification
- Results are degraded: ~40% of alphanumeric characters are replaced with
* - Spaces and punctuation are preserved
LicenseInfo.Customerreturns"DEMO"
Production JWT license
Contact Suntech to obtain a JWT license. You must provide the serial of each authorized device.
Getting the device serial:
# Method 1 — hardware serial (requires READ_PHONE_STATE)
adb shell getprop ro.serialno
# Method 2 — ANDROID_ID (always readable, resets on factory reset)
adb shell settings get secure android_id
The SDK tries the hardware serial first; if READ_PHONE_STATE is not granted
it automatically falls back to ANDROID_ID.
JWT payload structure:
{
"sub": "zebraai-maui",
"customer": "Acme Corp",
"allowedSerials": ["ABC123456", "XYZ789012"],
"features": ["barcode", "ocr"],
"exp": 1893456000
}
Checking license info at runtime:
var info = ZebraAiScanner.LicenseInfo;
if (info != null)
{
Console.WriteLine($"Customer: {info.Customer}");
Console.WriteLine($"Expires: {info.Expiry}");
Console.WriteLine($"Features: {string.Join(", ", info.Features)}");
Console.WriteLine($"Devices: {info.DeviceCount}");
}
Localization
The SDK ships a full-screen camera overlay with built-in UI strings (torch label, close button, settings panel, accumulate counter, etc.). These strings live inside the AAR as Android string resources and are merged into your APK at build time.
Supported languages
The AAR currently ships resources for the following locales:
| Locale | Folder in AAR |
|---|---|
| English (default) | values/ |
| Italian | values-it/ |
The overlay will automatically display in the device's system language if a matching locale is present; otherwise it falls back to English.
Restricting locale resources (reduce APK size)
By default the .NET Android linker keeps all locale folders from the AAR.
To include only the languages your app needs, add SupportedLocales to your
.csproj:
<PropertyGroup>
<SupportedLocales>en;it</SupportedLocales>
</PropertyGroup>
This maps to the Android resConfig build option and can meaningfully reduce
APK size when the AAR bundles many locales.
Adding or overriding translations
Create a strings.xml under the appropriate platform resource folder of your
app project and define the keys you want to override. .NET MAUI resource merging
gives your app's resources higher priority than those from the AAR.
Example — override the overlay close button label in Italian
(Platforms/Android/Resources/values-it/strings.xml):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="kazam_btn_close">Chiudi</string>
<string name="kazam_btn_send_all">Invia tutti</string>
</resources>
Tip: Run
aapt2 dump resources <path-to-aar>(or inspect the AAR as a zip) to list all available string keys that can be overridden.
Troubleshooting
LicenseException on Initialize
| Message | Cause | Fix |
|---|---|---|
"Invalid JWT format" |
The string is not a valid JWT (3 dot-separated parts). | Check the JWT string. |
"Invalid license signature" |
JWT was not signed with the Suntech private key. | Use the JWT provided by Suntech. |
"License expired on..." |
The exp field is in the past. |
Contact Suntech to renew. |
"License not valid for this product" |
sub is not zebraai-maui. |
Use the correct license for this SDK. |
"Device '...' not authorized" |
The current device serial is not in allowedSerials. |
Provide the serial to Suntech to update the license. |
Error CODE_SDK_NOT_AVAILABLE (1)
The Zebra AI DataCapture native libraries (libctolandroidsdkwrapper.so etc.) are not
present on the device. Ensure the device is a Zebra with AI DataCapture support
and the Zebra Android SDK is installed on it.
Error CODE_DECODER_INIT_FAILED (3)
The AI decoder failed to initialize. Common causes:
- Insufficient device memory (UHD_2160P model input with OCR is memory-intensive)
- AI DataCapture SDK version mismatch (this package ships SDK 3.2.8)
- First run on a fresh device (give the device time to warm up its AI runtime)
Reduce OcrModelInput or BarcodeModelInput to 640 or 1280 if this occurs.
Scan does not open (no callback called)
Verify that:
Initialize()was called and succeeded (no exception thrown).Platform.CurrentActivityis not null.- The calling activity is in the foreground.
OCR returns too many / too few results
Tune OcrFilter.MinConfidencePercent (raise to reduce false positives) and
OcrStabilizationFrames (raise for stability, lower for speed).
Support
For production license requests, device authorizations, or technical support:
- Email: info@suntechonline.it
- Website: https://www.suntechonline.it
- GitHub (demo / issues): https://github.com/Sun-Tech-Software/Kazam-Capture-AI
Please include the device model, Android version, SDK version (1.0.12),
and the full exception message or logcat output.
© 2025 Suntech Srl — All rights reserved. See LICENSE for terms.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-android36.0 is compatible. |
-
net10.0-android36.0
- Suntech.KazamCaptureAI.ZebraBarcode (>= 1.0.12)
- Suntech.KazamCaptureAI.ZebraOcr (>= 1.0.12)
- Xamarin.AndroidX.AppCompat (>= 1.7.1.3)
- Xamarin.AndroidX.Camera.Camera2 (>= 1.5.3.1)
- Xamarin.AndroidX.Camera.Core (>= 1.5.3.1)
- Xamarin.AndroidX.Camera.Lifecycle (>= 1.5.3.1)
- Xamarin.AndroidX.Camera.View (>= 1.5.3.1)
- Xamarin.AndroidX.ConstraintLayout (>= 2.2.1.5)
- Xamarin.AndroidX.Lifecycle.LiveData (>= 2.10.0.2)
- Xamarin.AndroidX.Lifecycle.LiveData.Core (>= 2.10.0.2)
- Xamarin.AndroidX.Tracing.Tracing (>= 1.3.0.3)
- Xamarin.AndroidX.Tracing.Tracing.Ktx (>= 1.3.0.3)
- Xamarin.Google.Android.Material (>= 1.13.0.2)
- Xamarin.Kotlin.StdLib (>= 2.3.10.1)
- Xamarin.KotlinX.Coroutines.Android (>= 1.10.2.3)
- Xamarin.KotlinX.Coroutines.Core.Jvm (>= 1.10.2.3)
- Xamarin.KotlinX.Serialization.Core.Jvm (>= 1.10.0.1)
- Xamarin.KotlinX.Serialization.Json.Jvm (>= 1.10.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.0.12: Rebuilt underlying zebraai-sdk AAR with Kotlin 2.3.20, AGP 9.1,
CameraX 1.6.0, compileSdk 36, serialization 1.11.0, coroutines 1.10.2.
All transitive dependencies aligned to latest stable. No public API changes.
v1.0.11: ZebraAiScanner.Initialize() now auto-pre-loads AI decoders
in background when called with an Activity context (no extra API call
needed). Use Platform.CurrentActivity from MAUI OnAppearing.
v1.0.10: Added ZebraAiScanner.PreloadDecoders(activity) — pre-loads
AI decoders in background after Initialize() so the first Scan()
starts the camera immediately instead of showing the "Initializing AI
engine" overlay for several seconds. Must be called from an Activity
context so JNI gets the correct classloader.
v1.0.9: Detect non-AI-capable Zebra devices upfront via ro.soc.model
(e.g. TC22 with QCM5430): ZebraAiScanner.Scan() returns
ZebraAiError.CODE_SDK_NOT_AVAILABLE immediately instead of opening
the camera and silently failing. Added BarcodeOverlayLabelSizeSp
and OcrOverlayLabelSizeSp on ZebraAiConfig (10-40 sp, default 18).
Overlay boxes now use distinct colors: green for barcode, blue for OCR.
v1.0.8: Added ZebraAiScanner.ShowDeviceId(context) public API — shows AlertDialog with
model + device ID + Copy button, and logs values to logcat (tag: ZebraAi.SDK).
v1.0.7: Added ZebraAiScanner.GetDeviceId(context) public API for license activation;
device info section (model + device ID + copy button) added to settings panel;
LicenseValidator uses 5-level fallback chain for device identifier (Android 14 compatible).