Set up the Active Scan Area and Location Selection
By default capture modes will try to read barcodes, text etc anywhere in the camera frames. However, in some cases you want to restrict the area in which the capture modes search. For example, you may want to scan codes only at one location to let users pick a barcode by precisely pointing at it. Or part of the camera preview is covered by UI elements and you want to ensure that no codes are scanned below these elements.
This page describes how to setup the scan area for data capture modes to get the optimal behavior for your app.
Setting up the Scan Area for Your Use Case
The Scan Area is Restricted to the Visible Part of the Preview
When displaying the processed frames in the SDCDataCaptureView, the scan area is automatically restricted to what is visible. This avoids unexpected scans as the code first has to be visible on screen before it can be scanned. This is especially important when the preview only shows a small part of the whole camera frame, e.g. when using a cropped view.
If you want to scan codes in the whole visible area, no further configuration is required. If there are some UI elements overlaying the camera preview you might want to further restrict the scan area to really only be the final visible part of the preview and avoid picking up codes that the user can’t see yet. For this you can change the SDCDataCaptureView.scanAreaMargins property on the SDCDataCaptureView.
If there is nothing laying on top of the camera preview but you still want to reduce the scan area please have a look at location selections for this instead of scan area margins. Location selections are centered on the point of interest and are sized like viewfinders which makes them a much better fit for such use cases.
Here is an example of restricting the scanning area by 200 device independent pixels from the bottom because a view is covering the bottom of the screen.
let view: DataCaptureView = ... view.scanAreaMargins = MarginsWithUnit(left: FloatWithUnit(value: 0, unit: .dip), top: FloatWithUnit(value: 0, unit: .dip), right: FloatWithUnit(value: 0, unit: .dip), bottom: FloatWithUnit(value: 200, unit: .dip))
If you want to adjust margins based on the view dimensions or orientation, e.g. to use different margins based on the device orientation, you can observe view size and orientation changes on the data capture view by registering a SDCDataCaptureViewListener on the data capture view.
Changing the Point of Interest
By default, scanning is optimized for the center of the visible part of the preview (or the center of the frame if the frame is not displayed in a SDCDataCaptureView). This is specified through what we call the point of interest. This point is also where code selection happens if it is enabled, more on that in the next section.
If you want to shift the scanning to another point, you can change the SDCDataCaptureView.pointOfInterest property. For example, the code below shifts the point of interest vertically to a fourth of the height:
let view: DataCaptureView = ... view.pointOfInterest = PointWithUnit(x: FloatWithUnit(value: 0.5, unit: .fraction), y: FloatWithUnit(value: 0.25, unit: .fraction))
When specifying fractions, they are relative to the visible area minus the margins. This means that a point of interest of 0.5/0.5 is always centered in the scan area defined through the size of the view and potentially added margins.
As indicated above, register a SDCDataCaptureViewListener on the data capture view to change the point of interest whenever the view dimension or orientation changes.
In case you are using multiple capture modes that care about the point of interest such as SDCBarcodeCapture and SDCTextCapture, you can overwrite the point of interest of the data capture view by setting the point of interest directly on the capture mode:
Location selection is not available for every SDCDataCaptureMode. This section will concentrate on SDCBarcodeCapture but it can be applied exactly the same to other modes that allow setting a SDCLocationSelection in their settings.
Sometimes it is necessary to let the user select which code to scan, e.g. to select one code from a dense stack of barcodes. Enabling full-image scanning is not desired in that case as any of the codes currently visible on screen could be returned as part of the results. To not return a random code but clearly target specific codes, a SDCLocationSelection can be set in the SDCBarcodeCaptureSettings. Location selections implement a specific strategy to select barcodes by their location.
Radius Location Selection
The SDCRadiusLocationSelection is the simplest and for barcode scanning the preferred way of location selection. It lets you define a radius around the point of interest (see previous section). Any barcode touched by the circle will be recognized and returned, any barcode not touched by the circle will be entirely ignored. Radius location selection can resolve all of the following scenarios that could not be handled properly with full-image scanning:
Selecting stacked codes, e.g. a sheet of vertically-stacked Code 128. Here the middle code will be returned as it is touched by the circle while the code above and below are not.
Selecting codes printed next to each other. Once again only the middle code is returned as it is the only one touched by the circle.
Both of those scenarios work with any symbology, here an example of Data Matrix codes printed next to each other.
As the code selection is done through a circle it works just as well for vertical codes, or codes at any other angle.
A SDCRadiusLocationSelection is created by specifying a radius and then setting it on the barcode capture settings with SDCBarcodeCaptureSettings.locationSelection. For example, the code below creates a radius location selection for a radius of 0 (a valid radius forcing barcodes to contain the point of interest):
let settings: BarcodeCaptureSettings = ... settings.locationSelection = RadiusLocationSelection(radius: .zero)
When choosing the radius it is important to consider two potential issues:
If the radius chosen is too large, it might often be touching multiple barcodes at the same time. In this case it is not a given that the central barcode will be returned and it is advicable to reduce the radius.
If the radius chosen is too small, higher precision is needed to touch a barcode. It can be helpful to the user experience to increase the radius in this case.
Rectangular Location Selection
The SDCRectangularLocationSelection lets you define the size of a rectangle around the point of interest (see previous section). Any code outside of the rectangle will not be recognized. One of the main use cases for the rectangular location selection is to restrict SDCTextCapture to only capture text inside a small area instead of the whole screen or restrict SDCBarcodeCapture to a small area if SDCRadiusLocationSelection is not a good fit.
A SDCRectangularLocationSelection is created by specifying the size of the rectangle and then setting it on the barcode/text capture settings with SDCBarcodeCaptureSettings.locationSelection. For example, the code below creates a rectangular location selection for a very thin area taking 10% of the view’s height and 90% of the view’s width:
let settings: BarcodeCaptureSettings = ... let size = SizeWithUnit(width: FloatWithUnit(value: 0.9, unit: .fraction), height: FloatWithUnit(value: 0.1, unit: .fraction)) settings.locationSelection = RectangularLocationSelection(size: size)
The size of the rectangle can also be set by only providing either the width or the height and then an aspect ratio to calculate the other dimension. This can be especially useful for defining a square area:
let settings: BarcodeCaptureSettings = ... let width = FloatWithUnit(value: 0.5, unit: .fraction) settings.locationSelection = RectangularLocationSelection(width: width, aspectRatio: 1)
Debugging The Scan Area And Location Selection
It can be important to visually debug the scan area to make sure that it is configured exactly how it should be.
To this purpose you can enable an overlay that visualizes everything that was set in the scan area through SDCBarcodeCaptureOverlay.shouldShowScanAreaGuides:
let overlay: BarcodeCaptureOverlay = ... overlay.shouldShowScanAreaGuides = true
The scan area including the margins by a light grey rectangle
The radius location selection by a green crosshair
The above visualization is for the following example settings:
let barcodeCaptureSettings: BarcodeCaptureSettings = ... barcodeCaptureSettings.locationSelection = RadiusLocationSelection(radius: FloatWithUnit(value: 5, unit: .dip)) let view: DataCaptureView = ... view.pointOfInterest = PointWithUnit(x: FloatWithUnit(value: 0.7, unit: .fraction), y: FloatWithUnit(value: 0.25, unit: .fraction)) view.scanAreaMargins = MarginsWithUnit(left: FloatWithUnit(value: 40, unit: .dip), top: .zero, right: FloatWithUnit(value: 40, unit: .dip), bottom: FloatWithUnit(value: 0.5, unit: .fraction))