Share via


VB.NET: Create QR Codes with Google Web APIs


Introduction

This article explains a simple method to create a QR Code inside a standard control. The solution is a UserControl for future re-usability. There  are many libraries which could help us in operations like that, but in this post I will use Google Charts (https://developers.google.com/chart/), together with System.Net and System.IO namespaces.

Google Charts can be queried though POST request (see here for details: https://developers.google.com/chart/image/docs/post_requests?csw=1), so we must: a) query remote server, with particular POST parameters (more on this later), b) retrieve the server's response (a PNG image), c) use it for our means, namely paint it on our control.

Creating UserControl

So, open a new project in Visual Studio, then add a new User Control. I've set BorderStyle property to Fixed3D, and DoubleBuffered to True (in order to avoid flickering when the control refresh itself).

The standard URL we will query is the following: http://chart.googleapis.com/chart?chs=%7BWIDTH%7Dx%7BHEIGHT%7D&cht=qr&chl=%7BDATA%7D (parameters in brackets will be replaced with real parameters). chs will specify QR Code resolution (width x height), while chl will contain the data to be represented through barcode. The parameter related to the barcode size could be easily deduced from our control's property (since a standard control naturally have a width and a height), but we will create a new property to store a certain amount of text, representing the data our QR Code will show.

In our UserControl, we start declaring the standard URI as a constant, our Data Property, and an internal variable to store data in the local context:

Const _GOOGLE_URL As String  = "http://chart.googleapis.com/chart?chs={WIDTH}x{HEIGHT}&cht=qr&chl={DATA}"
    Dim _DATA As String  = String.Empty
 
    Property Data As String
        Get
            Return _DATA
        End Get
        Set(value As  String)
            _DATA = value
        End Set
    End Property

When we will use our Control, Data Property will be available in both Code View and Design Mode:

Now that we can compose a URI with all the requested parameters, we must forge Data Property in order to encode its content before web request. This way, we can be sure no special character will come to break our query. I've implemented a private function for this. Calling on it return an URI with replaced parameters, the least of which will be encoded (thanks to the WebUtility.UrlEncode function)

Private Function  getQRURI() As  String
    Dim _qrAddr As String  = _GOOGLE_URL.Replace("{WIDTH}", Me.Width.ToString).Replace("{HEIGHT}", Me.Height.ToString)
    _qrAddr = _qrAddr.Replace("{DATA}", WebUtility.UrlEncode(_DATA))
 
    Return _qrAddr
End Function

We'll replace the first two tag parameters, {WIDTH} and {HEIGHT}, with our control's size, while the data's parameter will be the content of our Data Property, encoded (for details on WebUtility.UrlEncode, please refer here).

We're now ready to fetch our image from remote servers, and use the returning buffer to paint our QR Code on our control. Since i want QR Code to be painted at the standard OnPaint Event (taking advantage of the PaintEventArgs argument it exposes), i will override it, adding my code:

Protected Overrides  Sub OnPaint(e As PaintEventArgs)
    MyBase.OnPaint(e)
    If _DATA Is Nothing  Then Exit  Sub
 
    Dim client As New WebClient()
    Dim bytes() As Byte  = client.DownloadData(getQRURI())
    client.Dispose()
 
    Dim memStream As New IO.MemoryStream(bytes)
    Dim bmp As Bitmap = Bitmap.FromStream(memStream)
    memStream.Dispose()
 
    e.Graphics.DrawImage(bmp, 0, 0)
End Sub

MyBase.OnPaints calls on standard paint operations. Next, we check if there is data to query (exiting method otherwise), and proceeding querying remote server with a new instance of WebClient. Through the call at DownloadData, to which we pass the result of our URI-formatting function, we'll fill an array of bytes, which is the server response, i.e. the PNG image representing our QR Code.

An image-type variable can be initialized through reading a Stream (like when we wish to open an image existing on our hard-drive, a stream to our local copy of it). Since we'll have our bytes in memory, we can declare a MemoryStream based on our array, and use it as a Bitmap source. At this point, having a perfectly working bitmap, we can exploit the variable e, which the OnPaint event give access to us, to draw the image on our control, at [0;0] location.

Use QrBox in WinForm

After compiling our project, the QRBox will be available in the ToolBox, ready to be used on our Forms.

Using it is simple, it's sufficient to set it's Data Property, and call for a control's refresh.

The following example Form shows how it works: i've added to my Form a QrBox control, together with a standard TextBox ad Button.

When the user press the "Make" Button, we'll read the TextBox content, passing it to the QrBox Data Property, and invoking the Refresh() method, in order to start the remote query towards Google Charts. The code for the Button's click will be simply like that:

Private Sub Button1_Click(sender As  Object, e As EventArgs) Handles Button1.Click
    QrBox1.Data = TextBox1.Text
    QrBox1.Refresh()
End Sub

The complete code for QrBox UserControl is as follows:

Imports System.Net
 
Public Class  QRBox
    Const _GOOGLE_URL As String  = "http://chart.googleapis.com/chart?chs={WIDTH}x{HEIGHT}&cht=qr&chl={DATA}"
    Dim _DATA As String  = String.Empty
 
    Property Data As String
        Get
            Return _DATA
        End Get
        Set(value As  String)
            _DATA = value
        End Set
    End Property
 
    Private Function  getQRURI() As  String
        Dim _qrAddr As String  = _GOOGLE_URL.Replace("{WIDTH}", Me.Width.ToString).Replace("{HEIGHT}", Me.Height.ToString)
        _qrAddr = _qrAddr.Replace("{DATA}", WebUtility.UrlEncode(_DATA))
 
        Return _qrAddr
    End Function
 
    Protected Overrides  Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        If _DATA Is Nothing  Then Exit  Sub
 
        Dim client As New WebClient()
        Dim bytes() As Byte  = client.DownloadData(getQRURI())
        client.Dispose()
 
        Dim memStream As New IO.MemoryStream(bytes)
        Dim bmp As Bitmap = Bitmap.FromStream(memStream)
        memStream.Dispose()
 
        e.Graphics.DrawImage(bmp, 0, 0)
    End Sub
 
    Public Sub  New()
        InitializeComponent()
    End Sub
End Class

Demo

The code discussed in the article could be downloaded at: https://code.msdn.microsoft.com/Create-QR-Codes-with-f5fcb937

I hope this could be useful for your projects.