Creating QR Codes with Python
Join the DZone community and get the full member experience.
Join For FreeThe other day, I thought it would be fun to create a little program that could generate QR codes and show them onscreen with wxPython. Of course, I wanted to do it all with Python, so after a little looking, I came across 3 candidates:
- python-qrcode on github
- pyqrcode on sourceforge and
- pyqrnative on Google code
I tried python-qrcode and pyqrnative since they worked on Windows as well as Mac and Linux. They also didn’t require anything except the Python Imaging Library. The pyqrcode project requires several other prerequisites and didn’t work on Windows, so I didn’t want to mess with it. I ended up taking some old code based on my Photo Viewer application and modified it slightly to make this a QR Code viewer. If I’ve piqued your interest, then read on!
Getting Started
As I noted at the beginning, you will need the Python Imaging Library. We’ll be using wxPython for the GUI part, so you’ll need that as well. And you’ll want to download python-qrcode and pyqrnative. The main difference I have found is that python-qrcode is much faster at generating the images and it generates the type you’ve probably seen the most of. For some reason, pyqrnative take a lot longer to run and it creates a much denser looking QR code. There may be options for both of these projects that allow you to generate different kinds of codes, but the documentation for either project is abysmal. I ended up using the source and Wingware’s IDE to traverse the code more than anything else.
Generating QR Codes
Anyway, once you have all the prerequisites, you can run the following code and see what Python can do:
import os import wx try: import qrcode except ImportError: qrcode = None try: import PyQRNative except ImportError: PyQRNative = None ######################################################################## class QRPanel(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent) self.photo_max_size = 240 sp = wx.StandardPaths.Get() self.defaultLocation = sp.GetDocumentsDir() img = wx.EmptyImage(240,240) self.imageCtrl = wx.StaticBitmap(self, wx.ID_ANY, wx.BitmapFromImage(img)) qrDataLbl = wx.StaticText(self, label="Text to turn into QR Code:") self.qrDataTxt = wx.TextCtrl(self, value="http://www.mousevspython.com", size=(200,-1)) instructions = "Name QR image file" instructLbl = wx.StaticText(self, label=instructions) self.qrPhotoTxt = wx.TextCtrl(self, size=(200,-1)) browseBtn = wx.Button(self, label='Change Save Location') browseBtn.Bind(wx.EVT_BUTTON, self.onBrowse) defLbl = "Default save location: " + self.defaultLocation self.defaultLocationLbl = wx.StaticText(self, label=defLbl) qrcodeBtn = wx.Button(self, label="Create QR with qrcode") qrcodeBtn.Bind(wx.EVT_BUTTON, self.onUseQrcode) pyQRNativeBtn = wx.Button(self, label="Create QR with PyQRNative") pyQRNativeBtn.Bind(wx.EVT_BUTTON, self.onUsePyQR) # Create sizer self.mainSizer = wx.BoxSizer(wx.VERTICAL) qrDataSizer = wx.BoxSizer(wx.HORIZONTAL) locationSizer = wx.BoxSizer(wx.HORIZONTAL) qrBtnSizer = wx.BoxSizer(wx.VERTICAL) qrDataSizer.Add(qrDataLbl, 0, wx.ALL, 5) qrDataSizer.Add(self.qrDataTxt, 1, wx.ALL|wx.EXPAND, 5) self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.ALL|wx.EXPAND, 5) self.mainSizer.Add(qrDataSizer, 0, wx.EXPAND) self.mainSizer.Add(self.imageCtrl, 0, wx.ALL, 5) locationSizer.Add(instructLbl, 0, wx.ALL, 5) locationSizer.Add(self.qrPhotoTxt, 0, wx.ALL, 5) locationSizer.Add(browseBtn, 0, wx.ALL, 5) self.mainSizer.Add(locationSizer, 0, wx.ALL, 5) self.mainSizer.Add(self.defaultLocationLbl, 0, wx.ALL, 5) qrBtnSizer.Add(qrcodeBtn, 0, wx.ALL, 5) qrBtnSizer.Add(pyQRNativeBtn, 0, wx.ALL, 5) self.mainSizer.Add(qrBtnSizer, 0, wx.ALL|wx.CENTER, 10) self.SetSizer(self.mainSizer) self.Layout() #---------------------------------------------------------------------- def onBrowse(self, event): """""" dlg = wx.DirDialog(self, "Choose a directory:", style=wx.DD_DEFAULT_STYLE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.defaultLocation = path self.defaultLocationLbl.SetLabel("Save location: %s" % path) dlg.Destroy() #---------------------------------------------------------------------- def onUseQrcode(self, event): """ https://github.com/lincolnloop/python-qrcode """ qr = qrcode.QRCode(version=1, box_size=10, border=4) qr.add_data(self.qrDataTxt.GetValue()) qr.make(fit=True) x = qr.make_image() qr_file = os.path.join(self.defaultLocation, self.qrPhotoTxt.GetValue() + ".jpg") img_file = open(qr_file, 'wb') x.save(img_file, 'JPEG') img_file.close() self.showQRCode(qr_file) #---------------------------------------------------------------------- def onUsePyQR(self, event): """ http://code.google.com/p/pyqrnative/ """ qr = PyQRNative.QRCode(20, PyQRNative.QRErrorCorrectLevel.L) qr.addData(self.qrDataTxt.GetValue()) qr.make() im = qr.makeImage() qr_file = os.path.join(self.defaultLocation, self.qrPhotoTxt.GetValue() + ".jpg") img_file = open(qr_file, 'wb') im.save(img_file, 'JPEG') img_file.close() self.showQRCode(qr_file) #---------------------------------------------------------------------- def showQRCode(self, filepath): """""" img = wx.Image(filepath, wx.BITMAP_TYPE_ANY) # scale the image, preserving the aspect ratio W = img.GetWidth() H = img.GetHeight() if W > H: NewW = self.photo_max_size NewH = self.photo_max_size * H / W else: NewH = self.photo_max_size NewW = self.photo_max_size * W / H img = img.Scale(NewW,NewH) self.imageCtrl.SetBitmap(wx.BitmapFromImage(img)) self.Refresh() ######################################################################## class QRFrame(wx.Frame): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, title="QR Code Viewer", size=(550,500)) panel = QRPanel(self) if __name__ == "__main__": app = wx.App(False) frame = QRFrame() frame.Show() app.MainLoop()
The code for changing and showing the picture is explained in the previous article I wrote (and linked to above), so the only parts that you’ll probably care about are the two methods for generating the QR codes: onUseQrcode and onUsePyQR. I just took some examples from their respective websites and modified them slightly to create the QR code images. They’re very straight-forward, but not well documented, so I can’t really tell you what’s going on. Sadly at the time of this writing, the code for these projects is seriously lacking in docstrings, with only a few here and there. Still, I was able to generate some decent QR codes. The following was done using python-qrcode:
As you can see, it’s a pretty standard code. The next one is created with PyQRNative and is much denser looking:
I tried scanning both images with my Android cell phone’s barcode scanning application and both QR codes were read correctly by it. So if you’re in need of generating QR code images for your project, I hope one of these projects will fit your needs!
UPDATE 5/21/2012
One of my readers (Mike Farmer) contacted me recently about his
experiments with PyQRNative and told me that the “first argument is
container size and the second is redundancy/error
correction”. I kind of guessed what the second one was, but I don’t
really know what the error correction levels do. Anyway, if you change
the first number, you can grow or shrink the QR code image size. Anyway,
Mr. Farmer came up with some fun test code to help him figure out
exactly what the minimum size a QR code has to be. I am reproducing the
code below:
import PyQRNative def makeQR(data_string,path,level=1): quality={1: PyQRNative.QRErrorCorrectLevel.L, 2: PyQRNative.QRErrorCorrectLevel.M, 3: PyQRNative.QRErrorCorrectLevel.Q, 4: PyQRNative.QRErrorCorrectLevel.H} size=3 while 1: try: q = PyQRNative.QRCode(size,quality[level]) q.addData(data_string) q.make() im=q.makeImage() im.save(path,format="png") break except TypeError: size+=1
Published at DZone with permission of Mike Driscoll, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Integrate Cucumber in Playwright With Java
-
Azure Virtual Machines
-
Step Into Serverless Computing
-
Building the World's Most Resilient To-Do List Application With Node.js, K8s, and Distributed SQL
Comments