Round images in the image provider
This commit is contained in:
parent
24366b7520
commit
42d2b10d5d
@ -3,7 +3,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import "./ui"
|
import "./ui"
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.3
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
@ -50,8 +49,7 @@ Rectangle {
|
|||||||
smooth: true
|
smooth: true
|
||||||
sourceSize.width: avatar.width
|
sourceSize.width: avatar.width
|
||||||
sourceSize.height: avatar.height
|
sourceSize.height: avatar.height
|
||||||
layer.enabled: true
|
source: avatar.url ? (avatar.url + "?radius=" + radius + ((avatar.crop) ? "" : "&scale")) : ""
|
||||||
source: avatar.url + ((avatar.crop || !avatar.url) ? "" : "?scale")
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
@ -65,18 +63,6 @@ Rectangle {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.effect: OpacityMask {
|
|
||||||
cached: true
|
|
||||||
|
|
||||||
maskSource: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
width: avatar.width
|
|
||||||
height: avatar.height
|
|
||||||
radius: Settings.avatarCircles ? height / 2 : 3
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -6,7 +6,6 @@ import "./delegates"
|
|||||||
import "./emoji"
|
import "./emoji"
|
||||||
import "./ui"
|
import "./ui"
|
||||||
import Qt.labs.platform 1.1 as Platform
|
import Qt.labs.platform 1.1 as Platform
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.2
|
import QtQuick.Layouts 1.2
|
||||||
|
@ -8,7 +8,6 @@ import "./dialogs"
|
|||||||
import "./emoji"
|
import "./emoji"
|
||||||
import "./voip"
|
import "./voip"
|
||||||
import Qt.labs.platform 1.1 as Platform
|
import Qt.labs.platform 1.1 as Platform
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
@ -9,7 +9,6 @@ import "./emoji"
|
|||||||
import "./ui"
|
import "./ui"
|
||||||
import "./voip"
|
import "./voip"
|
||||||
import Qt.labs.platform 1.1 as Platform
|
import Qt.labs.platform 1.1 as Platform
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick 2.9
|
import QtQuick 2.9
|
||||||
import QtQuick.Controls 2.5
|
import QtQuick.Controls 2.5
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
@ -22,14 +24,26 @@ QHash<QString, mtx::crypto::EncryptedFile> infos;
|
|||||||
QQuickImageResponse *
|
QQuickImageResponse *
|
||||||
MxcImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
MxcImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
||||||
{
|
{
|
||||||
auto id_ = id;
|
auto id_ = id;
|
||||||
bool crop = true;
|
bool crop = true;
|
||||||
if (id.endsWith("?scale")) {
|
double radius = 0;
|
||||||
crop = false;
|
|
||||||
id_.remove("?scale");
|
auto queryStart = id.lastIndexOf('?');
|
||||||
|
if (queryStart != -1) {
|
||||||
|
id_ = id.left(queryStart);
|
||||||
|
auto query = id.midRef(queryStart + 1);
|
||||||
|
auto queryBits = query.split('&');
|
||||||
|
|
||||||
|
for (auto b : queryBits) {
|
||||||
|
if (b == "scale") {
|
||||||
|
crop = false;
|
||||||
|
} else if (b.startsWith("radius=")) {
|
||||||
|
radius = b.mid(7).toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MxcImageResponse *response = new MxcImageResponse(id_, crop, requestedSize);
|
MxcImageResponse *response = new MxcImageResponse(id_, crop, radius, requestedSize);
|
||||||
pool.start(response);
|
pool.start(response);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -53,14 +67,35 @@ MxcImageResponse::run()
|
|||||||
}
|
}
|
||||||
emit finished();
|
emit finished();
|
||||||
},
|
},
|
||||||
m_crop);
|
m_crop,
|
||||||
|
m_radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QImage
|
||||||
|
clipRadius(QImage img, double radius)
|
||||||
|
{
|
||||||
|
QImage out(img.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
out.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&out);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||||
|
|
||||||
|
QPainterPath ppath;
|
||||||
|
ppath.addRoundedRect(img.rect(), radius, radius);
|
||||||
|
|
||||||
|
painter.setClipPath(ppath);
|
||||||
|
painter.drawImage(img.rect(), img);
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MxcImageProvider::download(const QString &id,
|
MxcImageProvider::download(const QString &id,
|
||||||
const QSize &requestedSize,
|
const QSize &requestedSize,
|
||||||
std::function<void(QString, QSize, QImage, QString)> then,
|
std::function<void(QString, QSize, QImage, QString)> then,
|
||||||
bool crop)
|
bool crop,
|
||||||
|
double radius)
|
||||||
{
|
{
|
||||||
std::optional<mtx::crypto::EncryptedFile> encryptionInfo;
|
std::optional<mtx::crypto::EncryptedFile> encryptionInfo;
|
||||||
auto temp = infos.find("mxc://" + id);
|
auto temp = infos.find("mxc://" + id);
|
||||||
@ -69,12 +104,13 @@ MxcImageProvider::download(const QString &id,
|
|||||||
|
|
||||||
if (requestedSize.isValid() && !encryptionInfo) {
|
if (requestedSize.isValid() && !encryptionInfo) {
|
||||||
QString fileName =
|
QString fileName =
|
||||||
QString("%1_%2x%3_%4")
|
QString("%1_%2x%3_%4_radius%5")
|
||||||
.arg(QString::fromUtf8(id.toUtf8().toBase64(QByteArray::Base64UrlEncoding |
|
.arg(QString::fromUtf8(id.toUtf8().toBase64(QByteArray::Base64UrlEncoding |
|
||||||
QByteArray::OmitTrailingEquals)))
|
QByteArray::OmitTrailingEquals)))
|
||||||
.arg(requestedSize.width())
|
.arg(requestedSize.width())
|
||||||
.arg(requestedSize.height())
|
.arg(requestedSize.height())
|
||||||
.arg(crop ? "crop" : "scale");
|
.arg(crop ? "crop" : "scale")
|
||||||
|
.arg(radius);
|
||||||
QFileInfo fileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
|
QFileInfo fileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
|
||||||
"/media_cache",
|
"/media_cache",
|
||||||
fileName);
|
fileName);
|
||||||
@ -86,6 +122,10 @@ MxcImageProvider::download(const QString &id,
|
|||||||
image = image.scaled(
|
image = image.scaled(
|
||||||
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
|
if (radius != 0) {
|
||||||
|
image = clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
|
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
then(id, requestedSize, image, fileInfo.absoluteFilePath());
|
then(id, requestedSize, image, fileInfo.absoluteFilePath());
|
||||||
return;
|
return;
|
||||||
@ -100,8 +140,8 @@ MxcImageProvider::download(const QString &id,
|
|||||||
opts.method = crop ? "crop" : "scale";
|
opts.method = crop ? "crop" : "scale";
|
||||||
http::client()->get_thumbnail(
|
http::client()->get_thumbnail(
|
||||||
opts,
|
opts,
|
||||||
[fileInfo, requestedSize, then, id](const std::string &res,
|
[fileInfo, requestedSize, radius, then, id](const std::string &res,
|
||||||
mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
if (err || res.empty()) {
|
if (err || res.empty()) {
|
||||||
then(id, QSize(), {}, "");
|
then(id, QSize(), {}, "");
|
||||||
|
|
||||||
@ -113,6 +153,10 @@ MxcImageProvider::download(const QString &id,
|
|||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
image = image.scaled(
|
image = image.scaled(
|
||||||
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
|
if (radius != 0) {
|
||||||
|
image = clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
image.setText("mxc url", "mxc://" + id);
|
image.setText("mxc url", "mxc://" + id);
|
||||||
if (image.save(fileInfo.absoluteFilePath(), "png"))
|
if (image.save(fileInfo.absoluteFilePath(), "png"))
|
||||||
@ -126,8 +170,12 @@ MxcImageProvider::download(const QString &id,
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
QString fileName = QString::fromUtf8(id.toUtf8().toBase64(
|
QString fileName =
|
||||||
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
|
QString("%1_radius%2")
|
||||||
|
.arg(QString::fromUtf8(id.toUtf8().toBase64(
|
||||||
|
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)))
|
||||||
|
.arg(radius);
|
||||||
|
|
||||||
QFileInfo fileInfo(
|
QFileInfo fileInfo(
|
||||||
QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
|
QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
|
||||||
"/media_cache",
|
"/media_cache",
|
||||||
@ -148,6 +196,11 @@ MxcImageProvider::download(const QString &id,
|
|||||||
QImage image = utils::readImage(data);
|
QImage image = utils::readImage(data);
|
||||||
image.setText("mxc url", "mxc://" + id);
|
image.setText("mxc url", "mxc://" + id);
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
|
if (radius != 0) {
|
||||||
|
image =
|
||||||
|
clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
|
|
||||||
then(id,
|
then(id,
|
||||||
requestedSize,
|
requestedSize,
|
||||||
image,
|
image,
|
||||||
@ -158,6 +211,11 @@ MxcImageProvider::download(const QString &id,
|
|||||||
QImage image =
|
QImage image =
|
||||||
utils::readImageFromFile(fileInfo.absoluteFilePath());
|
utils::readImageFromFile(fileInfo.absoluteFilePath());
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
|
if (radius != 0) {
|
||||||
|
image =
|
||||||
|
clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
|
|
||||||
then(id,
|
then(id,
|
||||||
requestedSize,
|
requestedSize,
|
||||||
image,
|
image,
|
||||||
@ -169,7 +227,7 @@ MxcImageProvider::download(const QString &id,
|
|||||||
|
|
||||||
http::client()->download(
|
http::client()->download(
|
||||||
"mxc://" + id.toStdString(),
|
"mxc://" + id.toStdString(),
|
||||||
[fileInfo, requestedSize, then, id, encryptionInfo](
|
[fileInfo, requestedSize, then, id, radius, encryptionInfo](
|
||||||
const std::string &res,
|
const std::string &res,
|
||||||
const std::string &,
|
const std::string &,
|
||||||
const std::string &originalFilename,
|
const std::string &originalFilename,
|
||||||
@ -195,6 +253,10 @@ MxcImageProvider::download(const QString &id,
|
|||||||
auto data =
|
auto data =
|
||||||
QByteArray(tempData.data(), (int)tempData.size());
|
QByteArray(tempData.data(), (int)tempData.size());
|
||||||
QImage image = utils::readImage(data);
|
QImage image = utils::readImage(data);
|
||||||
|
if (radius != 0) {
|
||||||
|
image = clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
|
|
||||||
image.setText("original filename",
|
image.setText("original filename",
|
||||||
QString::fromStdString(originalFilename));
|
QString::fromStdString(originalFilename));
|
||||||
image.setText("mxc url", "mxc://" + id);
|
image.setText("mxc url", "mxc://" + id);
|
||||||
@ -205,6 +267,10 @@ MxcImageProvider::download(const QString &id,
|
|||||||
|
|
||||||
QImage image =
|
QImage image =
|
||||||
utils::readImageFromFile(fileInfo.absoluteFilePath());
|
utils::readImageFromFile(fileInfo.absoluteFilePath());
|
||||||
|
if (radius != 0) {
|
||||||
|
image = clipRadius(std::move(image), radius);
|
||||||
|
}
|
||||||
|
|
||||||
image.setText("original filename",
|
image.setText("original filename",
|
||||||
QString::fromStdString(originalFilename));
|
QString::fromStdString(originalFilename));
|
||||||
image.setText("mxc url", "mxc://" + id);
|
image.setText("mxc url", "mxc://" + id);
|
||||||
|
@ -19,10 +19,11 @@ class MxcImageResponse
|
|||||||
, public QRunnable
|
, public QRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MxcImageResponse(const QString &id, bool crop, const QSize &requestedSize)
|
MxcImageResponse(const QString &id, bool crop, double radius, const QSize &requestedSize)
|
||||||
: m_id(id)
|
: m_id(id)
|
||||||
, m_requestedSize(requestedSize)
|
, m_requestedSize(requestedSize)
|
||||||
, m_crop(crop)
|
, m_crop(crop)
|
||||||
|
, m_radius(radius)
|
||||||
{
|
{
|
||||||
setAutoDelete(false);
|
setAutoDelete(false);
|
||||||
}
|
}
|
||||||
@ -39,6 +40,7 @@ public:
|
|||||||
QSize m_requestedSize;
|
QSize m_requestedSize;
|
||||||
QImage m_image;
|
QImage m_image;
|
||||||
bool m_crop;
|
bool m_crop;
|
||||||
|
double m_radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MxcImageProvider
|
class MxcImageProvider
|
||||||
@ -54,7 +56,8 @@ public slots:
|
|||||||
static void download(const QString &id,
|
static void download(const QString &id,
|
||||||
const QSize &requestedSize,
|
const QSize &requestedSize,
|
||||||
std::function<void(QString, QSize, QImage, QString)> then,
|
std::function<void(QString, QSize, QImage, QString)> then,
|
||||||
bool crop = true);
|
bool crop = true,
|
||||||
|
double radius = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThreadPool pool;
|
QThreadPool pool;
|
||||||
|
Loading…
Reference in New Issue
Block a user