Add back end for QR code scanning
Co-authored-by: Melvin Keskin <melvo@olomono.de> Co-authored-by: Jonah Brüchert <jbb@kaidan.im>master
parent
024a3ece88
commit
6ee280bfd6
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
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
|
||||
|
|
18
LICENSE
18
LICENSE
|
@ -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();
|
||||
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 = "";
|
||||
});
|
||||
// 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,22 +205,59 @@ 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()
|
||||
{
|
||||
return s_instance;
|
||||
|
|
14
src/Kaidan.h
14
src/Kaidan.h
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
uchar yuvToGray(uchar Y, uchar U, uchar V)
|
||||
{
|
||||
const int C = int(Y) - 16;
|
||||
const int D = int(U) - 128;
|
||||
const int E = int(V) - 128;
|
||||
return gray(
|
||||
qBound<uchar>(0, uchar((298 * C + 409 * E + 128) >> 8), 255),
|
||||
qBound<uchar>(0, uchar((298 * C - 100 * D - 208 * E + 128) >> 8), 255),
|
||||
qBound<uchar>(0, uchar((298 * C + 516 * D + 128) >> 8), 255)
|
||||
);
|
||||
}
|
||||
|
||||
uchar yuvToGray2(uchar y, uchar u, uchar v)
|
||||
{
|
||||
double rD = y + 1.4075 * (v - 128);
|
||||
double gD = y - 0.3455 * (u - 128) - (0.7169 * (v - 128));
|
||||
double bD = y + 1.7790 * (u - 128);
|
||||
|
||||
return gray(
|
||||
qBound<uchar>(0, uchar(floor(rD)), 255),
|
||||
qBound<uchar>(0, uchar(floor(gD)), 255),
|
||||
qBound<uchar>(0, uchar(floor(bD)), 255)
|
||||
);
|
||||
}
|
||||
|
||||
static QImage* rgbDataToGrayscale(
|
||||
const uchar* data,
|
||||
const CaptureRect &captureRect,
|
||||
const int alpha,
|
||||
const int red,
|
||||
const int green,
|
||||
const int blue,
|
||||
const bool isPremultiplied = false
|
||||
) {
|
||||
const int stride = (alpha < 0) ? 3 : 4;
|
||||
|
||||
const int endX = captureRect.sourceWidth - captureRect.startX - captureRect.targetWidth;
|
||||
const int skipX = (endX + captureRect.startX) * stride;
|
||||
|
||||
QImage *image_ptr = new QImage(captureRect.targetWidth, captureRect.targetHeight, QImage::Format_Grayscale8);
|
||||
uchar* pixelInit = image_ptr->bits();
|
||||
data += (captureRect.startY * captureRect.sourceWidth + captureRect.startX) * stride;
|
||||
|
||||
for (int y = 1; y <= captureRect.targetHeight; ++y) {
|
||||
// Quick fix for iOS devices. Will be handled better in the future
|
||||
#ifdef Q_OS_IOS
|
||||
uchar* pixel = pixelInit + (y - 1) * captureRect.targetWidth;
|
||||
#else
|
||||
uchar* pixel = pixelInit + (captureRect.targetHeight - y) * captureRect.targetWidth;
|
||||
#endif
|
||||
|
||||
for (int x = 0; x < captureRect.targetWidth; ++x) {
|
||||
uchar r = data[red];
|
||||
uchar g = data[green];
|
||||
uchar b = data[blue];
|
||||
if (isPremultiplied) {
|
||||
uchar a = data[alpha];
|
||||
r = uchar((uint(r) * 255) / a);
|
||||
g = uchar((uint(g) * 255) / a);
|
||||
b = uchar((uint(b) * 255) / a);
|
||||
}
|
||||
*pixel = gray(r, g, b);
|
||||
++pixel;
|
||||
data += stride;
|
||||
}
|
||||
data += skipX;
|
||||
}
|
||||
|
||||
return image_ptr;
|
||||
}
|
||||
|
||||
void QrCodeVideoFrame::setData(QVideoFrame &frame)
|
||||
{
|
||||
frame.map(QAbstractVideoBuffer::ReadOnly);
|
||||
|
||||
// Copy video frame bytes to this.data.
|
||||
// This is made to try to get a better performance (less memory allocation, faster unmap)
|
||||
// Any other task is performed in a QFuture task, as we want to leave the UI thread asap.
|
||||
if (m_data.size() != frame.mappedBytes()) {
|
||||
m_data.resize(frame.mappedBytes());
|
||||
}
|
||||
memcpy(m_data.data(), frame.bits(), frame.mappedBytes());
|
||||
m_size = frame.size();
|
||||
m_pixelFormat = frame.pixelFormat();
|
||||
|
||||
frame.unmap();
|
||||
}
|
||||
|
||||
QImage *QrCodeVideoFrame::toGrayscaleImage()
|
||||
{
|
||||
const CaptureRect captureRect(QRect(), m_size.width(), m_size.height());
|
||||
const auto* data = reinterpret_cast<const uchar *>(m_data.constData());
|
||||
const auto *yuvPtr = reinterpret_cast<const uint32_t *>(data);
|
||||
uchar *pixel;
|
||||
int wh;
|
||||
int w_2;
|
||||
int wh_54;
|
||||
|
||||
QImage *image;
|
||||
switch (m_pixelFormat) {
|
||||
case QVideoFrame::Format_RGB32:
|
||||
image = rgbDataToGrayscale(data, captureRect, 0, 1, 2, 3);
|
||||
break;
|
||||
case QVideoFrame::Format_ARGB32:
|
||||
image = rgbDataToGrayscale(data, captureRect, 0, 1, 2, 3);
|
||||
break;
|
||||
case QVideoFrame::Format_ARGB32_Premultiplied:
|
||||
image = rgbDataToGrayscale(data, captureRect, 0, 1, 2, 3, true);
|
||||
break;
|
||||
case QVideoFrame::Format_BGRA32:
|
||||
image = rgbDataToGrayscale(data, captureRect, 3, 2, 1, 0);
|
||||
break;
|
||||
case QVideoFrame::Format_BGRA32_Premultiplied:
|
||||
image = rgbDataToGrayscale(data, captureRect, 3, 2, 1, 0, true);
|
||||
break;
|
||||
case QVideoFrame::Format_BGR32:
|
||||
image = rgbDataToGrayscale(data, captureRect, 3, 2, 1, 0);
|
||||
break;
|
||||
case QVideoFrame::Format_BGR24:
|
||||
image = rgbDataToGrayscale(data, captureRect, -1, 2, 1, 0);
|
||||
break;
|
||||
case QVideoFrame::Format_BGR555:
|
||||
/// This is a forced "conversion", colors end up swapped.
|
||||
image = new QImage(data, m_size.width(), m_size.height(), QImage::Format_RGB555);
|
||||
break;
|
||||
case QVideoFrame::Format_BGR565:
|
||||
/// This is a forced "conversion", colors end up swapped.
|
||||
image = new QImage(data, m_size.width(), m_size.height(), QImage::Format_RGB16);
|
||||
break;
|
||||
case QVideoFrame::Format_YUV420P:
|
||||
case QVideoFrame::Format_NV12:
|
||||
/// nv12 format, encountered on macOS
|
||||
image = new QImage(captureRect.targetWidth, captureRect.targetHeight, QImage::Format_Grayscale8);
|
||||
pixel = image->bits();
|
||||
wh = m_size.width() * m_size.height();
|
||||
w_2 = m_size.width() / 2;
|
||||
wh_54 = wh * 5 / 4;
|
||||
|
||||
for (int y = captureRect.startY; y < captureRect.endY; y++) {
|
||||
const int Y_offset = y * m_size.width();
|
||||
const int y_2 = y / 2;
|
||||
const int U_offset = y_2 * w_2 + wh;
|
||||
const int V_offset = y_2 * w_2 + wh_54;
|
||||
for (int x = captureRect.startX; x < captureRect.endX; x++) {
|
||||
const int x_2 = x / 2;
|
||||
const uchar Y = data[Y_offset + x];
|
||||
const uchar U = data[U_offset + x_2];
|
||||
const uchar V = data[V_offset + x_2];
|
||||
*pixel = yuvToGray(Y, U, V);
|
||||
++pixel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QVideoFrame::Format_YUYV:
|
||||
image = new QImage(captureRect.targetWidth, captureRect.targetHeight, QImage::Format_Grayscale8);
|
||||
pixel = image->bits();
|
||||
|
||||
for (int y = captureRect.startY; y < captureRect.endY; y++){
|
||||
const uint32_t *row = &yuvPtr[y*(m_size.width()/2)];
|
||||
int end = captureRect.startX/2 + (captureRect.endX - captureRect.startX)/2;
|
||||
for (int x = captureRect.startX/2; x < end; x++){
|
||||
const uint8_t *pxl = reinterpret_cast<const uint8_t *>(&row[x]);
|
||||
const uint8_t y0 = pxl[0];
|
||||
const uint8_t u = pxl[1];
|
||||
const uint8_t v = pxl[3];
|
||||
const uint8_t y1 = pxl[2];
|
||||
|
||||
*pixel = yuvToGray2(y0, u, v);
|
||||
++pixel;
|
||||
*pixel = yuvToGray2(y1, u, v);
|
||||
++pixel;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
/// TODO: Handle (create QImages from) YUV formats.
|
||||
default:
|
||||
image = new QImage(
|
||||
data,
|
||||
m_size.width(),
|
||||
m_size.height(),
|
||||
QVideoFrame::imageFormatFromPixelFormat(m_pixelFormat)
|
||||
);
|
||||
break;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
QByteArray QrCodeVideoFrame::data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
QSize QrCodeVideoFrame::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
QVideoFrame::PixelFormat QrCodeVideoFrame::pixelFormat() const
|
||||
{
|
||||
return m_pixelFormat;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef QRCODEVIDEOFRAME_H
|
||||
#define QRCODEVIDEOFRAME_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QSize>
|
||||
#include <QVideoFrame>
|
||||
class QImage;
|
||||
|
||||
/**
|
||||
* video frame which may contain a QR code
|
||||
*/
|
||||
class QrCodeVideoFrame
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Instantiates an empty video frame
|
||||
*/
|
||||
QrCodeVideoFrame()
|
||||
: m_size{0,0},
|
||||
m_pixelFormat{QVideoFrame::Format_Invalid}
|
||||
{}
|
||||
|
||||
/**
|
||||
* Sets the frame.
|
||||
*
|
||||
* @param frame frame to be set
|
||||
*/
|
||||
void setData(QVideoFrame &frame);
|
||||
|
||||
/**
|
||||
* Converts a given image to a grayscale image.
|
||||
*
|
||||
* @return grayscale image
|
||||
*/
|
||||
QImage *toGrayscaleImage();
|
||||
|
||||
/**
|
||||
* @return content of the frame which may contain a QR code
|
||||
*/
|
||||
QByteArray data() const;
|
||||
|
||||
/**
|
||||
* @return size of the frame
|
||||
*/
|
||||
QSize size() const;
|
||||
|
||||
/**
|
||||
* @return format of the frame
|
||||
*/
|
||||
QVideoFrame::PixelFormat pixelFormat() const;
|
||||
|
||||
private:
|
||||
QByteArray m_data;
|
||||
QSize m_size;
|
||||
QVideoFrame::PixelFormat m_pixelFormat;
|
||||
};
|
||||
|
||||
#endif // QRCODEVIDEOFRAME_H
|
|
@ -57,6 +57,9 @@
|
|||
#include "RosterModel.h"
|
||||
#include "StatusBar.h"
|
||||
#include "UploadManager.h"
|
||||
#include "EmojiModel.h"
|
||||
#include "Utils.h"
|
||||
#include "QrCodeScannerFilter.h"
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#include "static_plugins.h"
|
||||
|
@ -177,6 +180,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
qRegisterMetaType<QHash<QString,RosterItem>>("QHash<QString,RosterItem>");
|
||||
qRegisterMetaType<std::function<void(RosterItem&)>>("std::function<void(RosterItem&)>");
|
||||
qRegisterMetaType<std::function<void(Message&)>>("std::function<void(Message&)>");
|
||||
qRegisterMetaType<ClientWorker::Credentials>("ClientWorker::Credentials");
|
||||
// Enums for c++ member calls using enums
|
||||
qRegisterMetaType<Enums::ConnectionState>();
|
||||
qRegisterMetaType<Enums::DisconnectionReason>();
|
||||
|
@ -246,7 +250,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
|
||||
// open the XMPP-URI/link (if given)
|
||||
if (!parser.positionalArguments().isEmpty())
|
||||
kaidan.addOpenUri(parser.positionalArguments().first().toUtf8());
|
||||
kaidan.addOpenUri(parser.positionalArguments().first());
|
||||
|
||||
//
|
||||
// QML-GUI
|
||||
|
@ -274,6 +278,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
qmlRegisterType<StatusBar>("StatusBar", 0, 1, "StatusBar");
|
||||
qmlRegisterType<EmojiModel>("EmojiModel", 0, 1, "EmojiModel");
|
||||
qmlRegisterType<EmojiProxyModel>("EmojiModel", 0, 1, "EmojiProxyModel");
|
||||
qmlRegisterType<QrCodeScannerFilter>(APPLICATION_ID, 1, 0, "QrCodeScannerFilter");
|
||||
|
||||
qmlRegisterUncreatableType<QAbstractItemModel>("EmojiModel", 0, 1, "QAbstractItemModel", "Used by proxy models");
|
||||
qmlRegisterUncreatableType<Emoji>("EmojiModel", 0, 1, "Emoji", "Used by emoji models");
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "QXmppUri.h"
|
||||
#include <QUrlQuery>
|
||||
|
||||
/// actions, e.g. "join" in "group@example.org?join" for joining a groupchat
|
||||
/// actions, e.g. "join" in "xmpp:group@example.org?join" for joining a group chat
|
||||
|
||||
const QStringList ACTION_STRINGS = QStringList()
|
||||
<< ""
|
||||
|
|
|
@ -14,6 +14,7 @@ BUILD_TYPE="${BUILD_TYPE:-Debug}"
|
|||
KAIDAN_SOURCES=$(dirname "$(readlink -f "${0}")")/..
|
||||
KIRIGAMI_BUILD=/tmp/kirigami-mac-build
|
||||
QXMPP_BUILD=/tmp/qxmpp-mac-build
|
||||
ZXING_BUILD=/tmp/zxing-mac-build
|
||||
OSXCROSS_TARGET="x86_64-apple-darwin15"
|
||||
|
||||
echo "-- Starting $BUILD_TYPE build of Kaidan --"
|
||||
|
@ -32,6 +33,11 @@ if [ ! -e "$KAIDAN_SOURCES/3rdparty/qxmpp/" ]; then
|
|||
git clone https://github.com/qxmpp-project/qxmpp.git 3rdparty/qxmpp
|
||||
fi
|
||||
|
||||
if [ ! -e "$KAIDAN_SOURCES/3rdparty/zxing-cpp/" ]; then
|
||||
echo "Cloning ZXing"
|
||||
git clone https://github.com/nu-book/zxing-cpp.git 3rdparty/zxing-cpp
|
||||
fi
|
||||
|
||||
cdnew() {
|
||||
if [ -d "$1" ]; then
|
||||
rm -rf "$1"
|
||||
|
@ -77,6 +83,24 @@ echo "*****************************************"
|
|||
}
|
||||
fi
|
||||
|
||||
if [ ! -f "$ZXING_BUILD/lib/libZXingCore.dylib" ]; then
|
||||
echo "*****************************************"
|
||||
echo "Building ZXing"
|
||||
echo "*****************************************"
|
||||
{
|
||||
cdnew $KAIDAN_SOURCES/3rdparty/zxing-cpp/build
|
||||
${OSXCROSS_TARGET}-cmake .. \
|
||||
-DCMAKE_PREFIX_PATH=$QT_MACOS \
|
||||
-DBUILD_SHARED_LIBRARY=ON \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=$ZXING_BUILD
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
rm -rf $KAIDAN_SOURCES/3rdparty/zxing-cpp/build
|
||||
}
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f "$KAIDAN_SOURCES/misc/macos/kaidan.icns" ]; then
|
||||
echo "*****************************************"
|
||||
echo "Rendering logos"
|
||||
|
@ -120,6 +144,7 @@ echo "*****************************************"
|
|||
-DECM_DIR=/usr/local/share/ECM/cmake \
|
||||
-DCMAKE_PREFIX_PATH=$QT_MACOS\;$KIRIGAMI_BUILD\;$QXMPP_BUILD \
|
||||
-DKF5Kirigami2_DIR=$KIRIGAMI_BUILD/lib/cmake/KF5Kirigami2 \
|
||||
-DZXing_DIR=$ZXING_BUILD/lib/cmake/ZXing \
|
||||
-DI18N=1 \
|
||||
-DUSE_KNOTIFICATIONS=OFF \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
|
@ -134,7 +159,7 @@ echo "Macdeployqt"
|
|||
echo "*****************************************"
|
||||
{
|
||||
cd $KAIDAN_SOURCES/build
|
||||
export LD_LIBRARY_PATH=$QT_MACOS/lib/:$KIRIGAMI_BUILD/lib:$LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=$QT_MACOS/lib/:$KIRIGAMI_BUILD/lib:$ZXING_BUILD/lib:$LD_LIBRARY_PATH
|
||||
export PATH=$QT_MACOS/bin/:$PATH
|
||||
|
||||
# FIXME: Use `macdeployqt -qmlimport` when QTBUG-70977 is fixed
|
||||
|
@ -143,6 +168,11 @@ echo "*****************************************"
|
|||
ln -s $KIRIGAMI_BUILD/lib/qml/org/kde/kirigami.2 $QT_MACOS/qml/org/kde/kirigami.2
|
||||
fi
|
||||
|
||||
macdeployqt bin/kaidan.app -qmlimport=$QT_MACOS/qml -qmlimport=$KIRIGAMI_BUILD/lib/qml/ -qmldir=$KAIDAN_SOURCES/src/qml/ -libpath=$KIRIGAMI_BUILD/lib/ -libpath=$QXMPP_BUILD/lib -libpath=$QT_MACOS/lib/ -appstore-compliant -verbose=3
|
||||
# FIXME: Why does this assume /usr
|
||||
if [ ! -f /usr/lib/libZXingCore.1.dylib ]; then
|
||||
ln -s $ZXING_BUILD/lib/libZXingCore.1.dylib /usr/lib/libZXingCore.1.dylib
|
||||
fi
|
||||
|
||||
macdeployqt bin/kaidan.app -qmlimport=$QT_MACOS/qml -qmlimport=$KIRIGAMI_BUILD/lib/qml/ -qmldir=$KAIDAN_SOURCES/src/qml/ -libpath=$KIRIGAMI_BUILD/lib/ -libpath=$QXMPP_BUILD/lib -libpath=$QT_MACOS/lib/ -appstore-compliant -verbose=1
|
||||
${OSXCROSS_TARGET}-install_name_tool -add_rpath @executable_path/../Frameworks bin/kaidan.app/Contents/MacOS/kaidan
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ REPLACE_USER_IDS = [
|
|||
# These user ids will be excluded from any targets
|
||||
EXCLUDE_USER_IDS = [
|
||||
"Weblate <noreply@weblate.org>",
|
||||
"Hosted Weblate <hosted@weblate.org>",
|
||||
"anonymous <> <None>",
|
||||
"Kaidan Translations <translations@kaidan.im>",
|
||||
"Kaidan translations <translations@kaidan.im>",
|
||||
|
@ -136,6 +137,18 @@ 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."""
|
||||
|
||||
APACHE2_LICENSE = """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."""
|
||||
|
||||
class CopyrightAuthor:
|
||||
def __init__(self, score = 0, dates = None, years = "", uid = ""):
|
||||
self.dates = dates or list([]);
|
||||
|
@ -292,6 +305,13 @@ def main():
|
|||
"Konstantinos Sideris <siderisk@auth.gr>": CopyrightAuthor(years = "2017"),
|
||||
},
|
||||
),
|
||||
CopyrightTarget(
|
||||
files = ["src/QrCodeVideoFrame.h", "src/QrCodeVideoFrame.cpp"],
|
||||
licenseName = "apache-2.0",
|
||||
authorList = {
|
||||
"QZXing authors": CopyrightAuthor(years = "2017"),
|
||||
},
|
||||
),
|
||||
CopyrightTarget(
|
||||
files = ["data/images/message_checkmark.svg"],
|
||||
licenseName = "GPL-3+",
|
||||
|
@ -341,6 +361,10 @@ def main():
|
|||
LicenseTarget(
|
||||
name = "MIT-Apple",
|
||||
content = MIT_APPLE_LICENSE
|
||||
),
|
||||
LicenseTarget(
|
||||
name = "apache-2.0",
|
||||
content = APACHE2_LICENSE
|
||||
)
|
||||
];
|
||||
|
||||
|
|
Loading…
Reference in New Issue