2015-10-29 185 views
3

我正在嘗試將QImage傳遞給QML。有人能幫助我嗎?代碼如下。將QImage傳遞給QML

問題是,我所有試圖使圖像提供者可用的圖像都失敗。我曾嘗試在類中使用Q_PROPERTY和QImage成員,但當我嘗試訪問它以返回時,我的提供程序始終返回空圖像。

如何使QImage可用於提供者?

QML

Camera { 
    id: camera 

    captureMode: Camera.CaptureStillImage 

    imageCapture { 
     onImageCaptured: { 
      manipulaImagem.imagem = preview; 

      previewImage.source = manipulaImagem.recortarFotoPerfil(preview, viewfinder.mapRectToSource(Qt.rect(viewfinder.x, viewfinder.y, viewfinder.width, viewfinder.height))); 
     } 
    } 
} 
Image { 
    id: previewImage 

    fillMode: Image.PreserveAspectFit 
    anchors.top: parent.top 

    width: parent.width 
    height: parent.width 
} 

CPP

QImage manipulaImagem::recortarFotoPerfil(const QString &imagem, QRect rectRecorte) 
{ 
    QUrl caminhoImagem(imagem); 
    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 imagem1 = imageProvider->requestImage(imageId, &imageSize, imageSize); 
    imagem1 = imageProvider->requestImage(imageId, &imageSize, imageSize); 
    return imagem1; 
} 

當我使用這個我收到以下消息: 錯誤:無法分配的QImage來QUrl

我沒有發現任何東西來幫助我解決這個問題。我怎樣才能做到這一點?


我曾嘗試使用圖像提供商被鏈接的建議不同的方法,但它仍然沒有工作

下面是代碼

.H

#ifndef MANIPULAIMAGEM_H 
#define MANIPULAIMAGEM_H 

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

class manipulaImagem : public QObject, public QQuickImageProvider 
{ 
    Q_OBJECT 

public slots: 
    QString recortarFotoPerfil(const QString &imagem, QRect rectRecorte); 

public: 
    manipulaImagem(QObject *parent = 0); 

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

private: 
    void alocaImagem(const QString &imagem, QRect rectRecorte); 

    QImage imagemEditada; 
}; 

#endif // MANIPULAIMAGEM_H 

。 cpp

#include "manipulaimagem.h" 

#include <QDebug> 

manipulaImagem::manipulaImagem(QObject *parent) : QQuickImageProvider(QQmlImageProviderBase::Image) 
{ 

} 

QImage manipulaImagem::requestImage(const QString &id, QSize *size, const QSize &requestedSize) 
{ 
    if(imagemEditada.isNull()) 
    { 
     qDebug() << "Request image: (image is null)"; 
    } 
    else 
    { 
     qDebug() << "Request image: image is OK"; 
    } 

    return imagemEditada; 
} 

void manipulaImagem::alocaImagem(const QString &imagem, QRect rectRecorte) 
{ 
    QUrl caminhoImagem(imagem); 
    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); 
imagemEditada = imageProvider->requestImage(imageId, &imageSize, imageSize); 

    if(imagemEditada.isNull()) 
    { 
     qDebug() << "Loading image failed"; 
    } 
    else 
    { 
     qDebug() << "Loading image OK"; 
    } 
} 

QString manipulaImagem::recortarFotoPerfil(const QString &imagem, QRect rectRecorte) 
{ 
    this->alocaImagem(imagem, rectRecorte); 

    QString a = "image://ProvedorImagens/imagemEditada"; 

    if(imagemEditada.isNull()) 
    { 
     qDebug() << "Imagem is null"; 
    } 
    else 
    { 
     qDebug() << "Imagem is loaded"; 
    } 

    return a; 
} 

.qml

ManipulaImagem { 
    id: manipulaImagem 
} 

Camera { 
      id: camera 

      captureMode: Camera.CaptureStillImage 

      imageCapture { 
       onImageCaptured: { 
        previewImage.source = manipulaImagem.recortarFotoPerfil(preview, viewfinder.mapRectToSource(Qt.rect(viewfinder.x, viewfinder.y, viewfinder.width, viewfinder.height))); 
       } 
      } 
     } 

