Scalable SVG Icons

It’s a lot of work to provide icons for mobile devices, because of the large number of different formfactors and screen pixel-densities.

Android is using the following set of values:

Name DPI Scaling Factor Default Icon Size
ldpi (low) ~120dpi 0.7 18 x 18
mdpi (medium) ~160dpi 1.0 24 x 24
hdpi (high) ~240dpi 1.5 36 x 36
xhdpi (extra-high) ~320dpi 2.0 48 x 48
xxhdpi (extra-extra-high) ~480dpi 3.0 72 x 72
xxxhdpi (extra-extra-extra-high) ~640dpi 4.0 96 x 96

Source: http://developer.android.com/guide/practices/screens_support.html

To ensure that you get sharp icon shapes you need to provide different icon-files (usually png-files) for each DPI class.

Another approach is to make use of Scaleable Vectro Graphics (SVG).

It is good idea to create the SVG file with the default size of the unscaled icon (24 x 24 pixel at Android). As an example I have crated a cup icon with Adobe Illustrator.

icon-grid

Make sure that the horizontal and vertical lines of the shape are aligned to the pixel-grid. This will ensure, that the shape is sharp, when it is rasterized to the default size.

Then create a new file for the icon-control. I called it “IconSVG.qml”. I have added an ColorOverlay to provide the ability to colorize the icon.

import QtQuick 2.0
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0

Image {
    id: root
    property alias color: colorOverlay.color
    smooth: true

    ColorOverlay {
        id: colorOverlay
        anchors.fill: root
        source: root
        color: "#000000"    
    }
}

Now you can use it like this:

Row {
    spacing: 10

    IconSVG {
        source: "cup.svg"
        color: "#000000"
    }

    IconSVG {
        source: "cup.svg"
        color: "#0092CC"
    }

    IconSVG {
        source: "cup.svg"
        color: "#FF3333"
    }

    IconSVG {
        source: "cup.svg"
        color: "#DCD427"
    }

    IconSVG {
        source: "cup.svg"
        color: "#779933"
    }
}

The result should look like this on a desktop PC:

icons1

Lets scale-up the application to simulate a device with higher DPI, for example 480dpi, which means a scaling factor of 3. You can easily do this by adding the following line inside the “main.cpp” file:

qputenv("QT_SCALE_FACTOR", QByteArray("3")); // for testing purpose only. Remove it later 

The result is:

icons2

As expected, the SVG gets rasterized to the default size of 24 x 24 pixels and then scaled up to 96 x 96 pixels, causing an ugly blurry shape. That’s not exactly what we want.

Modify the “IconSVG.qml” file like this:

import QtQuick 2.0
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0

Image {
    id: root
    smooth: true
    
    property alias color: colorOverlay.color
    property int size: 24  // default
  
    sourceSize.width: size
    sourceSize.height: size

    ColorOverlay {
        id: colorOverlay
        anchors.fill: root
        source: root
        color: "#000000"
    }
}

When the “sourceSize” property is set explicitly it will trigger a new rendering of the SVG to the declared size and – magically – qt will even consider the scaling-factor of the application and multiplies it by default. In the example you just need to set this value to 24, the default size of the icon and you get a perfect 96 x 96 image:

icons3

As you can see, the icons are sharp and nicely colored.

 

Leave a Comment

*