]> Nutra Git (v1) - gamesguru/feather.git/commitdiff
scanner: replace zbar with zxing
authortobtoht <tob@featherwallet.org>
Tue, 10 Oct 2023 12:21:11 +0000 (14:21 +0200)
committertobtoht <tob@featherwallet.org>
Tue, 10 Oct 2023 12:41:45 +0000 (14:41 +0200)
22 files changed:
CMakeLists.txt
cmake/FindZBAR.cmake [deleted file]
cmake/FindZXing.cmake [new file with mode: 0644]
contrib/depends/packages/packages.mk
contrib/depends/packages/quirc.mk [deleted file]
contrib/depends/packages/zbar.mk [deleted file]
contrib/depends/packages/zxing-cpp.mk [new file with mode: 0644]
contrib/depends/patches/quirc/CMakeLists.txt [deleted file]
src/CMakeLists.txt
src/SendWidget.cpp
src/qrcode/scanner/QrCodeScanDialog.cpp
src/qrcode/scanner/QrCodeScanDialog.h
src/qrcode/scanner/QrCodeScanDialog.ui
src/qrcode/scanner/QrScanThread.cpp
src/qrcode/scanner/QrScanThread.h
src/qrcode/scanner_qt6/QrCodeScanDialog.cpp [deleted file]
src/qrcode/scanner_qt6/QrCodeScanDialog.h [deleted file]
src/qrcode/scanner_qt6/QrCodeScanDialog.ui [deleted file]
src/qrcode/scanner_qt6/QrScanThread.cpp [deleted file]
src/qrcode/scanner_qt6/QrScanThread.h [deleted file]
src/qrcode/utils/QrCodeUtils.cpp
src/qrcode/utils/QrCodeUtils.h

index c84d4709549d821afb41609a99605244d7db49d8..79942fd03898ded5acd9e7a0c210ccac2f3c8027 100644 (file)
@@ -92,11 +92,9 @@ if(Polyseed_SUBMODULE)
     add_subdirectory(src/third-party/polyseed EXCLUDE_FROM_ALL)
 endif()
 
-# ZBAR
+# ZXing
 if(WITH_SCANNER)
-    find_package(ZBAR REQUIRED)
-    message(STATUS "libzbar: include dir at ${ZBAR_INCLUDE_DIR}")
-    message(STATUS "libzbar: libraries at ${ZBAR_LIBRARIES}")
+    find_package(ZXing REQUIRED)
 endif()
 
 # libzip
diff --git a/cmake/FindZBAR.cmake b/cmake/FindZBAR.cmake
deleted file mode 100644 (file)
index 290f333..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-find_package(PkgConfig)
-
-if(PkgConfig_FOUND)
-    pkg_check_modules(PC_ZBAR QUIET zbar)
-    if(PC_ZBAR_FOUND)
-        set(ZBAR_DEFINITIONS ${PC_ZBAR_CFLAGS_OTHER})
-        find_library(ZBAR_LIBRARIES NAMES zbar HINTS ${PC_ZBAR_LIBDIR} ${PC_ZBAR_LIBRARY_DIRS})
-        find_path(ZBAR_INCLUDE_DIR Decoder.h HINTS ${PC_ZBAR_INCLUDEDIR} ${PC_ZBAR_INCLUDE_DIRS})
-    endif()
-endif()
-
-if(NOT ZBAR_INCLUDE_DIR)
-    find_path(ZBAR_H_PATH zbar.h)
-    if(ZBAR_H_PATH)
-        set(ZBAR_INCLUDE_DIR "${ZBAR_H_PATH}")
-    endif()
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(ZBAR  DEFAULT_MSG  ZBAR_LIBRARIES ZBAR_INCLUDE_DIR)
-message(STATUS "Found zbar libraries ${ZBAR_LIBRARIES}")
diff --git a/cmake/FindZXing.cmake b/cmake/FindZXing.cmake
new file mode 100644 (file)
index 0000000..ee03f13
--- /dev/null
@@ -0,0 +1,55 @@
+############################################################################
+# FindZxing.txt
+# Copyright (C) 2018  Belledonne Communications, Grenoble France
+#
+############################################################################
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+############################################################################
+#
+# - Find the zxing include file and library
+#
+#  ZXING_FOUND - system has zxing
+#  ZXING_INCLUDE_DIRS - the zxing include directory
+#  ZXING_LIBRARIES - The libraries needed to use zxing
+
+find_path(ZXING_INCLUDE_DIRS
+       NAMES
+               ZXing/BarcodeFormat.h
+               ZXing/BitHacks.h
+               ZXing/ByteArray.h
+               ZXing/CharacterSet.h
+               ZXing/Flags.h
+               ZXing/GTIN.h
+               ZXing/TextUtfEncoding.h
+               ZXing/ZXAlgorithms.h
+               ZXing/ZXConfig.h
+       PATH_SUFFIXES include
+)
+
+find_library(ZXING_LIBRARIES
+       NAMES ZXing libZXing
+       PATH_SUFFIXES Frameworks bin lib lib64
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ZXing
+       DEFAULT_MSG
+       ZXING_INCLUDE_DIRS ZXING_LIBRARIES
+)
+
+mark_as_advanced(ZXING_INCLUDE_DIRS ZXING_LIBRARIES)
+
index ab03407f5737dba7f7316fd681313f18a4075cfa..263e082a2f1214ca101a225fe7793aac3a36ac30 100644 (file)
@@ -1,4 +1,4 @@
-packages := boost openssl libiconv unbound qrencode zbar sodium polyseed hidapi protobuf libusb zlib libgpg-error libgcrypt expat libzip bc-ur quirc
+packages := boost openssl libiconv unbound qrencode sodium polyseed hidapi protobuf libusb zlib libgpg-error libgcrypt expat libzip bc-ur zxing-cpp
 native_packages := native_qt native_protobuf
 
 linux_packages := eudev libfuse libsquashfuse zstd appimage_runtime
