如何在QML中截取特定项目的屏幕截图?

时间:2015-10-17 06:49:45

标签: qt qml qt5 qtquick2

I know how to take a screenshot of the whole window in QML

我在QML窗口中有一个Video元素。该视频显示在Rectangle中。

如何截取 Rectangle 而不是整个窗口的屏幕截图?

3 个答案:

答案 0 :(得分:5)

这是一个非常有趣的问题。作为一种快速且有效的解决方案,我建议您使用grabToImage Item方法。它将第一个参数作为回调函数,第二个参数作为要保存的路径。

我写了一个小函数来抓取任何Item

// what -- name of item needed to be grabbed
// where -- string
function render(what, where) {
    // Find existent item with given name `what`
    var i = 0
    var found = false
    for (i = 0; i < window.contentItem.children.length; i++) {
        if (window.contentItem.children[i].objectName === what) {
            // We found respective item
            found = true
            break
        }
    }
    if (found) {
        console.log("We found item " + what + ". Grabbing it to " + where)
        var item = window.contentItem.children[i]
        // Grab image and save it (via callback f-ion)
        item.grabToImage( function(result) { result.saveToFile(where) })
    } else {
        console.warn("No item called " + what)
    }
}

所以你可以在QML / QtQuick那边使用它,就像在Qt上一样(使用QMetaObject::invokeMethod)。

还有QQuickItem::grabToImage方法,但我很高兴看到其使用的充分示例。

另一种抓取方式是使用ShaderEffectSource并按照您的意愿使用。

我在上面写的所有内容都是作为一个项目编写的,位于github。代码被评论,所以希望一切都清楚。你可以接受并做一些黑客攻击。欢迎提出拉动请求。

答案 1 :(得分:3)

查看Item grabToImage方法。

bool grabToImage(callback, targetSize)
  

将项目抓取到内存中的图像中。

     

抓取异步发生和JavaScript函数回调   抓取完成后调用。

     

使用targetSize指定目标图像的大小。默认情况下,   结果将与项目具有相同的大小。

     

如果无法启动抓取,则该函数返回false。

     

以下代码段显示了如何抓取项目并存储结果   到文件。

Rectangle {
    id: source
    width: 100
    height: 100
    gradient: Gradient {
        GradientStop { position: 0; color: "steelblue" }
        GradientStop { position: 1; color: "black" }
    }
}
    // ...
    source.grabToImage(function(result) {
                           result.saveToFile("something.png");
                       });
  

以下代码段显示了如何抓取项目并使用结果   另一个图像元素。

Image {
    id: image
}
    // ...
    source.grabToImage(function(result) {
                           image.source = result.url;
                       },
                       Qt.size(50, 50));
  

注意:此功能会将项目渲染到屏幕外表面   将该表面从GPU的内存复制到CPU的内存中   可能是相当昂贵的。对于&#34;直播&#34;预览,使用图层或   ShaderEffectSource。

这也适用于 QtQuick 2.0

答案 2 :(得分:0)

您可以使用grabWindow()方法,然后裁剪生成的图像。您需要在窗口上找到QML元素的绝对位置,只需获取其位置并将其添加到每个父元素的位置,直到您点击根元素,然后使用QImage::copy(x, y, w, h)将窗口图像裁剪为元素的位置和大小。

这有一些缺点 - 它较慢,因为它有抓住整个窗口和裁剪的开销,如果你的元素不是矩形和不透明,它也会抓住元素下可见的东西。但如果它是一个不透明的矩形,并且性能不是问题,那么这就是它的简单方法。

更难但更快的方法:您可以使用在QML中创建ShaderEffectSource并将其sourceItem设置为您想要的元素。这将有效地将该元素渲染为纹理,因此您可以对其使用着色器效果。然后在C ++方面,从QQuickShaderEffectSource你可以使用它的QSGTextureProvider *textureProvider()方法来获取纹理提供者,然后从中使用QSGTexture * QSGTextureProvider::texture()来获取纹理,从纹理中你可以找到纹理ID为int QSGTexture::textureId()。最后,您可以get an image from the texture id并使用原始数据构建QImage