SVG Rendering and Source Size:
-
Hi I have troubles rendering SVG file correctely when scale is set in parent items.
I saw maybe I should use sourcesize property but coud not figure how to use it.
Here a sample of code that illustrat the issu. Any svg file can be used. I do not want to set "smooth:true" because of performance issue (I am rendering interface on 11 full HD screens...is there any leads ?
width: 800 height: 800 Rectangle { width: 100 height: 100 //Graphic Image { id: iImageFrame x: 16; y: 42 source: "##.svg" } } Rectangle { x:150 width: 100 height: 100 scale: 1.2 //Graphic Image { x: 16; y: 42 source: "##.svg" sourceSize.width: width sourceSize.height: height } } Rectangle { x:300 width: 100 height: 100 scale: 0.8 //Graphic Image { x: 16; y: 42 source: "###.svg" sourceSize.width: width sourceSize.height: height } }
}@
-
The scale is correct, But juste like mentionned in other posts, it is ugly, Big pixels, or aliasing issues.
Even is scale is lower than 1 there are big aliasing issues.The svg is a vectorial format so I guess Qt is rendering a bitmap matrix and then apply the scale on it,
Maybe there is a way to render the SVG correctely?
-
I tried this :
- it changes the scale differently in x and in Y
- it moves the svg picture, I would expecte no modification in size not position of the svg file
@ Rectangle
{
x:181
y: 18
width: 100
height: 100
border.color: "#ca1f1f"
scale: 1.2
//Graphic
Image {
x: 16; y: 42
source: "##.svg"
sourceSize.height:height/scale
sourceSize.width: width/scale
scale:1/parent.scale
}
}@ -
I would say just don't scale the image then!?
I used some custom SVG files in my latest QML app and it works great, just scale the sourceSize and don't use the scale property, that will of course re-render the SVG but unless it is a very complex SVG it should be fine even for animations.
I think the default scale property is applied after the SVG is rasterized so it will ge "messy" even with antialiasing enabled (you know thee is an antialiasing property int he Item object, right?).In your last post you scale the parent rectangle of the Image, that will off course also scale the Image itself. in a real app i would just never use scale unless for some animations which end with scale:1 ... in most cases at least :)
-
Hi,
The thing is my Application must render real size object, on *any screen *configuration:
10cm square must be 10cm.So according to the screen hardware I must scale every thing.
And I have ~2000 objet to render, so I cannot manage this for every instance of imagesThe example above is to illustrate my situation in a simplified way.
So I thought of several leads:
- Trigger a re-rasterisation, but how ?
- find a way in the image instantiation using sourcesize, but how ?
Does any one hase some advice?
It is realla a shame that vectorial picture format can only be used as Bitmap... -
I found somethind interesting, in the following coe dpiratio is a global scale factor.
Putting the following code inside EVERY instance of Image QML item seems to work.
But This should be available inside the QT C++ code; It would be really more effectiv.THow I do not see yet how to do this and manage the global scale factor automaticcaly. Maybe by multiplying all parent object scale factor together or something alike.
@onSourceChanged: recomputesmoothness();
onStatusChanged: recomputesmoothness();
function recomputesmoothness()
{
if (status == Image.Ready)
{
if(typeof(dpiRatio)==='undefined'){return;}
var lw=width
var lh=height
sourceSize.width=widthdpiRatio
sourceSize.height=heightdpiRatio
width=lw
height=lh
}
}@Here is the complete Example code easy to test and see the results. A svg file is required
@Rectangle
{
property real dpiRatio:1.2
property real sourcesizeratio:1.2
property bool imageswitch:falseproperty string imagesource:"Images/"+(imageswitch?"fond_orange_haut.svg":"Base.svg") width: 800 height: 800 focus: true Keys.onPressed: { console.log(event.key) switch (event.key) { case Qt.Key_Return: dpiRatio = 1.0; sourcesizeratio=1.0 break; case Qt.Key_Plus: dpiRatio += 0.1; break; case Qt.Key_Minus: dpiRatio -= 0.1; break; case Qt.Key_PageUp: sourcesizeratio += 0.1; break; case Qt.Key_PageDown: sourcesizeratio -= 0.1; break; case Qt.Key_End: imageswitch=!imageswitch break; default : return; } } Text { id: text1 x: 38 y: 240 width: 71 height: 34 text: "imagesource: "+imagesource + "\nscale Factor:"+dpiRatio+"\nsourcesizeratio: "+sourcesizeratio verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft font.pixelSize: 12 } //--------------------------------------------------- Rectangle { width: 100 height: 100 border.color: "#000000" Rectangle { anchors.centerIn: parent width: 100 height: 100 border.color: "#000000" //Graphic Image { id: iImage1 x: 16; y: 42 source: imagesource } } } //----------------------------------------------------------- Rectangle { x:181 y: 0 width: 100 height: 100 border.color: "#ca1f1f" transformOrigin: Item.TopLeft scale: dpiRatio Text{ x: 0 y: 8 width: 100 height: 13 text: "Imge2 SourceSize:"+image2.sourceSize.width+" "+image2.sourceSize.height+ "\nImge2Size: "+image2.width+""+image2.height z: 2 } //Graphic Rectangle { anchors.centerIn: parent width: 100 height: 100 border.color: "#ca1f1f" //Graphic Image { id:image2 x: 16; y: 42 source: imagesource onSourceChanged: recomputesmoothness(); onStatusChanged: recomputesmoothness(); function recomputesmoothness() { if (status == Image.Ready) { if(typeof(dpiRatio)==='undefined'){return;} var lw=width var lh=height sourceSize.width=width*dpiRatio sourceSize.height=height*dpiRatio width=lw height=lh } } } } } //----------------------------------------------------------- Rectangle { x:454 y: 0 width: 100 height: 100 border.color: "#16b70a" scale: dpiRatio transformOrigin: Item.TopLeft Rectangle { anchors.centerIn: parent width: 100 height: 100 border.color: "#16b70a" //Graphic Image { x: 16; y: 42 source: imagesource } } }
}@
-
first Qt has real vector graphics, but if you know the technical aspects every SVG image has to be rasterized at some point because your monitor needs a raster image to display! so every program who wants to display vector images has to rasterize an image before you can see it :)
second actually I use a similar solution in my QML app, I have global properties to multiply a DPI factor to every size I use in QML Items, no matter if it is a Rectangle or Image or just a spacing in a ListView.. because than I can scale my app as a whole and the user can even zoom in or out the complete view as he wishes.
I think a feature like this is missing from QML as of now or I just didn't find a better solution but in my opinion that works great for most apps and is perfect for SVG images, text and every default QML view.Also if you know android development, the XML layouts used in android use a similar concept with the device independent pixel (DIP or DP) suffix for sizes, e.g. 5dp or 42dp and 12sp for font sizes.. I simply created global properties with a factor to accomplish a very similar effect so that in QML it looks like 5dp or 42dp and 12*sp and because that are real global properties if the value changes every item that uses that factor will be rescaled with the automatic property binding. :)
So I never (!) use the scale property anywhere other than for animations, I hope that insight helps you a little.maybe I write a blog post about it when i get some time, my app is almost finished if you want I could share some screenshots in different resolutions that you see what i mean?
android references:
http://developer.android.com/guide/practices/screens_support.html
http://developer.android.com/training/multiscreen/screendensities.htmlas you may know in QML every size is absolute pixels only, so you have to apply a factor or something to archive the same effect if you want the same size on every device, no matter f desktop computer or a mobile device, because mobiles devices in general have a very high DPI count and if you leave the values in absolute pixels everything will be very small with higher DPI values :/
-
Thanks for the input.
I know vectorial format must be rasterize, but I would have prefered it was rasterized correctely, or at least easy to configure....I will dig into the Declarative image source code, maybe there I could add a "Property real dpiRatio" so just adding this property trigger the mechanisme described above.
If someone already did such thing it will be appreciated.
-
an easy solution would be if you just use the Screen.pixelDensity property (The number of physical pixels per millimeter), are you aware of that? if you just want your image to be 10cm on any device and not really scaleable that would be the easist way I guess.
If you also want it scalable you add a custom scale property and multiply that by Screen.pixelDensity!?
@
property real zoomFactor: 1.0
property real zoom: Screen.pixelDensity * zoomFactorImage {
source: "..."
sourceSize.width: 100*zoom // because 100mm size
}
@
if the image is quadratic it should be fine just to set the width, the height will be scaled by QML automatically, but if you want set both :D
if you now change the zoomFactor property it will trigger a re-rasterization of the SVG so it should look as best as it gets.maybe that is to easy for you or what is the problem with this approach?
-
hey don't ask me I am no Qt developer. :D
if you check the doc http://qt-project.org/doc/qt-5/qml-qtquick-window-screen.html#pixelDensity-prop (since Qt 5.2 so that property is pretty new)but what I can tell you is how you may be able to use the same value with older versions of Qt, I don't use the pixelDensity property myself, but have a custom C++ class that does the trick with the "QScreen class":http://qt-project.org/doc/qt-5.0/qtgui/qscreen.html (look at all the dots per inch stuff).
In my project I use it like this:
@
QScreen *screen = qApp->primaryScreen(); // global app pointer
real dipScaleFactor = screen->physicalDotsPerInch() / screen->devicePixelRatio() / m_dipNorm;
@
m_dipNorm is the value I use to normalize the scale factor, if you've read the android stuff that is always 160 DPI on android for example, of course you can use whatever value you like (e.g. 72 or 96 DPI for desktop computers).
I just came up with that, so if you use 96 as the "norm" that means on a screen with 96 DPI 1 pixel is 1 pixel in size and if you have a a screen with highter DPI the pixel size will be larger so that the physical size will be identical on all screens not matter the size or resolution.usually you have larger values like 10 pixel so if you write 10*dp it is exactly 10 pixels on my computer (with 96 DPI) but may be 31 pixels on a smartphone with 300 DPI you know what I mean?
if you want to use the same value as Screen.pixelDensity you can convert the inch to millimeter (that is what the QML Screen object does):
@
qreal QQuickScreenAttached::pixelDensity() const
{
if (!m_screen)
return 0.0;
return m_screen->physicalDotsPerInch() / 25.4;
}
@
that replaces the "logicalPixelDensity" property, see the changelog:
- Screen type gained a pixelDensity property, deprecating logicalPixelDensity,
as logicalPixelDensity is less portable across some mobile platforms. -
So far I am following the lead of making a MyImae component.
But there is a side effect:- When the source image changed
- The status changed to 0 then to Image.Ready
- But the width and height are not yet the new ones !!!
- SO every time I replace an image source using a different size it messes everything up.
If I set a timer I see that width and height are correct some times after Image.Ready.
How can I get the NEW dimensions of the loaded source if not using StatusChanged and Image.Ready?This is the code to detect the width and height wrong values:
@
MyImageTest.qml
Image{
onSourceChanged: recomputesmoothness();
onStatusChanged: recomputesmoothness();
function recomputesmoothness()
{
if (status == Image.Ready)
{
console.log(width,height)
}
}
}@This is the code I would like to use:
@MyImage.qml
Image{
onSourceChanged: recomputesmoothness();
onStatusChanged: recomputesmoothness();
function recomputesmoothness()
{
if (status == Image.Ready)
{
if(typeof(dpiRatio)==='undefined'){return;}
var lw=width
var lh=height
sourceSize.width=widthdpiRatio
sourceSize.height=heightdpiRatio
width=lw
height=lh
}
}
}@ -
Yes I thaught of that but so far I did not find anythingelse than the "recomputesmoothness" function and it modify the properties sourceSize.W&H and he width end eight propertie. so it is likely to engender loops...
- Modifiyng sourceSize.width automatically modify width :(
- Modifiyng sourceSize.height automatically modify height :(
- That is why I reset width and height to their original values in this function...
But you are right, I will try to dig into onSourceSizeChanged....