Will59
Will59

Reputation: 1863

QQuickImageProvider::requestImage image scaling, how to handle it

I am trying to implement a simple PxImageProvider. The source image is static, and I am providing only one image. It seems to be that requestedSize is always empty. Even when I try to modify the image size on the QML side, the image gets re-scaled, but it doesn't look like my PxImageProvider is doing the rescaling... is this normal?

What I have done is implement my PxImageProvider subclass so that when requestedSize is empty (either width or height null or negative), I provide the flipped original image (so I know I didn't do any rescaling). But even when the QML side is trying to rescale the image, I always see my image flipped (rescaled, but flipped).

My .h header:

#include <QQmlApplicationEngine>
#include <QQuickImageProvider>
#include <QImage>

class MyImageProvider :
    public QQuickImageProvider
{
public:
  MyImageProvider(QQmlApplicationEngine *engine, const QString &qmlId, const QImage *image = Q_NULLPTR);
  QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
  void setImage(const QImage &image);

private:
  QImage _image;
};

and my .cpp:

#include "myimageprovider.h"

MyImageProvider::MyImageProvider(QQmlApplicationEngine *engine, const QString & qmlId, const QImage *image) :
  QQuickImageProvider(QQuickImageProvider::Image)
{
  if (image == Q_NULLPTR) {
    _image = QImage();
  }
  else {
    _image = *image;
  }
  engine->addImageProvider(qmlId, this);
}

QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
  // Ignoring the id field, just one image to output
  *size = _image.size();
  if (requestedSize.isEmpty())
    return (_image.mirrored(true, true));
  else
    return (_image.scaled(requestedSize, Qt::KeepAspectRatio));
}

void MyImageProvider::setImage(const QImage &image)
{
  _image = image;
}

I create an instance, feeding it a 100x100 pixels image. On the QML side:

    Rectangle {
      id: myImageBlock
      color: "grey"
      width: 250
      height: 250
      anchors.centerIn: parent

      Image {
        id: myImage
        source: "image://my_image/unusedId"
        anchors.centerIn: parent
        width: 50
        height: 50
      }
    }

I do get my image, rightly scaled to 50x50 over a 250x250 grey square... but the image is flipped, meaning the image wasn't scaled by my provider. Is this how it is supposed to work?

Upvotes: 2

Views: 413

Answers (1)

eyllanesc
eyllanesc

Reputation: 243887

As noted in the docs:

QImage QQuickImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)

Implement this method to return the image with id. The default implementation returns an empty image.

The id is the requested image source, with the "image:" scheme and provider identifier removed. For example, if the image source was "image://myprovider/icons/home", the given id would be "icons/home".

The requestedSize corresponds to the Image::sourceSize requested by an Image item. If requestedSize is a valid size, the image returned should be of that size.

In all cases, size must be set to the original size of the image. This is used to set the width and height of the relevant Image if these values have not been set explicitly.

Note: this method may be called by multiple threads, so ensure the implementation of this method is reentrant.

(emphasis mine)

You must use the sourceSize of Image.

Image {
    id: myImage
    source: "image://my_image/unusedId"
    anchors.centerIn: parent
    width: 50
    height: 50
    sourceSize.width: 50  // <---
    sourceSize.height: 50 // <---
}

Upvotes: 3

Related Questions