Skip to content

BorderImage is for Scaling! Scalable UIs 2.2

In the previous blog post, we talked about the importance of pixels and their indivisible nature, the way we deal with that in the icon area and introduced the concept of PPI dependable UIs – all this to have truly scalable graphics in QML.

We used the BorderImage element to illustrate how an element could scale and retain the same aspect ratio across a range of different screen PPIs and their corresponding screen definitions.

BorderImage is for Scaling!

When I first got into Qt Quick and QML, the one element that made me instantly fall in love with the entire thing was the BorderImage element. It made things that were complicated instantly trivial, plus it saved me, the designer, the tedious trouble of pre-slicing images into 9 rectangular elements, which dramatically helped with the “deliverables” problem and with small adjustments. Even today, with all of the new things we have like the Canvas or  Shaders, BorderImage remains my favourite element in QML. However that might not be enough (and it really is not enough). To expose what goes on when ppi changes, I created a video on a hypothetical screen. Using similar code to that shown in the last post: a BorderImage component that lived inside an element whose pixel count grew, and which then, when scaled back into the original size, mimicked the scaled appearance of a flexible dpi count screen… Here is the code that generates that central blue element:

.......
 BorderImage {
   id: scalableElement2
   source: "./Images/baseBImage.png"
   width: parent.width-ppi/2
   height: ppi*1.5
   anchors.centerIn: parent
   border.left: 27; border.top: 27
   border.right: 16; border.bottom: 16
 }
.......

(notice it is obviously not pixel perfect as pixels are scaled)

So as you can see the results are far from perfect. In spite of the created element retaining the desired overall size, its look radically changes as we grow the pixel count, the corner radius diminishes almost into nothing, and even the overly done drop shadow that is huge in 90dpi becomes almost invisible on an hypothetical 570 dpi screen.

An expected solution

One possible solution, and the most commonly used, gets its inspiration from the way we scale icons, this means using multiple source Image files for ppi ranges.

And the way we generate those source images is again very similar to the way we generate them for icons. Using a vector drawing program, we scale the source image into multiple scale size elements and render those into raster images, png’s, jpeg’s, etc.

rect5287

We can also define the sizes of the corners/borders in ppi/inches.  As long as the ppi is larger than the number of pixels the corner has, we will be just extending the place where border line cuts the image. You just need to pay attention to leaving enough margin in those areas, so that no gradient/texture scaling problems might become too visible. Just keep in mind that the slicing lines of the border image will not be in a precisely defined position.

Showing the Code

What I will show now is just demo code. There are better ways to do it with components now offered in Qt to facilitate this, but here I am just trying to expose the logic and the problems, so I have opted for this simple method.

.......
property var dir: ["MDPI","HDPI","XHDPI","XXHDPI",
                                    "XXXHDPI","XXXXHDPI"]
readonly property int ppiRange:{ 
 if (ppi>=540)
  5
 else if (ppi>=360)
  4
 else if (ppi>=270)
  3
 else if (ppi>=180)
  2
 else if (ppi>=135)
  1
 else
  0
 }
.......
...... 
BorderImage {
   id: scalableElement3
   source: "./Images/" + dir[ppiRange] + "/image.png"
   width: parent.width-ppi/2
   height: ppi*1.5
   anchors.centerIn: parent
   border.left: 0.3*ppi; border.top: 0.3*ppi
   border.right: 0.18*ppi; border.bottom: 0.18*ppi
 }
.......

What you can see here is a simple way to change the source directory, depending on the dpi and the the Border position cuts defined in inches via the ppi number… I generate all the images and place them in conveniently named directories that are mapped in our “dir” variant. This has proven to be a generally good idea in my experience when creating all of the assets; it makes it easy to compare directories and search for missing assets.

Again, here is a video showing how it all looks when we dynamically change the ppi. Remember once more that the real thing will look much better since it will not be scaling pixels – but it should give you an idea of how it works.

As you can see the results are much better now and the image retains its global appearance across the ppi range. There are still issues in the corners and shadow size, especially when reaching the 540 ppi area, and if you target a device that is only slightly below 540, you might want to create more assets for that segment. This is true for any case, the values I picked were somewhat arbitrary and a multiple of a 90 ppi theoretical screen. In real life you tend to target a specific set of devices and probably will want to use those as the ones that set your boundaries for the definition of your image assets. Just pay attention to where each range ends and another begins, and make sure you are not discarding important visual information.

In the next post we will discuss more exotic methods of scaling that might be useful, depending on what you want to scale.  So, see you soon.

 

 

 

Categories: Design / KDAB Blogs / KDAB on Qt / Scalable UIs

