From a3b9fe1ddd2d3b0a0cbb07ffc42317b30a1a3899 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Thu, 28 Dec 2017 11:26:59 +0900 Subject: Switch from QPixmap to QImage; add convenience avatar() overloads to Room and User The switch is necessary because MediaThumbnailJob is supposed to return something that can be worked on in non-GUI threads (as is the case of QML image providers), and QPixmap is not supposed for usage out of the main thread. --- avatar.cpp | 43 +++++++++++++++++++++++++------------------ avatar.h | 3 ++- jobs/mediathumbnailjob.cpp | 11 ++++++----- jobs/mediathumbnailjob.h | 6 +++--- room.cpp | 7 ++++++- room.h | 13 +++++++++++-- user.cpp | 7 ++++++- user.h | 3 ++- 8 files changed, 61 insertions(+), 32 deletions(-) diff --git a/avatar.cpp b/avatar.cpp index b2f50a67..9490347d 100644 --- a/avatar.cpp +++ b/avatar.cpp @@ -22,20 +22,22 @@ #include "events/eventcontent.h" #include "connection.h" +#include + using namespace QMatrixClient; class Avatar::Private { public: Private(Connection* c, QIcon di) : _connection(c), _defaultIcon(di) { } - QPixmap get(int width, int height, Avatar::notifier_t notifier); + QImage get(QSize size, Avatar::notifier_t notifier); Connection* _connection; const QIcon _defaultIcon; QUrl _url; - QPixmap _originalPixmap; + QImage _originalImage; - std::vector> _scaledPixmaps; + std::vector> _scaledImages; QSize _requestedSize; bool _valid = false; @@ -49,22 +51,25 @@ Avatar::Avatar(Connection* connection, QIcon defaultIcon) Avatar::~Avatar() = default; -QPixmap Avatar::get(int width, int height, Avatar::notifier_t notifier) +QImage Avatar::get(int dimension, Avatar::notifier_t notifier) { - return d->get(width, height, notifier); + return d->get({dimension, dimension}, notifier); } -QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier) +QImage Avatar::get(int width, int height, Avatar::notifier_t notifier) { - QSize size(width, height); + return d->get({width, height}, notifier); +} +QImage Avatar::Private::get(QSize size, Avatar::notifier_t notifier) +{ // FIXME: Alternating between longer-width and longer-height requests // is a sure way to trick the below code into constantly getting another // image from the server because the existing one is alleged unsatisfactory. // This is plain abuse by the client, though; so not critical for now. if( ( !(_valid || _ongoingRequest) - || width > _requestedSize.width() - || height > _requestedSize.height() ) && _url.isValid() ) + || size.width() > _requestedSize.width() + || size.height() > _requestedSize.height() ) && _url.isValid() ) { qCDebug(MAIN) << "Getting avatar from" << _url.toString(); _requestedSize = size; @@ -77,8 +82,9 @@ QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier) if (_ongoingRequest->status().good()) { _valid = true; - _originalPixmap = _ongoingRequest->scaledThumbnail(_requestedSize); - _scaledPixmaps.clear(); + _originalImage = + _ongoingRequest->scaledThumbnail(_requestedSize); + _scaledImages.clear(); for (auto n: notifiers) n(); } @@ -86,21 +92,22 @@ QPixmap Avatar::Private::get(int width, int height, Avatar::notifier_t notifier) }); } - if( _originalPixmap.isNull() ) + if( _originalImage.isNull() ) { if (_defaultIcon.isNull()) - return _originalPixmap; + return _originalImage; - _originalPixmap = _defaultIcon.pixmap(size); + QPainter p { &_originalImage }; + _defaultIcon.paint(&p, { QPoint(), _defaultIcon.actualSize(size) }); } - for (auto p: _scaledPixmaps) + for (auto p: _scaledImages) if (p.first == size) return p.second; - auto pixmap = _originalPixmap.scaled(size, + auto result = _originalImage.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - _scaledPixmaps.emplace_back(size, pixmap); - return pixmap; + _scaledImages.emplace_back(size, result); + return result; } QUrl Avatar::url() const { return d->_url; } diff --git a/avatar.h b/avatar.h index e71fecd7..d8b4b206 100644 --- a/avatar.h +++ b/avatar.h @@ -36,7 +36,8 @@ namespace QMatrixClient using notifier_t = std::function; - QPixmap get(int w, int h, notifier_t notifier); + QImage get(int dimension, notifier_t notifier); + QImage get(int w, int h, notifier_t notifier); QUrl url() const; bool updateUrl(const QUrl& newUrl); diff --git a/jobs/mediathumbnailjob.cpp b/jobs/mediathumbnailjob.cpp index 5945493a..c0d67a63 100644 --- a/jobs/mediathumbnailjob.cpp +++ b/jobs/mediathumbnailjob.cpp @@ -36,19 +36,20 @@ MediaThumbnailJob::MediaThumbnailJob(QUrl url, QSize requestedSize, })) { } -QPixmap MediaThumbnailJob::thumbnail() const +QImage MediaThumbnailJob::thumbnail() const { - return pixmap; + return _thumbnail; } -QPixmap MediaThumbnailJob::scaledThumbnail(QSize toSize) const +QImage MediaThumbnailJob::scaledThumbnail(QSize toSize) const { - return pixmap.scaled(toSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + return _thumbnail.scaled(toSize, + Qt::KeepAspectRatio, Qt::SmoothTransformation); } BaseJob::Status MediaThumbnailJob::parseReply(QByteArray data) { - if( !pixmap.loadFromData(data) ) + if( !_thumbnail.loadFromData(data) ) { qCDebug(JOBS) << "MediaThumbnailJob: could not read image data"; } diff --git a/jobs/mediathumbnailjob.h b/jobs/mediathumbnailjob.h index 292e7f14..f8f36fe9 100644 --- a/jobs/mediathumbnailjob.h +++ b/jobs/mediathumbnailjob.h @@ -32,13 +32,13 @@ namespace QMatrixClient MediaThumbnailJob(QUrl url, QSize requestedSize, ThumbnailType thumbnailType = ThumbnailType::Scale); - QPixmap thumbnail() const; - QPixmap scaledThumbnail(QSize toSize) const; + QImage thumbnail() const; + QImage scaledThumbnail(QSize toSize) const; protected: Status parseReply(QByteArray data) override; private: - QPixmap pixmap; + QImage _thumbnail; }; } // namespace QMatrixClient diff --git a/room.cpp b/room.cpp index 0024683d..1e159fd5 100644 --- a/room.cpp +++ b/room.cpp @@ -214,7 +214,12 @@ QString Room::topic() const return d->topic; } -QPixmap Room::avatar(int width, int height) +QImage Room::avatar(int dimension) +{ + return avatar(dimension, dimension); +} + +QImage Room::avatar(int width, int height) { if (!d->avatar.url().isEmpty()) return d->avatar.get(width, height, [=] { emit avatarChanged(); }); diff --git a/room.h b/room.h index 9a458c4e..f863d41b 100644 --- a/room.h +++ b/room.h @@ -108,11 +108,20 @@ namespace QMatrixClient Q_INVOKABLE int timelineSize() const; /** - * Returns a room avatar and requests it from the network if needed + * Returns a square room avatar with the given size and requests it + * from the network if needed * @return a pixmap with the avatar or a placeholder if there's none * available yet */ - Q_INVOKABLE QPixmap avatar(int width, int height); + Q_INVOKABLE QImage avatar(int dimension); + /** + * Returns a room avatar with the given dimensions and requests it + * from the network if needed + * @return a pixmap with the avatar or a placeholder if there's none + * available yet + */ + Q_INVOKABLE QImage avatar(int width, int height); + /** * @brief Produces a disambiguated name for a given user in * the context of the room diff --git a/user.cpp b/user.cpp index faad6231..6d2a2030 100644 --- a/user.cpp +++ b/user.cpp @@ -95,7 +95,12 @@ Avatar& User::avatarObject() return d->avatar; } -QPixmap User::avatar(int width, int height) +QImage User::avatar(int dimension) +{ + return avatar(dimension, dimension); +} + +QImage User::avatar(int width, int height) { return d->avatar.get(width, height, [=] { emit avatarChanged(this); }); } diff --git a/user.h b/user.h index 148ed64d..b7d67fb2 100644 --- a/user.h +++ b/user.h @@ -54,7 +54,8 @@ namespace QMatrixClient Q_INVOKABLE QString bridged() const; Avatar& avatarObject(); - QPixmap avatar(int requestedWidth, int requestedHeight); + QImage avatar(int dimension); + QImage avatar(int requestedWidth, int requestedHeight); QUrl avatarUrl() const; -- cgit v1.2.3