Rectangle { 
    id: previewRectangle 

    visible: false 

    anchors.fill: parent 

    Image { 
     id: previewImage 

     fillMode: Image.PreserveAspectFit 

     anchors.top: parent.top 

     width: parent.width 
     height: parent.width 
    } 

此代碼的輸出是:

  • 加載圖像行

  • IMAGEM加載

  • 請求圖像:(圖像爲null)

QML Image:無法從提供者獲取圖像:image:// verifiedorimagens/imagemEditada

會發生什麼情況是,當我調用函數時圖像不是null,但是當我嘗試使用提供程序返回QImage時不能返回圖像。我不知道爲什麼,但圖像提供商的圖像爲空。

我怎麼能解決這個問題?

+1

你必須執行,才能在QML使用'QImage'自己的圖像提供商。我有一個例子在這個答案中設置:http://stackoverflow.com/questions/27429371/qml-and-c-image-interoperability/27429586#27429586只是修改它的'QImage'而不是'QPixmap' – dtech

+1

可能的重複[Qt/QML:將QImage從C++發送到QML並在GUI上顯示QImage](http://stackoverflow.com/questions/20691414/qt-qml-send-qimage-from-c-to-qml-and- display-the-qimage-on-gui) – hyde

+0

問題是,我所有試圖使圖像提供程序可用的圖像都失敗。我曾嘗試在類中使用Q_PROPERTY和QImage成員,但當我嘗試訪問它以返回時,我的提供程序始終返回空圖像。 – GuiDupas

回答

6

回答我自己的問題 問題解決了。下面是解步步:

1 - 創建classQQuickImageProviderQObject繼承和裏面創建Image構件(QImage)待提供的圖像。

class provedorImagem : public QObject, public QQuickImageProvider 

執行virtual requestImage方法。這是將圖像旋轉回設爲Qml

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

創建方法加載提供的圖像返回

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

現在在main.cpp文件將其設置爲引擎圖像提供商的方法

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

2 - 創建從QObject繼承的另一個class

class processaImagem : public QObject 

裏面這個類,你必須實現從camera提供商獲取圖像,進行圖像的修改和返回修改後的圖像的方法。 PS:p_caminhoImagem是我在processaImagem class內部創建的property,它收到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 - 現在是主要部分。供應商方法的圖像requestImage必須從processaImagem class接收修改的圖像以將其提供給QML。要做到這一點的供應商class pointer必須對QML文件訪問,因此,在main.cpp文件只是使指針提供給QML爲property

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

並註冊processaImagem class作爲QML類型

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

現在我們將其鏈接的QML內文件

ProvedorImagem.carregaImagem(processaImagem.carregaImagem()); 

4 - 它完成。現在,剛剛從供應商請求圖像:

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

這裏是整個代碼:

的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; 

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

    engine.addImageProvider("provedor", provedorImg); 

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

    return app.exec(); 
} 

main.qml

import QtQuick 2.4 
import QtQuick.Window 2.2 
import QtQuick.Controls 1.3 
import QtMultimedia 5.4 

import ProcessaImagemQml 1.0 

Window { 
    visible: true 

    width: 360 
    height: 640 

    maximumHeight: 640 
    minimumHeight: 640 

    maximumWidth: 360 
    minimumWidth: 360 

    title: "Camera Preview Test" 

    Rectangle { 
     id: principal 

     anchors.fill: parent 

     ProcessaImagem { 
      id: processaImagem 

      caminhoImagem: camera.caminhoPreview 
      caminhoSalvar: camera.caminhoSalvar 
      rectRecorte: camera.rectRecorte 
      tamanhoImagem: camera.tamanhoImagem 
      anguloOrientacaoCamera: camera.orientation 
      posicaoCamera: camera.position 

      onCaminhoImagemChanged: { 
       rectRecorte = cameraView.mapRectToSource(Qt.rect(cameraView.x, cameraView.y, cameraView.width, cameraView.height)); 
       tamanhoImagem = Qt.size(cameraView.sourceRect.width, cameraView.sourceRect.height); 
       ProvedorImagem.carregaImagem(processaImagem.carregaImagem()); 
      } 

      onCaminhoSalvarChanged: { 
       removeImagemSalva(); 
      } 
     } 

     Rectangle { 
      id: cameraRectangle 

      width: parent.width 
      height: parent.width 

      anchors.top: parent.top 

      color: "lightGrey" 

      visible: true 

      Camera { 
       id: camera 

       property string caminhoPreview: "" 
       property string caminhoSalvar: "" 
       property int numeroImagem: 0 

       captureMode: Camera.CaptureStillImage 

       imageCapture { 
        onImageCaptured: { 
         camera.caminhoPreview = preview; 

         camera.stop(); 

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

         camera.numeroImagem = camera.numeroImagem + 1; 

         imagemPreviewRectangle.visible = true; 

         cameraRectangle.visible = false; 
        } 

        onImageSaved: { 
         camera.caminhoSalvar = path; 
        } 
       } 
      } 

      VideoOutput { 
       id: cameraView 

       visible: true 

       focus: visible 

       anchors.fill: parent 

       source: camera 
       orientation: camera.orientation 
       fillMode: VideoOutput.PreserveAspectCrop 
      } 
     } 

     Rectangle { 
      id: imagemPreviewRectangle 

      width: parent.width 
      height: parent.width 

      anchors.top: parent.top 

      color: "lightGrey" 

      visible: false 

      Image { 
       id: imagemPreview 

       fillMode: Image.PreserveAspectFit 

       anchors.fill: parent 
      } 
     } 

     Rectangle { 
      id: controleRectangle 

      width: parent.width 
      height: parent.height - cameraRectangle.height 

      color: "grey" 

      anchors.top: cameraRectangle.bottom 

      Button { 
       id: tirarFotoButton 

       text: "Tirar foto" 

       anchors.left: parent.left 
       anchors.top: parent.top 

       onClicked: { 
        camera.imageCapture.capture(); 
       } 
      } 

      Button { 
       id: novaFotoButton 

       text: "Tirar nova foto" 

       anchors.right: parent.right 
       anchors.top: parent.top 

       onClicked: { 
        camera.start(); 

        imagemPreviewRectangle.visible = false; 

        cameraRectangle.visible = true; 
       } 
      } 
     } 
    } 
} 

processaimagem.h

#ifndef PROCESSAIMAGEM_H 
#define PROCESSAIMAGEM_H 

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

#include "provedorimagem.h" 

class processaImagem : public QObject 
{ 
    Q_OBJECT 

    Q_PROPERTY(QString caminhoImagem READ caminhoImagem WRITE setCaminhoImagem NOTIFY caminhoImagemChanged) 
    Q_PROPERTY(QString caminhoSalvar READ caminhoSalvar WRITE setCaminhoSalvar NOTIFY caminhoSalvarChanged) 
    Q_PROPERTY(QRect rectRecorte READ rectRecorte WRITE setRectRecorte NOTIFY rectRecorteChanged) 
    Q_PROPERTY(QSize tamanhoImagem READ tamanhoImagem WRITE setTamanhoImagem NOTIFY tamanhoImagemChanged) 
    Q_PROPERTY(int anguloOrientacaoCamera READ anguloOrientacaoCamera WRITE setAnguloOrientacaoCamera NOTIFY anguloOrientacaoCameraChanged) 
    Q_PROPERTY(int posicaoCamera READ posicaoCamera WRITE setPosicaoCamera NOTIFY posicaoCameraChanged) 

public slots: 
    QImage carregaImagem(); 
    void removeImagemSalva(); 

public: 
    processaImagem(QObject *parent = 0); 

    QString caminhoImagem() const; 
    void setCaminhoImagem(const QString valor); 

    QString caminhoSalvar() const; 
    void setCaminhoSalvar(const QString valor); 

    QRect rectRecorte() const; 
    void setRectRecorte(const QRect valor); 

    QSize tamanhoImagem() const; 
    void setTamanhoImagem(const QSize valor); 

    int anguloOrientacaoCamera() const; 
    void setAnguloOrientacaoCamera(const int valor); 

    int posicaoCamera() const; 
    void setPosicaoCamera(const int valor); 

private: 
    QString p_caminhoImagem = ""; 
    QString p_caminhoSalvar = ""; 
    QRect p_rectRecorte = QRect(0, 0, 0, 0); 
    QSize p_tamanhoImagem = QSize(0, 0); 
    int p_anguloOrientacaoCamera = 0; 
    int p_posicaoCamera = 0; 

signals: 
    void caminhoImagemChanged(); 
    void caminhoSalvarChanged(); 
    void rectRecorteChanged(); 
    void tamanhoImagemChanged(); 
    void anguloOrientacaoCameraChanged(); 
    void posicaoCameraChanged(); 
}; 

#endif // PROCESSAIMAGEM_H 

processaimagem.cpp

#include "processaimagem.h" 

#include <QDebug> 

processaImagem::processaImagem(QObject *parent) 
{ 

} 

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()) 
    { 
     qDebug() << "Erro ao carregar a imagem"; 
     imagem = QImage(); 
    } 
    else 
    { 
     if((p_anguloOrientacaoCamera == 90) || (p_anguloOrientacaoCamera == 270)) 
     { 
      int larguraImagem = p_tamanhoImagem.width(); 
      int alturaImagem = p_tamanhoImagem.height(); 

      p_tamanhoImagem.setWidth(alturaImagem); 
      p_tamanhoImagem.setHeight(larguraImagem); 

      int recorteX = p_rectRecorte.x(); 
      int recorteY = p_rectRecorte.y(); 
      int recorteLargura = p_rectRecorte.width(); 
      int recorteAltura = p_rectRecorte.height(); 

      p_rectRecorte.setRect(recorteY, recorteX, recorteAltura, recorteLargura); 

      if(imagem.size().width() > imagem.size().height()) 
      { 
       QTransform rotacao; 
       rotacao.rotate(360 - p_anguloOrientacaoCamera); 
       imagem = imagem.transformed(rotacao); 

       qDebug() << "Rodou"; 
      } 
     } 

     if(imagem.width() != p_tamanhoImagem.width()) 
     { 
      imagem = imagem.scaled(p_tamanhoImagem); 
     } 

     imagem = imagem.copy(p_rectRecorte); 
    } 

    return imagem; 
} 

