Mobile Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Tip of The Day: Know The Fast Way To Scan Codes With Silverlight ZXing on Windows Phone

04.05.2013
| 3114 views |
  • submit to reddit

There is a popular open-source library that gives developers the ability to scan QR and barcodes - ZXing (pronounced "Zebra Crossing"). There is also a popular port of the project that can be used in the context of Windows Phone applications - Silverlight ZXing. Obviously, you can and should get the package from NuGet.


Assuming that you got the package installed and ready in your application, let's see how codes can be scanned. To make sure that I am not interfering with any other parts of my application, I delegated the task of showing the camera stream to a secondary page - CapturePage.xaml. Feel free to add one yourself, if the application needs it. If not, just use the main page instead.

The skeleton of the page itself should be very simple - you will only need a VideoBrush, and that can be set as the root grid background:

<Grid x:Name="LayoutRoot">
    <Grid.Background>
        <VideoBrush x:Name="coreBrush"></VideoBrush>
    </Grid.Background>
</Grid>

This will result in a somewhat skewed image, so you might want to add a transform to it.

<Grid x:Name="LayoutRoot">
    <Grid.Background>
        <VideoBrush x:Name="coreBrush">
            <VideoBrush.RelativeTransform>
                <CompositeTransform  
                    x:Name="brushTransform" CenterX=".5" CenterY=".5" />
            </VideoBrush.RelativeTransform>
        </VideoBrush>
    </Grid.Background>
</Grid>

In the code-behind, we will be operating with 4 core objects:

private DispatcherTimer _timer;
private PhotoCameraLuminanceSource _luminance;
private Reader _reader;
private PhotoCamera _photoCamera;

The DispatcherTimer will be used to perform a constant scan of the stream and passing the data to the code reader. PhotoCameraLuminanceSource is used by SilverlightZXing to process the incoming stream and transform the incoming buffer in order to be able to read it. The implementation I am using is available here.

The Reader instance is the core class that allows code processing. Instead of directly using a restricted type, such as QRCodeReader, I am using the interface that would allow me to swap types when necessary. 

NOTE: The interface here is incorrectly named Reader, when it should be IReader. This is established in the C# Interface Naming Guidelines.

Last but not least, PhotoCamera is used to get the visual and binary representation of the incoming camera stream.

When the page is loaded, the timer is initialized and a proper function is assigned to handle the Tick event:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    try
    {
        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(300);
        timer.Tick += (o, arg) => Scan();

        camera = new PhotoCamera();
        camera.Initialized += OnPhotoCameraInitialized;
        coreBrush.SetSource(camera);

        CameraButtons.ShutterKeyHalfPressed += (o, arg) => camera.Focus();
    }
    catch
    {
        
    }
    base.OnNavigatedTo(e);
}

It is important to highlight the fact that I am using 300ms time intervals to capture the image. Per-se, there is no requirement as to what this interval should be, but you need to play around to estimate the appropriate value for your specific application. Take into consideration the fact that because it takes some time for the reader to process the code from the image, there will be a lag between the capture and code recognition. 

There is the standard camera initialization routine that would give me image of what the user sees on the screen:

private void OnPhotoCameraInitialized(object sender, CameraOperationCompletedEventArgs e)
{
    try
    {
        int width = Convert.ToInt32(camera.PreviewResolution.Width);
        int height = Convert.ToInt32(camera.PreviewResolution.Height);

        luminance = new PhotoCameraLuminanceSource(width, height);
        reader = new QRCodeReader();

        Dispatcher.BeginInvoke(() =>
        {
            try
            {
                brushTransform.Rotation = camera.Orientation;

                if (timer != null)
                {
                    timer.Start();
                }
            }
            catch
            {
                // camera disposed.
            }
        });
    }
    catch
    {

    }
}

Here you have options. First of all, I am using QRCodeReader as the receiver class. Restricting this type to a single type of codes to be read allows me to have a relatively fast image processing turnout. I could use a com.google.zxing.oned.MultiFormatOneDReader which would allow me to scan any of the supported one-dimensional codes. As I mentioned earlier in this article, I can easily assign a new instance of this type to reader because it is going to be an inteface-based assignment, and MultiFormatOneDReader implements Reader.

With the default constructor, you will need to pass a dictionary that will indicate which codes should be scanned. With the current implementation, you will have to pass a dictionary with a DecodeHintType.POSSIBLE_FORMATS key and a List<DecodeHintType> as a bound value to show which types to scan for.

NOTE: Yes, I know this implementation can be optimized by simply having a flag-based constructor (e.g. something alike is used in .NET Reflection).

But here is a problem - because of the performance lag in Silverlight ZXing, there is a huge delay between the capture and full processing. Once you scan the frame, it might take up to 5 or 10 seconds to get a result from the frame, given that the frame itself was captured properly, which in most cases is not - you need a steady shot. While the processing mechanism will try to decode the image, the camera will be many frames ahead, and this creates an unnecessary overhead.

My recommendation here - if you are using Silverlight ZXing, make sure that you restrict the types of codes that you scan through a single frame cycle. To do this, use code-specific implementations:

  • QRCodeReader
  • Code128Reader
  • EAN13Reader
  • EAN8Reader
  • UPCAReader
  • UPCEANReader
  • UPCEReader
From the user's perspective, implement a switch that would let the user choose what codes should be scanned. If it is an application that can scan both QR codes and bar codes, a toggle control in the viewport might be helpful, considering the performance impact of a single scan.

So what happens when the timer goes through each iteration? Obviously, Scan:

private void Scan()
{
    try
    {
        camera.GetPreviewBufferY(luminance.PreviewBufferY);
        var binarizer = new HybridBinarizer(luminance);
        var binBitmap = new BinaryBitmap(binarizer);
        var result = reader.decode(binBitmap);

        timer.Stop();
        VerifyScannedItem(result.Text);
    }
    catch
    {
    }
}

The try/catch block here is necessary because in the current implementation, the reader will throw an exception if a code is not recognized. Because when the code is scanned you might want to take an action, the timer is stopped, after which VerifyScannedItem is invoked. On its completion, the timer can be reset.

As I mentioned in my previous article, make sure to disable the timer when you are navigating away from the page.