diff --git a/contrib/depends/packages/quirc.mk b/contrib/depends/packages/quirc.mk
deleted file mode 100644 (file)
index 2c32dc6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package=quirc
-$(package)_version=1.2
-$(package)_download_path=https://github.com/dlbeer/quirc/archive/refs/tags/
-$(package)_file_name=v1.2.tar.gz
-$(package)_sha256_hash=73c12ea33d337ec38fb81218c7674f57dba7ec0570bddd5c7f7a977c0deb64c5
-$(package)_patches += CMakeLists.txt
-
-define $(package)_preprocess_cmds
-  cp $($(package)_patch_dir)/CMakeLists.txt CMakeLists.txt
-endef
-
-define $(package)_config_cmds
-    $($(package)_cmake) -DCMAKE_INSTALL_PREFIX=$(host_prefix) .
-endef
-
-define $(package)_build_cmds
-    $(MAKE)
-endef
-
-define $(package)_stage_cmds
-    $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
diff --git a/contrib/depends/packages/zbar.mk b/contrib/depends/packages/zbar.mk
deleted file mode 100644 (file)
index e8d11f9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package=zbar
-$(package)_version=0.23.90
-$(package)_download_path=https://github.com/mchehab/zbar/archive/refs/tags/
-$(package)_download_file=$($(package)_version).tar.gz
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=25fdd6726d5c4c6f95c95d37591bfbb2dde63d13d0b10cb1350923ea8b11963b
-$(package)_dependencies=libiconv
-
-define $(package)_set_vars
-  $(package)_cflags+=-fPIE
-  $(package)_cxxflags+=-fPIE
-endef
-
-define $(package)_preprocess_cmds
-  autoreconf -vfi
-endef
-
-define $(package)_set_vars
-  $(package)_config_opts=--prefix=$(host_prefix) --disable-shared --without-imagemagick --disable-video --without-xv --with-gtk=no --with-python=no --enable-doc=no --host=$(host)
-endef
-
-define $(package)_config_cmds
-  $($(package)_autoconf) $($(package)_config_opts)
-endef
-
-define $(package)_build_cmds
-  $(MAKE) $($(package)_build_opts)
-endef
-
-define $(package)_stage_cmds
-  $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
\ No newline at end of file
diff --git a/contrib/depends/packages/zxing-cpp.mk b/contrib/depends/packages/zxing-cpp.mk
new file mode 100644 (file)
index 0000000..260d2ce
--- /dev/null
@@ -0,0 +1,22 @@
+package=zxing-cpp
+$(package)_version=2.1.0
+$(package)_download_path=https://github.com/$(package)/$(package)/archive/refs/tags
+$(package)_download_file=v$($(package)_version).tar.gz
+$(package)_file_name=$(package)-$($(package)_version).tar.gz
+$(package)_sha256_hash=6d54e403592ec7a143791c6526c1baafddf4c0897bb49b1af72b70a0f0c4a3fe
+
+define $(package)_set_vars
+  $(package)_config_opts=-DBUILD_WRITERS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_SHARED_LIBS=OFF
+endef
+
+define $(package)_config_cmds
+  $($(package)_cmake) .
+endef
+
+define $(package)_build_cmds
+  $(MAKE)
+endef
+
+define $(package)_stage_cmds
+  $(MAKE) DESTDIR=$($(package)_staging_dir) install
+endef
diff --git a/contrib/depends/patches/quirc/CMakeLists.txt b/contrib/depends/patches/quirc/CMakeLists.txt
deleted file mode 100644 (file)
index aef0598..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-cmake_minimum_required(VERSION 3.5)
-
-project(quirc)
-
-add_library(quirc STATIC
-        lib/decode.c
-        lib/identify.c
-        lib/quirc.c
-        lib/version_db.c
-        )
-
-target_include_directories(quirc PUBLIC lib)
-
-install(TARGETS quirc)
-
-install(FILES
-        lib/quirc.h
-        DESTINATION include/quirc)
index 17d73fad580529434ad97ac57a225ad8f40725ff..fdad5df2433812611685e9036ebb7876a89ac179 100644 (file)
@@ -85,18 +85,12 @@ if (WITH_SCANNER)
             "qrcode/utils/*.cpp")
 endif()
 
