HorusKol
HorusKol

Reputation: 8706

Load image in QML WebEngineView using QQuickImageProvider

I'm injecting HTML content into a QML WebEngineView using the loadHtml method, and I'm trying to get it to load the images through a QQuickImageProvider.

Up to now, we've been successfully loading images from a Qt resource container (qrc), but this is not flexible enough.

contentimageprovider.cpp

#include "contentimageprovider.h"

#include <QDebug>

ContentImageProvider::ContentImageProvider() : QQuickImageProvider(QQuickAsyncImageProvider::Image)
{

}

QImage ContentImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    qDebug() << __FUNCTION__ << id;
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtWebEngine/QtWebEngine>

#include "contentimageprovider.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    QtWebEngine::initialize();

    engine.addImageProvider(QLatin1String("content-images"), new ContentImageProvider);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml

import QtQuick 2.7
import QtQuick.Window 2.2
import QtWebEngine 1.4

Image {
    source: "image://content-images/this-image-is-requested";
}

WebEngineView {
    Component.onCompleted: {
        loadHtml("<img src='qrc://images/this-image-is-displayed.png' /><img src='image://content-images/this-image-should-also-be-requested' />", "/");
    }
}

Expected output

requestImage "this-image-is-requested"
requestImage "this-image-should-also-be-requested"

Actual output

requestImage "this-image-is-requested"

And the image loaded via qrc in the WebEngineView is displayed, and a broken image is shown for the other one.

Has anyone been able to get this to work?

Upvotes: 1

Views: 1133

Answers (1)

HorusKol
HorusKol

Reputation: 8706

Thanks to @Xplatforms who pointed out the initial error in assuming that the Chromium engine under the QML WebEngineView would interact with the QML Quick engine and trigger the image provider.

The solution was to implement a QWebEngineUrlSchemeHandler:

void ImageRequestHandler::requestStarted(QWebEngineUrlRequestJob *request)
{
    // request->requestUrl() is a QUrl
    QFile *image  = new QFile(QDir::currentPath() + "/storage/content/" + request->requestUrl().path() + ".png");

    // makes sure the image deletes itself when closing the file
    connect(image, &QIODevice::aboutToClose, image, &QObject::deleteLater);
    // close the file when the request job is done
    connect(request, &QObject::destroyed, image, &QIODevice::close);

    QMimeDatabase mimeDB;
    QMimeType mimeType = mimeDB.mimeTypeForFile(image->fileName());

    request->reply(mimeType.name().toUtf8(), image);
}

main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    // web engine to provide content display
    QtWebEngine::initialize();

    // intercept requests from the web engine to provide locally loaded content and images
    ImageRequestHandler *imageRequestHandler = new ImageRequestHandler();
    QQuickWebEngineProfile::defaultProfile()->installUrlSchemeHandler("image", imageRequestHandler);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

Upvotes: 0

Related Questions