From 9ef3674dba58a1145127ceaaa8d6718b34ad4a16 Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 24 Sep 2019 17:21:53 +0200 Subject: [PATCH] added qr code reader --- doorbird/doorbird.pro | 8 +- doorbird/qrcodereader.cpp | 189 ++++++++++++++++++++++++++++++++++++++ doorbird/qrcodereader.h | 88 ++++++++++++++++++ 3 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 doorbird/qrcodereader.cpp create mode 100644 doorbird/qrcodereader.h diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro index 0ea9d1fb..c519c376 100644 --- a/doorbird/doorbird.pro +++ b/doorbird/doorbird.pro @@ -2,12 +2,16 @@ include(../plugins.pri) QT += network +LIBS += -lzbar + TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird) SOURCES += \ deviceplugindoorbird.cpp \ - doorbird.cpp + doorbird.cpp \ + qrcodereader.cpp \ HEADERS += \ deviceplugindoorbird.h \ - doorbird.h + doorbird.h \ + qrcodereader.h \ diff --git a/doorbird/qrcodereader.cpp b/doorbird/qrcodereader.cpp new file mode 100644 index 00000000..658a2496 --- /dev/null +++ b/doorbird/qrcodereader.cpp @@ -0,0 +1,189 @@ +/***************************************************************************** + * Copyright: 2013 Michael Zanetti * + * * + * This file is part of ubuntu-authenticator * + * * + * This prject is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This project is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ****************************************************************************/ + +#include "qrcodereader.h" + +#include +#include +#include +#include + +QRCodeReader::QRCodeReader(QObject *parent) : + QObject(parent) +{ + connect(&m_readerThread, &QThread::started, this, &QRCodeReader::scanningChanged); + connect(&m_readerThread, &QThread::finished, this, &QRCodeReader::scanningChanged); +} + +bool QRCodeReader::valid() const +{ + return !m_type.isEmpty() && !m_text.isEmpty(); +} + +QString QRCodeReader::type() const +{ + return m_type; +} + +QString QRCodeReader::text() const +{ + return m_text; +} + +QImage QRCodeReader::image() const +{ + return m_image; +} + +QRect QRCodeReader::scanRect() const +{ + return m_scanRect; +} + +void QRCodeReader::setScanRect(const QRect &rect) +{ + if (m_scanRect != rect) { + m_scanRect = rect; + emit scanRectChanged(); + } +} + +bool QRCodeReader::scanning() const +{ + return m_readerThread.isRunning(); +} + +void QRCodeReader::grab(QImage image) +{ + m_type.clear(); + m_text.clear(); + emit validChanged(); + + if (m_scanRect.isValid()) { + image = image.copy(m_scanRect); + } + + Reader *reader = new Reader; + reader->moveToThread(&m_readerThread); + connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); + connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); + m_readerThread.start(); + + QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, img), Q_ARG(bool, false)); +} + +void QRCodeReader::processImage(const QUrl &url) +{ + QImage image; + if (!image.load(url.path())) { + qWarning() << "can't open" << url.path(); + return; + } + + Reader *reader = new Reader; + reader->moveToThread(&m_readerThread); + connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater())); + connect(reader, SIGNAL(finished()), &m_readerThread, SLOT(quit())); + connect(reader, SIGNAL(resultReady(QString, QString, QImage)), this, SLOT(handleResults(QString, QString, QImage))); + m_readerThread.start(); + + QMetaObject::invokeMethod(reader, "doWork", Q_ARG(QImage, image), Q_ARG(bool, false)); +} + +void QRCodeReader::handleResults(const QString &type, const QString &text, const QImage &codeImage) +{ + m_type = type; + m_text = text; + m_image = codeImage; + m_imageUuid = QUuid::createUuid(); + emit validChanged(); +} + +void Reader::doWork(const QImage &image, bool invert) +{ + // Prepare image + QImage copy = image; + if (invert) { + copy.invertPixels(); + } + zbar::QZBarImage img(copy.convertToFormat(QImage::Format_RGB32)); + zbar::Image tmp = img.convert(*(long*)"Y800"); + + // create a reader + zbar::ImageScanner scanner; + + // configure the reader + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1); + scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_POSITION, 1); + scanner.set_config(zbar::ZBAR_PARTIAL, zbar::ZBAR_CFG_ENABLE, 0); + + // scan the image for barcodes + int n = scanner.scan(tmp); +// qDebug() << "scanned. have" << n << "symbols"; + if (!invert && n == 0) { + // Nothing found... try again inverted + doWork(image, true); + return; + } + + img.set_symbols(tmp.get_symbols()); + + // extract results + for(zbar::Image::SymbolIterator symbol = img.symbol_begin(); symbol != img.symbol_end(); ++symbol) { + + QString typeName = QString::fromStdString(symbol->get_type_name()); + QString symbolString = QString::fromStdString(symbol->get_data()); + + int x0 = 999999; + int y0 = 999999; + int x1 = 0; + int y1 = 0; + + for (int i = 0; i < symbol->get_location_size(); ++i) { + int x = symbol->get_location_x(i); + int y = symbol->get_location_y(i); + qDebug() << "got point" << x << y; + if (x < x0) x0 = x; + if (y < y0) y0 = y; + if (x > x1) x1 = x; + if (y > y1) y1 = y; + } + + int width = x1 - x0; + int height = y1 - y0; + + // Workaround for zBar sometimes only giving us the first bar in a barcode. + if (width < 10) width = img.get_width() - x0; + if (height < 10) height = img.get_height() - y0; + + qDebug() << "extracting code image (" << x0 << y0 << ") ("<< x1 << y1 << ")"; + QImage codeImage = image.copy(x0, y0, width, height); + + qDebug() << "Code recognized:" << typeName << ", Text:" << symbolString; + + emit resultReady(typeName, symbolString, codeImage); + } + + tmp.set_data(NULL, 0); + img.set_data(NULL, 0); + + emit finished(); +} diff --git a/doorbird/qrcodereader.h b/doorbird/qrcodereader.h new file mode 100644 index 00000000..f0c22b05 --- /dev/null +++ b/doorbird/qrcodereader.h @@ -0,0 +1,88 @@ +/***************************************************************************** + * Copyright: 2013 Michael Zanetti * + * * + * This file is part of tagger * + * * + * This prject is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This project is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ****************************************************************************/ + +#ifndef QRCODEREADER_H +#define QRCODEREADER_H + +#include +#include +#include +#include + +class QRCodeReader : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool valid READ valid NOTIFY validChanged) + Q_PROPERTY(QString type READ type NOTIFY validChanged) + Q_PROPERTY(QString text READ text NOTIFY validChanged) + Q_PROPERTY(QImage image READ image NOTIFY validChanged) + Q_PROPERTY(QString imageSource READ imageSource NOTIFY validChanged) + Q_PROPERTY(QRect scanRect READ scanRect WRITE setScanRect NOTIFY scanRectChanged) + Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) + Q_PROPERTY(HistoryModel* history READ history CONSTANT) + +public: + explicit QRCodeReader(QObject *parent = nullptr); + + bool valid() const; + QString type() const; + QString text() const; + QImage image() const; + QString imageSource() const; + QRect scanRect() const; + void setScanRect(const QRect &rect); + bool scanning() const; + + +public slots: + void grab(QImage image); + void processImage(const QUrl &url); + +signals: + void validChanged(); + void scanRectChanged(); + void scanningChanged(); + +private slots: + void handleResults(const QString &type, const QString &text, const QImage &codeImage); + +private: + QString m_type; + QString m_text; + QImage m_image; + QUuid m_imageUuid; + QRect m_scanRect; + + QThread m_readerThread; +}; + +class Reader : public QObject +{ + Q_OBJECT + +public slots: + void doWork(const QImage &image, bool invert); + +signals: + void resultReady(const QString &type, const QString &text, const QImage &codeImage); + void finished(); +}; + +#endif // QRCODEREADER_H