Qt PayToEdit: add option to scan QR code from screen(shot)
this ports the following commits:448376e4416053f6f696
This commit is contained in:
committed by
SomberNight
parent
9d125118da
commit
b7b53e56bc
@@ -22,14 +22,15 @@
|
||||
# Note: this module is safe to import on all platforms.
|
||||
|
||||
import sys
|
||||
from typing import Callable, Optional, TYPE_CHECKING, Mapping
|
||||
from typing import Callable, Optional, TYPE_CHECKING, Mapping, Sequence
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox, QWidget
|
||||
from PyQt5.QtGui import QImage
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.util import UserFacingException
|
||||
from electrum.logging import get_logger
|
||||
from electrum.qrreader import MissingQrDetectionLib
|
||||
from electrum.qrreader import get_qr_reader, QrCodeResult, MissingQrDetectionLib
|
||||
|
||||
from electrum.gui.qt.util import MessageBoxMixin, custom_message_box
|
||||
|
||||
@@ -47,12 +48,26 @@ def scan_qrcode(
|
||||
config: 'SimpleConfig',
|
||||
callback: Callable[[bool, str, Optional[str]], None],
|
||||
) -> None:
|
||||
"""Scans QR code using camera."""
|
||||
if sys.platform == 'darwin' or sys.platform in ('windows', 'win32'):
|
||||
_scan_qrcode_using_qtmultimedia(parent=parent, config=config, callback=callback)
|
||||
else: # desktop Linux and similar
|
||||
_scan_qrcode_using_zbar(parent=parent, config=config, callback=callback)
|
||||
|
||||
|
||||
def scan_qr_from_image(image: QImage) -> Sequence[QrCodeResult]:
|
||||
"""Might raise exception: MissingQrDetectionLib."""
|
||||
qr_reader = get_qr_reader()
|
||||
image_y800 = image.convertToFormat(QImage.Format_Grayscale8)
|
||||
res = qr_reader.read_qr_code(
|
||||
image_y800.constBits().__int__(), image_y800.byteCount(),
|
||||
image_y800.bytesPerLine(),
|
||||
image_y800.width(),
|
||||
image_y800.height()
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
def find_system_cameras() -> Mapping[str, str]:
|
||||
"""Returns a camera_description -> camera_path map."""
|
||||
if sys.platform == 'darwin' or sys.platform in ('windows', 'win32'):
|
||||
|
||||
@@ -30,7 +30,9 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
|
||||
|
||||
def contextMenuEvent(self, e):
|
||||
m = self.createStandardContextMenu()
|
||||
m.addAction(_("Read QR code"), self.on_qr_input_btn)
|
||||
m.addSeparator()
|
||||
m.addAction(_("Read QR code from camera"), self.on_qr_from_camera_input_btn)
|
||||
m.addAction(_("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
|
||||
m.exec_(e.globalPos())
|
||||
|
||||
|
||||
@@ -46,6 +48,8 @@ class ScanShowQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
|
||||
|
||||
def contextMenuEvent(self, e):
|
||||
m = self.createStandardContextMenu()
|
||||
m.addAction(_("Read QR code"), self.on_qr_input_btn)
|
||||
m.addSeparator()
|
||||
m.addAction(_("Read QR code from camera"), self.on_qr_from_camera_input_btn)
|
||||
m.addAction(_("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
|
||||
m.addAction(_("Show as QR code"), self.on_qr_show_btn)
|
||||
m.exec_(e.globalPos())
|
||||
|
||||
@@ -30,6 +30,7 @@ from electrum.i18n import _, languages
|
||||
from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, resource_path
|
||||
from electrum.invoices import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN, PR_FAILED, PR_ROUTING, PR_UNCONFIRMED
|
||||
from electrum.logging import Logger
|
||||
from electrum.qrreader import MissingQrDetectionLib
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .main_window import ElectrumWindow
|
||||
@@ -879,7 +880,7 @@ class OverlayControlMixin:
|
||||
# The old code positioned the items the other way around, so we just insert at position 0 instead
|
||||
self.overlay_layout.insertWidget(0, widget)
|
||||
|
||||
def addButton(self, icon_name: str, on_click, tooltip: str) -> QAbstractButton:
|
||||
def addButton(self, icon_name: str, on_click, tooltip: str) -> QPushButton:
|
||||
button = QPushButton(self.overlay_widget)
|
||||
button.setToolTip(tooltip)
|
||||
button.setIcon(read_QIcon(icon_name))
|
||||
@@ -943,7 +944,7 @@ class OverlayControlMixin:
|
||||
):
|
||||
if setText is None:
|
||||
setText = self.setText
|
||||
def qr_input():
|
||||
def qr_from_camera_input() -> None:
|
||||
def cb(success: bool, error: str, data):
|
||||
if not success:
|
||||
if error:
|
||||
@@ -960,10 +961,39 @@ class OverlayControlMixin:
|
||||
from .qrreader import scan_qrcode
|
||||
scan_qrcode(parent=self, config=config, callback=cb)
|
||||
|
||||
def qr_from_screenshot_input() -> None:
|
||||
from .qrreader import scan_qr_from_image
|
||||
scanned_qr = None
|
||||
for screen in QApplication.instance().screens():
|
||||
try:
|
||||
scan_result = scan_qr_from_image(screen.grabWindow(0).toImage())
|
||||
except MissingQrDetectionLib as e:
|
||||
show_error(_("Unable to scan image.") + "\n" + repr(e))
|
||||
return
|
||||
if len(scan_result) > 0:
|
||||
if (scanned_qr is not None) or len(scan_result) > 1:
|
||||
show_error(_("More than one QR code was found on the screen."))
|
||||
return
|
||||
scanned_qr = scan_result
|
||||
if scanned_qr is None:
|
||||
show_error(_("No QR code was found on the screen."))
|
||||
return
|
||||
data = scanned_qr[0].data
|
||||
if allow_multi:
|
||||
new_text = self.text() + data + '\n'
|
||||
else:
|
||||
new_text = data
|
||||
setText(new_text)
|
||||
|
||||
icon = "camera_white.png" if ColorScheme.dark_scheme else "camera_dark.png"
|
||||
self.addButton(icon, qr_input, _("Read QR code"))
|
||||
# side-effect: we export this method:
|
||||
self.on_qr_input_btn = qr_input
|
||||
btn = self.addButton(icon, lambda: None, _("Read QR code"))
|
||||
menu = QMenu()
|
||||
menu.addAction(_("Read QR code from camera"), qr_from_camera_input)
|
||||
menu.addAction(_("Read QR code from screen"), qr_from_screenshot_input)
|
||||
btn.setMenu(menu)
|
||||
# side-effect: we export these methods:
|
||||
self.on_qr_from_camera_input_btn = qr_from_camera_input
|
||||
self.on_qr_from_screenshot_input_btn = qr_from_screenshot_input
|
||||
|
||||
def add_file_input_button(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user