在 C++ 中保存 QML 图像

Posted

技术标签:

【中文标题】在 C++ 中保存 QML 图像【英文标题】:Save QML image inside c++ 【发布时间】:2016-05-25 14:03:42 【问题描述】:

我正在尝试使用 qml 显示网络图像,然后使用 c++ 代码保存此图像,

这是qml代码,

import QtQuick 2.3
import QtQuick.Window 2.2
import com.login 1.0
Window 
    visible: true
    width : 500
    height: 500

     Loginid: login

    MouseArea 
        anchors.fill: parent
        onClicked: 
          //  Qt.quit();
            login.save(image);
        
    



    Image 
        id: image
        source: "http://www.test.com/webp/gallery/4.jpg"
    



在我的登录类中保存图像,

void Login::save( QQuickItem *item)

    qDebug()<<"width: "<<item->width();
    qDebug()<<"height: "<<item->height();

    QQuickWindow *window = item->window();
    QImage image = window->grabWindow();

    QPixmap pix = QPixmap::fromImage(image);
    pix.save("C:/Users/haris/Desktop/output.png");

我在 c++ 类中获得了正确的图像宽度和高度,但问题是我找不到从QQuickItem 保存图像项的方法。

现在我通过抓取窗口来保存图像,实际上并没有给出输出文件的实际图像大小,而是给出具有当前 qml 窗口大小的输出文件。

基本上我在这里关注saving QML image 的代码,但似乎QDeclarativeItem 在Qt5 中已被弃用,所以我选择QQuickItem,因为QQuickItem 中没有绘制选项。

【问题讨论】:

【参考方案1】:

幸运的是QQuickItem 有一个方便的grabToImage 函数可以做到这一点。

void Login::save( QQuickItem *item)

    QSharedPointer<const QQuickItemGrabResult> grabResult = item->grabToImage();

    connect(grabResult.data(), &QQuickItemGrabResult::ready, [=]() 
        grabResult->saveToFile("C:/Users/haris/Desktop/output.png");
        //grabResult->image() gives the QImage associated if you want to use it directly in the program
    );

不使用 lambda 的替代解决方案:

void Login::save( QQuickItem *item)

    QSharedPointer<const QQuickItemGrabResult> grabResult = item->grabToImage();
    
    /* Need to store grabResult somewhere persistent to avoid the SharedPointer mechanism from deleting it */
    ...

    connect(grabResult.data(), SIGNAL(ready()), this, SLOT(onAsynchroneousImageLoaded()));


void Login::onAsynchroneousImageLoaded() 
    auto grabResult = qobject_cast<const QQuickItemGrabResult*>(sender());
    if (grabResult) 
        grabResult->saveToFile("C:/Users/haris/Desktop/output.png");
     else 
        //something went wrong
    
);

【讨论】:

嗨,谢谢你的回答,我试过grabResult-&gt;saveToFile()grabResult-&gt;image(),但都失败了,在第一种情况下它总是返回false,在第二种情况下它返回空图像,可能是什么问题? 我认为问题出在文档中The grab happens asynchronously and the signal QQuickItemGrabResult::ready() is emitted when the grab has been completed,我可能需要使用就绪信号。 谢谢,我用处理该问题的代码编辑了答案,该代码使用 lambda 函数对信号作出反应。 我认为 lambda 函数存在语法错误,请您修改一下。其实我对 lambda 函数不是很熟悉。 完成。不要忘记确保您的项目启用了 c++ (CONFIG+=c++11)【参考方案2】:

在 QObject 派生类 (ImageSaver) 中注册它。它需要一个成员:

bool ImageSaver::saveImage(const QUrl &imageProviderUrl, const QString &filename)
    qDebug() << Q_FUNC_INFO <<imageProviderUrl << filename;
    QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase *imageProviderBase = engine->imageProvider(imageProviderUrl.host());
    QQuickImageProvider *imageProvider = static_cast<QQuickImageProvider*>(imageProviderBase);
    QSize imageActualSize;
    QSize imageRequestedSize;
QString imageId = imageProviderUrl.path().remove(0,1);

    QImage image = imageProvider->requestImage(imageId, &imageActualSize, imageRequestedSize);
    qDebug() << Q_FUNC_INFO << imageId << imageActualSize;
    return image.save(filename);

然后在 QML 中:

ImageSaver  id: imageSaver 
...
imageSaver.saveImage(image.source, "my.png");
...

而 grabToImage 将使用项目的大小抓取项目,这可以保留图像的实际大小。

【讨论】:

以上是关于在 C++ 中保存 QML 图像的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 更改 QML 图像源

使用grabToImage将QML项目作为图像保存到文件时出错

有没有办法在 qml 中从网上下载图像

Qml Item grabToImage 保存图像错误

尝试在 Blackberry Cascades QT 和 QML 中下载图像

在 Qml 中从字节数组加载到图像