Connecting QQuickImageProvider
-
Hello all!
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. 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; }
-
Hi,
Why not just emit a signal from the provider and connect it to whatever class you need ?
-
Can you describe your use case ?
-
Answering my own question
Problem solved. Here is the solution step by step:1 - Create a
class
that inherits fromQQuickImageProvider
andQObject
and inside it create aImage
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 QmlQImage 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
fileprovedorImagem *provedorImg = new provedorImagem; engine.rootContext()->setContextProperty("ProvedorImagem", provedorImg);
2 - Create another
class
that inherits fromQObject
.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: Thep_caminhoImagem
is aproperty
that I created inside theprocessaImagem class
that receives thecamera 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 theprocessaImagem class
to provide it to QML. To do it the providerclass pointer
must be accessible to the QML file, so, in themain.cpp
file just make the pointer available to QML as aproperty
engine.rootContext()->setContextProperty("ProvedorImagem", provedorImg);
and register the
processaImagem class
as a QML typeqmlRegisterType<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();
-
But why not do the processing directly in the image provider ?
-
Why not grab the image in the image provider ?
-
Unless I'm mistaken all what your processaImagem does is get the image from the image provider, apply some modification and set it again on the image provider, right ?
-
Are you using the Camera QML type to grab the image from the camera ?
-
In that case, why not use a ShaderEffect to "cut" your image square ?
-
@SGaist
Because I didnt know that ShaderEffect can "cut" an image. I read the documentation and I could not find how to do it with ShaderEffect.Now I am interested about how to perform the image modifications directly in the provider. How can I pass the image without other class to do it?
Another thing, the modifications performed in the image include rotate the image in case of wrong image orientation.