I know how to take a screenshot of the whole window in QML.
I have a Video
element in the QML window. That video is shown in a Rectangle
.
What would be the way to take a screenshot of that Rectangle
rather than the whole window?
I know how to take a screenshot of the whole window in QML.
I have a Video
element in the QML window. That video is shown in a Rectangle
.
What would be the way to take a screenshot of that Rectangle
rather than the whole window?
It is very interesting question. As a quick and working solution I can propose you to use grabToImage
method of Item
. It takes first argument as callback function, and the second as path where you want to save.
I wrote small function for grabbing any 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)
}
}
So you can use it as on QML/QtQuick side, as on Qt (using QMetaObject::invokeMethod
).
There is also QQuickItem::grabToImage
method, but I'll be glad to see any adequate example of its usage.
Another way of doing grab is to use ShaderEffectSource
and use as you wish.
All I wrote above was prepared as a project and located on github. Code is commented, so hopefully all will be clear. You can take it and do some hacking. Pull-requests are welcome as well.
Take a look at Item
's grabToImage
method.
bool grabToImage(callback, targetSize)
Grabs the item into an in-memory image.
The grab happens asynchronously and the JavaScript function callback is invoked when the grab is completed.
Use targetSize to specify the size of the target image. By default, the result will have the same size as the item.
If the grab could not be initiated, the function returns false.
The following snippet shows how to grab an item and store the results to a file.
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");
});
The following snippet shows how to grab an item and use the results in another image element.
Image {
id: image
}
// ...
source.grabToImage(function(result) {
image.source = result.url;
},
Qt.size(50, 50));
Note: This function will render the item to an offscreen surface and copy that surface from the GPU's memory into the CPU's memory, which can be quite costly. For "live" preview, use layers or ShaderEffectSource.
This works with QtQuick 2.0 too.
You can use the grabWindow()
method and then crop the resulting image. You will need to find the absolute position of the QML element on the window, just get its position and add it to the positions of every parent element until you hit the root element, and use QImage::copy(x, y, w, h)
to crop the window image to the element position and size.
There are few disadvantages to this - it is slower, since it has overhead of grabbing the entire window and cropping, and if your element is not rectangular and opaque, it will also grab stuff visible under the element. But if it is an opaque rectangle, and performance isn't an issue, this is the easy way to it.
The hard, but faster way: you can use create a ShaderEffectSource
in QML and set its sourceItem
to the element you want. This will effectively render that element into a texture so you can use shader effects on it. Then on the C++ side, from QQuickShaderEffectSource
you can use its QSGTextureProvider *textureProvider()
method to get the texture provider, then from it you use QSGTexture * QSGTextureProvider::texture()
to get the texture, and from the texture you can find the texture id with int QSGTexture::textureId()
. Then finally, you can get an image from the texture id and use the raw data to construct a QImage
.