-if (WITH_SCANNER AND NOT Qt6_FOUND)
+if (WITH_SCANNER AND Qt6_FOUND)
     file(GLOB SCANNER_FILES
             "qrcode/scanner/*.h"
             "qrcode/scanner/*.cpp")
 endif()
 
-if (WITH_SCANNER AND Qt6_FOUND)
-    file(GLOB SCANNER_FILES
-            "qrcode/scanner_qt6/*.h"
-            "qrcode/scanner_qt6/*.cpp")
-endif()
-
 list(APPEND SOURCE_FILES
         ${UPDATER_FILES}
         ${QRCODE_UTILS_FILES}
@@ -161,9 +155,9 @@ target_include_directories(feather PUBLIC
 
 if(WITH_SCANNER)
     target_include_directories(feather PUBLIC
-            ${ZBAR_INCLUDE_DIR}
             ${QtMultimedia_INCLUDE_DIRS}
             ${QtMultimediaWidgets_INCLUDE_DIRS}
+            ${ZXING_INCLUDE_DIRS}
     )
 endif()
 
@@ -191,7 +185,7 @@ if(XMRIG)
     target_compile_definitions(feather PRIVATE HAS_XMRIG=1)
 endif()
 
-if(WITH_SCANNER)
+if(WITH_SCANNER AND Qt6_FOUND)
     target_compile_definitions(feather PRIVATE WITH_SCANNER=1)
 endif()
 
@@ -281,9 +275,9 @@ endif()
 
 if (WITH_SCANNER)
     target_link_libraries(feather
-            ${ZBAR_LIBRARIES}
             Qt::Multimedia
             Qt::MultimediaWidgets
+            ${ZXING_LIBRARIES}
     )
 endif()
 
index 43d2a6f30568e4076af285b404e8a9f1d6843d67..21d1fd6d5477753be5f7a5052a786d3616b71462 100644 (file)
 #include "Icons.h"
 #include "libwalletqt/WalletManager.h"
 
-#if defined(WITH_SCANNER) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#if defined(WITH_SCANNER)
 #include "qrcode/scanner/QrCodeScanDialog.h"
-#include <QtMultimedia/QCameraInfo>
-#elif defined(WITH_SCANNER)
-#include "qrcode/scanner_qt6//QrCodeScanDialog.h"
 #include <QMediaDevices>
 #endif
 
index 78388c1b41572c3d589c441f955abd5030220ec5..6bc4eb1d0e387b2fdccc25903a1556f397da5139 100644 (file)
 #include "QrCodeScanDialog.h"
 #include "ui_QrCodeScanDialog.h"
 
+#include <QCamera>
+#include <QMediaDevices>
+#include <QCameraDevice>
 #include <QMessageBox>
-#include <QtMultimedia/QCamera>
-#include <QtMultimedia/QCameraInfo>
+#include <QImageCapture>
+#include <QVideoFrame>
+
+#include "Utils.h"
 
 QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
-    : QDialog(parent)
-    , ui(new Ui::QrCodeScanDialog)
+        : QDialog(parent)
+        , ui(new Ui::QrCodeScanDialog)
+        , m_sink(new QVideoSink(this))
 {
     ui->setupUi(this);
-    this->setWindowTitle("Scan QR Code");
+    this->setWindowTitle("Scan QR code");
 
     QPixmap pixmap = QPixmap(":/assets/images/warning.png");
     ui->icon_warning->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));
 
-    m_cameras = QCameraInfo::availableCameras();
-
-    for (const auto &camera : m_cameras) {
-#ifdef Q_OS_WIN
+    const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
+    for (const auto &camera : cameras) {
         ui->combo_camera->addItem(camera.description());
-#else
-        ui->combo_camera->addItem(camera.deviceName());
-#endif
     }
-
+    
     connect(ui->combo_camera, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QrCodeScanDialog::onCameraSwitched);
 
+    connect(ui->viewfinder->videoSink(), &QVideoSink::videoFrameChanged, this, &QrCodeScanDialog::handleFrameCaptured);
+
     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::handleFrameCaptured(const QVideoFrame &frame) {
+    QImage img = this->videoFrameToImage(frame);
+    m_thread->addImage(img);
 }
 
-void QrCodeScanDialog::onCameraSwitched(int index) {
-    if (index >= m_cameras.size()) {
-        return;
-    }
+QImage QrCodeScanDialog::videoFrameToImage(const QVideoFrame &videoFrame)
+{
+    auto handleType = videoFrame.handleType();
 
-    m_camera.reset(new QCamera(m_cameras.at(index)));
+    if (handleType == QVideoFrame::NoHandle) {
 
-    auto captureMode = QCamera::CaptureStillImage;
-    if (m_camera->isCaptureModeSupported(captureMode)) {
-        m_camera->setCaptureMode(captureMode);
-    }
+        QImage image = videoFrame.toImage();
 
-    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);
-    });
+        if (image.isNull()) {
+            return {};
+        }
 
-    m_imageCapture.reset(new QCameraImageCapture(m_camera.data()));
-    if (!m_imageCapture->isCaptureDestinationSupported(QCameraImageCapture::CaptureToBuffer)) {
-        qDebug()  << "Capture to buffer is NOT supported";
+        if (image.format() != QImage::Format_ARGB32) {
+            image = image.convertToFormat(QImage::Format_ARGB32);
+        }
+        
+        return image.copy();
     }
+    
+    return {};
+}
 
-    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_camera->start();
-}
+void QrCodeScanDialog::onCameraSwitched(int index) {
+    const QList<QCameraDevice> cameras = QMediaDevices::videoInputs();
 
-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);
-}
+    if (index >= cameras.size()) {
+        return;
+    }
 
