Как можно сделать снимок экрана определенного элемента в QML?

Я знаю, как сделать скриншот всего окна в QML.

у меня есть Video элемент в окне QML. Это видео показано в Rectangle,

Какой бы способ сделать скриншот этогоRectangle а не все окно?

3 ответа

Решение

Взгляни на Item "s 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));

Примечание. Эта функция визуализирует элемент за пределами экрана и копирует эту поверхность из памяти графического процессора в память центрального процессора, что может быть довольно дорогостоящим. Для "живого" предварительного просмотра используйте слои или ShaderEffectSource.

Это работает и с QtQuick 2.0.

Это очень интересный вопрос. В качестве быстрого и рабочего решения я могу предложить вам использовать 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. Код комментируется, так что, надеюсь, все будет ясно. Вы можете взять его и взломать. Pull-запросы также приветствуются.

Вы можете использовать grabWindow() метод, а затем обрезать полученное изображение. Вам нужно будет найти абсолютную позицию элемента QML в окне, просто получить его позицию и добавить его в позиции каждого родительского элемента, пока вы не нажмете на корневой элемент, и использовать QImage::copy(x, y, w, h) обрезать изображение окна до положения и размера элемента.

В этом есть несколько недостатков - он медленнее, так как требует дополнительных затрат на захват всего окна и обрезку, и если ваш элемент не является прямоугольным и непрозрачным, он также будет захватывать вещи, видимые под элементом. Но если это непрозрачный прямоугольник, а производительность не является проблемой, это легкий путь к этому.

Трудный, но более быстрый способ: вы можете использовать создать ShaderEffectSource в QML и установите его sourceItem к элементу, который вы хотите. Это будет эффективно преобразовывать этот элемент в текстуру, чтобы вы могли использовать на нем эффекты шейдера. Затем на стороне C++, из QQuickShaderEffectSource Вы можете использовать его QSGTextureProvider *textureProvider() способ получить провайдер текстуры, тогда из него ты используешь QSGTexture * QSGTextureProvider::texture() чтобы получить текстуру, и из текстуры вы можете найти идентификатор текстуры с int QSGTexture::textureId(), Затем, наконец, вы можете получить изображение из идентификатора текстуры и использовать необработанные данные для построения QImage,

Другие вопросы по тегам