Reading QRCode with Windows 8 RC

[UPDATE: for latest code to build your Windows 8 app with a QR Code reader, please have a look here]

I have been looking around the web for reading a QR Code from the camera of their Windows 8 device.

No luck I found nothing that was looking in that direction.

So I just take the ZXing barcode scanning library from Codeplex, modified it a bit, but the biggest part was around getting the output of the webcam as stream to get frames from it and send it over to this barcode library.

First problem, Windows 8 doesn’t support getting frames out of Video stream from managed code.

I am not really in the mood of writing C++ right now, so I just used the MediaCapture.CapturePhotoToStreamAsync method to get periodically the image from the webcam and send it over to the QRCodeReader.

Second problem, the stream received by the CapturePhotoToStreamAsync method is a BMP format in my case, and Windows 8 doesn’t expose a lot of ways to manipulate bits within the image, especially in the case I need luminance from the BMP ARGB format.

I ended up skipping the first 54 bytes of the stream (BMP header bytes) and then reading against all values to create a luminance byte array to give to the QRDecoder (that only work with luminance actually).

The last trick I tried to sue was to display a preview video stream on the screen while getting images from the photo stream, but even though Windows 8 doesn’t crash when creating, initializing and reading from multiple MediaCapture objects, it actually doesn’t display anything on the video stream part.

At the end the solution I am sharing here is displaying the same image used for scanning he barcode, which explain quite some latency between displays.

Feel free to use it and to share it for optimizing it a little bit 🙂

UPDATE: I just completely rewrote the code in a more WinRT (async await) way, which gives the app far more responsive for scanning QR Codes!!

Code sample here.

