mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-22 11:39:25 +00:00
QrScanner: macOS support
This commit is contained in:
parent
3db3e330d5
commit
a1db9ade6b
8 changed files with 83 additions and 152 deletions
|
@ -42,7 +42,7 @@ RUN git clone -b v3.18.4 --depth 1 https://github.com/Kitware/CMake && \
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
# freetype2: Required for Qt 5.15
|
||||
# freetype2: Required for Qt 5.15, fontconfig
|
||||
RUN git clone -b VER-2-10-2 --depth 1 https://git.savannah.gnu.org/git/freetype/freetype2.git && \
|
||||
cd freetype2 && \
|
||||
git reset --hard 132f19b779828b194b3fede187cee719785db4d8 && \
|
||||
|
|
1
Makefile
1
Makefile
|
@ -59,6 +59,7 @@ depends:
|
|||
mac-release: CMAKEFLAGS += -DSTATIC=Off
|
||||
mac-release: CMAKEFLAGS += -DTOR_BIN=$(or ${TOR_BIN},OFF)
|
||||
mac-release: CMAKEFLAGS += -DCHECK_UPDATES=$(or ${CHECK_UPDATES}, Off)
|
||||
mac-release: CMAKEFLAGS += -DWITH_SCANNER=$(or ${WITH_SCANNER}, On)
|
||||
mac-release: CMAKEFLAGS += -DBUILD_TAG="mac-x64"
|
||||
mac-release: CMAKEFLAGS += -DCMAKE_BUILD_TYPE=Release
|
||||
mac-release:
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::QrCodeScanDialog)
|
||||
, m_scanner(new QrCodeScanner(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowTitle("Scan QR Code");
|
||||
|
@ -31,10 +30,16 @@ QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
|
|||
|
||||
connect(ui->combo_camera, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QrCodeScanDialog::onCameraSwitched);
|
||||
|
||||
connect(m_scanner, &QrCodeScanner::decoded, this, &QrCodeScanDialog::onDecoded);
|
||||
connect(m_scanner, &QrCodeScanner::notifyError, this, &QrCodeScanDialog::notifyError);
|
||||
|
||||
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) {
|
||||
|
@ -42,24 +47,60 @@ void QrCodeScanDialog::onCameraSwitched(int index) {
|
|||
return;
|
||||
}
|
||||
|
||||
m_scanner->setSource(nullptr);
|
||||
delete m_camera;
|
||||
m_camera.reset(new QCamera(m_cameras.at(index)));
|
||||
|
||||
m_camera = new QCamera(m_cameras.at(index), this);
|
||||
connect(m_camera, &QCamera::statusChanged, [this](QCamera::Status status){
|
||||
auto captureMode = QCamera::CaptureStillImage;
|
||||
if (m_camera->isCaptureModeSupported(captureMode)) {
|
||||
m_camera->setCaptureMode(captureMode);
|
||||
}
|
||||
|
||||
connect(m_camera.data(), QOverload<QCamera::Error>::of(&QCamera::error), this, &QrCodeScanDialog::displayCameraError);
|
||||
connect(m_camera.data(), &QCamera::statusChanged, [this](QCamera::Status status){
|
||||
bool unloaded = (status == QCamera::Status::UnloadedStatus);
|
||||
ui->frame_unavailable->setVisible(unloaded);
|
||||
});
|
||||
|
||||
m_camera->setCaptureMode(QCamera::CaptureViewfinder);
|
||||
m_imageCapture.reset(new QCameraImageCapture(m_camera.data()));
|
||||
if (!m_imageCapture->isCaptureDestinationSupported(QCameraImageCapture::CaptureToBuffer)) {
|
||||
qDebug() << "Capture to buffer is NOT supported";
|
||||
}
|
||||
|
||||
m_imageCapture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
|
||||
|
||||
connect(m_imageCapture.data(), &QCameraImageCapture::imageAvailable, this, &QrCodeScanDialog::processAvailableImage);
|
||||
connect(m_imageCapture.data(), QOverload<int, QCameraImageCapture::Error, const QString &>::of(&QCameraImageCapture::error),
|
||||
this, &QrCodeScanDialog::displayCaptureError);
|
||||
|
||||
m_camera->setViewfinder(ui->viewfinder);
|
||||
|
||||
m_scanner->setSource(m_camera);
|
||||
m_scanner->setEnabled(true);
|
||||
|
||||
m_camera->start();
|
||||
}
|
||||
|
||||
void QrCodeScanDialog::displayCaptureError(int id, const QCameraImageCapture::Error error, const QString &errorString)
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
Q_UNUSED(error);
|
||||
QMessageBox::warning(this, "Image Capture Error", errorString);
|
||||
}
|
||||
|
||||
void QrCodeScanDialog::displayCameraError()
|
||||
{
|
||||
QMessageBox::warning(this, "Camera Error", m_camera->errorString());
|
||||
}
|
||||
|
||||
void QrCodeScanDialog::processAvailableImage(int id, const QVideoFrame &frame) {
|
||||
Q_UNUSED(id);
|
||||
QImage img = frame.image();
|
||||
img.convertTo(QImage::Format_RGB32);
|
||||
m_thread->addImage(img);
|
||||
}
|
||||
|
||||
void QrCodeScanDialog::takeImage()
|
||||
{
|
||||
if (m_imageCapture->isReadyForCapture()) {
|
||||
m_imageCapture->capture();
|
||||
}
|
||||
}
|
||||
|
||||
void QrCodeScanDialog::onDecoded(int type, const QString &data) {
|
||||
decodedString = data;
|
||||
this->accept();
|
||||
|
@ -71,6 +112,12 @@ void QrCodeScanDialog::notifyError(const QString &msg) {
|
|||
|
||||
QrCodeScanDialog::~QrCodeScanDialog()
|
||||
{
|
||||
delete m_camera;
|
||||
m_thread->stop();
|
||||
m_thread->quit();
|
||||
if (!m_thread->wait(5000))
|
||||
{
|
||||
m_thread->terminate();
|
||||
m_thread->wait();
|
||||
}
|
||||
delete ui;
|
||||
}
|
|
@ -6,8 +6,11 @@
|
|||
|
||||
#include <QDialog>
|
||||
#include <QCamera>
|
||||
#include <QCameraImageCapture>
|
||||
#include <QTimer>
|
||||
#include <QVideoFrame>
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include "QrScanThread.h"
|
||||
|
||||
namespace Ui {
|
||||
class QrCodeScanDialog;
|
||||
|
@ -29,11 +32,19 @@ private slots:
|
|||
void notifyError(const QString &msg);
|
||||
|
||||
private:
|
||||
void processAvailableImage(int id, const QVideoFrame &frame);
|
||||
void displayCaptureError(int, QCameraImageCapture::Error, const QString &errorString);
|
||||
void displayCameraError();
|
||||
void takeImage();
|
||||
|
||||
Ui::QrCodeScanDialog *ui;
|
||||
|
||||
QScopedPointer<QCamera> m_camera;
|
||||
QScopedPointer<QCameraImageCapture> m_imageCapture;
|
||||
|
||||
QrScanThread *m_thread;
|
||||
QTimer m_imageTimer;
|
||||
QList<QCameraInfo> m_cameras;
|
||||
QCamera *m_camera = nullptr;
|
||||
QrCodeScanner *m_scanner;
|
||||
};
|
||||
|
||||
#endif //FEATHER_QRCODESCANDIALOG_H
|
|
@ -1,72 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2021, The Monero Project.
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include <WalletManager.h>
|
||||
#include <QVideoProbe>
|
||||
#include <QCamera>
|
||||
|
||||
QrCodeScanner::QrCodeScanner(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_processTimerId(-1)
|
||||
, m_processInterval(750)
|
||||
, m_enabled(true)
|
||||
{
|
||||
m_probe = new QVideoProbe(this);
|
||||
m_thread = new QrScanThread(this);
|
||||
m_thread->start();
|
||||
|
||||
connect(m_thread, &QrScanThread::decoded, this, &QrCodeScanner::decoded);
|
||||
connect(m_thread, &QrScanThread::notifyError, this, &QrCodeScanner::notifyError);
|
||||
connect(m_probe, &QVideoProbe::videoFrameProbed, this, &QrCodeScanner::processFrame);
|
||||
}
|
||||
|
||||
void QrCodeScanner::setSource(QCamera *camera)
|
||||
{
|
||||
m_probe->setSource((QMediaObject *)camera);
|
||||
}
|
||||
|
||||
void QrCodeScanner::processFrame(const QVideoFrame &frame)
|
||||
{
|
||||
if (frame.isValid()){
|
||||
m_curFrame = frame;
|
||||
}
|
||||
}
|
||||
|
||||
bool QrCodeScanner::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void QrCodeScanner::setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
if(!enabled && (m_processTimerId != -1) )
|
||||
{
|
||||
this->killTimer(m_processTimerId);
|
||||
m_processTimerId = -1;
|
||||
}
|
||||
else if (enabled && (m_processTimerId == -1) )
|
||||
{
|
||||
m_processTimerId = this->startTimer(m_processInterval);
|
||||
}
|
||||
emit enabledChanged();
|
||||
}
|
||||
|
||||
void QrCodeScanner::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == m_processTimerId) {
|
||||
m_thread->addFrame(m_curFrame);
|
||||
}
|
||||
}
|
||||
|
||||
QrCodeScanner::~QrCodeScanner()
|
||||
{
|
||||
m_thread->stop();
|
||||
m_thread->quit();
|
||||
if (!m_thread->wait(5000))
|
||||
{
|
||||
m_thread->terminate();
|
||||
m_thread->wait();
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2014-2020, The Monero Project.
|
||||
|
||||
|
||||
#ifndef QRCODESCANNER_H_
|
||||
#define QRCODESCANNER_H_
|
||||
|
||||
#include <QImage>
|
||||
#include <QVideoFrame>
|
||||
#include "QrScanThread.h"
|
||||
|
||||
class QVideoProbe;
|
||||
class QCamera;
|
||||
|
||||
class QrCodeScanner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
|
||||
public:
|
||||
explicit QrCodeScanner(QObject *parent = nullptr);
|
||||
~QrCodeScanner() override;
|
||||
void setSource(QCamera*);
|
||||
|
||||
bool enabled() const;
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
public slots:
|
||||
void processFrame(const QVideoFrame &frame);
|
||||
|
||||
signals:
|
||||
void enabledChanged();
|
||||
void decoded(int type, const QString &data);
|
||||
void decode(int type, const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *);
|
||||
QrScanThread *m_thread;
|
||||
int m_processTimerId;
|
||||
int m_processInterval;
|
||||
int m_enabled;
|
||||
QVideoFrame m_curFrame;
|
||||
QVideoProbe *m_probe;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -69,34 +69,28 @@ void QrScanThread::processQImage(const QImage &qimg)
|
|||
}
|
||||
}
|
||||
|
||||
void QrScanThread::processVideoFrame(const QVideoFrame &frame)
|
||||
{
|
||||
processQImage(frame.image());
|
||||
}
|
||||
|
||||
void QrScanThread::stop()
|
||||
{
|
||||
m_running = false;
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::addFrame(const QVideoFrame &frame)
|
||||
void QrScanThread::addImage(const QImage &img)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_queue.append(frame);
|
||||
m_queue.append(img);
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
void QrScanThread::run()
|
||||
{
|
||||
QVideoFrame frame;
|
||||
while (m_running) {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
while (m_queue.isEmpty() && m_running) {
|
||||
m_waitCondition.wait(&m_mutex);
|
||||
}
|
||||
if (!m_queue.isEmpty()) {
|
||||
processVideoFrame(m_queue.takeFirst());
|
||||
processQImage(m_queue.takeFirst());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QEvent>
|
||||
#include <QVideoFrame>
|
||||
#include <QCamera>
|
||||
#include <zbar.h>
|
||||
|
||||
|
@ -18,7 +17,7 @@ class QrScanThread : public QThread, public zbar::Image::Handler
|
|||
|
||||
public:
|
||||
QrScanThread(QObject *parent = nullptr);
|
||||
void addFrame(const QVideoFrame &frame);
|
||||
void addImage(const QImage &img);
|
||||
virtual void stop();
|
||||
|
||||
signals:
|
||||
|
@ -27,7 +26,6 @@ signals:
|
|||
|
||||
protected:
|
||||
virtual void run();
|
||||
void processVideoFrame(const QVideoFrame &);
|
||||
void processQImage(const QImage &);
|
||||
void processZImage(zbar::Image &image);
|
||||
virtual void image_callback(zbar::Image &image);
|
||||
|
@ -39,6 +37,6 @@ private:
|
|||
bool m_running;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
QList<QVideoFrame> m_queue;
|
||||
QList<QImage> m_queue;
|
||||
};
|
||||
#endif
|
Loading…
Reference in a new issue