1
mirror of https://github.com/monero-project/monero-gui synced 2024-12-20 04:15:53 +01:00

add qrcode scanner

This commit is contained in:
MoroccanMalinois 2017-01-31 04:36:08 +00:00
parent 43d5bd3e2d
commit 93d2eb5e1a
13 changed files with 627 additions and 14 deletions

View File

@ -85,15 +85,15 @@ Packaging for your favorite distribution would be a welcome contribution!
- For Ubuntu 16.04 i386
`sudo apt-get install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-xmllistmodel qttools5-dev-tools qml-module-qtquick-dialogs`
`sudo apt-get install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-xmllistmodel qttools5-dev-tools qml-module-qtquick-dialogs libzbar-dev`
- For Ubuntu 16.04 x64
`sudo apt-get install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-xmllistmodel qttools5-dev-tools qml-module-qtquick-dialogs qml-module-qt-labs-settings libqt5qml-graphicaleffects`
`sudo apt-get install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-xmllistmodel qttools5-dev-tools qml-module-qtquick-dialogs qml-module-qt-labs-settings libqt5qml-graphicaleffects libzbar-dev`
- For Linux Mint 18 "Sarah" - Cinnamon (64-bit)
`sudo apt install qml-module-qt-labs-settings qml-module-qtgraphicaleffects`
`sudo apt install qml-module-qt-labs-settings qml-module-qtgraphicaleffects libzbar-dev`
6. Build the GUI.

View File

@ -24,12 +24,12 @@ elif [ "$BUILD_TYPE" == "release-static" ]; then
BIN_PATH=release/bin
elif [ "$BUILD_TYPE" == "release-android" ]; then
echo "Building release for ANDROID"
CONFIG="CONFIG+=release static";
CONFIG="CONFIG+=release static WITH_SCANNER";
ANDROID=true
BIN_PATH=release/bin
elif [ "$BUILD_TYPE" == "debug-android" ]; then
echo "Building debug for ANDROID : ultra INSECURE !!"
CONFIG="CONFIG+=debug qml_debug";
CONFIG="CONFIG+=debug qml_debug WITH_SCANNER";
ANDROID=true
BIN_PATH=debug/bin
elif [ "$BUILD_TYPE" == "debug" ]; then

View File

@ -0,0 +1,134 @@
// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.0
import QtMultimedia 5.4
import QtQuick.Dialogs 1.2
import moneroComponents.QRCodeScanner 1.0
Rectangle {
id : root
x: 0
y: 0
z: parent.z+1
width: parent.width
height: parent.height
visible: false
color: "black"
state: "Stopped"
signal qrcode_decoded(string address, string payment_id, string amount, string tx_description, string recipient_name)
states: [
State {
name: "Capture"
StateChangeScript {
script: {
root.visible = true
camera.captureMode = Camera.CaptureStillImage
camera.start()
finder.enabled = true
}
}
},
State {
name: "Stopped"
StateChangeScript {
script: {
camera.stop()
root.visible = false
finder.enabled = false
}
}
}
]
Camera {
id: camera
objectName: "qrCameraQML"
captureMode: Camera.CaptureStillImage
focus {
focusMode: Camera.FocusContinuous
}
}
QRCodeScanner {
id : finder
objectName: "QrFinder"
onDecoded : {
root.qrcode_decoded(address, payment_id, amount, tx_description, recipient_name)
root.state = "Stopped"
}
onNotifyError : {
if( warning )
messageDialog.icon = StandardIcon.Critical
else {
messageDialog.icon = StandardIcon.Warning
root.state = "Stopped"
}
messageDialog.text = error
messageDialog.visible = true
}
}
VideoOutput {
id: viewfinder
visible: root.state == "Capture"
x: 0
y: 0
z: parent.z+1
width: parent.width
height: parent.height
source: camera
autoOrientation: true
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressAndHold: {
if (camera.lockStatus == Camera.locked)camera.unlock()
camera.searchAndLock()
}
onDoubleClicked: {
root.state = "Stopped"
}
}
}
MessageDialog {
id: messageDialog
title: "Scanning QrCode"
onAccepted: {
root.state = "Stopped"
}
}
}