30 thoughts on “Reading QRCode with Windows 8 RC

  1. hey I am glad that you giving out the interesting codes. I have tried the codes but it isn’t work. Why? Please help me out. Thanks

  2. Hey there,

    Just saying it’s not working will not help me to help you 🙂
    Do you any error message? What is actually not working?

    Cheers, Ben

  3. An exception of type ‘com.google.zxing.ReaderException’ occurred in Silverlight.DLL but was not handled in user code

  4. The ZXing library is raising an exception when the given image is not containing a readable QR code, which is pointing out that your Visual Studio setup is configured to break on any exception, handled or not.
    Please into the Debug menu -> Exceptions…, and uncheck all checkboxes in the Thrown column.
    That should do the trick 🙂

  5. Hi Benjamin,

    I am getting exception like “An unhandled exception of type ‘System.Exception’ occurred in mscorlib.dll.Additional information: Exception from HRESULT: 0xC00DABE0”

    Thanks,
    Kishore

  6. Hello Benjamin,

    I was trying to get the QRCodeReader, to decode an image that i added to the project, So hear’s what i’ve done so far:


    StorageFile st = await Package.Current.InstalledLocation.GetFileAsync(@"Alec-Bradley-QR-Code.bmp");
    _imageStream = new InMemoryRandomAccessStream();
    Stream s = await st.OpenStreamForReadAsync();
    s.CopyTo(_imageStream.AsStreamForWrite());
    _datareader = new DataReader(_imageStream.GetInputStreamAt((ulong)54));

    The problem is when getting “luminanceBits[]” I have 2 more/less bits, and that is driving the code to throw an exception “attempted to access data outside the valid range”.
    I am running out of ideas here….. don’t no if skipping 54 bits is the wrong thing or the way i am getting the stream. What’s wrong ?

    (Thank you !)

  7. Hello,

    I managed to get the InMemoryAccessStream from the image and this is what i’ve done:


    StorageFile file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("Alec-Bradley-QR-Code.bmp");
    _imageStream = new InMemoryRandomAccessStream();
    using (var inputStream = await file.OpenReadAsync())
    {
    await RandomAccessStream.CopyAsync(inputStream, _imageStream);
    }
    _imageStream.Seek(0);

    After getting the stream and the bitmapImage (i get the width and height of the image), I reset the following variables => ‘_dimensions’ ‘_encodingProps’ .

    Now I’m getting this error after decoding the bar-code : ” Index was outside the bounds of the array.” Will keep this topic updated 😉 …

  8. Hi Guys,

    I am trying the same. Do you guys have any success in scanning the QR code image?
    I am trying with a sample image which has QR code in it.

    Thanks & Regards,
    Suman

  9. Hello,
    Great work porting this library to WinRT! However, I was unable to run the sample app. It crashes with an unhandled exception in the _capture.InitializeAsync() line…
    Nevertheless, I wrapped the encoding features of your zxing port into a new library, which I plan to publish on my blog soon.. It features a Task to generate QR codes in one line of code.. If you might want to see the code, or prefer a way to credit you as the one who did the complicated part, just drop me an email =)
    I’d really like to wrap the decoding mechanism as well, but..

    greetings,
    ~theCake

  10. Hello,

    I have tried your sample but the problem is that I always get the “Exception of type ‘com.google.zxing.ReaderException’ was thrown.” at the QRCodeReader decode and the result is always an empty string. I have not managed to read a QR Barcode yet! Do you have any clue why I can’t get a result?

    @”theCake” : You should not run the project to a simulator. Check it!

  11. Thanx for the response!

    Yes I have already made these changes.

    The problem is that in the ReedSolomonDecoder.cs the findErrorLocations functions always throws an “throw new ReedSolomonException(“Error locator degree does not match number of roots”)” because the int e is never equal to the numErrors and then everything breaks!

    Can you figure out what is going on?

  12. Hi Benjamin I am using this code

    using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
    {
    // Set the image source to the selected bitmap
    BitmapImage bitmapImage = new BitmapImage();
    bitmapImage.DecodePixelHeight = decodePixelHeight;
    bitmapImage.DecodePixelWidth = decodePixelWidth;
    bitmapImage.SetSource(fileStream);
    var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0));
    await reader.LoadAsync((uint)fileStream.Size);
    byte[] pixels = new byte[fileStream.Size];
    reader.ReadBytes(pixels);
    com.google.zxing.LuminanceSource source = new RGBLuminanceSource(pixels, bitmapImage.DecodePixelWidth,
    bitmapImage.DecodePixelHeight);
    var binarizer = new HybridBinarizer(source);
    var binBitmap = new BinaryBitmap(binarizer);
    var qrRead = new com.google.zxing.oned.MultiFormatUPCEANReader(zxingHints); ;
    var results = qrRead.decode(binBitmap);
    }

    I am trying your project for decoding barcode, but I am getting exception in decode function of OneDReader class. Any help?

  13. Hi,

    I’ve tried to use the code to scan barcodes instead of QR codes but I keep getting reader errors. Do you know if there are any issues with the MultiFormatReader?

  14. Hi folks,
    This code is provided as an example, and therefore you should have to check against your image binary content to see where is the issue is coming from.
    As far as I looked at it, the ZXing lib is working pretty fine even with an image opened from the file-system 🙂

    Cheers, Ben

  15. hi Benjamin,

    I go through your sample code which is absolutely fine for camera reading.

    but I want to encode QRCode depends on user inputs.
    I know how to call encode function but how to form image after getting BitMatrix in WIRT ?

    Could you please guide me for this ?

  16. Hi Benjamin,

    thanks for your great work and the help you provide to users astonishingly quick!

    There is only one silly question, which might seem a bit off topic:
    Wouldn’t it be possible to change the project output “Silverlight.DLL” to something more expressive like e.g. bsQRLib or bsQRLibrary_ZXingPort?
    “Silverlight” is a very general term and a registered trade mark, so using it could lead to confusion (what exactly does this DLL do?) or other problems.

    This said, I really don’t want to appear petty, but rather help to earn your project the respect it deserves, by suggesting to use your OWN NAME (hence the bs prefix) and set it seperate from other projects that might also use “Silverlight” in any other form.

    Cheers,

    Scruff.R

  17. Hello Vivek,

    This is acutally something put aside from C# here, for good performance reasons; this points to doing this in C++ instead.
    Don’t forget that my lazyness led me to do it this way, but the best way would still be to do all the image handling in C++ and then only do the image QRCode mapping in C#.

    Still, if wou want ot have a look at doing bitmap matrix manipulation in C# you definitely need t have a look here, this project actually is an implementation of the missing pieces of Bitmap manipulation in C#.

    Cheers,
    Ben

  18. Hello Scruff,

    That’s a good point, I’ll be doing something around this soon (next 2 weeks time I hope); check back then for new package 🙂

    Cheers,
    Ben

  19. Hi Ben,

    now some C# stuff.
    While playing a bit with your code, I stumbled over the really slow RGBLuminanceSource(WritableBitmap, int, int) and RGBLuminanceSource(byte[], int, int) didn’t work for me either (same as e.g. post of Adi 16.8. 11:55).
    After reading some comments dealing with these problem in the original ZXing.Net forum, too, I slightly tweaked your code of RGBLuminanceSource into an ARGBLuminanceSource and avoided the time consuming GetPixeli(x,y) by reusing the (byte[], int, int) constructor.

    public ARGBLuminanceSource(byte[] d, int W, int H) : base(W, H)
    {
    __width = W;
    __height = H;
    int pixelCount = W * H; // can forget about 2D (might save time building product W*H over and over again)
    int posSource = 0; // incremenal cursor instead of permanently calculating position might save time
    // additionally rids us of the need to know number of bytes per pixel (add or remove an ++)
    int r, g, b; // declare only once (might save time?)

    // In order to measure pure decoding speed, we convert the entire image to a greyscale array
    // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
    luminances = new sbyte[pixelCount];

    // drop extra loop (might save time?)
    for (int posTarget = 0; posTarget > 2);
    }
    }
    }

    public ARGBLuminanceSource(WriteableBitmap d, int W, int H) : this(d.ToByteArray(), W, H) { }

    Cheers,
    Scruff.R

  20. I am also receiving the following error:

    An exception of type ‘com.google.zxing.ReaderException’ occurred in Silverlight.DLL but was not handled in user code

    All of the debug exceptions in the thrown column are not checked.

    I put a try catch around this statement in mainpage.xaml.cs

    Result r = c.decode(bbm);

    if (!String.IsNullOrEmpty(r.Text))
    {
    result = r.Text;
    }

    In the hopes it would ignore the error.

    Any other ideas? I am running VS2012.

    Thanks! You really did a great job here!

  21. I can never get it to read a QR Code. The same as @Chris.

    Here is the image file: http://sensorytech.net/photo%20(63).jpg

    But I got around the getPixel slowness by converting the WriteableBmp into a byte[]

    Stream stream = wb.PixelBuffer.AsStream();
    byte[] pixels = new byte[stream.Length];
    stream.Seek(0, 0);
    stream.Read(pixels, 0, pixels.Length);

    com.google.zxing.LuminanceSource source = new RGBLuminanceSource(pixels, wb.PixelWidth, wb.PixelHeight);

  22. The problem has to do with the colors. From a bitmap using zxing library my first color of my image at (x,y) = (0,0) = R:78, G:10, B:6 but from the writeablebitmap at (0,0) = R:109,G:47,B:24. I am thinking it is the wrong colorspace. Like one is BGR and the other is RGB.

    The FinderPatternInfo never finds any possible centers so never locates the bar code.

    It fails at this line:

    // A winner?
    if (foundPatternCross(stateCount))

    Because the colors are wrong. I am trying to work through the issue but if you guys are better image processors than I am that would be great.

  23. Okay I can finally read a bar code. Feel free to enhance this code but here is how I did it. I added a routine to take the Writeablebitmap into the Sbyte array of luminances.

    private sbyte[] GetLuminance(WriteableBitmap modifiedImage)
    {
    int r = 0, a = 0, i = 0;
    int h = modifiedImage.PixelHeight;
    int w = modifiedImage.PixelWidth;
    Stream stream = modifiedImage.PixelBuffer.AsStream();
    byte[] StreamBuffer = new byte[stream.Length];
    //byte[] tempbuffer = new byte[64000];
    stream.Seek(0, 0);
    stream.Read(StreamBuffer, 0, StreamBuffer.Length);

    sbyte[] luminances = new sbyte[w * h];
    int currentX = 0;
    int currentY = 0;

    for (i = 0; i < StreamBuffer.Length – 4; i = i + 4)
    {
    var a1 = StreamBuffer[i + 3];
    var r1 = StreamBuffer[i + 2];
    var g1 = StreamBuffer[i + 1];
    var b1 = StreamBuffer[i + 0];

    a = 0xff;

    currentX = (i / 4) % w;
    currentY = (i / 4) / w;
    int offset = currentY * w;

    luminances[offset + currentX] = (sbyte)(((int)r1) << 16 | ((int)g1) << 8 | ((int)b1));
    }
    //stream.Seek(0, 0);
    //stream.Write(StreamBuffer, 0, StreamBuffer.Length);
    stream.Dispose();
    modifiedImage.Invalidate();
    return luminances;
    }

    Then I created an overridden method in RGBLuminanceSource.cs

    public RGBLuminanceSource(sbyte[] d, int W, int H, bool Is8Bit)
    : base(W, H)
    {
    __width = W;
    __height = H;
    luminances = d;
    }

    Then I call it like this:

    StorageFile file = await StorageFile.GetFileFromPathAsync(pImageFilePath);

    WriteableBitmap wb = new WriteableBitmap(1, 1);
    wb = await wbm.FromStream(await file.OpenReadAsync());

    com.google.zxing.LuminanceSource source = new RGBLuminanceSource(GetLuminance(wb), wb.PixelWidth, wb.PixelHeight,true);
    var binarizer = new HybridBinarizer(source);
    var binBitmap = new BinaryBitmap(binarizer);

    returnValue = reader.decode(binBitmap).Text;

    Yeah! So excited!

  24. Hello Linda,

    I came up the the same conclusion; I actually found a really faster method to get Bitmap bytes using the BitmapDecoder object.
    But for some reasons the bits given by the BitmapDecoder class against my old slow parsing with DataReader is not giving me the same Bitmap bytes at all!

    This means additional time would be needed to find an acccurate way to either get those bits right or to find the good values for building up the luminance table used by ZXing.

    Cheers,
    Ben

  25. I need some more time to mess with it but I had this code commented out. It is probably something along these lines where you have to switch the colors.

    // Decode image format
    /*var decoder = await BitmapDecoder.CreateAsync(await file.OpenReadAsync());
    var transform = new BitmapTransform();
    var pixelData = await decoder.GetPixelDataAsync(decoder.BitmapPixelFormat, decoder.BitmapAlphaMode, transform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.ColorManageToSRgb);

    // Swap R and B channels since it’s reversed
    var pixels = pixelData.DetachPixelData();
    for (var i = 0; i < pixels.Length; i += 4)
    {
    var r = pixels[i];
    var b = pixels[i + 2];
    pixels[i] = b;
    pixels[i + 2] = r;
    }*/

  26. Do you know how to build zxing on windows phone 81.(store app).I know silverlight wp can use the PhotoCameraLuminanceSource to decode camera preview ,but not support store app .
    Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *