How to create and use an image provider, more exactly a QQuickAsyncImageProvider.
Full example can be found at https://github.com/g-fb/qml-custom-image-provider.
Create the provider class
customimageprovider.h
#ifndef CUSTOMIMAGEPROVIDER_H
#define CUSTOMIMAGEPROVIDER_H
#include <QQuickAsyncImageProvider>
#include <QRunnable>
class CustomImageProvider : public QQuickAsyncImageProvider
{
public:
explicit CustomImageProvider();
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
};
class CustomImageResponse : public QQuickImageResponse
{
public:
CustomImageResponse(const QString &id, const QSize &requestedSize);
QQuickTextureFactory *textureFactory() const override;
private:
QImage m_image;
};
class AsyncImageResponseRunnable : public QObject, public QRunnable
{
Q_OBJECT
public:
AsyncImageResponseRunnable(const QString &id, const QSize &requestedSize);
void run() override;
Q_SIGNALS:
void done(QImage image);
private:
QString m_id;
QSize m_requestedSize;
};
#endif // CUSTOMIMAGEPROVIDER_H
customimageprovider.cpp
#include "customimageprovider.h"
#include <QTransform>
#include <QThreadPool>
CustomImageProvider::CustomImageProvider()
: QQuickAsyncImageProvider()
{
}
QQuickImageResponse *CustomImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
{
auto response = new CustomImageResponse(id, requestedSize);
return response;
}
CustomImageResponse::CustomImageResponse(const QString &id, const QSize &requestedSize)
{
auto runnable = new AsyncImageResponseRunnable(id, requestedSize);
connect(runnable, &AsyncImageResponseRunnable::done, this, [this](QImage image) {
m_image = image;
Q_EMIT finished();
});
QThreadPool::globalInstance()->start(runnable);
}
QQuickTextureFactory *CustomImageResponse::textureFactory() const
{
return QQuickTextureFactory::textureFactoryForImage(m_image);
}
AsyncImageResponseRunnable::AsyncImageResponseRunnable(const QString &id, const QSize &requestedSize)
: m_id{id}
, m_requestedSize{requestedSize}
{
}
void AsyncImageResponseRunnable::run()
{
QImage image{m_id};
QImage scaled = image.scaled(m_requestedSize);
QImage rotatedImage = scaled.transformed(QTransform().rotate(180.0));
Q_EMIT done(rotatedImage);
}
When creating image providers we need to implement the requestImageResponse function. requestImageResponse takes to arguments an id and a requestedSize, these come from the QML side.
In the case of an async provider requestImageResponse creates and returns an QQuickImageResponse, in this example CustomImageResponse.
Inside the constructor of CustomImageResponse:
- create an instance of
AsyncImageResponseRunnable - connect
AsyncImageResponseRunnable::donesignal to a lambda; the lambda sets CustomImageResponse’sm_imageto the image received through the signal and emitsfinishedto let the provider know the response has finishedm_imageis used inCustomImageResponse::textureFactory
- start the runnable through a
QThreadPool, which executes theAsyncImageResponseRunnable::runfunction where the image is created and manipulated using theidandrequestedSize, when the final image is readydoneis emited with the image as argument
Add the files to cmake
qt_add_qml_module(appexample_image_provider
URI example_image_provider
VERSION 1.0
QML_FILES
Main.qml
SOURCES customimageprovider.h customimageprovider.cpp # <--
)
Add the provider to the QQmlApplicationEngine
main.cpp
#include "customimageprovider.h"
...
QQmlApplicationEngine engine;
engine.addImageProvider(QStringLiteral("provider_name"), new CustomImageProvider());
...
Use the provider
Main.qml
Window {
...
Image {
anchors.centerIn: parent
source: "image://provider_name//path/to/image.jpg"
width: 300
height: 500
sourceSize.width: 200
sourceSize.height: 300
}
}
The source is composed of multiple parts
image://- the url scheme, tells theImageto use an image providerprovider_name- the name set when adding the provider to theQQmlApplicationEngine/- separator between provider name and the id/path/to/image.jpeg- the id passed to the image provider
The sourceSize is the size passed to the image provider (requestedSize).
In this example the id passed to the image provider is a local path, but it can be anything,
for example it could be the id of a database record where images are stored as blobs.