[Dev Tip] How to display a QR code in ASP.NET and WPF


I’ve half-jokingly said that there’s never a good reason to use a QR Code. However, I’m working on an MVP (minimally viable product) for a small startup with Greg Shackles and we actually have a good reason to use one. We have a mobile device, a Web Site, and a Windows Application, and a QR Code is a pretty quick way to move data between the mobile device and the other applications without the mess of Bluetooth pairing.

As I mentioned, we display the QR code on an ASP.NET website, as well as within a Windows app that happens to be written in WPF. The iPhone app uses C# and Xamarin.

There’s a great QR Code library called “ZXing” (Zebra Crossing) with ports in Java and also in C#. The C#/.NET one, ZXing.NETis a really fantastically well put together project with assemblies available for everything from .NET 2 to 4.5, Windows RT, Unity3D, Portable libraries and more. The site is filled with demo clients as well, although we didn’t find one for ASP.NET or WPF. No matter, it’s all just generating and showing PNGs.

I pulled in ZXing.NET from the NuGet package here, just install-package ZXing.Net.

HOW TO DISPLAY A QR CODE IN ASP.NET

If you’re generating a QR code with ASP.NET MVC, you’ll have the page that the code lives on, but then you’ll need to decide if you want to make an HTTP Handler that generates the graphic, like:

<img src="/path/to/httphandlerthatmakesQRcodepng">

or, you could take a different approach like we did, and embed the code in the HTML page itself.

Greg used an HTML Helper to output the entire image tag, including the inlined image, as in:

<img src="data:image/gif;base64,iVBORw0KG..." />

Images in HTML directly as Data URIs are super fun and I think, often forgotten. If you show one to the average web dev they’ll say “oh, ya…I knew about those, but never really used it.” In fact, Data URIs have been around for a LONG time. Learn more about them at DataUrl.net.

Here’s generating a QR Code within ASP.NET MVC from an HTML Helper:

public static class HtmlHelperExtensions
{
    public static IHtmlString GenerateRelayQrCode(this HtmlHelper html, string groupName, int height = 250, int width = 250, int margin = 0)
    {
        var qrValue = "whatever data you want to put in here";
        var barcodeWriter = new BarcodeWriter
        {
            Format = BarcodeFormat.QR_CODE,
            Options = new EncodingOptions
            {
                Height = height,
                Width = width,
                Margin = margin
            }
        };
        using (var bitmap = barcodeWriter.Write(qrValue))
        using (var stream = new MemoryStream())
        {
            bitmap.Save(stream, ImageFormat.Gif);
            var img = new TagBuilder("img");
            img.MergeAttribute("alt", "your alt tag");
            img.Attributes.Add("src", String.Format("data:image/gif;base64,{0}",
                Convert.ToBase64String(stream.ToArray())));
            return MvcHtmlString.Create(img.ToString(TagRenderMode.SelfClosing));
        }
    }
}

Nice and simple. The BarcodeWriter class within ZXing.NET does the hard work. We don’t need to save our QR Code to disk, and because we’re doing it inline from our HTML page via this helper, there’s no need for a separate call to get the image. Also, the caching policy that we decide to use for the page applies to the image within, simplifying things vs. two calls.

HOW TO DISPLAY A QR CODE IN WPF

Note: This code here may be wrong. I’m happy to hear your suggestion, Dear Reader, because I’m either missing something completely or there is no clear and clean way to get from a System.Drawing.Bitmap to a System.Windows.Media.imaging.BitmapImage. The little dance here with the saving to a MemoryStream, then moving into a BitmapImage (with the unintuitive but totally required setting of CacheOption as well) just sets off my Spideysense. It can’t be right, although it works.

I’ll update the post when/if a cleaner way is found.

See below for update!

First, the exact same BarcodeWriter usage from the ZXing.NET library.

var qrcode = new QRCodeWriter();
var qrValue = "your magic here";
var barcodeWriter = new BarcodeWriter
{
    Format = BarcodeFormat.QR_CODE,
    Options = new EncodingOptions
    {
        Height = 300,
        Width = 300,
        Margin = 1
    }
};
using (var bitmap = barcodeWriter.Write(qrValue))
using (var stream = new MemoryStream())
{
    bitmap.Save(stream, ImageFormat.Png);
    BitmapImage bi = new BitmapImage();
      bi.BeginInit();
        stream.Seek(0, SeekOrigin.Begin);
        bi.StreamSource = stream;
        bi.CacheOption = BitmapCacheOption.OnLoad;
      bi.EndInit();
      QRCode.Source = bi; //A WPF Image control
}

Later, writing the Bitmap to a MemoryStream for manipulation, except in this case, we’re putting the QR Code into the Source property of a WPF Image Control.

UPDATE: Thomas Levesque in the comments below suggests an extension within System.Windows.Interop (which explains me not finding it) called CreateBitmapSourceFromHBitmap. This still feels gross as it appears to requires a call to the native DeleteObject, but regardless, that’s the price you pay I guess. It looks like this:

using (var bitmap = barcodeWriter.Write(qrValue))
{
    var hbmp = bitmap.GetHbitmap();
    try
    {
        var source = Imaging.CreateBitmapSourceFromHBitmap(hbmp, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        QRCode.Source = source;
    }
    finally
    {
        DeleteObject(hbmp);
    }
}

It works well!

Ref: http://www.hanselman.com/blog/CategoryView.aspx?category=NuGetPOW

Advertisements

One thought on “[Dev Tip] How to display a QR code in ASP.NET and WPF

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s