Как можно сделать снимок экрана определенного элемента в 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
,