在 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->saveToFile()
和grabResult->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 图像的主要内容,如果未能解决你的问题,请参考以下文章
使用grabToImage将QML项目作为图像保存到文件时出错