What would be the way to take a screenshot of a particular Item in QML?

别说谁变了你拦得住时间么 提交于 2019-12-06 16:00:10

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/33183743/what-would-be-the-way-to-take-a-screenshot-of-a-particular-item-in-qml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!