-void QrCodeScanDialog::displayCameraError()
-{
-    QMessageBox::warning(this, "Camera Error", m_camera->errorString());
-}
+    m_camera.reset(new QCamera(cameras.at(index)));
+    m_captureSession.setCamera(m_camera.data());
+    m_captureSession.setVideoOutput(ui->viewfinder);
 
-void QrCodeScanDialog::processAvailableImage(int id, const QVideoFrame &frame) {
-    Q_UNUSED(id);
-    QImage img = frame.image();
-    img.convertTo(QImage::Format_RGB32);
-    m_thread->addImage(img);
-}
+    connect(m_camera.data(), &QCamera::activeChanged, [this](bool active){
+        ui->frame_unavailable->setVisible(!active);
+    });
 
-void QrCodeScanDialog::takeImage()
-{
-    if (m_imageCapture->isReadyForCapture()) {
-        m_imageCapture->capture();
-    }
+    m_camera->start();
 }
 
-void QrCodeScanDialog::onDecoded(int type, const QString &data) {
+void QrCodeScanDialog::onDecoded(const QString &data) {
     decodedString = data;
     this->accept();
 }
 
-void QrCodeScanDialog::notifyError(const QString &msg) {
-    qDebug() << "QrScanner error: " << msg;
-}
-
 QrCodeScanDialog::~QrCodeScanDialog()
 {
     m_thread->stop();
index 47735d67422d2855e09f37155c2d920e7ea55bde..43ac9b08776c10aff5626e6ff3fc1a9667186401 100644 (file)
@@ -6,9 +6,10 @@
 
 #include <QDialog>
 #include <QCamera>
-#include <QCameraImageCapture>
+#include <QScopedPointer>
+#include <QMediaCaptureSession>
 #include <QTimer>
-#include <QVideoFrame>
+#include <QVideoSink>
 
 #include "QrScanThread.h"
 
@@ -28,23 +29,19 @@ public:
 
 private slots:
     void onCameraSwitched(int index);
-    void onDecoded(int type, const QString &data);
-    void notifyError(const QString &msg);
+    void onDecoded(const QString &data);
 
 private:
-    void processAvailableImage(int id, const QVideoFrame &frame);
-    void displayCaptureError(int, QCameraImageCapture::Error, const QString &errorString);
-    void displayCameraError();
-    void takeImage();
+    QImage videoFrameToImage(const QVideoFrame &videoFrame);
+    void handleFrameCaptured(const QVideoFrame &videoFrame);
 
     QScopedPointer<Ui::QrCodeScanDialog> ui;
 
-    QScopedPointer<QCamera> m_camera;
-    QScopedPointer<QCameraImageCapture> m_imageCapture;
-
     QrScanThread *m_thread;
-    QTimer m_imageTimer;
-    QList<QCameraInfo> m_cameras;
+    QScopedPointer<QCamera> m_camera;
+    QMediaCaptureSession m_captureSession;
+    QVideoSink m_sink;
 };
 
-#endif //FEATHER_QRCODESCANDIALOG_H
\ No newline at end of file
+
+#endif //FEATHER_QRCODESCANDIALOG_H
index fb555ebb7beea9067753108cddc3a5292538eb3e..9cda99941c41a8fa35b8f6f6c9269d680dcc3b32 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>400</width>
-    <height>300</height>
+    <width>490</width>
+    <height>422</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -15,7 +15,7 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="QCameraViewfinder" name="viewfinder" native="true">
+    <widget class="QVideoWidget" name="viewfinder" native="true">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
        <horstretch>0</horstretch>
@@ -32,7 +32,7 @@
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
-     <layout class="QHBoxLayout" name="horizontalLayout">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
       <item>
        <widget class="QLabel" name="icon_warning">
         <property name="sizePolicy">
         </property>
         <property name="sizeHint" stdset="0">
          <size>
-          <width>10</width>
+          <width>55</width>
           <height>0</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
-       <widget class="QLabel" name="label">
+       <widget class="QLabel" name="label_2">
         <property name="text">
          <string>Lost connection to camera. Please restart scan dialog.</string>
         </property>
@@ -99,9 +99,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>QCameraViewfinder</class>
+   <class>QVideoWidget</class>
    <extends>QWidget</extends>
-   <header>qcameraviewfinder.h</header>
+   <header>qvideowidget.h</header>
    <container>1</container>
   </customwidget>
  </customwidgets>
index 54a699bde56425a36b9ab74586a1963358762b64..98f1f7953f048595f9f0c9a35775f8edb6e88210 100644 (file)
@@ -2,70 +2,27 @@
 // SPDX-FileCopyrightText: 2020-2023 The Monero Project
 
 #include "QrScanThread.h"
-#include <QtGlobal>
 #include <QDebug>
 
+#include <ZXing/ReadBarcode.h>
+
 QrScanThread::QrScanThread(QObject *parent)
     : QThread(parent)
     , m_running(true)
 {
-    m_scanner.set_handler(*this);
 }
 
-void QrScanThread::image_callback(zbar::Image &image)
+void QrScanThread::processQImage(const QImage &qimg)
 {
-    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);
-        }
-    }
-}
+    const auto hints = ZXing::DecodeHints()
+            .setFormats(ZXing::BarcodeFormat::QRCode | ZXing::BarcodeFormat::DataMatrix)
+            .setTryHarder(true)
+            .setBinarizer(ZXing::Binarizer::FixedThreshold);
 