View File

@ -39,6 +39,7 @@
#include "WalletManager.h"
#include "Wallet.h"
#include "QRCodeImageProvider.h"
#include "QrCodeScanner.h"
#include "PendingTransaction.h"
#include "UnsignedTransaction.h"
#include "TranslationManager.h"
@ -109,6 +110,8 @@ int main(int argc, char *argv[])
qRegisterMetaType<TransactionInfo::Direction>();
qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>();
qmlRegisterType<QrCodeScanner>("moneroComponents.QRCodeScanner", 1, 0, "QRCodeScanner");
QQmlApplicationEngine engine;
OSCursor cursor;
@ -167,5 +170,15 @@ int main(int argc, char *argv[])
//WalletManager::instance()->setLogLevel(WalletManager::LogLevel_Max);
bool builtWithScanner = false;
#ifdef WITH_SCANNER
builtWithScanner = true;
QObject *qmlCamera = rootObject->findChild<QObject*>("qrCameraQML");
QCamera *camera_ = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
QObject *qmlFinder = rootObject->findChild<QObject*>("QrFinder");
qobject_cast<QrCodeScanner*>(qmlFinder)->setSource(camera_);
#endif
engine.rootContext()->setContextProperty("builtWithScanner", builtWithScanner);
return app.exec();
}

View File

