Criando QR Codes com Python

Se você não tem nada a ver com programação, nem tem interesse no assunto, simplesmente ignore este artigo.


Mike Driscoll tem um blog dedicado a Python chamado The Mouse vs. the Python e eventualmente há excelentes artigos por lá.

Esta é uma tradução livre do artigo Creating QR Codes with Python e modifiquei sutilmente algumas coisas, incluindo os exemplos.

QR Code, para quem não sabe, é um estilo de código de barras bidimensional, podendo conter um fragmento de texto, o endereço de um site, um email ou mesmo uma ficha de informações pessoais básicas (reunindo tudo isso). Veja mais sobre esses códigos na Wikipedia.


QR Porco

Outro dia eu pensei que seria divertido criar em wxPython um pequeno programa que gerasse códigos QR e os mostrasse na tela. Eu queria fazer tudo com Python, assim eu procurei e encontrei 3 candidatos:

Testei o python-qrcode e o pyqrnative uma vez já que ambos funcionam tanto no Windows quanto no Mac e no Linux. Eles também não requerem nada a não ser o Python Imaging Library. O projeto pyqrcode requer vários outros pré-requisitos e não funciona em Windows, assim eu nem quis mexer nele. Terminei pegando algum código antigo baseado na minha aplicação Photo Viewer e o modificando levemente para torná-lo um visualizador de QR Code. Se isso te interessa, então continue lendo!

Começando

Como eu disse no início, você precisará da Python Imaging Library. Usaremos o wxPython para fazer a parte gráfica, assim você precisará deles também. E você vai ter que usar o python-qrcode ou o pyqrnative. A principal diferença que achei é que o python-qrcode é muito mais rápido na geração de imagens e gera o tipo que provavelmente você vai ver por aí. Por alguma razão, pyqrnative leva mais tempo pra executar e gera QR codes de aspecto muito mais denso. Deve haver opções para esses projetos que nos permitam gerar diferentes tipos de códigos, mas a documentação para ambos é abismal. Terminei usando o código e a IDE Wingware para navegar pelo código mais do que qualquer outra coisa.

Gerando QR Codes

De qualquer forma, uma vez que você tenha os pré-requisitos, você pode executar o seguinte código e ver o que o Python pode fazer:

# coding: utf-8
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="Texto a transformar no QR Code:")
        self.qrDataTxt = wx.TextCtrl(self, value="http://www.mousevspython.com", size=(200,-1))
        instructions = "Nome do arquivo do QR Code"
        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="Criar QR com qrcode")
        qrcodeBtn.Bind(wx.EVT_BUTTON, self.onUseQrcode)
        pyQRNativeBtn = wx.Button(self, label="Criar QR com 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, "Escolher  um diretório:",
                           style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.defaultLocation = path
            self.defaultLocationLbl.SetLabel("Local de salvamento: %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)
        # redimensionar imagem, preservando proporção
        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="Visualizador de QR Code", size=(550,500))
        panel = QRPanel(self)
 
if __name__ == "__main__":
    app = wx.App(False)
    frame = QRFrame()
    frame.Show()
    app.MainLoop()

O código para modificar e exibir imagens é tratado no artigo anterior que eu escrevi (e com link acima), assim as únicas partes com que você provavelmente terá que se preocupar são dois métodos para gerar códigos QR: onUseQrcode e onUsePyQR. Eu apenas peguei alguns exemplos de seus respectivos sites e os modifiquei para criar as imagens de códigos QR. Eles são muito simples, mas não são bem documentados, de modo que eu não posso realmente lhe dizer o que está acontecendo neles. Infelizmente, no momento em que escrevia este texto, o código desses projetos carece seriamente de comentários, com apenas alguns aqui e ali. Ainda assim, eu estava apto a gerar códigos QR decentes. O código a seguir foi feito usando python-qrcode.

Tela do código em execução, modo qrcode

Como vovcê podever, é um código padrão bastante simples. O próximo foi criado com PyQRNative e tem um aspecto muito mais denso:

Imagem do código em execução, modo PyQRNative

Tentei escanear ambas as imagens com o aplicativo leitor de códigos debarra do meu celular com android e ambos os códigos QR foram corretamente lidos por ele. Assim, se você precisa gerar códigos QR para o seu projeto, tenho esperanças de que ao menos um dos dois atenda às suas necessidades!

ATUALIZAÇÃO 21/05/2012

Um dos meus leitores (Mike Farmer) me contactou recentemente sobre seus experimentos com PyQRNative e me disse que "o primeiro parâmetro é o tamanho do container e o segundo é a correção de redundância/erro". Eu meio que adivinho o que o primeiro parâmetro quer dizer, mas realmente não entendi isso de correção de erro. Felizmente, Sr. Farmer me explicou isso: Se a correção de erros é menor, manchas e marcas não serão toleradas na leitura. Se aumentar o nível de erro, obviamente o código qr será aumentado, mas o que foi feito foi a duplicação dos dados dentro da etiqueta. Assim, se a etiqueta for manchada ou rasgada, ainda poderá sr possível ler e recuperar os dados restantes. Deste modo, se sua aplicação estiver criando etiquetas que podem ser danificadas, é sábio aumentar a correção de erros. Você também pode fazer coisas legais com isso, como sobrepor imagens ou textos na tag, aumentando a correção de erros, fazendo com que os dados redundantes tolerem o "dano". De qualquer forma, se você mudar o primeiro número, você pode expandir o tamanho do da imagem do código QR. Por que você faria isso? Bem, quanto mais informações você precisar guardar na imagem, maior ela precisará ser. Sr. Farmer veio com um código de testes divertido que nos ajuda a descobrir qual o tamanho mínimo que um código QR deve ter. Estou reproduzindo o código a seguir:

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

P. S.: foto usada no post: QRCode Piggy Bank, de B3OK.

Special: 
Avalie: 
Average: 5 (2 votes)

Comentários

imagem de Daniel Antonio

Boa tarde amigo, primeiro gostaria de agradecer por você ter dado esse maravilhoso script para criar qrcode no pyqrnative, devo informar que acabei de descobrir que pyqrnative não é uma imagem de aspecto denso basta só mudar o atributo na hora da declaração :
Na função onUsePyQR

 qr = PyQRNative.QRCode(20, PyQRNative.QRErrorCorrectLevel.L)

o valor 20 pode ser substituido por 2 assim:

 qr = PyQRNative.QRCode(2, PyQRNative.QRErrorCorrectLevel.L)

quando gerar o código com o pyqrnative verá que o código será igual ao do pyqrcode.

Obrigado amigo se puder me informar como ler um qr em python usando o programa eu agradeceria muito mais smiley

Comentar