Is there any possible way to make grabToImage()
buffer different from what's displayed in GUI? I'm using ChartView
without legend in GUI and want to export it to PNG
with legend. So I try:
chartView.legend.visible = true
chartView.update()
chartView.grabToImage(function(result) {
console.log("grabbed")
var path = filename.toString().replace(/^(file:\/{2})/,"");
console.log(path + result.saveToFile(path));
chartView.legend.visible = false
update();
});
But both those updates happen only after the control comes out of this function, so I don't get legend drawn in PNG. Also I would like the appearance of legend to be unnoticable to user. Are there any ways to do that in QML?
I am unsure, whether I got you quite right.
My suggestion is, to not grab the Item
you display, but a copy of it, that you then modify as you like.
Copy here does not mean, that you have the same object twice, but that you render it twice by using a ShaderEffectSource
. Before you grab this ShaderEffectSource
to image, you can add anything you like.
In my example I display a simple Rectangle
with a nice gradient. What I save is the same Rectangle
that is extended by the Text
'I am legend'. The user won't see this text apearing in the view at any time.
Rectangle {
id: commonView
width: 200
height: 200
gradient: Gradient {
GradientStop { position: 0; color: 'steelblue' }
GradientStop { position: 1; color: 'orange' }
}
MouseArea {
anchors.fill: parent
// don't grab the rectangle itself.
onClicked: legendView.grabToImage(function(result) {
console.log(result.saveToFile("something.png"));
});
}
}
ShaderEffectSource {
id: legendView
visible: false // Does not need to be shown.
sourceItem: commonView
width: 200
height: 200
Text {
anchors {
right: parent.right
bottom: parent.bottom
}
text: 'I am legend'
}
}
You might optimize the performance by only having the ShaderEffectSource
active or even created when needed.
You might use the ShaderEffectSource.live
-property to disable updating of it. Then use scheduleUpdate()
to trigger the update.
This might look like this:
Rectangle {
id: commonView
width: 200
height: 200
gradient: Gradient {
GradientStop { position: 0; color: 'steelblue' }
GradientStop { id: gs1; position: 1; color: 'orange' }
}
MouseArea {
anchors.fill: parent
onClicked: {
gs1.position -= 0.1
legendView.save()
}
}
}
ShaderEffectSource {
id: legendView
y: 200
visible: false // Do not render it (will only be rendered when called grapToImage()
sourceItem: commonView
width: 200
height: 200
live: false // Will only be updated, when explicitly called for
function save() {
console.log('Schedule Save')
scheduleUpdate() // explicitly update. grabToImage() will force rendering afterwards.
legendView.grabToImage(function(result) {
console.log(result.saveToFile("something" +gs1.position.toFixed(1) + ".png"));
})
}
// Put additional stuff on it.
Text {
anchors {
right: parent.right
bottom: parent.bottom
}
text: 'I am legend!'
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With