Properly scaling SVG Images
-
wrote on 12 Mar 2015, 10:31 last edited by A Former User
I try to instantiate an SVG image scaled by factor 2 like this:
Image { scale: 2.0 source: "myImage.svg" }
The issue with this version is that it looks like the image is first rendered and then scaled. Even using
smooth: true
or
antialiasing: true
didn't solve the problem at all. The only way I found for generically scalling my SVG files was the following work around:
Image { // the following line causes a binding loop sourceSize.width: 2*width source: "myImage.svg" }
This really produces the expected result but of course also prints a warning about a binding loop for sourceSize. I would prefer not to use a previously scaled image since I use the same image in different scalings in various places of the application. Also I would prefer if needn't give an explicit sourceSize.width since at that place in the QML the actual source is dynamic and the images can have different dimensions.
Is there a nicer way to solve this problem?
-
wrote on 12 Mar 2015, 13:03 last edited by
Hi swegmann!
The following code is more an ugly trick than a solution, but at least it does what it's supposed to do and you get rid of the binding loop:
Image { source: "file:///home/pw/Downloads/SVG_logo.svg" sourceSize: Qt.size( img.sourceSize.width*2, img.sourceSize.height*2 ) Image { id: img source: parent.source width: 0 height: 0 } }
-
wrote on 13 Mar 2015, 09:09 last edited by
Hi Wieland
Well, it's not beautiful, but it does the job ;-) Thanks for your help!
-
wrote on 15 Mar 2015, 14:22 last edited by
See here: https://bugreports.qt.io/browse/QTBUG-44863
SVG scaling is quite confusing and hackish in QML.
Basically what you need to set is the "target" size and not the "source" size...hence the confusion. -
See here: https://bugreports.qt.io/browse/QTBUG-44863
SVG scaling is quite confusing and hackish in QML.
Basically what you need to set is the "target" size and not the "source" size...hence the confusion.wrote on 16 Mar 2015, 14:37 last edited by@mcallegari79 I'm a little confused by your remark. Do you mean there actually is a property called 'targetSize'? Because I couldn't find such a property neither in Image nor in Item. Or do you mean the property 'sourceSize' should be called 'targetSize'? Because I thought, I understood how that part worked. But I didn't know how to properly get the "original" size of the SVG, multipling this by my scaling factor and applying this to sourceSize. And as it currently looks there is no nicer way than what @Wieland has shown.
-
Hi swegmann!
The following code is more an ugly trick than a solution, but at least it does what it's supposed to do and you get rid of the binding loop:
Image { source: "file:///home/pw/Downloads/SVG_logo.svg" sourceSize: Qt.size( img.sourceSize.width*2, img.sourceSize.height*2 ) Image { id: img source: parent.source width: 0 height: 0 } }
wrote on 6 Mar 2020, 21:50 last edited by@A-Former-User said in Properly scaling SVG Images:
Hi swegmann!
The following code is more an ugly trick than a solution, but at least it does what it's supposed to do and you get rid of the binding loop:
Image { source: "file:///home/pw/Downloads/SVG_logo.svg" sourceSize: Qt.size( img.sourceSize.width*2, img.sourceSize.height*2 ) Image { id: img source: parent.source width: 0 height: 0 } }
(Funny. When I clicked "reply" the forum wanted to caution me that this thread is quite old. And yet... I arrived here because I still needed to learn the
sourceSize
hack this many years later.)The code snippet above demonstrating how to fix SVG blur using
sourceSize
is great.I'm surely not the first to notice, but you can also then go "one small step further" and make a reusable custom element that will be well-behaved for scaling factors other than "2". Indeed, it should be generalized/reusable for an SVG of any size (any "native" or "starting" size) and any target size or any stretch-due-to-anchoring.
It would look like this:
import QtQuick 2.12 import QtQuick.Controls 2.12 Image { // Thanks to this hack, qml can now only DOWN-SCALE/SHRINK the SVG, which won't cause blurriness/pixelation sourceSize: Qt.size( // first "trick" qml that the SVG is larger than we EVER NEED Math.max(hiddenImg.sourceSize.width, 250), // change 250 to a per-project "biggest icon in project" value Math.max(hiddenImg.sourceSize.height, 250)) Image { id: hiddenImg source: parent.source width: 0 height: 0 } }
You can build-and-run a full working sample here. (It can also be launched simply with qmlscene).
-
Hi swegmann!
The following code is more an ugly trick than a solution, but at least it does what it's supposed to do and you get rid of the binding loop:
Image { source: "file:///home/pw/Downloads/SVG_logo.svg" sourceSize: Qt.size( img.sourceSize.width*2, img.sourceSize.height*2 ) Image { id: img source: parent.source width: 0 height: 0 } }
wrote on 29 Nov 2023, 16:33 last edited bySolution works! We personally just made a custom component that takes desired height, divides that into width to maintain aspect ratio, and is easy to expose a bunch of times without all this boiler plate.
Of note, the width/height set is essential, because without it, changing the source during runtime (say if a target image needed to switch from a nondirectional to right) causes an additional instance of the image to spawn. See image below
// Need to include this as shown in original post width: 0 height: 0
Otherwise we get the huge version that clips out. Note: I set onSourceChanged to set color to red, so we have an idea of what the original one is and which is the artifact.