@ -32,6 +32,7 @@ import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import QtMultimedia 5.4
import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
@ -65,6 +66,7 @@ ApplicationWindow {
property bool viewOnly: false
property bool foundNewBlock: false
property int timeToUnlock: 0
property bool qrScannerEnabled: builtWithScanner && (QtMultimedia.availableCameras.length > 0)
// true if wallet ever synchronized
property bool walletInitialized : false
@ -874,7 +876,10 @@ ApplicationWindow {
messageText: qsTr("Please wait...")
}
QRCodeScanner {
id: cameraUi
visible : false
}
Item {
id: rootItem

View File

@ -1,6 +1,6 @@
TEMPLATE = app
QT += qml quick widgets
QT += qml quick widgets multimedia
WALLET_ROOT=$$PWD/monero
@ -12,6 +12,7 @@ QMAKE_DISTCLEAN += -r $$WALLET_ROOT
INCLUDEPATH += $$WALLET_ROOT/include \
$$PWD/src/libwalletqt \
$$PWD/src/QR-Code-generator \
$$PWD/src/QR-Code-scanner \
$$PWD/src \
$$WALLET_ROOT/src
@ -37,8 +38,8 @@ HEADERS += \
src/model/AddressBookModel.h \
src/libwalletqt/AddressBook.h \
src/zxcvbn-c/zxcvbn.h \
src/libwalletqt/UnsignedTransaction.h
src/libwalletqt/UnsignedTransaction.h \
src/QR-Code-scanner/QrCodeScanner.h
SOURCES += main.cpp \
filter.cpp \
@ -61,7 +62,8 @@ SOURCES += main.cpp \
src/model/AddressBookModel.cpp \
src/libwalletqt/AddressBook.cpp \
src/zxcvbn-c/zxcvbn.c \
src/libwalletqt/UnsignedTransaction.cpp
src/libwalletqt/UnsignedTransaction.cpp \
src/QR-Code-scanner/QrCodeScanner.cpp
lupdate_only {
SOURCES = *.qml \
@ -76,6 +78,22 @@ LIBS += -L$$WALLET_ROOT/lib \
$$WALLET_ROOT/build/release/contrib/epee/src/libepee.a \
-lunbound
CONFIG(WITH_SCANNER) {
if( greaterThan(QT_MINOR_VERSION, 5) ) {
message("using camera scanner")
DEFINES += "WITH_SCANNER"
HEADERS += src/QR-Code-scanner/QrScanThread.h
SOURCES += src/QR-Code-scanner/QrScanThread.cpp
android {
INCLUDEPATH += $$PWD/../ZBar/include
LIBS += -lzbarjni -liconv
} else {
LIBS += -lzbar
}
} else {
message("Skipping camera scanner because of Incompatible Qt Version !")
}
}
# currently we only support x86 build as qt.io only provides prebuilt qt for x86 mingw

View File

@ -62,12 +62,31 @@ Rectangle {
tipText: qsTr("<b>Tip tekst test</b>") + translationManager.emptyString
}
StandardButton {
id: qrfinderButton
anchors.left: parent.left
anchors.leftMargin: 17
anchors.topMargin: 5
anchors.top: addressLabel.bottom
text: qsTr("QRCODE") + translationManager.emptyString
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C"
pressedColor: "#FF4304"
visible : appWindow.qrScannerEnabled
enabled : visible
width: visible ? 60 : 0
onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
}
LineEdit {
id: addressLine
anchors.left: parent.left
anchors.left: qrfinderButton.right
anchors.right: parent.right
anchors.top: addressLabel.bottom
anchors.leftMargin: 17
anchors.rightMargin: 17
anchors.topMargin: 5
error: true;
@ -275,5 +294,13 @@ Rectangle {
root.model = currentWallet.addressBookModel;
}
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
console.log("updateFromQrCode")
addressLine.text = address
paymentIdLine.text = payment_id
//amountLine.text = amount
descriptionLine.text = recipient_name + " " + tx_description
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
}
}

View File

@ -77,6 +77,15 @@ Rectangle {
privacyLabel.text = qsTr("Privacy level (mixin %1)").arg(mixin) + translationManager.emptyString
}
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
console.log("updateFromQrCode")
addressLine.text = address
paymentIdLine.text = payment_id
amountLine.text = amount
descriptionLine.text = recipient_name + " " + tx_description
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
}
// Information dialog
StandardDialog {
// dynamically change onclose handler
@ -249,11 +258,29 @@ Rectangle {
anchors.right: parent.right
anchors.top: addressLabel.bottom
StandardButton {
id: qrfinderButton
anchors.left: parent.left
anchors.leftMargin: 17
anchors.topMargin: 5
text: qsTr("QRCODE") + translationManager.emptyString
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C"
pressedColor: "#FF4304"
visible : appWindow.qrScannerEnabled
enabled : visible
width: visible ? 60 : 0
onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
}
LineEdit {
id: addressLine
anchors.left: parent.left
anchors.left: qrfinderButton.right
anchors.right: resolveButton.left
anchors.leftMargin: 17
//anchors.leftMargin: 17
anchors.topMargin: 5
placeholderText: "4..."
// validator: RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }

View File

@ -125,5 +125,6 @@
<file>wizard/WizardPasswordUI.qml</file>
<file>wizard/WizardCreateViewOnlyWallet.qml</file>
<file>components/DaemonConsole.qml</file>
<file>components/QRCodeScanner.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,108 @@
// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#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)
{
#ifdef WITH_SCANNER
m_probe = new QVideoProbe(this);
m_thread = new QrScanThread(this);
m_thread->start();
QObject::connect(m_thread, SIGNAL(decoded(int,QString)), this, SLOT(processCode(int,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)));
#endif
}
void QrCodeScanner::setSource(QCamera *camera)
{
m_probe->setSource(camera);
}
void QrCodeScanner::processCode(int type, const QString &data)
{
if (! m_enabled) return;
qDebug() << "decoded - type: " << type << " data: " << data;
QString address, payment_id, tx_description, recipient_name, error;
QVector<QString> unknown_parameters;
uint64_t amount(0);
if( ! WalletManager::instance()->parse_uri(data, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error) )
{
qDebug() << "Failed to parse_uri : " << error;
emit notifyError(error);
return;
}
if(unknown_parameters.size() > 0)
{
qDebug() << "unknown parameters " << unknown_parameters;
emit notifyError(error, true);
}
qDebug() << "Parsed URI : " << address << " " << payment_id << " " << amount << " " << tx_description << " " << recipient_name << " " << error;
QString s_amount = WalletManager::instance()->displayAmount(amount);
qDebug() << "Amount passed " << s_amount ;
emit decoded(address, payment_id, s_amount, tx_description, recipient_name);
}
void QrCodeScanner::processFrame(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();
}
#ifdef WITH_SCANNER
void QrCodeScanner::timerEvent(QTimerEvent *event)
{
if( (event->timerId() == m_processTimerId) ){
m_thread->addFrame(m_curFrame);
}
}
#endif

View File

@ -0,0 +1,79 @@
// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef QRCODESCANNER_H_
#define QRCODESCANNER_H_
#include <QImage>
#include <QVideoFrame>
#ifdef WITH_SCANNER
#include "QrScanThread.h"
#endif
class QVideoProbe;
class QCamera;
class QrCodeScanner : public QObject
{
Q_OBJECT
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
public:
QrCodeScanner(QObject *parent = Q_NULLPTR);
void setSource(QCamera*);
bool enabled() const;
void setEnabled(bool enabled);
public Q_SLOTS:
void processCode(int type, const QString &data);
void processFrame(QVideoFrame);
Q_SIGNALS:
void enabledChanged();
void decoded(const QString &address, const QString &payment_id, const QString &amount, const QString &tx_description, const QString &recipient_name);
void decode(int type, const QString &data);
void notifyError(const QString &error, bool warning = false);
protected:
#ifdef WITH_SCANNER
void timerEvent(QTimerEvent *);
QrScanThread *m_thread;
#endif
int m_processTimerId;
int m_processInterval;
int m_enabled;
QVideoFrame m_curFrame;
QVideoProbe *m_probe;
};
#endif

View File

@ -0,0 +1,132 @@
// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QrScanThread.h"
#include <QtGlobal>
#include <QDebug>
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
extern QImage qt_imageFromVideoFrame(const QVideoFrame &f);
#else
QImage qt_imageFromVideoFrame(const QVideoFrame &f){
Q_ASSERT_X(0 != 0, "qt_imageFromVideoFrame", "Should have been managed in .pro");
return QImage();
}
#endif
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");
unsigned long datalen = qimg.byteCount();
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::processVideoFrame(const QVideoFrame &frame)
{
processQImage( qt_imageFromVideoFrame(frame) );
}
void QrScanThread::stop()
{
m_running = false;
}
void QrScanThread::addFrame(const QVideoFrame &frame)
{
QMutexLocker locker(&m_mutex);
m_queue.append(frame);
m_waitCondition.wakeOne();
}
void QrScanThread::run()
{
QVideoFrame frame;
while(m_running) {
QMutexLocker locker(&m_mutex);
while(m_queue.isEmpty())
m_waitCondition.wait(&m_mutex);
processVideoFrame(m_queue.takeFirst());
}
}

View File

@ -0,0 +1,69 @@
// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _QRSCANTHREAD_H_
#define _QRSCANTHREAD_H_
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QEvent>
#include <QVideoFrame>
#include <QCamera>
#include <zbar.h>
class QrScanThread : public QThread, public zbar::Image::Handler
{
Q_OBJECT
public:
QrScanThread(QObject *parent = Q_NULLPTR);
void addFrame(const QVideoFrame &frame);
Q_SIGNALS:
void decoded(int type, const QString &data);
void notifyError(const QString &error, bool warning = false);
protected:
virtual void run();
virtual void stop();
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;
bool m_running;
QMutex m_mutex;
QWaitCondition m_waitCondition;
QList<QVideoFrame> m_queue;
};
#endif