gerum
gerum

Reputation: 1134

QML and QQuickImageProvider size

I have a writen a QML application with shows QImages from an image provider. I wrote a class which inherits from QQuickImageProvider. In QML I have two Image objects.

ColumnLayout {
    RowLayout {
        Image {
            source: "image://backend/1"
            width: parent.width/2
        }
        Image {
            source: "image://backend/1"
            width: parent.width/2
        }

And this is the code of the provider:

QImage qmlProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    QSize req(requestedSize.width()<0?100:requestedSize.width(),
              requestedSize.height()<0?100:requestedSize.height());
    try {
        QImage ret=assign.at(id)->scaled(req,Qt::KeepAspectRatio);
        *size=ret.size();
        return ret;
    }
    catch( out_of_range ) {
        QImage ret(req,QImage::Format_RGB16);
        *size=ret.size();
    ret.fill(QColor(qrand()/(RAND_MAX/255),qrand()/(RAND_MAX/255),qrand()/(RAND_MAX/255)).rgba());

        return ret;
    }
}

It works so far which means that the picture ist shown. Now I want that these pictures are scaled. I want each picture to fill one half of my application window, but it doesn't work. Each width I set is ignored and image provider get every time an invalid requested size.

What do I have to do to achive this?

Upvotes: 0

Views: 923

Answers (2)

Tomilov Anatoliy
Tomilov Anatoliy

Reputation: 16691

Example of correct implementation of (caching) image provider:

// videoplayerimageprovider.hpp:

#pragma once

#include <QtQuick>

Q_DECLARE_LOGGING_CATEGORY(videoPlayerImageProviderCategory)

class VideoPlayerImageProvider
        : public QQuickImageProvider
{

    Q_DECLARE_TR_FUNCTIONS(VideoPlayerImageProvider)

public :

    VideoPlayerImageProvider(QQmlEngine * const engine);

    QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize) Q_DECL_OVERRIDE;

private :

    QQmlEngine * const engine;
    QHash< QString, QImage > images;

};

// videoplayerimageprovider.cpp:

#include "videoplayerimageprovider.hpp"

Q_LOGGING_CATEGORY(videoPlayerImageProviderCategory, "videoPlayerImageProvider")

VideoPlayerImageProvider::VideoPlayerImageProvider(QQmlEngine * const engine)
    : QQuickImageProvider{QQuickImageProvider::Image}
    , engine{engine}
{ ; }

QImage VideoPlayerImageProvider::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
{
    const auto selector = QQmlFileSelector::get(engine)->selector();
    const auto imagePath = selector->select(QStringLiteral(":/images/videoplayer/%1").arg(id));
#if 0
    qDebug().noquote()
            << tr("Selected filepath: %1. Installed file selectors: %2")
               .arg(imagePath, selector->allSelectors().join(QStringLiteral(", ")));
#endif
    QImage image;
    if (!images.contains(imagePath)) {
        QImageReader imageReader{imagePath};
        image = imageReader.read();
        if (image.isNull()) {
            qCCritical(videoPlayerImageProviderCategory).noquote()
                    << tr("Unable to read image from %1: %3 (%2)")
                       .arg(imagePath, imageReader.errorString()).arg(imageReader.error());
        } else {
            images.insert(imagePath, image);
        }
    } else {
        image = images[imagePath];
    }
    if (size) { // should be assigned size of original image
        *size = image.size();
    }
    if (requestedSize.isEmpty() || (image.size() == requestedSize)) { // avoid returning invalid QImage
        return image;
    }
    return image.scaled(requestedSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}

If you don't need file selector for your image file, then you may remove engine and selector.

I note, that during loading of the scene there are not a single call to the same id. First of them are with invalid sizes.

Upvotes: 1

folibis
folibis

Reputation: 12854

Since your item's size managed by Layout you should set Layout's preferred size instead of item's size:

RowLayout {
    anchors.fill: parent
    Image {
        source: "image://backend/1"
        Layout.preferredHeight: parent.height
        Layout.preferredWidth: parent.width / 2
    }
    Image {
        source: "image://backend/1"
        Layout.preferredHeight: parent.height
        Layout.preferredWidth: parent.width / 2
    }
}

More info could be found here

Upvotes: 3

Related Questions