使用 Google 的 Web API 创建二维码 已翻译 100%

oschina 投递于 2015/01/04 12:19 (共 6 段, 翻译完成于 01-09)
阅读 5334
收藏 81
4
加载中

Introduction

In this article I'll cover a simple method to create a QR Code inside a standard control, wrapping up everything inside a UserControl for future reference. 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.

Background

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.

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).

已有 1 人翻译此段
我来翻译

Using the code

The standard URL we will query is the following: http://chart.googleapis.com/chart?chs={WIDTH}x{HEIGHT}&cht=qr&chl={DATA} (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= [This link is external to TechNet Wiki. It will open in a new window.] {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:

已有 1 人翻译此段
我来翻译

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).

已有 1 人翻译此段
我来翻译

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.

已有 1 人翻译此段
我来翻译

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.

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.

已有 1 人翻译此段
我来翻译

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

UserControl's complete source code

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

I hope this could be useful for your projects.
Happy coding, and good luck with your work!

已有 1 人翻译此段
我来翻译
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(24)

小薇
小薇
http://api.setin.cn/
南漂一卒
南漂一卒

引用来自“羊半仙”的评论

http://qr.liantu.com/api.php?text=
联图网的二维码api,不知道能用多久
个人项目亲测 —— 调用只要不太频繁,用着还是很靠谱的~
谢浩哲
谢浩哲
我只有一个问题,在我大天朝可以用Google的API吗?
有色白水
谷歌的api还是不错的,就是对中文支持的不好,有些中文会解析失败而返回错误,以前用过,删除特定的字符就好了
TGVvbmFyZA
TGVvbmFyZA
我早就做出來這種軟件了
巴拉巴拉啦啦
巴拉巴拉啦啦
有QRcode js 插件
小薇
小薇
一个js都能实现的东西,为什么要搞这么复杂?http://www.atool.org/qrcode.php
还扯上了vs,是用来装bi吗?
kingnait
kingnait
Google能到吗
李剑
李剑
103
范特彪西
范特彪西
jquery.qrcode.min.js
返回顶部
顶部