mirror of
https://github.com/feather-wallet/feather.git
synced 2025-01-05 10:29:27 +00:00
Enable webcam QR scanner
This commit is contained in:
parent
68e3f3aecd
commit
23d4b0cd1c
11 changed files with 334 additions and 56 deletions
|
@ -25,9 +25,7 @@ option(CHECK_UPDATES "Enable checking for application updates" OFF)
|
||||||
option(PLATFORM_INSTALLER "Built-in updater fetches installer (windows-only)" OFF)
|
option(PLATFORM_INSTALLER "Built-in updater fetches installer (windows-only)" OFF)
|
||||||
option(USE_DEVICE_TREZOR "Trezor support compilation" ON)
|
option(USE_DEVICE_TREZOR "Trezor support compilation" ON)
|
||||||
option(DONATE_BEG "Prompt donation window every once in a while" ON)
|
option(DONATE_BEG "Prompt donation window every once in a while" ON)
|
||||||
|
option(WITH_SCANNER "Enable webcam QR scanner" ON)
|
||||||
|
|
||||||
option(WITH_SCANNER "Enable webcam QR scanner" OFF)
|
|
||||||
|
|
||||||
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
|
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
include(CheckCCompilerFlag)
|
include(CheckCCompilerFlag)
|
||||||
|
|
|
@ -69,8 +69,8 @@ file(GLOB SOURCE_FILES
|
||||||
"polyseed/*.h"
|
"polyseed/*.h"
|
||||||
"polyseed/*.cpp"
|
"polyseed/*.cpp"
|
||||||
"polyseed/*.c"
|
"polyseed/*.c"
|
||||||
"qrcode_scanner/QrCodeUtils.cpp"
|
"qrcode_utils/QrCodeUtils.cpp"
|
||||||
"qrcode_scanner/QrCodeUtils.h"
|
"qrcode_utils/QrCodeUtils.h"
|
||||||
"monero_seed/argon2/blake2/*.c"
|
"monero_seed/argon2/blake2/*.c"
|
||||||
"monero_seed/argon2/*.c"
|
"monero_seed/argon2/*.c"
|
||||||
"monero_seed/*.cpp"
|
"monero_seed/*.cpp"
|
||||||
|
@ -175,7 +175,7 @@ if(XMRIG)
|
||||||
target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
|
target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_SCANNER AND NOT Qt6_FOUND)
|
if(WITH_SCANNER)
|
||||||
target_compile_definitions(feather PRIVATE WITH_SCANNER=1)
|
target_compile_definitions(feather PRIVATE WITH_SCANNER=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#if defined(WITH_SCANNER) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if defined(WITH_SCANNER) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
#include "qrcode_scanner/QrCodeScanDialog.h"
|
#include "qrcode_scanner/QrCodeScanDialog.h"
|
||||||
#include <QtMultimedia/QCameraInfo>
|
#include <QtMultimedia/QCameraInfo>
|
||||||
|
#elif defined(WITH_SCANNER)
|
||||||
|
#include "qrcode_scanner_qt6/QrCodeScanDialog.h"
|
||||||
|
#include <QMediaDevices>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SendWidget::SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
SendWidget::SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
||||||
|
@ -123,6 +126,17 @@ void SendWidget::scanClicked() {
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
ui->lineAddress->setText(dialog->decodedString);
|
ui->lineAddress->setText(dialog->decodedString);
|
||||||
dialog->deleteLater();
|
dialog->deleteLater();
|
||||||
|
#elif defined(WITH_SCANNER)
|
||||||
|
auto cameras = QMediaDevices::videoInputs();
|
||||||
|
if (cameras.empty()) {
|
||||||
|
QMessageBox::warning(this, "QR code scanner", "No available cameras found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dialog = new QrCodeScanDialog(this);
|
||||||
|
dialog->exec();
|
||||||
|
ui->lineAddress->setText(dialog->decodedString);
|
||||||
|
dialog->deleteLater();
|
||||||
#else
|
#else
|
||||||
QMessageBox::warning(this, "QR scanner", "Feather was built without webcam QR scanner support.");
|
QMessageBox::warning(this, "QR scanner", "Feather was built without webcam QR scanner support.");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,23 +7,99 @@
|
||||||
#include <QCamera>
|
#include <QCamera>
|
||||||
#include <QMediaDevices>
|
#include <QMediaDevices>
|
||||||
#include <QCameraDevice>
|
#include <QCameraDevice>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QImageCapture>
|
||||||
|
#include <QVideoFrame>
|
||||||
|
|
||||||
QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
|
QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::QrCodeScanDialog)
|
, ui(new Ui::QrCodeScanDialog)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
this->setWindowTitle("Scan QR code");
|
||||||
|
|
||||||
m_camera.reset(new QCamera(QMediaDevices::defaultVideoInput()));
|
QPixmap pixmap = QPixmap(":/assets/images/warning.png");
|
||||||
|
ui->icon_warning->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));
|
||||||
|
|
||||||
|
const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
|
||||||
|
for (const auto &camera : cameras) {
|
||||||
|
ui->combo_camera->addItem(camera.description());
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(ui->combo_camera, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QrCodeScanDialog::onCameraSwitched);
|
||||||
|
|
||||||
|
this->onCameraSwitched(0);
|
||||||
|
|
||||||
|
m_thread = new QrScanThread(this);
|
||||||
|
m_thread->start();
|
||||||
|
|
||||||
|
connect(m_thread, &QrScanThread::decoded, this, &QrCodeScanDialog::onDecoded);
|
||||||
|
connect(m_thread, &QrScanThread::notifyError, this, &QrCodeScanDialog::notifyError);
|
||||||
|
|
||||||
|
connect(&m_imageTimer, &QTimer::timeout, this, &QrCodeScanDialog::takeImage);
|
||||||
|
m_imageTimer.start(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::onCameraSwitched(int index) {
|
||||||
|
const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
|
||||||
|
|
||||||
|
if (index >= cameras.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_camera.reset(new QCamera(cameras.at(index)));
|
||||||
m_captureSession.setCamera(m_camera.data());
|
m_captureSession.setCamera(m_camera.data());
|
||||||
|
|
||||||
m_captureSession.setVideoOutput(ui->viewfinder);
|
m_captureSession.setVideoOutput(ui->viewfinder);
|
||||||
|
|
||||||
m_camera->start();
|
m_imageCapture = new QImageCapture;
|
||||||
|
m_captureSession.setImageCapture(m_imageCapture);
|
||||||
|
|
||||||
const QList<QCameraDevice> availableCameras = QMediaDevices::videoInputs();
|
connect(m_imageCapture, &QImageCapture::imageCaptured, this, &QrCodeScanDialog::processCapturedImage);
|
||||||
|
connect(m_camera.data(), &QCamera::errorOccurred, this, &QrCodeScanDialog::displayCameraError);
|
||||||
|
connect(m_camera.data(), &QCamera::activeChanged, [this](bool active){
|
||||||
|
ui->frame_unavailable->setVisible(!active);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_camera->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::processCapturedImage(int requestId, const QImage& img) {
|
||||||
|
Q_UNUSED(requestId);
|
||||||
|
QImage image{img};
|
||||||
|
image.convertTo(QImage::Format_RGB32);
|
||||||
|
m_thread->addImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::takeImage()
|
||||||
|
{
|
||||||
|
if (m_imageCapture->isReadyForCapture()) {
|
||||||
|
m_imageCapture->capture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::onDecoded(int type, const QString &data) {
|
||||||
|
decodedString = data;
|
||||||
|
this->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::displayCameraError()
|
||||||
|
{
|
||||||
|
if (m_camera->error() != QCamera::NoError) {
|
||||||
|
QMessageBox::warning(this, tr("Camera Error"), m_camera->errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCodeScanDialog::notifyError(const QString &msg) {
|
||||||
|
qDebug() << "QrScanner error: " << msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QrCodeScanDialog::~QrCodeScanDialog()
|
QrCodeScanDialog::~QrCodeScanDialog()
|
||||||
{
|
{
|
||||||
|
m_thread->stop();
|
||||||
|
m_thread->quit();
|
||||||
|
if (!m_thread->wait(5000))
|
||||||
|
{
|
||||||
|
m_thread->terminate();
|
||||||
|
m_thread->wait();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,9 @@
|
||||||
#include <QCamera>
|
#include <QCamera>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QMediaCaptureSession>
|
#include <QMediaCaptureSession>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "QrScanThread.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class QrCodeScanDialog;
|
class QrCodeScanDialog;
|
||||||
|
@ -21,9 +24,23 @@ public:
|
||||||
explicit QrCodeScanDialog(QWidget *parent);
|
explicit QrCodeScanDialog(QWidget *parent);
|
||||||
~QrCodeScanDialog() override;
|
~QrCodeScanDialog() override;
|
||||||
|
|
||||||
|
QString decodedString = "";
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onCameraSwitched(int index);
|
||||||
|
void onDecoded(int type, const QString &data);
|
||||||
|
void notifyError(const QString &msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void processCapturedImage(int requestId, const QImage& img);
|
||||||
|
void displayCameraError();
|
||||||
|
void takeImage();
|
||||||
|
|
||||||
QScopedPointer<Ui::QrCodeScanDialog> ui;
|
QScopedPointer<Ui::QrCodeScanDialog> ui;
|
||||||
|
|
||||||
|
QrScanThread *m_thread;
|
||||||
|
QImageCapture *m_imageCapture;
|
||||||
|
QTimer m_imageTimer;
|
||||||
QScopedPointer<QCamera> m_camera;
|
QScopedPointer<QCamera> m_camera;
|
||||||
QMediaCaptureSession m_captureSession;
|
QMediaCaptureSession m_captureSession;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>816</width>
|
<width>490</width>
|
||||||
<height>688</height>
|
<height>422</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -15,20 +15,88 @@
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QVideoWidget" name="viewfinder" native="true"/>
|
<widget class="QVideoWidget" name="viewfinder" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QFrame" name="frame_unavailable">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="icon_warning">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>icon</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="sizeType">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<enum>QSizePolicy::Preferred</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>55</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Lost connection to camera. Please restart scan dialog.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Camera:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="combo_camera"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>QVideoWidget</class>
|
<class>QVideoWidget</class>
|
||||||
|
@ -38,38 +106,5 @@
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>QrCodeScanDialog</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>248</x>
|
|
||||||
<y>254</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>157</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>rejected()</signal>
|
|
||||||
<receiver>QrCodeScanDialog</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>316</x>
|
|
||||||
<y>260</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>286</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
</ui>
|
||||||
|
|
96
src/qrcode_scanner_qt6/QrScanThread.cpp
Normal file
96
src/qrcode_scanner_qt6/QrScanThread.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// SPDX-FileCopyrightText: 2020-2022 The Monero Project
|
||||||
|
|
||||||
|
#include "QrScanThread.h"
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
QrScanThread::QrScanThread(QObject *parent)
|
||||||
|
: QThread(parent)
|
||||||
|
, m_running(true)
|
||||||
|
{
|
||||||
|
m_scanner.set_handler(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::image_callback(zbar::Image &image)
|
||||||
|
{
|
||||||
|
qDebug() << "image_callback : Found Code ! " ;
|
||||||
|
for (zbar::Image::SymbolIterator sym = image.symbol_begin(); sym != image.symbol_end(); ++sym) {
|
||||||
|
if (!sym->get_count()) {
|
||||||
|
QString data = QString::fromStdString(sym->get_data());
|
||||||
|
emit decoded(sym->get_type(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::processZImage(zbar::Image &image)
|
||||||
|
{
|
||||||
|
m_scanner.recycle_image(image);
|
||||||
|
zbar::Image tmp = image.convert(zbar_fourcc('Y', '8', '0', '0'));
|
||||||
|
m_scanner.scan(tmp);
|
||||||
|
image.set_symbols(tmp.get_symbols());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QrScanThread::zimageFromQImage(const QImage &qimg, zbar::Image &dst)
|
||||||
|
{
|
||||||
|
switch (qimg.format()) {
|
||||||
|
case QImage::Format_RGB32 :
|
||||||
|
case QImage::Format_ARGB32 :
|
||||||
|
case QImage::Format_ARGB32_Premultiplied :
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
qDebug() << "Format: " << qimg.format();
|
||||||
|
emit notifyError(QString("Invalid QImage Format !"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned int bpl( qimg.bytesPerLine() ), width( bpl / 4), height( qimg.height());
|
||||||
|
dst.set_size(width, height);
|
||||||
|
dst.set_format("BGR4");
|
||||||
|
unsigned long datalen = qimg.sizeInBytes();
|
||||||
|
dst.set_data(qimg.bits(), datalen);
|
||||||
|
if((width * 4 != bpl) || (width * height * 4 > datalen)){
|
||||||
|
emit notifyError(QString("QImage to Zbar::Image failed !"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::processQImage(const QImage &qimg)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
m_image = QSharedPointer<zbar::Image>(new zbar::Image());
|
||||||
|
if (!zimageFromQImage(qimg, *m_image))
|
||||||
|
return;
|
||||||
|
processZImage(*m_image);
|
||||||
|
}
|
||||||
|
catch(std::exception &e) {
|
||||||
|
qDebug() << "ERROR: " << e.what();
|
||||||
|
emit notifyError(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::stop()
|
||||||
|
{
|
||||||
|
m_running = false;
|
||||||
|
m_waitCondition.wakeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::addImage(const QImage &img)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
m_queue.append(img);
|
||||||
|
m_waitCondition.wakeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrScanThread::run()
|
||||||
|
{
|
||||||
|
while (m_running) {
|
||||||
|
QMutexLocker locker(&m_mutex);
|
||||||
|
while (m_queue.isEmpty() && m_running) {
|
||||||
|
m_waitCondition.wait(&m_mutex);
|
||||||
|
}
|
||||||
|
if (!m_queue.isEmpty()) {
|
||||||
|
processQImage(m_queue.takeFirst());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/qrcode_scanner_qt6/QrScanThread.h
Normal file
42
src/qrcode_scanner_qt6/QrScanThread.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// SPDX-FileCopyrightText: 2020-2022 The Monero Project
|
||||||
|
|
||||||
|
#ifndef _QRSCANTHREAD_H_
|
||||||
|
#define _QRSCANTHREAD_H_
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QCamera>
|
||||||
|
#include <zbar.h>
|
||||||
|
|
||||||
|
class QrScanThread : public QThread, public zbar::Image::Handler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QrScanThread(QObject *parent = nullptr);
|
||||||
|
void addImage(const QImage &img);
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void decoded(int type, const QString &data);
|
||||||
|
void notifyError(const QString &error, bool warning = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void run();
|
||||||
|
void processQImage(const QImage &);
|
||||||
|
void processZImage(zbar::Image &image);
|
||||||
|
virtual void image_callback(zbar::Image &image);
|
||||||
|
bool zimageFromQImage(const QImage&, zbar::Image &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
zbar::ImageScanner m_scanner;
|
||||||
|
QSharedPointer<zbar::Image> m_image;
|
||||||
|
bool m_running;
|
||||||
|
QMutex m_mutex;
|
||||||
|
QWaitCondition m_waitCondition;
|
||||||
|
QList<QImage> m_queue;
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "libwalletqt/WalletManager.h"
|
#include "libwalletqt/WalletManager.h"
|
||||||
#include "model/ModelUtils.h"
|
#include "model/ModelUtils.h"
|
||||||
#include "qrcode_scanner/QrCodeUtils.h"
|
#include "qrcode_utils/QrCodeUtils.h"
|
||||||
|
|
||||||
PayToEdit::PayToEdit(QWidget *parent) : QPlainTextEdit(parent)
|
PayToEdit::PayToEdit(QWidget *parent) : QPlainTextEdit(parent)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue