1
Fork 0
qtblurhash/imageprovider/blurhashimageprovider.cpp
2024-07-20 11:21:20 -04:00

97 lines
3 KiB
C++

// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: MIT
#include "blurhashimageprovider.h"
#include "blurhash.h"
/*
* Qt unfortunately re-encodes the base83 string in QML.
* The only special ASCII characters used in the blurhash base83 string are:
* #$%*+,-.:;=?@[]^_{|}~
* QUrl::fromPercentEncoding is too greedy, and spits out invalid characters
* for parts of valid base83 like %14.
*/
// clang-format off
static const QMap<QLatin1String, QLatin1String> knownEncodings = {
{QLatin1String("%23A"), QLatin1String(":")},
{QLatin1String("%3F"), QLatin1String("?")},
{QLatin1String("%23"), QLatin1String("#")},
{QLatin1String("%5B"), QLatin1String("[")},
{QLatin1String("%5D"), QLatin1String("]")},
{QLatin1String("%40"), QLatin1String("@")},
{QLatin1String("%24"), QLatin1String("$")},
{QLatin1String("%2A"), QLatin1String("*")},
{QLatin1String("%2B"), QLatin1String("+")},
{QLatin1String("%2C"), QLatin1String(",")},
{QLatin1String("%2D"), QLatin1String("-")},
{QLatin1String("%2E"), QLatin1String(".")},
{QLatin1String("%3D"), QLatin1String("=")},
{QLatin1String("%25"), QLatin1String("%")},
{QLatin1String("%5E"), QLatin1String("^")},
{QLatin1String("%7C"), QLatin1String("|")},
{QLatin1String("%7B"), QLatin1String("{")},
{QLatin1String("%7D"), QLatin1String("}")},
{QLatin1String("%7E"), QLatin1String("~")},
};
// clang-format on
class AsyncImageResponseRunnable : public QObject, public QRunnable
{
Q_OBJECT
Q_SIGNALS:
void done(QImage image);
public:
AsyncImageResponseRunnable(const QString &id, const QSize &requestedSize)
: m_id(id)
, m_requestedSize(requestedSize)
{
if (m_requestedSize.width() == -1)
m_requestedSize.setWidth(64);
if (m_requestedSize.height() == -1)
m_requestedSize.setHeight(64);
}
void run() override
{
if (m_id.isEmpty())
return;
QString decodedId = m_id;
for (auto i = knownEncodings.constBegin(); i != knownEncodings.constEnd(); ++i)
decodedId.replace(i.key(), i.value());
Q_EMIT done(BlurHash::decode(decodedId, m_requestedSize));
}
private:
QString m_id;
QSize m_requestedSize;
};
AsyncImageResponse::AsyncImageResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool)
{
const auto runnable = new AsyncImageResponseRunnable(id, requestedSize);
connect(runnable, &AsyncImageResponseRunnable::done, this, &AsyncImageResponse::handleDone);
pool->start(runnable);
}
void AsyncImageResponse::handleDone(QImage image)
{
m_image = std::move(image);
Q_EMIT finished();
}
QQuickTextureFactory *AsyncImageResponse::textureFactory() const
{
return QQuickTextureFactory::textureFactoryForImage(m_image);
}
QQuickImageResponse *BlurHashImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
{
return new AsyncImageResponse(id, requestedSize, &pool);
}
#include "blurhashimageprovider.moc"