void processaImagem::removeImagemSalva() 
{ 
    QFile::remove(p_caminhoSalvar); 
} 

QString processaImagem::caminhoImagem() const 
{ 
    return p_caminhoImagem; 
} 

void processaImagem::setCaminhoImagem(const QString valor) 
{ 
    if (valor != p_caminhoImagem) 
    { 
     p_caminhoImagem = valor; 
     emit caminhoImagemChanged(); 
    } 
} 

QString processaImagem::caminhoSalvar() const 
{ 
    return p_caminhoSalvar; 
} 

void processaImagem::setCaminhoSalvar(const QString valor) 
{ 
    if (valor != p_caminhoSalvar) 
    { 
     p_caminhoSalvar = valor; 
     emit caminhoSalvarChanged(); 
    } 
} 

QRect processaImagem::rectRecorte() const 
{ 
    return p_rectRecorte; 
} 

void processaImagem::setRectRecorte(const QRect valor) 
{ 
    bool alterou = false; 

    if (valor.x() != p_rectRecorte.x()) 
    { 
     p_rectRecorte.setX(valor.x()); 
     alterou = true; 
    } 

    if (valor.y() != p_rectRecorte.y()) 
    { 
     p_rectRecorte.setY(valor.y()); 
     alterou = true; 
    } 

    if (valor.width() != p_rectRecorte.width()) 
    { 
     p_rectRecorte.setWidth(valor.width()); 
     alterou = true; 
    } 

    if (valor.height() != p_rectRecorte.height()) 
    { 
     p_rectRecorte.setHeight(valor.height()); 
     alterou = true; 
    } 

    if(alterou) 
    { 
     emit rectRecorteChanged(); 
    } 
} 

