GuiDupas
GuiDupas

Reputation: 1701

Connecting QQuickImageProvider

I have to connect a QQuickImageProvider with a class to pass an image that the image provider must return, but I am not finding a way to do that.

I have a class called provedorImagem.cpp with a virtual requestImage function implemented and I have also a class called processaImagem.cpp that is the class to perform modification at the image.

The provedorImagem class is passed to engine as a provider: engine.addImageProvider("provedor", provedorImg) in main.cpp

What I need is a way to connect a slot in the provider in main.cpp with a signal in processaImagem.cpp. Doing that the processaImagem.cpp can send the image I must return to Qml to provedorImagem.cpp and send it back to Qml.

Could someone help me?

Code below

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QtQml>

#include "processaimagem.h"
#include "provedorimagem.h"

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

    qmlRegisterType<processaImagem>("ProcessaImagemQml", 1, 0, "ProcessaImagem");

    QQmlApplicationEngine engine;

    provedorImagem *provedorImg = new provedorImagem;

    //------------  I have to create a connection here between the provider slot and a signal in processaImagem with the image to provide  -----------------

    engine.addImageProvider("provedor", provedorImg);

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

    return app.exec();
}

processaImagem.h

#ifndef PROCESSAIMAGEM_H
#define PROCESSAIMAGEM_H

#include <QObject>
#include <QImage>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQuickImageProvider>

#include "provedorimagem.h"

class processaImagem : public QObject
{
    Q_OBJECT

public slots:
    QString recebeImagem(const QString &caminho);

public:
    processaImagem(QObject *parent = 0);

    QImage carregaImagem(const QString &caminho);

signals:
    void enviaImagem(QImage);
};

#endif // PROCESSAIMAGEM_H

processaImagem.cpp

#include "processaimagem.h"

#include <QDebug>

processaImagem::processaImagem(QObject *parent)
{

}

QString processaImagem::recebeImagem(const QString &caminho)
{
    QImage imagem = this->carregaImagem(caminho);

    QString caminhoRetorno;

    if(imagem.isNull())
    {
        qDebug() << "Erro ao receber a imagem";
    }
    else
    {
        qDebug() << "Imagem recebida";
        caminhoRetorno = "image://provedor/imagemEditada";
    }

    return caminhoRetorno;
}

QImage processaImagem::carregaImagem(const QString &caminho)
{
    QUrl caminhoImagem(caminho);
    QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase *imageProviderBase = engine->imageProvider(caminhoImagem.host());
    QQuickImageProvider *imageProvider = static_cast<QQuickImageProvider*>(imageProviderBase);

    QSize imageSize;
    QString imageId = caminhoImagem.path().remove(0, 1);
    QImage imagem = imageProvider->requestImage(imageId, &imageSize, imageSize);

    if(imagem.isNull())
    {
        qDebug() << "Erro ao carregar a imagem";
        imagem = QImage();
    }
    else
    {
        qDebug() << "Imagem carregada";
    }

    return imagem;
}

provedorimagem.h

#ifndef PROVEDORIMAGEM_H
#define PROVEDORIMAGEM_H

#include <QImage>
#include <QQuickImageProvider>

class provedorImagem : public QQuickImageProvider
{
public:
    provedorImagem();

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

    void carregaImagem();

public slots:
    void carregaImagem(QImage imagemRecebida);

private:
    QImage imagem;
};

#endif // PROVEDORIMAGEM_H

provedorimagem.cpp

#include "provedorimagem.h"

#include <QDebug>

provedorImagem::provedorImagem() : QQuickImageProvider(QQuickImageProvider::Image)
{

}

QImage provedorImagem::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    if(imagem.isNull())
    {
        qDebug() << "Erro ao prover a imagem";
    }
    else
    {
        qDebug() << "Imagem provida";
    }

    return imagem;
}

void provedorImagem::carregaImagem(QImage imagemRecebida)
{
    imagem = imagemRecebida;
}

Upvotes: 1

Views: 2208

Answers (3)

GuiDupas
GuiDupas

Reputation: 1701

Answering my own question Problem solved. Here is the solution step by step:

1 - Create a class that inherits from QQuickImageProvider and QObject and inside it create a Image member (QImage) that is the image to be provided.

class provedorImagem : public QObject, public QQuickImageProvider

Implement the virtual requestImage method. This is the method that will return the image to Qml

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

Create a method to load the provider’s image to return

void provedorImagem::carregaImagem(QImage imagemRecebida)
{
    imagem = imagemRecebida;
}

Now set it as the engine image provider in the main.cpp file

provedorImagem *provedorImg = new provedorImagem;
engine.rootContext()->setContextProperty("ProvedorImagem", provedorImg);

2 - Create another class that inherits from QObject.

class processaImagem : public QObject

Inside this class you must implement a method that will get the image from camera provider, perform the image modifications and return the modified image. PS: The p_caminhoImagem is a property that I created inside the processaImagem class that receives the camera preview path.

QImage processaImagem::carregaImagem()
{
    QUrl caminhoImagem(p_caminhoImagem);
    QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase *imageProviderBase = engine->imageProvider(caminhoImagem.host());
    QQuickImageProvider *imageProvider = static_cast<QQuickImageProvider*>(imageProviderBase);


    QSize imageSize;
    QString imageId = caminhoImagem.path().remove(0, 1);
    QImage imagem = imageProvider->requestImage(imageId, &imageSize, imageSize);

    if(imagem.isNull())
    {
        imagem = QImage();
    }
    else
    {
        //Perform the modifications
    }

    return imagem;
}

3 - Now is the main part. The image requestImage provider method must receive the modified image from the processaImagem class to provide it to QML. To do it the provider class pointer must be accessible to the QML file, so, in the main.cpp file just make the pointer available to QML as a property

engine.rootContext()->setContextProperty("ProvedorImagem", provedorImg);

and register the processaImagem class as a QML type

qmlRegisterType<processaImagem>("ProcessaImagemQml", 1, 0, "ProcessaImagem");

Now we link it inside the QML file

ProvedorImagem.carregaImagem(processaImagem.carregaImagem());

4 - It is done. Now just request the image from the provider:

imagemPreview.source = "image://provedor/imagemEditada_" + camera.numeroImagem.toString();

Upvotes: 2

Alexander V
Alexander V

Reputation: 8698

For image provider to work one of the below methods needs to be implemented:

virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);

Derived from the example above.

QImage provedorImagem::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    // the id has value like "imagemEditada" or the last word in URL
    if(imagem.isNull())
    {
        qDebug() << "Erro ao prover a imagem";
    }
    else if (caminhoRetorno.endsWith(id, Qt::CaseInsensitive)) // that will be a check for id after "provedor"
    {
        qDebug() << "Imagem provida";
        return imagem; // provide an image
    }
    return QImage(); // no match with id from url
}

And your QML code should have something like:

    Image {
        // // //
        source: "image://provedor/imagemEditada"
    }

There is a nice complete example in Qt docs.

@GuiDupas, from your corrected question it seems that you would like to recognize the image provided. The method to check the last word in URL with QString::endsWith is for the demo of course.

Upvotes: 0

vishnukumar
vishnukumar

Reputation: 375

I hope you are trying to send a image from qt(c++) code to display in qml. Please look the below camera application source. Passing the camera image to qml using QQuickPaintedItem.

https://github.com/econsysqtcam/qtcam.git

Have a look at videostreaming.cpp/ videostreaming.h and their connection to qml. Hope that helps

Upvotes: 0

Related Questions