ZXing 2.0 – Windows Phone 7 library 11

This weekend I’ve spent some good hours into porting the ZXing 2.0 library to a Windows Phone 7 library as well as a simple library called SimpleCameraReader that makes scanning for codes with the in-built camera an ease! Look forward to the next post for how to use the SimpleCameraReader.

So what is ZXing? Taken from the official homepage for the library:

[box icon="info"]ZXing (pronounced “zebra crossing”) is an open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. Our focus is on using the built-in camera on mobile phones to scan and decode barcodes on the device, without communicating with a server. However the project can be used to encode and decode barcodes on desktops and servers as well. We currently support these formats:

  • UPC-A and UPC-E
  • EAN-8 and EAN-13
  • Code 39
  • Code 93
  • Code 128
  • ITF
  • Codabar
  • RSS-14 (all variants)
  • QR Code
  • Data Matrix
  • Aztec (‘beta’ quality)
  • PDF 417 (‘alpha’ quality)

[/box]

There’s a C# version for ZXing 2.0 which I used as a base (I’m hoping to rewrite the whole thing) in which I had to fix around 400-500 errors before it could compile as a Windows Phone 7 class library. The C# version also seems to be ported using a Java to C# tool so the codebase was a bit messy. I’ve fixed parts of it, trying to change and use newer techniques where I had the opportunity. That said, I haven’t gone through all the files and made changes so there’s plenty of room for improving!

View the zxingwp7 library on Github!

Or download the binaries!

How do I use it?

When I first looked up how to use zxing in Windows Phone 7 I stumbled a cross a really nice guide showing you all the steps you need (the steps all apply with my port too!) to get your app scanning for codes using an older version of the ZXing library. You can check it out here. It’s wrriten by Jonas Follesø and is an excellent example of how to use both the old library and mine.

The first thing you want to do is create a new Windows Phone 7 application and reference the zxingwp7 library which you can download here.

Next up is editing the MainPage.xaml and replace the LayoutRoot grid with the following code (Sorry Jonas, I’m copying your code!)

[box]

MainPage.xaml


<Grid x:Name="LayoutRoot" Background="Transparent">
    <Rectangle x:Name="_previewRect"
               Margin="0"
               Height="800"
               Width="600"
              HorizontalAlignment="Center"
               VerticalAlignment="Center">
       <Rectangle.Fill>
           <VideoBrush x:Name="_previewVideo">
                <VideoBrush.RelativeTransform>
                   <CompositeTransform
                        x:Name="_previewTransform" CenterX=".5" CenterY=".5" />
                </VideoBrush.RelativeTransform>
            </VideoBrush>
        </Rectangle.Fill>
    </Rectangle>
    <ListBox Margin="10" x:Name="_matchesList" FontSize="30" FontWeight="ExtraBold" />
</Grid>

[/box]

What’s happening here is that we’re creating a Rectangle element that will hold our camera feed and specify that our rectangle’s fill should be a new element, VideoBrush. VideoBrush lets you paint any XAML element using a video source, which comes in handy when we want to display the camera feed. Then we apply a CompositeTransform that lets us rotate the VideoBrush-element to match the cameras orientation depending on how we’re holding the phone. In essence, this means that you can turn your phone around and it will always end up showing correctly.

Next step is to implement some functionality; initiating our camera and connect the camera to our VideoBrush element!

[box]

MainPage.xaml.cs


        private readonly DispatcherTimer _timer;
        private readonly ObservableCollection<string> _matches;

        private PhotoCameraLuminanceSource _luminance;
        private QRCodeReader _reader;
        private PhotoCamera _photoCamera;

       public MainPage()
       {
            InitializeComponent();

           _matches = new ObservableCollection<string>();
            _matchesList.ItemsSource = _matches;
            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(250);
            _timer.Tick += (o, arg) => ScanPreviewBuffer();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            _photoCamera = new PhotoCamera();
            _photoCamera.Initialized += OnPhotoCameraInitialized;
            _previewVideo.SetSource(_photoCamera);

            CameraButtons.ShutterKeyHalfPressed += (o, arg) => _photoCamera.Focus();

            base.OnNavigatedTo(e);
        }

[/box]

In this snippet we instantiate a ObservableCollection to hold our results, a timer that will on a reguler basis scan the camera feed for codes, our PhotoCamera object that talks directly to the Camera on WP7 and in this instance a QRCodeReader which can detect and decode QR codes from a image.

