qml: add QR code imageprovider using qrcode/PIL
adds buildozer 'pillow' recipe to requirements add initial PoC on qml receive tab
This commit is contained in:
@@ -51,7 +51,8 @@ requirements =
|
||||
libsecp256k1,
|
||||
cryptography,
|
||||
pyqt5sip,
|
||||
pyqt5
|
||||
pyqt5,
|
||||
pillow
|
||||
|
||||
# (str) Presplash of the application
|
||||
#presplash.filename = %(source.dir)s/gui/kivy/theming/splash.png
|
||||
|
||||
32
electrum/gui/qml/components/Receive.qml
Normal file
32
electrum/gui/qml/components/Receive.qml
Normal file
@@ -0,0 +1,32 @@
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
import org.electrum 1.0
|
||||
|
||||
Pane {
|
||||
id: rootItem
|
||||
visible: Daemon.currentWallet !== undefined
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 20
|
||||
|
||||
Image {
|
||||
id: img
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: text
|
||||
}
|
||||
|
||||
Button {
|
||||
text: 'generate'
|
||||
onClicked: {
|
||||
img.source = 'image://qrgen/' + text.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,11 +63,9 @@ Item {
|
||||
currentIndex: tabbar.currentIndex
|
||||
|
||||
Item {
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
y: 20
|
||||
spacing: 20
|
||||
Receive {
|
||||
id: receive
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from .qeconfig import QEConfig
|
||||
from .qedaemon import QEDaemon, QEWalletListModel
|
||||
from .qenetwork import QENetwork
|
||||
from .qewallet import QEWallet
|
||||
from .qeqr import QEQR
|
||||
from .qeqr import QEQR, QEQRImageProvider
|
||||
from .qewalletdb import QEWalletDB
|
||||
from .qebitcoin import QEBitcoin
|
||||
|
||||
@@ -36,6 +36,9 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
self.engine = QQmlApplicationEngine(parent=self)
|
||||
self.engine.addImportPath('./qml')
|
||||
|
||||
self.qr_ip = QEQRImageProvider()
|
||||
self.engine.addImageProvider('qrgen', self.qr_ip)
|
||||
|
||||
self.context = self.engine.rootContext()
|
||||
self._singletons['config'] = QEConfig(config)
|
||||
self._singletons['network'] = QENetwork(daemon.network)
|
||||
@@ -63,7 +66,7 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
|
||||
def message_handler(self, line, funct, file):
|
||||
# filter out common harmless messages
|
||||
if re.search('file:///.*TypeError:\ Cannot\ read\ property.*null$', file):
|
||||
if re.search('file:///.*TypeError: Cannot read property.*null$', file):
|
||||
return
|
||||
self.logger.warning(file)
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl
|
||||
from PyQt5.QtGui import QImage
|
||||
from PyQt5.QtQuick import QQuickImageProvider
|
||||
|
||||
from electrum.logging import get_logger
|
||||
|
||||
#from PIL import Image
|
||||
import qrcode
|
||||
#from qrcode.image.styledpil import StyledPilImage
|
||||
#from qrcode.image.styles.moduledrawers import *
|
||||
|
||||
from PIL import Image, ImageQt
|
||||
|
||||
from ctypes import *
|
||||
|
||||
class QEQR(QObject):
|
||||
@@ -11,22 +18,25 @@ class QEQR(QObject):
|
||||
self._text = text
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
scan_ready_changed = pyqtSignal()
|
||||
|
||||
_ready = True
|
||||
scanReadyChanged = pyqtSignal()
|
||||
imageChanged = pyqtSignal()
|
||||
|
||||
_scanReady = True
|
||||
_image = None
|
||||
|
||||
@pyqtSlot('QImage')
|
||||
def scanImage(self, image=None):
|
||||
if not self._ready:
|
||||
if not self._scanReady:
|
||||
self._logger.warning("Already processing an image. Check 'ready' property before calling scanImage")
|
||||
return
|
||||
self._ready = False
|
||||
self.scan_ready_changed.emit()
|
||||
self._scanReady = False
|
||||
self.scanReadyChanged.emit()
|
||||
|
||||
pilimage = self.convertToPILImage(image)
|
||||
self.parseQR(pilimage)
|
||||
|
||||
self._ready = True
|
||||
self._scanReady = True
|
||||
|
||||
def logImageStats(self, image):
|
||||
self._logger.info('width: ' + str(image.width()))
|
||||
@@ -47,13 +57,32 @@ class QEQR(QObject):
|
||||
memmove(c_buf, c_void_p(rawimage.__int__()), numbytes)
|
||||
buf2 = bytes(buf)
|
||||
|
||||
return None #Image.frombytes('RGBA', (image.width(), image.height()), buf2, 'raw')
|
||||
return Image.frombytes('RGBA', (image.width(), image.height()), buf2, 'raw')
|
||||
|
||||
def parseQR(self, image):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
@pyqtProperty(bool, notify=scan_ready_changed)
|
||||
def ready(self):
|
||||
return self._ready
|
||||
@pyqtProperty(bool, notify=scanReadyChanged)
|
||||
def scanReady(self):
|
||||
return self._scanReady
|
||||
|
||||
@pyqtProperty('QImage', notify=imageChanged)
|
||||
def image(self):
|
||||
return self._image
|
||||
|
||||
class QEQRImageProvider(QQuickImageProvider):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(QQuickImageProvider.Image)
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def requestImage(self, qstr, size):
|
||||
self._logger.debug('QR requested for %s' % qstr)
|
||||
qr = qrcode.QRCode(version=1, box_size=8, border=2)
|
||||
qr.add_data(qstr)
|
||||
qr.make(fit=True)
|
||||
|
||||
pimg = qr.make_image(fill_color='black', back_color='white') #image_factory=StyledPilImage, module_drawer=CircleModuleDrawer())
|
||||
qimg = ImageQt.ImageQt(pimg)
|
||||
return qimg, qimg.size()
|
||||
|
||||
Reference in New Issue
Block a user