Создать QR-код на Python (PyQt)

В настоящее время я использую PyQt4 и qrcode4.0.4.

from PyQt4 import QtGui, QtCore
from PIL.ImageQt import ImageQt
import qrcode

class QRLabel(QtGui.QLabel):
    def __init__(self, text=""):
        super(QRLabel, self).__init__()
        self.setCode(text)

    def setCode(self, text=""):        
        self.text = text      
        qrImg = qrcode.make(text)
        imgQt = ImageQt(qrImg.convert("RGB"))   # keep a reference!
        pixm = QtGui.QPixmap.fromImage(imgQt)
        self.setPixmap(pixm.scaled(self.size(),QtCore.Qt.KeepAspectRatio))

Как видите, есть несколько препятствий, которые необходимо преодолеть, прежде чем вы получите изображение на экране. QR-код начинается как изображение RGBA PIL, затем преобразуется в RGB, затем в объект PIL ImageQt, затем в QPixmap, который затем помещается на QLabel с исправлением масштабирования.

Если вы явно не сохраните ссылку imgQt, вы получите мусор при загрузке виджета.

Мой вопрос: могу ли я что-нибудь сделать, чтобы улучшить это, поскольку кажется, что задействовано так много конверсий.


person Stefaan Ghysels    schedule 08.12.2013    source источник


Ответы (4)


Судя по документам qrcode, вы можете создать свой собственный image_factory, который может упростить процесс.

Вам просто нужно создать подкласс qrcode.image.base.BaseImage и заново реализовать методы new_image, drawrect и save. Этот подкласс может обернуть QImage и, следовательно, устранить необходимость в шаге преобразования PIL.

ОБНОВЛЕНИЕ:

Вот демонстрация, которая устраняет зависимость PIL (что тоже хорошо, потому что я обнаружил сбои PIL при определенных входных данных):

from PyQt4 import QtGui, QtCore
import qrcode

class Image(qrcode.image.base.BaseImage):
    def __init__(self, border, width, box_size):
        self.border = border
        self.width = width
        self.box_size = box_size
        size = (width + border * 2) * box_size
        self._image = QtGui.QImage(
            size, size, QtGui.QImage.Format_RGB16)
        self._image.fill(QtCore.Qt.white)

    def pixmap(self):
        return QtGui.QPixmap.fromImage(self._image)

    def drawrect(self, row, col):
        painter = QtGui.QPainter(self._image)
        painter.fillRect(
            (col + self.border) * self.box_size,
            (row + self.border) * self.box_size,
            self.box_size, self.box_size,
            QtCore.Qt.black)

    def save(self, stream, kind=None):
        pass

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.label = QtGui.QLabel(self)
        self.edit = QtGui.QLineEdit(self)
        self.edit.returnPressed.connect(self.handleTextEntered)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.label)
        layout.addWidget(self.edit)

    def handleTextEntered(self):
        text = unicode(self.edit.text())
        self.label.setPixmap(
            qrcode.make(text, image_factory=Image).pixmap())

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 200, 200)
    window.show()
    sys.exit(app.exec_())
person ekhumoro    schedule 08.12.2013

Вы также можете использовать PNG в качестве промежуточного формата и хранить его в памяти с помощью StringIO.

import qrcode
import StringIO

def set_qr_label(label, text):
    """
    set qrcode image on QLabel

    @param label: QLabel
    @param text: text for the QR code
    """
    buf = StringIO.StringIO()
    img = qrcode.make(text)
    img.save(buf, "PNG")
    label.setText("")
    qt_pixmap = QtGui.QPixmap()
    qt_pixmap.loadFromData(buf.getvalue(), "PNG")
    label.setPixmap(qt_pixmap)
person mgmax    schedule 20.06.2015

Отличный ответ от mgmax, но только на Python2. Для Python3 используйте:

import qrcode
from io import BytesIO

def set_qr_label(label, text):
    """
    set qrcode image on QLabel

    @param label: QLabel
    @param text: text for the QR code
    """
    buf = BytesIO()
    img = qrcode.make(text)
    img.save(buf, "PNG")
    label.setText("")
    qt_pixmap = QtGui.QPixmap()
    qt_pixmap.loadFromData(buf.getvalue(), "PNG")
    label.setPixmap(qt_pixmap)
person frennkie    schedule 05.10.2019
comment
Не ссылайтесь на имя пользователя, вставьте ссылку на ответ этого пользователя для python2.. - person Naveen Jain; 05.10.2019

Это ответ эхуморо, работающий в pyqt5 в python3, надеюсь, он поможет кому-то в будущем.

from PyQt5 import QtWidgets, QtCore, QtGui
import qrcode

class Image(qrcode.image.base.BaseImage):
    def __init__(self, border, width, box_size):
        self.border = border
        self.width = width
        self.box_size = box_size
        size = (width + border * 2) * box_size
        self._image = QtGui.QImage(
            size, size, QtGui.QImage.Format_RGB16)
        self._image.fill(QtCore.Qt.white)

    def pixmap(self):
        return QtGui.QPixmap.fromImage(self._image)

    def drawrect(self, row, col):
        painter = QtGui.QPainter(self._image)
        painter.fillRect(
            (col + self.border) * self.box_size,
            (row + self.border) * self.box_size,
            self.box_size, self.box_size,
            QtCore.Qt.black)

    def save(self, stream, kind=None):
        pass

class Window(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.label = QtWidgets.QLabel(self)
        self.edit = QtWidgets.QLineEdit(self)
        self.edit.returnPressed.connect(self.handleTextEntered)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.label)
        layout.addWidget(self.edit)

    def handleTextEntered(self):
        text = self.edit.text()#text = unicode(self.edit.text())
        self.label.setPixmap(
            qrcode.make(text, image_factory=Image).pixmap())

if __name__ == '__main__':

    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 200, 200)
    window.show()
    sys.exit(app.exec_())

person temp    schedule 16.04.2020
comment
Хотя этот код может решить проблему, включая объяснение того, как и почему это решает проблему, действительно поможет улучшить качество. вашего сообщения и, вероятно, приведет к большему количеству голосов. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для того, кто задает сейчас. Пожалуйста, отредактируйте свой ответ, чтобы добавить пояснения и указать, какие ограничения и предположения применяются. - person Brian; 16.04.2020