I will not 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 make a simple photo, we usually do not bother ourselves and just take a picture. If we process a snapshot, it is necessary that the quality of the image is the best. Therefore, when you initialize 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. It 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 media capture:
if (rearCamera != null) { await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings { VideoDeviceId = rearCamera.Id }); }
Setting the resolution is as follows:
public async Task SetResolution() { System.Collections.Generic.IReadOnlyList<IMediaEncodingProperties> 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]); } }
Capture and image recognition will be something like this:
IRandomAccessStream fileStream = new InMemoryRandomAccessStream(); await mediaCapture.CapturePhotoToStreamAsync(Windows.Media.MediaProperties.ImageEncodingProperties.CreateBmp(), fileStream); string res = await BarcodeDecoder.DecodeStreamToBarcode(fileStream);
For stream recognition, the
BarcodeDecoder class is
used , which was taken from
Mike Taulty
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<string> 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; } }
In this class, barcodes of QR_CODE and All_1D formats are recognized. In this case, All_1D includes the following formats: UPC-A, UPC-E, EAN-8 and EAN-13. You can add more formats. Let's 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 method of recognition is well suited for existing images. If you use a camera, you will have to take a lot of photos until you get a successful recognizable image. In other words, the first pancake turned out to be a lump, 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 a basis. Image capture comes from preview mode.
Here, a little bit late, the realization came to me that a camera without focusing capabilities would not be able to take a normal macro photograph. Theoretically, you can try to scan the barcode and phones with a camera without autofocus, but the chances are small. You can try it yourself. However, cameras with focusing can support autofocus, and they can also focus in manual mode. For manual mode, I made a timer autofocus every 3 seconds.
In addition, the backlight was turned off, which created glare and interfered with the recognition
if (mediaCapture.VideoDeviceController.FlashControl.Supported) mediaCapture.VideoDeviceController.FlashControl.Auto = false;
As a result of removing the excess and making corrections, this is the example:
Barcode_Scanner_UWP
I invite everyone to join the project. I will be glad to improvements and adjustments.
To use it in your project, you need to add the BarcodeScannerControl.xaml user control along with C # code behind. Then, in the code for the page from which the call will occur (in the example, this is MainPage.xaml), add a Popup with a User Control inside
<Popup x:Name="BarcodePopup" IsOpen="False" IsLightDismissEnabled="False"> <Grid> <local:BarcodeScannerControl x:Name="barcodecontrol" Width="{Binding ElementName=MainGrid,Path=ActualWidth}" Height="{Binding ElementName=MainGrid,Path=ActualHeight}"></local:BarcodeScannerControl> </Grid> </Popup>
In this case, the width and height of the user control are tied to the size of the window container element named MainGrid.
In the C # code you need to add 2 methods. One will be called in case of a successful barcode search, the second in case of an error. The signatures of the methods are such that the parameter of one is string, the parameter of the second exception. In the example, this is void
BarcodeFound (string barcode) and
void OnError (Exception e) .
Now you can open the Popup and execute the method that launches the 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 “suspended” state, it is necessary to stop the process of viewing the image from the camera, searching for the barcode and closing the Popup. That is, add this 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 minuses. Minus one, - ZXing.Net library has not been updated for 2 years. Although on the other hand, if it works without bugs and does not need new functions, then perhaps there is nothing wrong with that. The project is unofficial, so work on it goes when developers have free time. The site on the old school
Codeplex is quite a sign of life. You can also find the source code on it. The good news is that the library itself is planned to be updated in the near future, that is, the project is not abandoned.