The nice thing about ObservableCollection in case you haven’t used it before is that when you add or remove items from it, it will notify the component that is bound to the ObservableCollection that it needs to update. That means when we add an item to our _matches object it will automatically popup in the Listbox without us having to tell our Listbox that it needs to update. Handy little thingie.

In our constructor we set up our ObservableCollection (_matches) and databind it to our ListBox (_matchesList.ItemsSource = _matches) as well as setting up our timer with interval of 250 milliseconds. The tick event fires off every 250 milliseconds and will then call a method called ScanPreviewBuffer() which we will take a look at in a bit. Notice that the timer hasn’t started yet; we have to call _timer.Start(); before it will start ticking. You will see how this is done in a bit.

The next method is an overriden event-method inherited from the PhoneApplicationPage class. This method gets called when this page gets navigated to and it’s here we’ll setup our Camera and bind it to our VideoBrush element. We create a new instance of PhotoCamera and bind to the Initialized event that gets fired when the camera is ready to go.

[box]


_previewVideo.SetSource(_photoCamera);

[/box]

Here’s the code that tells our VideoBrush to use our PhotoCamera as it’s video source.

[box]


CameraButtons.ShutterKeyHalfPressed += (o, arg) => _photoCamera.Focus();

[/box]

This piece of code tells that when you half-press the camera button it should start the auto-focus process.

The next step is to set up our QRCodeReader and start the timer when the Camera has initialized:

[box]

MainPage.xaml.cs


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

            _luminance = new PhotoCameraLuminanceSource(width, height);
            _reader = new QRCodeReader();

            Dispatcher.BeginInvoke(() => {
                _previewTransform.Rotation = _photoCamera.Orientation;
                _timer.Start();
            });
        }

[/box]

When the camera has initialized we create a new instance of PhotoCameraLuminanceSource with the width and height of the preview resolution. The class inherits from LuminanceSource and is responsible for extracting luminance data from an image. Next up we create an instance of QRCodeReader which is responsible for detecting and decoding the image to scan for a QR code. I’ll show you later on how to read other formats as well! When it’s all set up we use the Dispatcher to invoke the next methods (get our code to run on the UI-thread instead of the thread that the Camera runs on). We set the rotation of the preview and start our timer.

[box]

MainPage.xaml.cs


private void ScanPreviewBuffer()
        {
            try
            {
                _photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
                var binarizer = new HybridBinarizer(_luminance);
                var binBitmap = new BinaryBitmap(binarizer);
                var result = _reader.decode(binBitmap);
                Dispatcher.BeginInvoke(() => DisplayResult(result.Text));
            }
            catch
            {
            }
        }

        private void DisplayResult(string text)
        {
            if(!_matches.Contains(text))
                _matches.Add(text);
        }

[/box]

The ScanPreviewBuffer is the method where all the magic happens. To best explain the process I’m going to copy the description from Jonas Follesø’s guide:

[box icon="info"]

The GetPreviewBufferY method takes a byte array as its parameter and will populate this byte array with the luminance data from the preview buffer. We pass in the PreviewBufferY property from the PhotoCameraLuminanceSource. Once we have captured the luminance data we create a HybridBinarizer and a BinaryBitmap. They are part of the ZXing library. I haven’t worked enough with ZXing yet to fully understand the architecture, but these classes are steps the luminance data pass through before being passed to the decode method of the QRCodeReader. If the decode is successful the decoded text is added to the ObservableCollection, which in turn will update the ListBox. The QRCodeReader decode method will throw an exception if it is not able to decode the image, so we need to wrap the code in a try-catch block.

[/box]

And that’s all there is for a simple QR code scanning app. Try it!

You can download the tutorials source code here.

So, where to go from here?

I’ve only shown how to scan QR codes, but the library has a ton of other formats as shown in the start of this post. To get the individual readers for each format just replace QRCodeReader with EAN13Reader or EAN8Reader for European product barcodes. If you want to create an app that can scan for multiple codes at the same time you can use the MultiFormatReader. This one requires a little bit of extra effort of adding what formats to scan for but it’s really simple.

[box]


var multiReader = new MultiFormatReader();

var formats = new List<BarcodeFormat>
    {BarcodeFormat.QR_CODE, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8, BarcodeFormat.UPC_A};

