mirror of
https://github.com/monero-project/monero-gui
synced 2024-11-21 12:44:14 +01:00
QR-Code-scanner: integrate QUIRC library, implement QrDecoder, drop ZBar
This commit is contained in:
parent
df771470c2
commit
8d4cda030e
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -2,3 +2,6 @@
|
||||
path = monero
|
||||
url = https://github.com/monero-project/monero
|
||||
ignore = all
|
||||
[submodule "external/quirc"]
|
||||
path = external/quirc
|
||||
url = https://github.com/dlbeer/quirc/
|
||||
|
@ -131,12 +131,8 @@ message(STATUS "OpenSSL: Version ${OPENSSL_VERSION}")
|
||||
message(STATUS "OpenSSL: include dir at ${OPENSSL_INCLUDE_DIR}")
|
||||
message(STATUS "OpenSSL: libraries at ${OPENSSL_LIBRARIES} ${OPENSSL_SSL_LIBRARIES}")
|
||||
|
||||
# Zbar (for QR scanner)
|
||||
if(WITH_SCANNER)
|
||||
add_definitions(-DWITH_SCANNER)
|
||||
find_package(ZBar0 REQUIRED)
|
||||
message(STATUS "libzbar: include dir at ${ZBAR_INCLUDE_DIR}")
|
||||
message(STATUS "libzbar: libraries at ${ZBAR_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Sodium
|
||||
@ -563,6 +559,6 @@ if (HIDAPI_FOUND OR LibUSB_COMPILE_TEST_PASSED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(external)
|
||||
add_subdirectory(translations)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
@ -151,25 +151,6 @@ RUN set -ex \
|
||||
&& make -j${THREADS} install \
|
||||
&& rm -rf $(pwd)
|
||||
|
||||
RUN git clone https://github.com/ZBar/ZBar.git --depth 1 \
|
||||
&& cd ZBar \
|
||||
&& git reset --hard 854a5d97059e395807091ac4d80c53f7968abb8f \
|
||||
&& sed -i 's/SHARED/STATIC/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CPP_FEATURES := exceptions rtti features\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS := -Wno-multichar\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -D_ANDROID\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DLIBDIR="\\".\\""\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DBUILDING_LIBICONV\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DBUILDING_LIBCHARSET\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -DIN_LIBRARY\n\0/' android/jni/Android.mk \
|
||||
&& sed -i -E 's/(.*BUILD_STATIC_LIBRARY.*)/LOCAL_CFLAGS += -fno-stack-protector\n\0/' android/jni/Android.mk \
|
||||
&& echo "APP_ABI := arm64-v8a \nAPP_STL := c++_shared \nTARGET_PLATFORM := ${ANDROID_API} \nTARGET_ARCH_ABI := arm64-v8a \nAPP_CFLAGS += -target aarch64-none-linux-android -fexceptions -fstack-protector-strong -fno-limit-debug-info -mfloat-abi=softfp -fno-builtin-memmove -fno-omit-frame-pointer -fno-stack-protector\n" \
|
||||
>> android/jni/Application.mk \
|
||||
&& cd android \
|
||||
&& CC=${ANDROID_CLANG} CXX=${ANDROID_CLANGPP} ${ANDROID_NDK_ROOT}/ndk-build ICONV_SRC=${WORKDIR}/libiconv-${ICONV_VERSION} -B V=1 NDK_APPLICATION_MK=jni/Application.mk \
|
||||
&& cp obj/local/arm64-v8a/lib* ${PREFIX}/lib \
|
||||
&& cp -r ../include/* ${PREFIX}/include
|
||||
|
||||
RUN git clone -b libgpg-error-1.38 --depth 1 git://git.gnupg.org/libgpg-error.git \
|
||||
&& cd libgpg-error \
|
||||
&& git reset --hard 71d278824c5fe61865f7927a2ed1aa3115f9e439 \
|
||||
|
10
README.md
10
README.md
@ -217,13 +217,13 @@ The following instructions will fetch Qt from your distribution's repositories i
|
||||
|
||||
- For Ubuntu
|
||||
|
||||
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia libzbar-dev`
|
||||
`sudo apt install qtmultimedia5-dev qml-module-qtmultimedia`
|
||||
|
||||
- For Gentoo
|
||||
|
||||
The *qml* USE flag must be enabled.
|
||||
|
||||
`emerge dev-qt/qtmultimedia:5 media-gfx/zbar`
|
||||
`emerge dev-qt/qtmultimedia:5`
|
||||
|
||||
|
||||
3. Clone repository
|
||||
@ -290,12 +290,6 @@ The Monero GUI on Windows is 64 bits only; 32-bit Windows GUI builds are not off
|
||||
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-libgcrypt
|
||||
```
|
||||
|
||||
Optional : To build the flag `WITH_SCANNER`
|
||||
|
||||
```
|
||||
pacman -S mingw-w64-x86_64-zbar
|
||||
```
|
||||
|
||||
You find more details about those dependencies in the [Monero documentation](https://github.com/monero-project/monero). Note that that there is no more need to compile Boost from source; like everything else, you can install it now with a MSYS2 package.
|
||||
|
||||
4. Install Qt5
|
||||
|
@ -1,38 +0,0 @@
|
||||
# from http://code.google.com/p/low-cost-vision-2012/source/browse/CMakeModules/FindZBar0.cmake?name=2-helium-1&r=d61f248bd5565b3c086bf4769a04bfd98f7079df
|
||||
# - Try to find ZBar
|
||||
# This will define
|
||||
#
|
||||
# ZBAR_FOUND -
|
||||
# ZBAR_LIBRARY_DIR -
|
||||
# ZBAR_INCLUDE_DIR -
|
||||
# ZBAR_LIBRARIES -
|
||||
#
|
||||
|
||||
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} PATH_SUFFIXES zbar)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ZBAR_LIBRARIES AND ANDROID)
|
||||
find_library(ZBARJNI_LIBRARY NAMES zbarjni)
|
||||
find_library(ICONV_LIBRARY NAMES iconv)
|
||||
if(ZBARJNI_LIBRARY AND ICONV_LIBRARY)
|
||||
set(ZBAR_LIBRARIES ${ZBARJNI_LIBRARY} ${ICONV_LIBRARY})
|
||||
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}/zbar")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ZBAR DEFAULT_MSG ZBAR_LIBRARIES ZBAR_INCLUDE_DIR)
|
||||
message(STATUS "Found zbar libraries ${ZBAR_LIBRARIES}")
|
7
external/CMakeLists.txt
vendored
Normal file
7
external/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
add_library(quirc STATIC
|
||||
quirc/lib/decode.c
|
||||
quirc/lib/identify.c
|
||||
quirc/lib/quirc.c
|
||||
quirc/lib/version_db.c
|
||||
)
|
||||
target_include_directories(quirc PUBLIC quirc/lib)
|
1
external/quirc
vendored
Submodule
1
external/quirc
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 7e7ab596e4d0988faf1c12ae89c354b114181c40
|
@ -55,13 +55,6 @@ if(ENABLE_PASS_STRENGTH_METER)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
file(GLOB QR_CODE_FILES
|
||||
"QR-Code-scanner/*.h"
|
||||
"QR-Code-scanner/*.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(EXECUTABLE_FLAG)
|
||||
if(MINGW)
|
||||
set(EXECUTABLE_FLAG WIN32)
|
||||
@ -84,7 +77,6 @@ endif()
|
||||
set(monero_wallet_gui_sources
|
||||
${SOURCE_FILES}
|
||||
${PASS_STRENGTH_FILES}
|
||||
${QR_CODE_FILES}
|
||||
${RESOURCES}
|
||||
)
|
||||
|
||||
@ -128,7 +120,6 @@ target_include_directories(monero-wallet-gui PUBLIC
|
||||
${X11_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${ZBAR_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(monero-wallet-gui
|
||||
@ -159,6 +150,7 @@ target_link_libraries(monero-wallet-gui
|
||||
${EXTRA_LIBRARIES}
|
||||
${ICU_LIBRARIES}
|
||||
openpgp
|
||||
qrdecoder
|
||||
translations
|
||||
)
|
||||
|
||||
@ -171,16 +163,14 @@ if(X11_FOUND)
|
||||
endif()
|
||||
|
||||
if(WITH_SCANNER)
|
||||
if(NOT ANDROID)
|
||||
target_link_libraries(monero-wallet-gui qrscanner)
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_libraries(monero-wallet-gui
|
||||
${ZBAR_LIBRARIES}
|
||||
jpeg
|
||||
v4l2
|
||||
v4lconvert
|
||||
rt
|
||||
)
|
||||
else()
|
||||
target_link_libraries(monero-wallet-gui ${ZBAR_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
file(GLOB_RECURSE SRC_SOURCES *.cpp)
|
||||
file(GLOB_RECURSE SRC_HEADERS *.h)
|
||||
|
||||
add_library(qrdecoder STATIC
|
||||
Decoder.cpp
|
||||
)
|
||||
target_link_libraries(qrdecoder
|
||||
PUBLIC
|
||||
Qt5::Gui
|
||||
PRIVATE
|
||||
quirc
|
||||
)
|
||||
|
||||
if(WITH_SCANNER)
|
||||
add_library(qrscanner
|
||||
QrCodeScanner.cpp
|
||||
QrScanThread.cpp
|
||||
)
|
||||
target_link_libraries(qrscanner
|
||||
PUBLIC
|
||||
Qt5::Multimedia
|
||||
qrdecoder
|
||||
)
|
||||
endif()
|
||||
|
71
src/QR-Code-scanner/Decoder.cpp
Normal file
71
src/QR-Code-scanner/Decoder.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "Decoder.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "quirc.h"
|
||||
|
||||
QrDecoder::QrDecoder()
|
||||
: m_qr(quirc_new())
|
||||
{
|
||||
if (m_qr == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate memory");
|
||||
}
|
||||
}
|
||||
|
||||
QrDecoder::~QrDecoder()
|
||||
{
|
||||
quirc_destroy(m_qr);
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decode(const QImage &image)
|
||||
{
|
||||
if (image.format() == QImage::Format_Grayscale8)
|
||||
{
|
||||
return decodeGrayscale8(image);
|
||||
}
|
||||
return decodeGrayscale8(image.convertToFormat(QImage::Format_Grayscale8));
|
||||
}
|
||||
|
||||
std::vector<std::string> QrDecoder::decodeGrayscale8(const QImage &image)
|
||||
{
|
||||
if (quirc_resize(m_qr, image.width(), image.height()) < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to allocate video memory");
|
||||
}
|
||||
|
||||
uint8_t *rawImage = quirc_begin(m_qr, nullptr, nullptr);
|
||||
if (rawImage == nullptr)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get image buffer");
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
std::copy(image.constBits(), image.constBits() + image.sizeInBytes(), rawImage);
|
||||
#else
|
||||
std::copy(image.constBits(), image.constBits() + image.byteCount(), rawImage);
|
||||
#endif
|
||||
quirc_end(m_qr);
|
||||
|
||||
const int count = quirc_count(m_qr);
|
||||
if (count < 0)
|
||||
{
|
||||
throw std::runtime_error("QUIRC: failed to get the number of recognized QR-codes");
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
result.reserve(static_cast<size_t>(count));
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
quirc_code code;
|
||||
quirc_extract(m_qr, index, &code);
|
||||
|
||||
quirc_data data;
|
||||
const quirc_decode_error_t err = quirc_decode(&code, &data);
|
||||
if (err == QUIRC_SUCCESS)
|
||||
{
|
||||
result.emplace_back(&data.payload[0], &data.payload[data.payload_len]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
21
src/QR-Code-scanner/Decoder.h
Normal file
21
src/QR-Code-scanner/Decoder.h
Normal file
@ -0,0 +1,21 @@
|
||||
#include <QImage>
|
||||
|
||||
struct quirc;
|
||||
|
||||
class QrDecoder
|
||||
{
|
||||
public:
|
||||
QrDecoder(const QrDecoder &) = delete;
|
||||
QrDecoder &operator=(const QrDecoder &) = delete;
|
||||
|
||||
QrDecoder();
|
||||
~QrDecoder();
|
||||
|
||||
std::vector<std::string> decode(const QImage &image);
|
||||
|
||||
private:
|
||||
std::vector<std::string> decodeGrayscale8(const QImage &image);
|
||||
|
||||
private:
|
||||
quirc *m_qr;
|
||||
};
|
@ -27,7 +27,6 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "QrCodeScanner.h"
|
||||
#include <WalletManager.h>
|
||||
#include <QVideoProbe>
|
||||
#include <QCamera>
|
||||
|
||||
@ -40,7 +39,7 @@ QrCodeScanner::QrCodeScanner(QObject *parent)
|
||||
m_probe = new QVideoProbe(this);
|
||||
m_thread = new QrScanThread(this);
|
||||
m_thread->start();
|
||||
QObject::connect(m_thread, SIGNAL(decoded(int, QString)), this, SIGNAL(decoded(int, QString)));
|
||||
QObject::connect(m_thread, SIGNAL(decoded(QString)), this, SIGNAL(decoded(QString)));
|
||||
QObject::connect(m_thread, SIGNAL(notifyError(const QString &, bool)), this, SIGNAL(notifyError(const QString &, bool)));
|
||||
connect(m_probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ public Q_SLOTS:
|
||||
Q_SIGNALS:
|
||||
void enabledChanged();
|
||||
|
||||
void decoded(int type, const QString &data);
|
||||
void decode(int type, const QString &data);
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
|
@ -38,62 +38,15 @@ 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(*(long*)"Y800");
|
||||
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 :
|
||||
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");
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
unsigned long datalen = qimg.sizeInBytes();
|
||||
#else
|
||||
unsigned long datalen = qimg.byteCount();
|
||||
#endif
|
||||
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);
|
||||
for (const std::string &code : m_decoder.decode(qimg))
|
||||
{
|
||||
emit decoded(QString::fromStdString(code));
|
||||
}
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
qDebug() << "ERROR: " << e.what();
|
||||
|
@ -35,9 +35,10 @@
|
||||
#include <QEvent>
|
||||
#include <QVideoFrame>
|
||||
#include <QCamera>
|
||||
#include <zbar.h>
|
||||
|
||||
class QrScanThread : public QThread, public zbar::Image::Handler
|
||||
#include "Decoder.h"
|
||||
|
||||
class QrScanThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -47,20 +48,16 @@ public:
|
||||
virtual void stop();
|
||||
|
||||
Q_SIGNALS:
|
||||
void decoded(int type, const QString &data);
|
||||
void decoded(const QString &data);
|
||||
void notifyError(const QString &error, bool warning = false);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
void processVideoFrame(const QVideoFrame &);
|
||||
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;
|
||||
QrDecoder m_decoder;
|
||||
bool m_running;
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
|
Loading…
Reference in New Issue
Block a user