Round images in the image provider

This commit is contained in:
Nicolas Werner 2021-08-14 17:17:50 +02:00
parent 24366b7520
commit 42d2b10d5d
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
6 changed files with 87 additions and 35 deletions

View file

@ -3,7 +3,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
import "./ui"
import QtGraphicalEffects 1.0
import QtQuick 2.6
import QtQuick.Controls 2.3
import im.nheko 1.0
@ -50,8 +49,7 @@ Rectangle {
smooth: true
sourceSize.width: avatar.width
sourceSize.height: avatar.height
layer.enabled: true
source: avatar.url + ((avatar.crop || !avatar.url) ? "" : "?scale")
source: avatar.url ? (avatar.url + "?radius=" + radius + ((avatar.crop) ? "" : "&scale")) : ""
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 {

View file

@ -6,7 +6,6 @@ import "./delegates"
import "./emoji"
import "./ui"
import Qt.labs.platform 1.1 as Platform
import QtGraphicalEffects 1.0
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2

View file

@ -8,7 +8,6 @@ import "./dialogs"
import "./emoji"
import "./voip"
import Qt.labs.platform 1.1 as Platform
import QtGraphicalEffects 1.0
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.3

View file

@ -9,7 +9,6 @@ import "./emoji"
import "./ui"
import "./voip"
import Qt.labs.platform 1.1 as Platform
import QtGraphicalEffects 1.0
import QtQuick 2.9
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3

View file

@ -11,6 +11,8 @@
#include <QByteArray>
#include <QDir>
#include <QFileInfo>
#include <QPainter>
#include <QPainterPath>
#include <QStandardPaths>
#include "Logging.h"
@ -22,14 +24,26 @@ QHash<QString, mtx::crypto::EncryptedFile> infos;
QQuickImageResponse *
MxcImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
{
auto id_ = id;
bool crop = true;
if (id.endsWith("?scale")) {
crop = false;
id_.remove("?scale");
auto id_ = id;
bool crop = true;
double radius = 0;
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);
return response;
}
@ -53,14 +67,35 @@ MxcImageResponse::run()
}
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
MxcImageProvider::download(const QString &id,
const QSize &requestedSize,
std::function<void(QString, QSize, QImage, QString)> then,
bool crop)
bool crop,
double radius)
{
std::optional<mtx::crypto::EncryptedFile> encryptionInfo;
auto temp = infos.find("mxc://" + id);
@ -69,12 +104,13 @@ MxcImageProvider::download(const QString &id,
if (requestedSize.isValid() && !encryptionInfo) {
QString fileName =
QString("%1_%2x%3_%4")
QString("%1_%2x%3_%4_radius%5")
.arg(QString::fromUtf8(id.toUtf8().toBase64(QByteArray::Base64UrlEncoding |
QByteArray::OmitTrailingEquals)))
.arg(requestedSize.width())
.arg(requestedSize.height())
.arg(crop ? "crop" : "scale");
.arg(crop ? "crop" : "scale")
.arg(radius);
QFileInfo fileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
"/media_cache",
fileName);
@ -86,6 +122,10 @@ MxcImageProvider::download(const QString &id,
image = image.scaled(
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (radius != 0) {
image = clipRadius(std::move(image), radius);
}
if (!image.isNull()) {
then(id, requestedSize, image, fileInfo.absoluteFilePath());
return;
@ -100,8 +140,8 @@ MxcImageProvider::download(const QString &id,
opts.method = crop ? "crop" : "scale";
http::client()->get_thumbnail(
opts,
[fileInfo, requestedSize, then, id](const std::string &res,
mtx::http::RequestErr err) {
[fileInfo, requestedSize, radius, then, id](const std::string &res,
mtx::http::RequestErr err) {
if (err || res.empty()) {
then(id, QSize(), {}, "");
@ -113,6 +153,10 @@ MxcImageProvider::download(const QString &id,
if (!image.isNull()) {
image = image.scaled(
requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (radius != 0) {
image = clipRadius(std::move(image), radius);
}
}
image.setText("mxc url", "mxc://" + id);
if (image.save(fileInfo.absoluteFilePath(), "png"))
@ -126,8 +170,12 @@ MxcImageProvider::download(const QString &id,
});
} else {
try {
QString fileName = QString::fromUtf8(id.toUtf8().toBase64(
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
QString fileName =
QString("%1_radius%2")
.arg(QString::fromUtf8(id.toUtf8().toBase64(
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)))
.arg(radius);
QFileInfo fileInfo(
QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
"/media_cache",
@ -148,6 +196,11 @@ MxcImageProvider::download(const QString &id,
QImage image = utils::readImage(data);
image.setText("mxc url", "mxc://" + id);
if (!image.isNull()) {
if (radius != 0) {
image =
clipRadius(std::move(image), radius);
}
then(id,
requestedSize,
image,
@ -158,6 +211,11 @@ MxcImageProvider::download(const QString &id,
QImage image =
utils::readImageFromFile(fileInfo.absoluteFilePath());
if (!image.isNull()) {
if (radius != 0) {
image =
clipRadius(std::move(image), radius);
}
then(id,
requestedSize,
image,
@ -169,7 +227,7 @@ MxcImageProvider::download(const QString &id,
http::client()->download(
"mxc://" + id.toStdString(),
[fileInfo, requestedSize, then, id, encryptionInfo](
[fileInfo, requestedSize, then, id, radius, encryptionInfo](
const std::string &res,
const std::string &,
const std::string &originalFilename,
@ -195,6 +253,10 @@ MxcImageProvider::download(const QString &id,
auto data =
QByteArray(tempData.data(), (int)tempData.size());
QImage image = utils::readImage(data);
if (radius != 0) {
image = clipRadius(std::move(image), radius);
}
image.setText("original filename",
QString::fromStdString(originalFilename));
image.setText("mxc url", "mxc://" + id);
@ -205,6 +267,10 @@ MxcImageProvider::download(const QString &id,
QImage image =
utils::readImageFromFile(fileInfo.absoluteFilePath());
if (radius != 0) {
image = clipRadius(std::move(image), radius);
}
image.setText("original filename",
QString::fromStdString(originalFilename));
image.setText("mxc url", "mxc://" + id);

View file

@ -19,10 +19,11 @@ class MxcImageResponse
, public QRunnable
{
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_requestedSize(requestedSize)
, m_crop(crop)
, m_radius(radius)
{
setAutoDelete(false);
}
@ -39,6 +40,7 @@ public:
QSize m_requestedSize;
QImage m_image;
bool m_crop;
double m_radius;
};
class MxcImageProvider
@ -54,7 +56,8 @@ public slots:
static void download(const QString &id,
const QSize &requestedSize,
std::function<void(QString, QSize, QImage, QString)> then,
bool crop = true);
bool crop = true,
double radius = 0);
private:
QThreadPool pool;