Tags: / / /
Senior Graphic Designer and Illustrator. Specialized in iconography, themes user interface design and Qml wire-framing/prototyping/implementation. Nuno's works include general illustrations, UI design, web design, corporate design as well as other works in creative areas. He is known for the Oxygen Project.

11 thoughts on “BorderImage is for Scaling!”

  1. Qt should adjust size by itself in low level. Developers should not write any code to deal with DPI.

    1. Nuno Pinheiro

      @ M thank your for your comment.
      By now it should have become evident enough that its not that simple, some cases it might be as easy as what I state above, and in some cases (depending on the platform) you can simple use components that are some version of what I show above, The problem is that normally it’s not that simple and the designer will want a custom component widget that works across platforms and DPI ranges, and for that you need to understand the intricacies of the issues. This is the main focus of this blog posts to expose them so that wen you have to create something that is scalable you understand a bit better the issues, and multitude of strategies you can use to circumvent them…

  2. I dont like at all the PPI scaling. I don’t get at all any benefits from using higher resolution display to show more content. Instead I am forced to just get higher pixel density and same content size why doesn’t help at all or give a reason to spend money for better display.

    1. Nuno Pinheiro

      @ fri13
      Well over the years we created several computer technologies, just to be able to mitigate the problems created by the rather poor and low PPI densities of screens, Anti-aliasing, font kerning and hinting, gradient post dithering etc etc are all but tricks we created over the yaers to mitigate one form or other of screens limitations.

      The current my ppi is bigger than yours fest is, I will agree a bit silly but overall if you look at a mobile screen with say 80 PPI’s and compare it to screen with 300 the image quality difference is staggering.

      The content volume cant really be changed as its limited by your 1 eyes , 2 the size of your thumb…Its still the same thing its just looks prettier, sharper and more accurate…

  3. hello Nuno, great series, thanks. Will you be talking about scaling-strategies in general UI development (i.e. text, widgets, editors and there relative positioning) in these posts as well?

    1. Nuno Pinheiro

      Hey jeroen, thank you for the comment.
      I will try to talk about that in the end of the series, right now I’m focusing more on the technical side and the implementation possibilities, By the end i will try to venture a bit on dynamically positioned UI’s, that adjust to form factor changes dynamically. and to do that we need to talk about the issues you rise… Next blog post will be about my favourite format SVG and how come its the wrong format so many times.

  4. Hello Nuno,
    Great work!!! I was looking for detail implementation of such things and you explained it in a perfect way . Thanks a lot. I am looking forward for your next blog.

  5. Hi Nuno. Thank you for your postings here, very interesting insight directly from an icon artist. I have a question though, which I think wasn’t covered explicitly:

    What behavior is assumed when application has icon assets prepared for, say, 120 and 160 dpi screens, but for some reason is being run on a system with 140 dpi screen? Imagine, application has an area measured in device independent pixels where some icon should be displayed. Should it display smaller 120 dpi icon as is? Or scale it up? Or, oppositely, scale larger 160 dpi icon down?

    Thank you!

    1. Nuno Pinheiro

      Hey Sergey, thank you for the kind words.
      There is no one fits all answer for this sort of questions so depending on the specific UI the answer might be slightly different. Things like style shape of icon etc can sometimes provide fuel for different strategies.
      But generally the common answer to your problem would be to use the 120 dpi one all the way up to 159 never scaling it, the result of witch is that its physical size would decrease as you increase the dpi.
      Now the goals of the specif UI need to be taken in to account and you should evaluate if this side effect is something you can live with, if not you can try to downscale the 160 one and see if the resulting blurriness of the icon is tolerable or not…#note that scaling icons is usually a bad idea specially in this dpi area were pixels are still very visible.
      Hope this helped.

  6. Hi there,

    I know I’m a bit late to the party, but I would like to point out there’s a simpler solution for this. One that doesn’t require coming up with multiple versions of your image file. You just have to leverage Item.scale, applying it to your BorderImage to compensate for DPI changes while keeping its original size (width and height properties) as they would be in the reference DPI (ie, the DPI intended for the source image).

    This was done here:
    http://code.qt.io/cgit/qt-apps/neptune3-ui.git/tree/imports/shared/controls/ScalableBorderImage.qml

    1. Nuno Pinheiro

      Thank you for your question/comment
      But you will no longer have it pixel perfect. Depending on your source original raster file size you might
      1 Be Showing of upscale visible pixels if low res
      2 Or wasting gpu/cpu memory if high res than needs be. (usually low res monitors have also low memory hardware alongside)

      Think, if it was that easy I would not talk about it ;).

      option 2 I use it sometimes if I’m feeling lasy and dont want to spend to much time on a component and its fairly decorative without much need of pixel perfection.

Leave a Reply

Your email address will not be published. Required fields are marked *