Barcode Detection
The Camera SDK has a built-in barcode detector that will help you identify different kind of barcodes in real-time.
We support the following set of barcodes, exposed through the Barcode.Kind enumeration:
| Value | Description |
|---|---|
Barcode.Kind.QRBarcode.Kind.qr | Quick Response Code, a 2D matrix barcode. |
Barcode.Kind.MicroQRBarcode.Kind.microQr | Smaller version of QR code with reduced data capacity. |
Barcode.Kind.EAN13Barcode.Kind.ean13 | European Article Number, 13-digit barcode. |
Barcode.Kind.EAN8Barcode.Kind.ean8 | European Article Number, 8-digit barcode. |
Barcode.Kind.UPCABarcode.Kind.upca | Universal Product Code A, 12-digit barcode. |
Barcode.Kind.UPCEBarcode.Kind.upce | Universal Product Code E, 6-digit barcode. |
Barcode.Kind.Code128Barcode.Kind.code128 | Code128, high-density linear barcode. |
Barcode.Kind.DataMatrixBarcode.Kind.dataMatrix | DataMatrix 2D matrix barcode. |
Barcode.Kind.AztecBarcode.Kind.aztec | Aztec 2D matrix barcode. |
If your barcode is not on the list, please let us know - we may provide more options in the future.
Configuration
Requirements
Barcode detection works on all devices. The only requirement is to declare your intention to use it during manager initialization.
We provide a special feature object called CameraFeature.BarcodeCameraFeature.barcode.
Barcode detection doesn't need a visible preview. You may use the barcode feature without
CameraFeature.PreviewCameraFeature.previewand it will work out of the box.
To interact with all barcode APIs, you'll use the BarcodeDetector class:
swiftlet detector: BarcodeDetector = cameraManager.barcodeDetector
kotlinval detector: BarcodeDetector = cameraManager.barcodeDetector
Options
The BarcodeDetector.Options class and the BarcodeDetector.options field will let you configure the detection options,
which can affect performance, amount and type of symbols to be retrieved and more.
| Value | Type | Default | Description |
|---|---|---|---|
Options.count | Int | 1 | The maximum number of barcodes to return. A number higher than 1 means that if a barcode is found in the scene, the engine will keep looking for more in the same frame. |
Options.kinds | List of Barcode.Kind | [Kind.QR][.qr] | The set of barcode kinds to detect. The processing time per frame grows with the number of kinds. |
Options.priority | Priority enum | Priority.Speed.speed | Choose between speed and accuracy. In accurate mode, the engine will spend more time and resources looking for barcodes. |
Options.surface | String? | First available surface | The name of a preview surface, so that barcodes can be easily drawn on the current screen. |
Options.interval | Long (ms)TimeInterval | 1 second | The time that the engine should wait after an unsuccessful frame, before requesting a new one. Doesn't apply to frames with barcodes: in that case, no time is wasted to update the barcode position smoothly. |
swiftlet detector: BarcodeDetector = cameraManager.barcodeDetector
detector.options = Options(count: 3, kinds: [.qr, .microQr])
kotlinval detector: BarcodeDetector = cameraManager.barcodeDetector
detector.options = Options(count = 3, kinds = listOf(QR, MicroQR))
Disabling detection
Detection can be disabled in a number of ways:
- The
CameraFeature.BarcodeCameraFeature.barcodewas not set - The
Optionsvalue has a non-positivecount - The
Optionsvalue has a negativeinterval - The
Optionsvalue has an emptykindsarray - The
Optionsvalue has a non-emptysurface, but no surface with that name exists
Disabling detection can be useful to save resources (CPU and battery) when not needed, for example while recording videos.
Observing barcodes
Once the barcode feature is declared and the CameraDevice is open, detection will start automatically. The barcode detector
will then provide you with a sequence of one or more Barcode objects with the following properties:
| Value | Type | Description |
|---|---|---|
Barcode.kind | Barcode.Kind | The kind of detected barcode (QR code, UPC-A, ...). |
Barcode.content | String | The barcode contents as a String. Depending on the barcode kind the string may be contain only numbers, or it may have structured data (URL, Wi-Fi network and password, location, contacts, ...). |
Barcode.position | Polygon | The barcode position on the current preview surface (see Options.surface), in normalized values in the 0...1 range. Use Polygon.points to draw the four corners, or Polygon.box to draw the bounding box. |
There are two ways to receive Barcode updates:
- By reading barcode detector's state, which updates automatically
- By receiving barcode detection events
State
On every processed frame, BarcodeDetector will update its barcodes property which can be read to retrieve a list of Barcode objects.
Note that in the majority of frames, the list will be empty. The list of barcodes can also be observed
through the provided coroutines Flowthe provided publisher:
kotlinval detector: BarcodeDetector = cameraManager.barcodeDetector
val flow: StateFlow<List<Barcode>> = detector.barcodes
swiftlet detector: BarcodeDetector = cameraManager.barcodeDetector
let publisher: AnyPublisher<[Barcode], Never> = detector.barcodesPublisher
The stateful APIs are the recommended way to receive barcode updates to update the UI (e.g. draw the barcode box on screen), because you'll be able to receive position updates for a barcode that was initially detected in previous frames.
Events
In addition, you can register an observer lambda that will be executed for any new barcode, as soon as it is found.
The difference with the previous approach is that you won't get duplicate updates: if a Barcode is detected on frames
i, i + 1, .... i + 100 you'll only get the event on frame i.
This mode can be useful if all you care about is the barcode contents. Remember to return true to continue receiving
updates, and false to remove the observer:
kotlinval detector: BarcodeDetector = cameraManager.barcodeDetector
detector.observe { barcode ->
// Handle barcode...
true // Keep observing
}
swiftlet detector: BarcodeDetector = cameraManager.barcodeDetector
detector.observe { barcode in
// Handle barcode...
return true // Keep observing
}
