Skip to content

Commit

Permalink
Refactoring (#23)
Browse files Browse the repository at this point in the history
* Refactoring

* Fix best size for thumbnails
  • Loading branch information
zhulik authored Jul 13, 2023
1 parent cba28eb commit e99aff3
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 35 deletions.
100 changes: 65 additions & 35 deletions src/cachethumbnailimageprovider.cpp
Original file line number Diff line number Diff line change
@@ -1,54 +1,50 @@
#include "cachethumbnailimageprovider.h"

#include <algorithm>

#include <QFutureWatcher>
#include <QQuickImageResponse>
#include <QtConcurrent/QtConcurrent>

#include "abstractcache.h"
#include "qfilesystemwatcher.h"

static const auto ThumbnailSizebase = 125;

class AsyncImageResponse : public QQuickImageResponse {
public:
AsyncImageResponse(const QString &id, const QSize &requestedSize, AbstractCache *cache) {
auto watcher = new QFutureWatcher<QImage>();
AsyncImageResponse(const QString &id, const QSize &requestedSize, AbstractCache *cache)
: m_id(id), m_requestedSize(requestedSize) {
auto watcher = new QFutureWatcher<void>(this);

auto f = QtConcurrent::run([id, requestedSize, this, cache]() {
QImage result;
connect(watcher, &QFutureWatcher<void>::finished, this, &AsyncImageResponse::finished);
connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFileSystemWatcher::deleteLater);

if (requestedSize.isEmpty()) {
return result;
auto f = QtConcurrent::run([id, requestedSize, this, cache]() {
if (requestedSize.isEmpty() || cache == nullptr) {
m_image = fetchImage().first;
return;
}

if (cache != nullptr) {
auto data = cache->withCache(imageCacheId(id, requestedSize), [id, requestedSize]() {
QByteArray ba;
QImage image(id); // TODO: add support for network sources
if (image.isNull()) {
return ba;
}
if (!image.isNull()) {
image = image.scaled(requestedSize, Qt::KeepAspectRatio);
}
auto data = cache->withCache(imageCacheId(), [this]() {
auto pair = fetchImage();
m_image = pair.first;
auto skipCache = pair.second;

QByteArray ba;

if (!m_image.isNull() && !skipCache) {
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
Q_ASSERT(image.save(&buffer, "png"));
qDebug() << ba.size();
return ba;
});

result.loadFromData(data);
} else {
QImage image(id); // TODO: add support for network sources
if (!image.isNull()) {
result = image.scaled(requestedSize, Qt::KeepAspectRatio);
Q_ASSERT(m_image.save(&buffer, "png"));
}
}
return result;
});

connect(watcher, &QFutureWatcher<QImage>::finished, watcher, [this, f, watcher]() {
m_image = f.result();
emit finished();
watcher->deleteLater();
return ba;
});

if (!data.isEmpty() && !data.isNull()) {
Q_ASSERT(m_image.loadFromData(data));
}
});

watcher->setFuture(f);
Expand All @@ -59,10 +55,44 @@ class AsyncImageResponse : public QQuickImageResponse {
}

private:
QString m_id;
QSize m_requestedSize;
QImage m_image;

QString imageCacheId(const QString &id, const QSize &size) const {
return QString("%1//%2x%3").arg(id).arg(size.width()).arg(size.height());
QString imageCacheId() const {
auto size = findBestSize();
return QString("%1//%2x%3").arg(m_id).arg(size.width()).arg(size.height());
}

QPair<QImage, bool> fetchImage() const {
QImage image(m_id); // TODO: add support for network sources
auto skipCache = false;

auto size = findBestSize();

if (image.width() < size.width() || image.height() < size.height()) {
size = image.size();
}

if (!image.isNull() && !size.isNull()) {
image = image.scaled(size, Qt::KeepAspectRatio);
}
return QPair{image, skipCache};
}

QSize findBestSize() const {
if (m_requestedSize.isNull()) {
return m_requestedSize;
}
auto bestSize = ThumbnailSizebase;

auto requestedSize = std::max(m_requestedSize.width(), m_requestedSize.height());

while (bestSize < requestedSize) {
bestSize *= 2;
}

return QSize(bestSize, bestSize);
}
};

Expand Down
3 changes: 3 additions & 0 deletions src/diskcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ QByteArray DiskCache::get(const QString &key) const {
}

void DiskCache::set(const QString &key, const QByteArray &data) {
if (data.isEmpty()) {
return;
}
auto info = keyToPath(key);
Q_ASSERT(m_root.mkpath(info.path()));

Expand Down

0 comments on commit e99aff3

Please sign in to comment.