mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-12-22 19:49:34 +00:00
add qrcode scanner
This commit is contained in:
parent
43d5bd3e2d
commit
93d2eb5e1a
13 changed files with 627 additions and 14 deletions
|
@ -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.
|
||||
|
||||
|
|
4
build.sh
4
build.sh
|
@ -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
|
||||
|
|
134
components/QRCodeScanner.qml
Normal file
134
components/QRCodeScanner.qml
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
13
main.cpp
13
main.cpp
|
@ -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();
|
||||
}
|
||||
|
|
7
main.qml
7
main.qml
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
1
qml.qrc
1
qml.qrc
|
@ -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>
|
||||
|
|
108
src/QR-Code-scanner/QrCodeScanner.cpp
Normal file
108
src/QR-Code-scanner/QrCodeScanner.cpp
Normal 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
|
||||
|
79
src/QR-Code-scanner/QrCodeScanner.h
Normal file
79
src/QR-Code-scanner/QrCodeScanner.h
Normal 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
|
||||
|
132
src/QR-Code-scanner/QrScanThread.cpp
Normal file
132
src/QR-Code-scanner/QrScanThread.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
|
69
src/QR-Code-scanner/QrScanThread.h
Normal file
69
src/QR-Code-scanner/QrScanThread.h
Normal 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
|
Loading…
Reference in a new issue