diff --git a/Dockerfile b/Dockerfile index 2a620ff..a162361 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 && \ diff --git a/Makefile b/Makefile index 7d01330..dc0c2a3 100644 --- a/Makefile +++ b/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: diff --git a/src/qrcode_scanner/QrCodeScanDialog.cpp b/src/qrcode_scanner/QrCodeScanDialog.cpp index 9d70f17..502f308 100644 --- a/src/qrcode_scanner/QrCodeScanDialog.cpp +++ b/src/qrcode_scanner/QrCodeScanDialog.cpp @@ -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::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::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::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; } \ No newline at end of file diff --git a/src/qrcode_scanner/QrCodeScanDialog.h b/src/qrcode_scanner/QrCodeScanDialog.h index 5fe1ff4..8227ed1 100644 --- a/src/qrcode_scanner/QrCodeScanDialog.h +++ b/src/qrcode_scanner/QrCodeScanDialog.h @@ -6,8 +6,11 @@ #include #include +#include +#include +#include -#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 m_camera; + QScopedPointer m_imageCapture; + + QrScanThread *m_thread; + QTimer m_imageTimer; QList m_cameras; - QCamera *m_camera = nullptr; - QrCodeScanner *m_scanner; }; #endif //FEATHER_QRCODESCANDIALOG_H \ No newline at end of file diff --git a/src/qrcode_scanner/QrCodeScanner.cpp b/src/qrcode_scanner/QrCodeScanner.cpp deleted file mode 100644 index 44c211c..0000000 --- a/src/qrcode_scanner/QrCodeScanner.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2014-2021, The Monero Project. - -#include "QrCodeScanner.h" -#include -#include -#include - -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(); - } -} diff --git a/src/qrcode_scanner/QrCodeScanner.h b/src/qrcode_scanner/QrCodeScanner.h deleted file mode 100644 index 5339faf..0000000 --- a/src/qrcode_scanner/QrCodeScanner.h +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2014-2020, The Monero Project. - - -#ifndef QRCODESCANNER_H_ -#define QRCODESCANNER_H_ - -#include -#include -#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 diff --git a/src/qrcode_scanner/QrScanThread.cpp b/src/qrcode_scanner/QrScanThread.cpp index 2cfb0b7..a74d141 100644 --- a/src/qrcode_scanner/QrScanThread.cpp +++ b/src/qrcode_scanner/QrScanThread.cpp @@ -33,7 +33,7 @@ void QrScanThread::processZImage(zbar::Image &image) bool QrScanThread::zimageFromQImage(const QImage &qimg, zbar::Image &dst) { - switch( qimg.format() ){ + switch (qimg.format()) { case QImage::Format_RGB32 : case QImage::Format_ARGB32 : case QImage::Format_ARGB32_Premultiplied : @@ -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()); } } } \ No newline at end of file diff --git a/src/qrcode_scanner/QrScanThread.h b/src/qrcode_scanner/QrScanThread.h index 9575340..bba7823 100644 --- a/src/qrcode_scanner/QrScanThread.h +++ b/src/qrcode_scanner/QrScanThread.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -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 m_queue; + QList m_queue; }; #endif \ No newline at end of file