Commit 6ee280bf authored by LNJ's avatar LNJ 💬

Add back end for QR code scanning

Co-authored-by: melvo's avatarMelvin Keskin <melvo@olomono.de>
Co-authored-by: default avatarJonah Brüchert <jbb@kaidan.im>
parent 024a3ece
......@@ -82,6 +82,7 @@ android:
- sudo apt -y install inkscape optipng
- GIT_EXTRA="--branch ${KF5_VERSION}" /opt/helpers/build-kde-dependencies --withProject kirigami
- /opt/helpers/build-cmake qxmpp https://github.com/qxmpp-project/qxmpp.git -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF
- /opt/helpers/build-cmake zxing-cpp https://github.com/nu-book/zxing-cpp.git
- GIT_EXTRA="--branch ${CI_COMMIT_REF_NAME} --recursive" /opt/helpers/build-cmake ${CI_PROJECT_NAME} ${CI_REPOSITORY_URL} -DQTANDROID_EXPORTED_TARGET=kaidan -DANDROID_APK_DIR=${CI_PROJECT_DIR}/src/${CI_PROJECT_NAME}/misc/android -DI18N=1 -DUSE_KNOTIFICATIONS=OFF
- ${CI_PROJECT_DIR}/src/${CI_PROJECT_NAME}/utils/render-logos.sh
- /opt/helpers/create-apk ${CI_PROJECT_NAME}
......
......@@ -7,3 +7,6 @@
[submodule "3rdparty/qxmpp"]
path = 3rdparty/qxmpp
url = https://github.com/qxmpp-project/qxmpp
[submodule "3rdparty/zxing-cpp"]
path = 3rdparty/zxing-cpp
url = https://github.com/nu-book/zxing-cpp
Subproject commit baecef0d69b81ace79cd44035ac859bc201f1847
......@@ -55,8 +55,9 @@ kde_enable_exceptions()
# Find packages
find_package(PkgConfig REQUIRED)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Qml Quick Svg Sql QuickControls2 Xml)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Qml Quick Svg Sql QuickControls2 Xml Multimedia)
find_package(KF5Kirigami2 REQUIRED)
find_package(ZXing REQUIRED COMPONENTS Core)
pkg_search_module(QXmpp REQUIRED qxmpp>=1.0)
# Optional QtQuickCompiler
......@@ -167,6 +168,8 @@ target_link_libraries(${PROJECT_NAME}
Qt5::Svg
Qt5::Network
Qt5::Xml
Qt5::Multimedia
ZXing::Core
${__Qt5Widgets_LIBRARIES}
${__KF5Notifications_LIBRARIES}
# currently needs to be hardcoded for windows builds
......
......@@ -61,6 +61,11 @@ Files: src/EmojiModel.cpp
Copyright: 2017, Konstantinos Sideris <siderisk@auth.gr>
License: GPL-3+
Files: src/QrCodeVideoFrame.h
src/QrCodeVideoFrame.cpp
Copyright: 2017, QZXing authors
License: apache-2.0
Files: data/images/message_checkmark.svg
Copyright: 2014, Michael Kurz <betheg@bitcloner.org>
License: GPL-3+
......@@ -169,3 +174,16 @@ License: MIT-Apple
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
License: apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
......@@ -39,10 +39,11 @@ how to do that:
### Dependencies
Here are the general dependencies of Kaidan listed:
* [Qt](https://doc.qt.io/qt-5/build-sources.html) (Core Qml Quick Svg Sql QuickControls2) (>= 5.10.0)
* [Qt](https://doc.qt.io/qt-5/build-sources.html) (Core Qml Quick Svg Sql QuickControls2 Multimedia) (>= 5.10.0)
* [QXmpp][qxmpp] (>= 1.0.0)
* [Kirigami 2](https://phabricator.kde.org/source/kirigami/) (>= 5.42.0)
* [ECM (extra-cmake-modules)](https://api.kde.org/ecm/manual/ecm.7.html)
* [ZXing-cpp](https://github.com/nu-book/zxing-cpp)
* [KNotifications][knotif] (`-DUSE_KNOTIFICATIONS=OFF` to disable)
### Build instructions
......
......@@ -20,6 +20,19 @@
"-DCMAKE_INSTALL_PREFIX=../../../bin/ubuntu-touch/tmp"
],
"postbuild": "make install"
},
"zxing-cpp": {
"template": "cmake",
"src_dir": "3rdparty/zxing-cpp",
"make_jobs": 2,
"build_args": [
"-DCMAKE_BUILD_TYPE=Release",
"-DBUILD_SHARED_LIBRARY=ON",
"-DLINK_CPP_STATICALLY=OFF",
"-DCMAKE_PREFIX_PATH=../../../bin/ubuntu-touch/tmp",
"-DCMAKE_INSTALL_PREFIX=../../../bin/ubuntu-touch/tmp"
],
"postbuild": "make install"
}
}
}
......@@ -26,6 +26,9 @@ set(KAIDAN_SOURCES
src/DownloadManager.cpp
src/QmlUtils.cpp
src/Utils.cpp
src/QrCodeDecoder
src/QrCodeScannerFilter.cpp
src/QrCodeVideoFrame.cpp
# needed to trigger moc generation / to be displayed in IDEs
src/Enums.h
......
......@@ -37,7 +37,7 @@
#include <QThread>
// QXmpp
#include "qxmpp-exts/QXmppColorGenerator.h"
#include <QXmppClient.h>
#include "qxmpp-exts/QXmppUri.h"
// Kaidan
#include "AvatarFileStorage.h"
#include "Database.h"
......@@ -152,17 +152,19 @@ void Kaidan::mainDisconnect(bool openLogInPage)
void Kaidan::setConnectionState(QXmppClient::State state)
{
this->connectionState = static_cast<ConnectionState>(state);
emit connectionStateChanged();
// Open the possibly cached URI when connected.
// This is needed because the XMPP URIs can't be opened when Kaidan is not connected.
if (connectionState == ConnectionState::StateConnected && !openUriCache.isEmpty()) {
// delay is needed because sometimes the RosterPage needs to be loaded first
QTimer::singleShot(300, [=] () {
emit xmppUriReceived(openUriCache);
openUriCache = "";
});
if (this->connectionState != static_cast<ConnectionState>(state)) {
this->connectionState = static_cast<ConnectionState>(state);
emit connectionStateChanged();
// Open the possibly cached URI when connected.
// This is needed because the XMPP URIs can't be opened when Kaidan is not connected.
if (connectionState == ConnectionState::StateConnected && !openUriCache.isEmpty()) {
// delay is needed because sometimes the RosterPage needs to be loaded first
QTimer::singleShot(300, [=] () {
emit xmppUriReceived(openUriCache);
openUriCache = "";
});
}
}
}
......@@ -177,6 +179,7 @@ void Kaidan::setJid(const QString &jid)
creds.jid = jid;
// credentials were modified -> first try
creds.isFirstTry = true;
emit jidChanged();
}
void Kaidan::setJidResource(const QString &jidResource)
......@@ -186,6 +189,7 @@ void Kaidan::setJidResource(const QString &jidResource)
creds.jidResource = jidResource;
m_caches->settings->setValue(KAIDAN_SETTINGS_AUTH_RESOURCE, jidResource);
emit jidResourceChanged();
}
void Kaidan::setPassword(const QString &password)
......@@ -193,6 +197,7 @@ void Kaidan::setPassword(const QString &password)
creds.password = password;
// credentials were modified -> first try
creds.isFirstTry = true;
emit passwordChanged();
}
quint8 Kaidan::getDisconnReason() const
......@@ -200,20 +205,57 @@ quint8 Kaidan::getDisconnReason() const
return static_cast<quint8>(disconnReason);
}
void Kaidan::addOpenUri(const QByteArray &uri)
void Kaidan::addOpenUri(const QString &uri)
{
qDebug() << "[main]" << uri;
if (!uri.startsWith("xmpp:") || !uri.contains("@"))
if (!QXmppUri::isXmppUri(uri))
return;
if (connectionState == ConnectionState::StateConnected) {
emit xmppUriReceived(QString::fromUtf8(uri));
emit xmppUriReceived(uri);
} else {
//: The link is an XMPP-URI (i.e. 'xmpp:kaidan@muc.kaidan.im?join' for joining a chat)
emit passiveNotificationRequested(tr("The link will be opened after you have connected."));
openUriCache = QString::fromUtf8(uri);
openUriCache = uri;
}
}
void Kaidan::loginByUri(const QString &uri)
{
// input does not start with 'xmpp:'
if (!QXmppUri::isXmppUri(uri)) {
notifyLoginUriNotFound();
return;
}
// parse
QXmppUri parsedUri(uri);
// no JID provided
if (parsedUri.jid().isEmpty()) {
notifyLoginUriNotFound();
return;
}
setJid(parsedUri.jid());
// URI has no login action or no password
if (!parsedUri.hasAction(QXmppUri::Action::Login) || parsedUri.password().isEmpty()) {
// reset password
setPassword(QString());
emit passiveNotificationRequested(tr("No password found. Please enter it."));
return;
}
setPassword(parsedUri.password());
// try to connect
mainConnect();
}
void Kaidan::notifyLoginUriNotFound()
{
qWarning() << "[main]" << "No valid login URI found.";
emit passiveNotificationRequested(tr("No valid login QR code found."));
}
Kaidan *Kaidan::instance()
......
......@@ -195,7 +195,14 @@ public:
/**
* Adds XMPP URI to open as soon as possible
*/
void addOpenUri(const QByteArray &uri);
void addOpenUri(const QString &uri);
/**
* Connects to the server by the parsed credentials (bare JID and password)
* from a given XMPP URI (e.g. from scanning a QR code)
* like "xmpp:user@example.org?login;password=abc"
*/
Q_INVOKABLE void loginByUri(const QString &uri);
/**
* Returns whether an HTTP File Upload service has been found
......@@ -385,6 +392,11 @@ public slots:
private:
void connectDatabases();
/**
* Notifies if no login URI was found
*/
void notifyLoginUriNotFound();
QmlUtils *m_utils;
Database *m_database;
QThread *m_dbThrd;
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "QrCodeDecoder.h"
// Qt
#include <QColor>
#include <QImage>
// ZXing-cpp
#include <ZXing/BarcodeFormat.h>
#include <ZXing/DecodeHints.h>
#include <ZXing/GenericLuminanceSource.h>
#include <ZXing/HybridBinarizer.h>
#include <ZXing/LuminanceSource.h>
#include <ZXing/MultiFormatReader.h>
#include <ZXing/Result.h>
#include <ZXing/TextUtfEncoding.h>
using namespace ZXing;
QrCodeDecoder::QrCodeDecoder(QObject *parent)
: QObject(parent)
{
}
void QrCodeDecoder::decodeImage(const QImage &image)
{
// options for decoding
DecodeHints decodeHints;
// Advise the decoder to also decode rotated QR codes.
decodeHints.setShouldTryRotate(true);
// Advise the decoder to only decode QR codes.
std::vector<BarcodeFormat> allowedFormats;
allowedFormats.emplace_back(BarcodeFormat::QR_CODE);
decodeHints.setPossibleFormats(allowedFormats);
MultiFormatReader reader(decodeHints);
// Create an image source to be decoded later.
GenericLuminanceSource source(
image.width(),
image.height(),
image.bits(),
image.width(),
1,
0,
1,
2
);
// Create an image source specific for decoding black data on white background.
HybridBinarizer binImage(std::shared_ptr<LuminanceSource>(&source, [](void*) {}));
// Decode the specific image source.
auto result = reader.read(binImage);
// If a QR code could be found and decoded, emit a signal with the decoded string.
// Otherwise, emit a signal for failed decoding.
if (result.isValid())
emit decodingSucceeded(QString::fromStdString(TextUtfEncoding::ToUtf8(result.text())));
else
emit decodingFailed();
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QRCODEDECODER_H
#define QRCODEDECODER_H
#include <QObject>
/**
* Decoder for QR codes. This is a backend for \c QrCodeScanner .
*/
class QrCodeDecoder : public QObject
{
Q_OBJECT
public:
/**
* Instantiates a QR code decoder.
*
* @param parent parent object
*/
explicit QrCodeDecoder(QObject *parent = nullptr);
signals:
/**
* Emitted when the decoding failed.
*/
void decodingFailed();
/**
* Emitted when the decoding succeeded.
*
* @param tag string which was decoded by the QR code decoder
*/
void decodingSucceeded(const QString &tag);
public slots:
/**
* Tries to decode the QR code from the given image. When decoding has
* finished @c decodingFinished() will be emitted. In case a QR code was found,
* also @c tagFound() will be emitted.
*
* @param image image which may contain a QR code to decode to a string.
* It needs to be in grayscale format (one byte per pixel).
*/
void decodeImage(const QImage &image);
};
#endif // QRCODEDECODER_H
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "QrCodeScannerFilter.h"
#include <QDebug>
#include <QtConcurrent/QtConcurrent>
QrCodeScannerFilter::QrCodeScannerFilter(QObject *parent)
: QAbstractVideoFilter(parent),
m_decoder(new QrCodeDecoder(this))
{
connect(m_decoder, &QrCodeDecoder::decodingFailed,
this, &QrCodeScannerFilter::scanningFailed);
connect(m_decoder, &QrCodeDecoder::decodingSucceeded,
this, &QrCodeScannerFilter::scanningSucceeded);
}
QrCodeScannerFilter::~QrCodeScannerFilter()
{
if (!m_processThread.isFinished()) {
m_processThread.cancel();
m_processThread.waitForFinished();
}
}
QrCodeDecoder *QrCodeScannerFilter::decoder()
{
return m_decoder;
}
QVideoFilterRunnable *QrCodeScannerFilter::createFilterRunnable()
{
return new QrCodeScannerFilterRunnable(this);
}
QrCodeScannerFilterRunnable::QrCodeScannerFilterRunnable(QrCodeScannerFilter *filter)
: QObject(nullptr),
m_filter(filter)
{
}
QVideoFrame QrCodeScannerFilterRunnable::run(
QVideoFrame *input,
const QVideoSurfaceFormat &,
RunFlags
) {
// Only one frame is processed at a time.
if (input == nullptr
|| !input->isValid()
|| !m_filter->m_processThread.isFinished()) {
return *input;
}
// Copy the data to be filtered.
m_filter->m_frame.setData(*input);
// Run a separate thread for processing the data.
m_filter->m_processThread = QtConcurrent::run(
this,
&QrCodeScannerFilterRunnable::processVideoFrameProbed,
m_filter->m_frame
);
return *input;
}
void QrCodeScannerFilterRunnable::processVideoFrameProbed(QrCodeVideoFrame &videoFrame)
{
// Return if the frame is empty.
if (videoFrame.data().length() < 1)
return;
// Create an image from the frame.
const QImage *image = videoFrame.toGrayscaleImage();
// Return if no conversion from the frame to the image failed.
if (image->isNull()) {
qDebug() << "QrCodeScannerFilterRunnable error: Cannot create image file to process.";
qDebug() << "Maybe it was a format conversion problem.";
qDebug() << "VideoFrame format:" << videoFrame.pixelFormat();
qDebug() << "Image corresponding format:"
<< QVideoFrame::imageFormatFromPixelFormat(videoFrame.pixelFormat());
return;
}
// Decode the image.
m_filter->decoder()->decodeImage(*image);
delete image;
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QRCODESCANNERFILTER_H
#define QRCODESCANNERFILTER_H
#include <QObject>
#include <QAbstractVideoFilter>
#include <QFuture>
#include <ZXing/DecodeHints.h>
#include "QrCodeDecoder.h"
#include "QrCodeVideoFrame.h"
/**
* video filter to be registered in C++, instantiated and attached in QML
*/
class QrCodeScannerFilter : public QAbstractVideoFilter
{
friend class QrCodeScannerFilterRunnable;
Q_OBJECT
Q_PROPERTY(QrCodeDecoder* decoder READ decoder)
public:
/**
* Instantiates a QR code scanner filter.
*
* @param parent parent object
*/
explicit QrCodeScannerFilter(QObject *parent = nullptr);
~QrCodeScannerFilter() override;
/**
* @return decoder for decoding a video frame
*/
QrCodeDecoder *decoder();
QVideoFilterRunnable *createFilterRunnable();
signals:
/**
* Emitted when the scanning of an image did not succeed, i.e. no valid QR code was found.
*/
void scanningFailed();
/**
* Emitted when the scanning of an image succeeded, i.e. a valid QR code was found and decoded.
*
* @param result decoded content of the QR code
*/
void scanningSucceeded(const QString& result);
private:
QrCodeDecoder *m_decoder;
/**
* frame of the video which may contain a QR code
*/
QrCodeVideoFrame m_frame;
QFuture<void> m_processThread;
};
/**
* runnable which is created everytime the filter gets a new frame
*/
class QrCodeScannerFilterRunnable : public QObject, public QVideoFilterRunnable
{
Q_OBJECT
public:
explicit QrCodeScannerFilterRunnable(QrCodeScannerFilter *m_filter);
/**
* Runs the decoding in a new thread whenever a new frame is taken by the camera.
*/
QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags);
/**
* Converts a given frame, which may contain a QR code, to an image and then tries to decode it.
*
* @param videoFrame frame to be converted and which may contain a QR code to be decoded
*/
void processVideoFrameProbed(QrCodeVideoFrame &videoFrame);
private:
QrCodeScannerFilter *m_filter;
};
#endif // QRCODESCANNERFILTER_H
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2019 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan 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.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan 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 Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2017 QZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "QrCodeVideoFrame.h"
#include <QImage>
#include <cmath>
/**
* rectangle of the video frame which may contain a QR code
*/
struct CaptureRect
{
CaptureRect(const QRect& captureRect, int sourceWidth, int sourceHeight)
: isValid(captureRect.x() >= 0 && captureRect.y() >= 0 && captureRect.isValid()),
sourceWidth(sourceWidth),
sourceHeight(sourceHeight),
startX(isValid ? captureRect.x() : 0),
targetWidth(isValid ? captureRect.width() : sourceWidth),
endX(startX + targetWidth),
startY(isValid ? captureRect.y() : 0),
targetHeight(isValid ? captureRect.height() : sourceHeight),
endY(startY + targetHeight)
{}
bool isValid;
int sourceWidth;
int sourceHeight;
int startX;
int targetWidth;
int endX;
int startY;
int targetHeight;
int endY;
};
uchar gray(uchar r, uchar g, uchar b)
{
return (306 * (r & 0xFF) +
601 * (g & 0xFF) +
117 * (b & 0xFF) +
0x200) >> 10;