-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());
-}
+    const auto result = QrCodeUtils::ReadBarcode(qimg, hints);
 
-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());
+    if (result.isValid()) {
+        emit decoded(result.text());
     }
 }
 
index 849e7758c4db81b302f41a59495968da698cb728..771f35234c64ba201c2a36270023b45b2c93af2c 100644 (file)
@@ -1,39 +1,36 @@
 // SPDX-License-Identifier: BSD-3-Clause
 // SPDX-FileCopyrightText: 2020-2023 The Monero Project
 
-#ifndef _QRSCANTHREAD_H_
-#define _QRSCANTHREAD_H_
+#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
+#include <ZXing/ReadBarcode.h>
+
+#include "qrcode/utils/QrCodeUtils.h"
+
+class QrScanThread : public QThread
 {
     Q_OBJECT
 
 public:
-    QrScanThread(QObject *parent = nullptr);
+    explicit 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);
+    void decoded(const QString &data);
 
 protected:
-    virtual void run();
+    void run() override;
     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;
diff --git a/src/qrcode/scanner_qt6/QrCodeScanDialog.cpp b/src/qrcode/scanner_qt6/QrCodeScanDialog.cpp
deleted file mode 100644 (file)
index 21a2e77..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 The Monero Project
-
-#include "QrCodeScanDialog.h"
-#include "ui_QrCodeScanDialog.h"
-
-#include <QCamera>
-#include <QMediaDevices>
-#include <QCameraDevice>
-#include <QMessageBox>
-#include <QImageCapture>
-#include <QVideoFrame>
-
-#include "Utils.h"
-
-QrCodeScanDialog::QrCodeScanDialog(QWidget *parent)
-        : QDialog(parent)
-        , ui(new Ui::QrCodeScanDialog)
-{
-    ui->setupUi(this);
-    this->setWindowTitle("Scan QR code");
-
-    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.setVideoOutput(ui->viewfinder);
-
-    m_imageCapture = new QImageCapture;
-    m_captureSession.setImageCapture(m_imageCapture);
-
-    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) {
-        Utils::showError(this, "Camera error", m_camera->errorString());
-    }
-}
-
-void QrCodeScanDialog::notifyError(const QString &msg) {
-    qDebug() << "QrScanner error: " << msg;
-}
-
-QrCodeScanDialog::~QrCodeScanDialog()
-{
-    m_thread->stop();
-    m_thread->quit();
-    if (!m_thread->wait(5000))
-    {
-        m_thread->terminate();
-        m_thread->wait();
-    }
-}
\ No newline at end of file
diff --git a/src/qrcode/scanner_qt6/QrCodeScanDialog.h b/src/qrcode/scanner_qt6/QrCodeScanDialog.h
deleted file mode 100644 (file)
index 74b82e3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 The Monero Project
-
-#ifndef FEATHER_QRCODESCANDIALOG_H
-#define FEATHER_QRCODESCANDIALOG_H
-
-#include <QDialog>
-#include <QCamera>
-#include <QScopedPointer>
-#include <QMediaCaptureSession>
-#include <QTimer>
-
-#include "QrScanThread.h"
-
-namespace Ui {
-    class QrCodeScanDialog;
-}
-
-class QrCodeScanDialog : public QDialog
-{
-    Q_OBJECT
-
-public:
-    explicit QrCodeScanDialog(QWidget *parent);
-    ~QrCodeScanDialog() override;
-
-    QString decodedString = "";
-
-private slots:
-    void onCameraSwitched(int index);
-    void onDecoded(int type, const QString &data);
-    void notifyError(const QString &msg);
-
-private:
-    void processCapturedImage(int requestId, const QImage& img);
-    void displayCameraError();
-    void takeImage();
-
-    QScopedPointer<Ui::QrCodeScanDialog> ui;
-
-    QrScanThread *m_thread;
-    QImageCapture *m_imageCapture;
-    QTimer m_imageTimer;
-    QScopedPointer<QCamera> m_camera;
-    QMediaCaptureSession m_captureSession;
-};
-
-
-#endif //FEATHER_QRCODESCANDIALOG_H
diff --git a/src/qrcode/scanner_qt6/QrCodeScanDialog.ui b/src/qrcode/scanner_qt6/QrCodeScanDialog.ui
deleted file mode 100644 (file)
index 9cda999..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>QrCodeScanDialog</class>
- <widget class="QDialog" name="QrCodeScanDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>490</width>
-    <height>422</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <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>
-    <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">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeType">
-         <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>
-       </widget>
-      </item>
-     </layout>
-    </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>
-  <customwidget>
-   <class>QVideoWidget</class>
-   <extends>QWidget</extends>
-   <header>qvideowidget.h</header>
-   <container>1</container>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/qrcode/scanner_qt6/QrScanThread.cpp b/src/qrcode/scanner_qt6/QrScanThread.cpp
deleted file mode 100644 (file)
index 54a699b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 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());
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/qrcode/scanner_qt6/QrScanThread.h b/src/qrcode/scanner_qt6/QrScanThread.h
deleted file mode 100644 (file)
index 849e775..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-// SPDX-FileCopyrightText: 2020-2023 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
\ No newline at end of file
index beb8d9fb3ddba9a2609bb3847dd99c909fd13e1f..c531c7f92d5070cdcce47e6c0c4a156adfa325d3 100644 (file)
@@ -2,52 +2,46 @@
 // SPDX-FileCopyrightText: 2020-2023 The Monero Project
 
 #include "QrCodeUtils.h"