QSize processaImagem::tamanhoImagem() const 
{ 
    return p_tamanhoImagem; 
} 

void processaImagem::setTamanhoImagem(const QSize valor) 
{ 
    bool alterou = false; 

    if (valor.width() != p_tamanhoImagem.width()) 
    { 
     p_tamanhoImagem.setWidth(valor.width()); 
     alterou = true; 
    } 

    if (valor.height() != p_tamanhoImagem.height()) 
    { 
     p_tamanhoImagem.setHeight(valor.height()); 
     alterou = true; 
    } 

    if(alterou) 
    { 
     emit tamanhoImagemChanged(); 
    } 
} 

int processaImagem::anguloOrientacaoCamera() const 
{ 
    return p_anguloOrientacaoCamera; 
} 

void processaImagem::setAnguloOrientacaoCamera(const int valor) 
{ 
    if (valor != p_anguloOrientacaoCamera) 
    { 
     p_anguloOrientacaoCamera = valor; 
     emit anguloOrientacaoCameraChanged(); 
    } 
} 

int processaImagem::posicaoCamera() const 
{ 
    return p_posicaoCamera; 
} 

void processaImagem::setPosicaoCamera(const int valor) 
{ 
    if (valor != p_posicaoCamera) 
    { 
     p_posicaoCamera = valor; 
     emit posicaoCameraChanged(); 
    } 
} 

provedorimagem.h

#ifndef PROVEDORIMAGEM_H 
#define PROVEDORIMAGEM_H 

#include <QObject> 
#include <QImage> 
#include <QQuickImageProvider> 

class provedorImagem : public QObject, public QQuickImageProvider 
{ 
    Q_OBJECT 

public: 
    provedorImagem(); 

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

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"; 
    } 

    return imagem; 
} 

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

感謝您發佈此信息。然而,這個例子會因爲用英文課程和成員名稱寫成而受益。並非世界上每個人都讀葡萄牙語...... –

+0

我沒有用英文寫它,因爲它是我的一個應用程序的一部分,這個應用程序是用葡萄牙語寫的。 – GuiDupas

+0

@KlaasvanGend我不明白這個變量來自哪裏:'imagemEditada_'。 GuiDupas請幫忙。 –