
Recognition of barcodes and QR codes in UWP applications

I won’t discover America if I say that the most popular barcode recognition library is ZXing (“Zebra Crossing”). The list of supported formats is quite impressive and includes: EAN-8 and EAN-13, QR Code, UPC-A and UPC-E, Code 39, Code 93, Code 128 and others.
There is a port for WinRT, which means that the library can be used with the universal Windows platform.
PCL for barcode recognition is called ZXing.Net. The name seems to hint that you can use this library also with .Net applications
What immediately had to pay attention. If we take a simple photo, we usually don’t bother ourselves and just take a picture. If we process any image, it is necessary that the image quality is the best. Therefore, when initializing the camera, you must set the maximum possible resolution. To do this, use a code similar to the example code: Camera resolution sample
In addition, you must determine whether the device has a front or rear camera. This is not difficult:
var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation frontCamera = null;
DeviceInformation rearCamera = null;
foreach (var device in devices)
{
switch (device.EnclosureLocation.Panel)
{
case Windows.Devices.Enumeration.Panel.Front:
frontCamera = device;
break;
case Windows.Devices.Enumeration.Panel.Back:
rearCamera = device;
break;
}
}
Then you can initialize the media capture:
if (rearCamera != null)
{
await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings { VideoDeviceId = rearCamera.Id });
}
Setting permission is as follows:
public async Task SetResolution()
{
System.Collections.Generic.IReadOnlyList res;
res = mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo);
uint maxResolution = 0;
int indexMaxResolution = 0;
if (res.Count >= 1)
{
for (int i = 0; i < res.Count; i++)
{
VideoEncodingProperties vp = (VideoEncodingProperties)res[i];
if (vp.Width > maxResolution)
{
indexMaxResolution = i;
maxResolution = vp.Width;
}
}
await mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, res[indexMaxResolution]);
}
}
Image capture and recognition will happen something like this:
IRandomAccessStream fileStream = new InMemoryRandomAccessStream();
await mediaCapture.CapturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.CreateBmp(), fileStream);
string res = await BarcodeDecoder.DecodeStreamToBarcode(fileStream);
To recognize the stream, the BarcodeDecoder class , which was taken from Mike Taulty, is used.
The class code is hidden under the spoiler
internal static class BarcodeDecoder
{
static BarcodeReader barcodeReader;
static BarcodeDecoder()
{
barcodeReader = new ZXing.BarcodeReader();
barcodeReader.Options.PureBarcode = false;
barcodeReader.Options.Hints.Add(DecodeHintType.TRY_HARDER, true);
barcodeReader.Options.PossibleFormats = new BarcodeFormat[] { BarcodeFormat.QR_CODE,BarcodeFormat.All_1D };
barcodeReader.Options.TryHarder = true;
barcodeReader.AutoRotate = true;
}
public async static Task DecodeStreamToBarcode(IRandomAccessStream photoStream)
{
BitmapDecoder bitmapDecoder = await BitmapDecoder.CreateAsync(photoStream);
BitmapTransform emptyBitmapTransform = new BitmapTransform();
PixelDataProvider pixelDataProvider = await bitmapDecoder.GetPixelDataAsync(
BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Premultiplied,
emptyBitmapTransform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
var zxingResult = barcodeReader.Decode(pixelDataProvider.DetachPixelData(),
(int)bitmapDecoder.PixelWidth, (int)bitmapDecoder.PixelHeight, BitmapFormat.RGBA32);
string res = "";
if (!String.IsNullOrEmpty(zxingResult?.Text)) res = zxingResult?.Text;
return res;
}
}
This class recognizes QR_CODE and All_1D barcodes. In this case, All_1D includes the following formats: UPC-A, UPC-E, EAN-8 and EAN-13. You can also add other formats. Say the decoder we use supports the following formats: UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, Code 128, ITF, Codabar, MSI, RSS-14 (all options) , QR Code, Data Matrix, Aztec and PDF-417
This recognition method is well suited for existing images. If you use the camera, you will have to take many photos until you get a successful recognizable picture. In other words, the first pancake turned out to be lumpy, but some useful experience was obtained.
Code Recognition on the fly
As a result of intensive searches, the following VideoScanZXingWinRT repository was found , which was taken as the basis. Image capture comes from preview mode.
Here, a little belatedly, the realization came to me that a camera without focusing capabilities would not be able to take a normal macro shot. Theoretically, you can try to scan the barcode with phones with a camera without autofocus, but the chances are small. You can try it yourself. Focused cameras can support autofocus, and can focus in manual mode. For manual mode, I did auto-timer timer every 3 seconds.
In addition, the backlight was turned off, which created glare and interfered with recognition
if (mediaCapture.VideoDeviceController.FlashControl.Supported) mediaCapture.VideoDeviceController.FlashControl.Auto = false;
As a result of removing the superfluous and making corrections, we got such an example:
Barcode_Scanner_UWP I
invite everyone to join the project. I will be glad to improvements and adjustments.
For use in your project, you must add the BarcodeScannerControl.xaml user control along with C # code behind. Then, in the code of the page from which the call will come (in the example it is MainPage.xaml), add Popup with User Control inside
In this case, the width and height of the user control are tied to the size of the window container element named MainGrid.
You need to add 2 methods to the C # code. One will be called in case of a successful barcode search, the second in case of an error. The method signatures are such that the parameter of one is string, the parameter of the second exception. In the example, these are void BarcodeFound (string barcode) and void OnError (Exception e) .
Now you can open Popup and execute a method that launches a preview of the image from the camera and scanning the barcode:
BarcodePopup.IsOpen = true;
await barcodecontrol.StartScan(BarcodeFound, OnError);
One thing to keep in mind is the life cycle of a UWP application. In our case, if the application enters the “paused” state, it is necessary to stop the process of viewing the picture from the camera, searching for a barcode and closing Popup. That is, add the following code:
private async void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
await barcodecontrol.Cleanup();
BarcodePopup.IsOpen = false;
deferral.Complete();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Application.Current.Suspending += App_Suspending;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
Application.Current.Suspending -= App_Suspending;
}
Now about the cons. One minus - the ZXing.Net library has not been updated for 2 years. Although, on the other hand, if it works without bugs and new functions are not needed, then perhaps there is nothing wrong with that. The project is unofficial, so work on it goes when developers have free time. A site on the old-school Codeplex shows signs of life for itself. On it you can find the source code. The good news is that an update of the library itself is planned in the near future, that is, the project is not abandoned.