Building a Mobile Scanner with ZBar: Step-by-Step Tutorial
Overview
A concise guide to create a mobile barcode/QR scanner using ZBar. This tutorial assumes a simple Android app using Kotlin and the ZBar SDK via JNI (or the zbar-android binding). It covers permissions, camera capture, frame processing, ZBar integration, and UI feedback.
Requirements
- Android Studio (latest stable)
- Kotlin
- Android device or emulator with camera support
- ZBar Android binding (zbar-android) or native ZBar compiled for Android
- Gradle, CameraX library
1. Project setup
- Create a new Android project (Empty Activity) with Kotlin.
- Add CameraX dependencies in module build.gradle:
gradle
implementation “androidx.camera:camera-core:1.2.0” implementation “androidx.camera:camera-camera2:1.2.0” implementation “androidx.camera:camera-lifecycle:1.2.0” implementation “androidx.camera:camera-view:1.2.0”
- Add ZBar dependency (use zbar-android or a compiled native .so):
gradle
implementation ‘com.github.dm77:barcode-reader:1.0.3’ // example binding
2. Permissions
- Add to AndroidManifest.xml:
xml
<uses-permission android:name=“android.permission.CAMERA”/>
- Request runtime permission in Activity before starting camera.
3. Camera preview with CameraX
- In activitymain.xml add a PreviewView:
xml
<androidx.camera.view.PreviewView android:id=“@+id/previewView” android:layout_width=“match_parent” android:layout_height=“matchparent”/>
- Start camera and bind lifecycle in Activity:
kotlin
val cameraProvider = ProcessCameraProvider.getInstance(this).get() val preview = Preview.Builder().build().also { it.setSurfaceProvider(previewView.surfaceProvider) } val imageAnalysis = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), YourAnalyzer()) cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACKCAMERA, preview, imageAnalysis)
4. Image analyzer: prepare frames for ZBar
- Implement ImageAnalysis.Analyzer:
kotlin
class YourAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image ?: run { imageProxy.close(); return } val rotation = imageProxy.imageInfo.rotationDegrees // Convert mediaImage (YUV) to grayscale byte array or Bitmap val bitmap = yuvToBitmap(mediaImage, rotation) val result = scanWithZBar(bitmap) if (result != null) { // handle result (UI thread) } imageProxy.close() } }
- Use a fast YUV-to-grayscale conversion to minimize latency.
5. Integrate ZBar scanning
- Initialize ZBar scanner (example using zbar-android wrapper):
kotlin
val scanner = ImageScanner().apply { setConfig(0, Config.X_DENSITY, 3) setConfig(0, Config.Y_DENSITY, 3) } fun scanWithZBar(bitmap: Bitmap): String? { val width = bitmap.width; val height = bitmap.height val pixels = IntArray(width height) bitmap.getPixels(pixels, 0, width, 0, 0, width, height) val gray = ByteArray(width height) for (i in pixels.indices) { val c = pixels[i] val r = (c shr 16) and 0xff val g = (c shr 8) and 0xff val b = c and 0xff gray[i] = ((0.299r + 0.587g + 0.114*b).toInt() and 0xFF).toByte() } val image = Image(width, height, “Y800”) image.data = gray val result = scanner.scanImage(image) if (result > 0) { val symbolSet = scanner.results for (sym in symbolSet) return sym.data } return null }
6. UI feedback and handling results
- On detection, run UI updates on main thread: show bounding box, vibrate, play sound, or display decoded text.
- Debounce detections to avoid repeated processing (e.g., ignore repeats for 1.5s).
7. Performance tips
- Downscale frames to a reasonable size (e.g., 640px wide) before scanning.
- Use a dedicated single-thread executor for analysis.
- Tune ZBar X/Y density for faster scans vs accuracy.
- Reuse buffers to reduce GC.
8. Testing and edge cases
- Test with different lighting and barcode sizes.
- Handle rotated scans by rotating image bytes according to rotationDegrees.
- Provide fallback: capture still image and run higher-resolution scan if live scanning fails.
9. Deployment notes
- Ensure camera permission text shows clear purpose.
- Test on multiple devices and Android versions.
- If using native .so, include armeabi-v7a and arm64-v8a builds.
This gives a full, actionable path to build a mobile scanner with ZBar on Android. If you want, I can provide a complete sample project (files: AndroidManifest, Activity.kt, Analyzer.kt, Gradle files).
Leave a Reply