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 - 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 - 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) - 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. 6. Build the GUI.

View file

@ -24,12 +24,12 @@ elif [ "$BUILD_TYPE" == "release-static" ]; then
BIN_PATH=release/bin BIN_PATH=release/bin
elif [ "$BUILD_TYPE" == "release-android" ]; then elif [ "$BUILD_TYPE" == "release-android" ]; then
echo "Building release for ANDROID" echo "Building release for ANDROID"
CONFIG="CONFIG+=release static"; CONFIG="CONFIG+=release static WITH_SCANNER";
ANDROID=true ANDROID=true
BIN_PATH=release/bin BIN_PATH=release/bin
elif [ "$BUILD_TYPE" == "debug-android" ]; then elif [ "$BUILD_TYPE" == "debug-android" ]; then
echo "Building debug for ANDROID : ultra INSECURE !!" echo "Building debug for ANDROID : ultra INSECURE !!"
CONFIG="CONFIG+=debug qml_debug"; CONFIG="CONFIG+=debug qml_debug WITH_SCANNER";
ANDROID=true ANDROID=true
BIN_PATH=debug/bin BIN_PATH=debug/bin
elif [ "$BUILD_TYPE" == "debug" ]; then 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 "WalletManager.h"
#include "Wallet.h" #include "Wallet.h"
#include "QRCodeImageProvider.h" #include "QRCodeImageProvider.h"
#include "QrCodeScanner.h"
#include "PendingTransaction.h" #include "PendingTransaction.h"
#include "UnsignedTransaction.h" #include "UnsignedTransaction.h"
#include "TranslationManager.h" #include "TranslationManager.h"
@ -109,6 +110,8 @@ int main(int argc, char *argv[])
qRegisterMetaType<TransactionInfo::Direction>(); qRegisterMetaType<TransactionInfo::Direction>();
qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>(); qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>();
qmlRegisterType<QrCodeScanner>("moneroComponents.QRCodeScanner", 1, 0, "QRCodeScanner");
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
OSCursor cursor; OSCursor cursor;
@ -167,5 +170,15 @@ int main(int argc, char *argv[])
//WalletManager::instance()->setLogLevel(WalletManager::LogLevel_Max); //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(); return app.exec();
} }

View file

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

View file

@ -1,6 +1,6 @@
TEMPLATE = app TEMPLATE = app
QT += qml quick widgets QT += qml quick widgets multimedia
WALLET_ROOT=$$PWD/monero WALLET_ROOT=$$PWD/monero
@ -12,6 +12,7 @@ QMAKE_DISTCLEAN += -r $$WALLET_ROOT
INCLUDEPATH += $$WALLET_ROOT/include \ INCLUDEPATH += $$WALLET_ROOT/include \
$$PWD/src/libwalletqt \ $$PWD/src/libwalletqt \
$$PWD/src/QR-Code-generator \ $$PWD/src/QR-Code-generator \
$$PWD/src/QR-Code-scanner \
$$PWD/src \ $$PWD/src \
$$WALLET_ROOT/src $$WALLET_ROOT/src
@ -37,8 +38,8 @@ HEADERS += \
src/model/AddressBookModel.h \ src/model/AddressBookModel.h \
src/libwalletqt/AddressBook.h \ src/libwalletqt/AddressBook.h \
src/zxcvbn-c/zxcvbn.h \ src/zxcvbn-c/zxcvbn.h \
src/libwalletqt/UnsignedTransaction.h src/libwalletqt/UnsignedTransaction.h \
src/QR-Code-scanner/QrCodeScanner.h
SOURCES += main.cpp \ SOURCES += main.cpp \
filter.cpp \ filter.cpp \
@ -61,7 +62,8 @@ SOURCES += main.cpp \
src/model/AddressBookModel.cpp \ src/model/AddressBookModel.cpp \
src/libwalletqt/AddressBook.cpp \ src/libwalletqt/AddressBook.cpp \
src/zxcvbn-c/zxcvbn.c \ src/zxcvbn-c/zxcvbn.c \
src/libwalletqt/UnsignedTransaction.cpp src/libwalletqt/UnsignedTransaction.cpp \
src/QR-Code-scanner/QrCodeScanner.cpp
lupdate_only { lupdate_only {
SOURCES = *.qml \ SOURCES = *.qml \
@ -76,6 +78,22 @@ LIBS += -L$$WALLET_ROOT/lib \
$$WALLET_ROOT/build/release/contrib/epee/src/libepee.a \ $$WALLET_ROOT/build/release/contrib/epee/src/libepee.a \
-lunbound -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 # 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 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 { LineEdit {
id: addressLine id: addressLine
anchors.left: parent.left anchors.left: qrfinderButton.right
anchors.right: parent.right anchors.right: parent.right
anchors.top: addressLabel.bottom anchors.top: addressLabel.bottom
anchors.leftMargin: 17
anchors.rightMargin: 17 anchors.rightMargin: 17
anchors.topMargin: 5 anchors.topMargin: 5
error: true; error: true;
@ -275,5 +294,13 @@ Rectangle {
root.model = currentWallet.addressBookModel; 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 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 // Information dialog
StandardDialog { StandardDialog {
// dynamically change onclose handler // dynamically change onclose handler
@ -249,11 +258,29 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.top: addressLabel.bottom 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 { LineEdit {
id: addressLine id: addressLine
anchors.left: parent.left anchors.left: qrfinderButton.right
anchors.right: resolveButton.left anchors.right: resolveButton.left
anchors.leftMargin: 17 //anchors.leftMargin: 17
anchors.topMargin: 5 anchors.topMargin: 5
placeholderText: "4..." placeholderText: "4..."
// validator: RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g } // validator: RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }

View file

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