-#include <QDebug>
-
-bool QrCodeUtils::zimageFromQImage(const QImage &qImg, zbar::Image &dst) {
-    qDebug() << qImg.format();
-    switch (qImg.format()) {
-        case QImage::Format_RGB32 :
-        case QImage::Format_ARGB32 :
-        case QImage::Format_ARGB32_Premultiplied :
-            break;
-        default :
-            return false;
-    }
-
-    unsigned int bpl(qImg.bytesPerLine());
-    unsigned int width(bpl / 4);
-    unsigned int 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)) {
-        return false;
-    }
-    return true;
+
+Result QrCodeUtils::ReadBarcode(const QImage& img, const ZXing::DecodeHints& hints)
+{
+    auto ImgFmtFromQImg = [](const QImage& img){
+        switch (img.format()) {
+            case QImage::Format_ARGB32:
+            case QImage::Format_RGB32:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+                return ZXing::ImageFormat::BGRX;
+
+#else
+                return ZXing::ImageFormat::XRGB;
+
+#endif
+            case QImage::Format_RGB888: return ZXing::ImageFormat::RGB;
+
+            case QImage::Format_RGBX8888:
+            case QImage::Format_RGBA8888: return ZXing::ImageFormat::RGBX;
+
+            case QImage::Format_Grayscale8: return ZXing::ImageFormat::Lum;
+
+            default: return ZXing::ImageFormat::None;
+        }
+    };
+
+    auto exec = [&](const QImage& img){
+        return Result(ZXing::ReadBarcode({ img.bits(), img.width(), img.height(), ImgFmtFromQImg(img) }, hints));
+    };
+
+    return ImgFmtFromQImg(img) == ZXing::ImageFormat::None ? exec(img.convertToFormat(QImage::Format_RGBX8888)) : exec(img);
 }
 
