在QML中拍摄特定项目的屏幕截图的方式是什么?

问题描述:

I know how to take a screenshot of the whole window in QML在QML中拍摄特定项目的屏幕截图的方式是什么?

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

什么是采取的Rectangle,而不是整个窗口截图的方式吗?

看看ItemgrabToImage方法。

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的内存, 可以是相当昂贵的表面。对于“实时”预览,请使用ShaderEffectSource图层或 。

这与QtQuick 2.0一起使用。

+0

** ShaderEffectSource真的更快吗?从Qt文档中看起来并不是这样**尽管[ShaderEffectSource]的官方文档(http://doc.qt.io/qt-5/qml-qtquick-shadereffectsource.html)明确指出带有* Warning *标签在大多数情况下,它会降低性能并增加视频内存使用量。你能澄清一下吗?我正在寻找最快的方式来保存图像。我也看到Qt官方文档指出'ShaderEffectSource'依赖于底层硬件,并且可能在所有设备上都没有相同的功能,特别是如果您的QtApp在多种Android设备上运行。 –

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

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

困难但速度更快的方法:您可以使用在QML中创建ShaderEffectSource并将其sourceItem设置为所需的元素。这将有效地将该元素渲染到纹理中,以便您可以使用它的着色器效果。然后在C++端,从QQuickShaderEffectSource可以使用其QSGTextureProvider *textureProvider()方法获取纹理提供程序,然后使用QSGTexture * QSGTextureProvider::texture()获取纹理,并从纹理中可以找到纹理标识int QSGTexture::textureId()。最后,你可以get an image from the texture id并使用原始数据构建一个QImage

+0

请分享ShaderEffectSource解决方案的代码吗? – mabg

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

我写的小功能,用于抓取任何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写道。代码被评论,所以希望所有人都会清楚。你可以拿它并做一些黑客行为。拉请求也是受欢迎的。