var hints = new Dictionary<DecodeHintType, Object>();
hints.Add(DecodeHintType.POSSIBLE_FORMATS, formats);

multiReader.Hints = hints;

multiReader.decodeWithState(binBitmap);

[/box]

For the MultiFormatReader we need to create a list of type BarcodeFormat of the formats we want to include in the scan, and then create a Dictionary of type DecodeHintType as the key and Object as value. We add our formats to the hint dictionary with DecodeHintType of POSSIBLE_FORMATS. We could also add another hint for the Reader to try harder:

[box]


hints.add(DecodeHintType.TRY_HARDER, true);

[/box]

That’s all there is to set that up, and replace _reader.decode(binBitmap) with multiReader.decodeWithState(binBitmap); — The decodeWithState tells the MultiFormatReader to use our hints.

If you want to include all the formats then I’ve added an extra touch to the ZXing library; just replace var formats = … with:

[box]


var formats = BarcodeFormat.AllFormats;

[/box]

That’s pretty much there is for a basic barcode scanning app. There’s a bit of code to get it done but if you check my blog in a couple of days I’ll have a tutorial up explaining how to use my SimpleCameraReader class for simplifying the process a bit. If you’re eager you can check it out at Github already! Just click here

11 thoughts on “ZXing 2.0 – Windows Phone 7 library

  1. Pingback: SimpleCameraReader – easy to use wrapper class for ZXing 2.0 for WP7 « henning.ms

  2. Reply Michael Feb 22, 2012 22:23

    Hi,

    I’m not sure if it would be an option for you but there are some ready-to-use wp7 versions of zxing out there.
    I started a fork of the C# port too which you can find here:
    http://zxingnet.codeplex.com/
    Currently it is completely synchronized with the development of the java version.

    Regards,
    Michael

  3. Reply henning.ms Feb 22, 2012 22:43

    Hi Michael!

    That’s awesome :) When I searched for ZXing WP7 I couldn’t find any up-to-date version (I might have done a lousy search). So for that I ended up just porting the Java version to have the core-library available and then creating the SimpleCameraReader-library for easy decoding using that and it works quite well.

    Thanks for the tip! I will be sure to watch closely :)

  4. Reply ranouf Jun 13, 2012 14:41

    Hi the option BarcodeFormat.AllFormats doesn’t exists in my version (I use nugget to get Zxing)

  5. Reply henning.ms Jun 13, 2012 14:46

    Hi ranouf!

    For this to work you’ll have to use the version I supply here I’m afraid :)

  6. Reply Tomas Jun 17, 2012 05:51

    Hi there! Do you know some way to improve the performace of the Scanner? i see some others that decode faster or leave the space with more light in the rectangle of the QRCODE . If know, it would be nice to improve it. Thank You!

  7. Reply Tomas Jun 17, 2012 07:26

    If you would want to personalize what happen with each Type of Code (Text,URL,ContactInfo…) where in this code (the simpleCamerReader code) would you can check the type of the QR you just decoded? Thanks for this info it has been really helpfully.

  8. Reply Zauk Aug 10, 2012 12:51

    HI, I am facing problems in configuring it for MultiformateReader,
    Can you tell me what is problem there?
    Please follow this question:
    http://stackoverflow.com/questions/11898693/multiformatereader-is-not-working

    Thanks

  9. Reply alessio Apr 17, 2013 17:42

    Hi all

    I’m facing the following exception during datamatrix scanning, have you ever found this error?

    at zxingwp7.datamatrix.detector.Detector.detect()
    at zxingwp7.datamatrix.DataMatrixReader.decode(BinaryBitmap image, Dictionary`2 hints)
    at zxingwp7.datamatrix.DataMatrixReader.decode(BinaryBitmap image)

    thanks

  10. Reply henning.ms Apr 20, 2013 17:51

    Hi Alessio!

    I haven’t encountered that error no, so thank you for spotting it! :) Have you taken a look at the source code and found a solution?

  11. Reply chwilówki Jun 6, 2013 19:25

    Woah! I’m really digging the template/theme of this site. It’s simple, yet effective.A lot of times it’s hard to get that “perfect balance” between user friendliness and visual appearance. I must say that you’ve done a amazing job with this. Additionally, the blog loads super fast for me on Opera. Superb Blog!

Leave a Reply

  

  

  


*