+
 QString QrCodeUtils::scanImage(const QImage &img) {
-    zbar::ImageScanner scanner;
-    scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
-
-    zbar::Image zImg;
-    int r = zimageFromQImage(img, zImg);
-    if (!r) {
-        qWarning() << "Unable to convert QImage into zbar::Image";
-        return "";
-    }
-
-    zbar::Image scanImg = zImg.convert(zbar_fourcc('Y', '8', '0', '0'));
-    scanner.scan(scanImg);
-
-    QString result;
-    for (zbar::Image::SymbolIterator sym = scanImg.symbol_begin(); sym != scanImg.symbol_end(); ++sym) {
-        if (!sym->get_count()) {
-            result = QString::fromStdString(sym->get_data());
-        }
-    }
-    return result;
+    const auto hints = ZXing::DecodeHints()
+            .setFormats(ZXing::BarcodeFormat::QRCode | ZXing::BarcodeFormat::DataMatrix)
+            .setTryHarder(true)
+            .setBinarizer(ZXing::Binarizer::FixedThreshold);
+
+    const auto result = ReadBarcode(img, hints);
+
+    return result.text();
 }
\ No newline at end of file
index f934838093b1c161f53c9765d89e167a0f82a59f..2898fe4b4277c176fa70e4c99738091293ffd4d4 100644 (file)
@@ -5,13 +5,26 @@
 #define FEATHER_QRCODEUTILS_H
 
 #include <QImage>
-#include <zbar.h>
+
+#include <ZXing/ReadBarcode.h>
+
+class Result : private ZXing::Result
+{
+public:
+    explicit Result(ZXing::Result&& r) :
+            m_result(std::move(r)){ }
+
+    inline QString text() const { return QString::fromStdString(m_result.text()); }
+    bool isValid() const { return m_result.isValid(); }
+
+private:
+    ZXing::Result m_result;
+};
 
 class QrCodeUtils {
 public:
-    static bool zimageFromQImage(const QImage &qImg, zbar::Image &dst);
     static QString scanImage(const QImage &img);
+    static Result ReadBarcode(const QImage& img, const ZXing::DecodeHints& hints = { });
 };
 
-
 #endif //FEATHER_QRCODEUTILS_H