从关于 StackOverflow 的讨论中,我能够将 QML 项目中的图像保存为png/jpeg
.
如何叠加或合并两个不同的qml
图层并将它们合并为一个,以将其保存到 png/jpeg 中?
注意:我可以保存一个QQuickItem
. 只需要知道如何覆盖 2 QQuickItem
s
从关于 StackOverflow 的讨论中,我能够将 QML 项目中的图像保存为png/jpeg
.
如何叠加或合并两个不同的qml
图层并将它们合并为一个,以将其保存到 png/jpeg 中?
注意:我可以保存一个QQuickItem
. 只需要知道如何覆盖 2 QQuickItem
s
只需让两个 qml 对象成为根的子Item
项,然后抓取该根项,它将捕获其所有内容。
只需确保根项足够大以包围子项,并且子项不在负空间中,因为它只会捕获根项的足迹内的内容。
您还可以从 C++ 甚至 QML 进行手动组合。
您评论中描述的问题是您无法移动东西,那么您能做什么?您可以拥有两个元素,而不是将原始 QML 对象作为同一根的父对象Image
,然后捕获项目 A 并将捕获结果设置为图像 A 的源,然后对项目 B 执行相同操作,最后,您捕获根项目,它将一起捕获两个图像。
好的,这是一个简单的例子,它看起来有点复杂,因为抓取是异步的,你必须等待单个抓取结果完成才能抓取“最终”根项目,因此计时器的使用。在此示例中,不同的项目排成一排,但您可以按照自己喜欢的方式组合它们:
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
Rectangle {
id: s1
visible: false
width: 200
height: 200
color: "red"
}
Rectangle {
id: s2
visible: false
width: 200
height: 200
color: "blue"
}
Row {
id: joiner
visible: false
Image { id: t1 }
Image { id: t2 }
}
Image {
id: result
y: 200
}
Timer {
id: finish
interval: 10
onTriggered: joiner.grabToImage(function(res) {result.source = res.url})
}
Component.onCompleted: {
s1.grabToImage(function(res) {t1.source = res.url})
s2.grabToImage(function(res) {t2.source = res.url; finish.start() })
}
}
首先捕获两个矩形并将其用作连接器中图像的源,然后捕获连接器并显示在结果图像中,隐藏除最终结果图像之外的所有对象。
更简单的是,您可以使用这个漂亮的小助手在单个图像中快速加入任意数量的项目:
Item {
id: joinHelper
visible: false
property Component ic: Image { }
property var cb: null
Row { id: joiner }
Timer {
id: finish
interval: 100
onTriggered: joiner.grabToImage(joinHelper.cb)
}
function join(callback) {
if (arguments.length < 2) return // no items were passed
var i
if (joiner.children.length) { // clean previous captures
for (i = 0; i < joiner.children.length; ++i) {
joiner.children[i].destroy()
}
}
cb = callback // set callback for later
for (i = 1; i < arguments.length; ++i) { // for every item passed
var img = ic.createObject(joiner) // create empty image
// need to capture img by "value" because of JS scoping rules
// otherwise you end up with only one image - the final one
arguments[i].grabToImage(function(temp){ return function(res){temp.source = res.url}}(img))
}
finish.start() // trigger the finishing step
}
}
你像这样使用它:
joinHelper.join(function(res) { result.source = res.url }, s1, s2)
它仍然使用一行,但您可以轻松地对其进行调整以进行自己的布局。它通过传递最终回调和您要捕获的所有项目来工作,在内部它为每个项目创建一个图像,将它们放入容器中,然后触发完成计时器。
请注意,根据系统的速度和项目的复杂程度以及它们的数量,您可能需要延长计时器间隔,因为最终的回调需要在所有捕获完成后执行,图像源已分配并调整图像大小以使行具有适当的尺寸。
我还对大部分内容进行了注释,以便于理解。
这个问题似乎与这个问题密切相关
解决方案是将有Item
问题的 s 渲染到第二个项目的纹理中,您不需要渲染到屏幕上。您可以Item
根据需要添加多个ShaderEffectSource
s 作为子项,根据需要将它们彼此相对放置,并将它们的源设置为Item
您想要抓取到 Image 的 s。
然后你抓住Item
图像。
一个通用的例子,它公开了一个函数来获取一个Item
s 的列表到一个图像,其中每个Item
都堆叠在彼此之上,每个不透明度为 0.2:
import QtQuick 2.0
Rectangle {
id: root
visible: false
color: 'white'
function grabMultipleToImage(url, objects) {
imgRep.url = url
width = Math.max.apply(root, objects.map(function(e) { return e.width }))
height = Math.max.apply(root, objects.map(function(e) { return e.height }))
imgRep.ready = 0
imgRep.model = objects
}
Repeater {
id: imgRep
onReadyChanged: {
if (ready > 0 && ready === model.length) {
console.log(root.width, root.height, imgRep.url)
root.grabToImage(function (res) { res.saveToFile(imgRep.url); model = null })
}
}
property int ready: 0
property string url
delegate: ShaderEffectSource {
sourceItem: modelData
width: modelData.width
height: modelData.height
opacity: 0.2
live: false
Component.onCompleted: { imgRep.ready++ }
}
}
}
这个的用法是这样的:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: myWindow
visible: true
width: 600
height: 600
color: 'white'
Button {
text: 'grab'
onClicked: {
test.grabMultipleToImage('testimg.jpg', [rect1, rect2, rect3])
}
}
ImageGrabber {
id: test
}
Rectangle {
x: 100
y: 205
id: rect1
color: 'blue'
width: 10
height: 20
}
Rectangle {
x: 250
y: 12
id: rect2
color: 'green'
width: 20
height: 30
}
Rectangle {
x: 100
y: 100
id: rect3
color: 'red'
width: 100
height: 5
}
}
但是,如果您需要更复杂的合并,您也可以手动创建此对象并在需要时抓取它。
根据文档中的说明,无需计量
注意:此函数会将项目渲染到屏幕外表面并将该表面从 GPU 的内存复制到 CPU 的内存中,这可能会非常昂贵。对于“实时”预览,请使用图层或 ShaderEffectSource。
这个解决方案应该比使用Image
s 和ItemGrabResult
s 作为源更有效,因为它将这些东西保留在 GPU 内存中,直到它被抓取和存储。