На днях я подумал, что было бы интересно создать небольшую программу, которая могла бы генерировать QR-коды и показывать их на экране с помощью wxPython. Конечно, я хотел сделать все это с Python, поэтому после небольшого осмотра я наткнулся на 3 кандидата:
- python-qrcode на github
- pyqrcode на sourceforge и
- pyqrnative в коде Google
Я пробовал python-qrcode и pyqrnative, так как они работали на Windows, а также на Mac и Linux. Им также не требовалось ничего, кроме библиотеки изображений Python. Проект pyqrcode требует нескольких других предварительных условий и не работает в Windows, поэтому я не хотел связываться с ним. В итоге я взял старый код, основанный на приложении Photo Viewer, и немного изменил его, чтобы он стал средством просмотра QR-кода. Если я пробудил ваш интерес, тогда читайте дальше!
Начиная
Как я уже отмечал в начале, вам понадобится библиотека изображений Python . Мы будем использовать wxPython для графического интерфейса, так что вам это понадобится. И вы захотите скачать python-qrcode и pyqrnative. Основное отличие, которое я обнаружил, заключается в том, что python-qrcode намного быстрее генерирует изображения и генерирует тип, который вы, вероятно, видели чаще всего. По какой-то причине pyqrnative занимает намного больше времени, и он создает более плотно выглядящий QR-код. Могут быть варианты для обоих этих проектов, которые позволяют вам генерировать различные виды кодов, но документация для любого проекта ужасна. В итоге я использовал исходный код и IDE Wingware для обхода кода больше всего на свете.
Генерация QR-кодов
В любом случае, когда у вас есть все необходимые условия, вы можете запустить следующий код и посмотреть, что может делать Python:
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()
Код для изменения и отображения рисунка объяснен в предыдущей статье, которую я написал (и связан с вышеупомянутым), поэтому единственные части, которые вам, вероятно, понадобятся, — это два метода для генерации QR-кодов: onUseQrcode и onUsePyQR . Я просто взял несколько примеров с их соответствующих веб-сайтов и немного изменил их, чтобы создать изображения QR-кода. Они очень прямолинейны, но плохо документированы, поэтому я не могу точно сказать вам, что происходит. К сожалению, на момент написания этой статьи в коде этих проектов не хватало строк документации, и только некоторые из них были здесь и там. Тем не менее, я смог сгенерировать несколько приличных QR-кодов. Следующее было сделано с использованием python-qrcode:
Как видите, это довольно стандартный код. Следующий создается с помощью PyQRNative и выглядит намного плотнее:
Я попытался отсканировать оба изображения с помощью приложения для сканирования штрих-кодов моего мобильного телефона Android, и оба QR-кода были правильно прочитаны им. Поэтому, если вам нужно создать изображения QR-кода для вашего проекта, я надеюсь, что один из этих проектов подойдет вам!
ОБНОВЛЕНИЕ 21.05.2012
Один из моих читателей (Майк Фармер) недавно связался со мной по поводу своих экспериментов с PyQRNative и сказал, что «первый аргумент — это размер контейнера, а второй — избыточность / исправление
ошибок». Я как-то догадался, что это был за второй, но я не совсем понимаю, что делают уровни коррекции ошибок. В любом случае, если вы измените первое число, вы можете увеличить или уменьшить размер изображения QR-кода. Во всяком случае, мистер Фармер придумал забавный тестовый код, чтобы помочь ему точно определить, каким должен быть минимальный размер QR-кода. Я воспроизводю код ниже:
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