Basic HiDPI Question

I’m still struggling getting a conceptual hold on HiDPI and graphics in Xojo.

In the old days I would create a new Picture with a size, and I would draw into it several times with hardcoded coordinates, because I always knew the size. I have that type of coding many times in my apps.

But if I go the HiDPI way in my apps, those days are gone, right? If I do:

P = w.BitmapForCaching(48, 48)

P might be 48x48, or it could be 96x96 - it depends on the monitor the user is using, right? The divisors are the ScaleX and ScaleY, correct?

So in all my drawing routines, I have to factor the Scale[] parameters in so my drawing coordinates are always correct. Is that right?

In 99% of all drawing you can ignore HiDPI. Here I would use the width and the height of the icon.

I have a small example of a canvas drawing area with zoom and size adjustment

You don’t. By default We take scale into account for you.

The only time you will need to care is if you want to draw pixel by pixel on the 2x or 3x images.

So why when I do BitmapForCaching(48, 48) I get a 96x96 Picture? Then I do Canvas1.Backdrop = P (Canvas1 being 48x48) I only get the Left-Top quadrant of P - because P is not 48x48 of course.

What are p and w? Please show more code.

I wrote a blog post about this:

And Joe Ranieri did an advanced follow up:

I’ve read this before - it’s a great article BTW. Now it’s ingrained that the Graphics W/H are different than the Picture objects W/H.

So the Picture object - regardless of user’s display - is ALWAYS going to be 2x the size you specify in BitmapForCaching? Meaning that I always have to half-size it when I assign the Picture to Canvas.Backdrop, or draw it in the Canvas’s Paint event?

No. the picture object you get back from BitmapForCaching is multiplied based on the scale factor of the screen that the window is on when you call the method. You should also keep in mind that on Windows, the multipliers are not always whole numbers.

Just out of curiosity, what is it that you are trying to do that’s not working the way you think it should?

It’s working the “way it should”, I’m just trying to understand what “should” means =) See my quasi-example above.

In the article you say “The value of widthPic will differ depending on whether your application is running on a HiDPI screen or not” and you say pay attention the Graphics W/H to the Pictures W/H. But those don’t make a difference when I do Canvas.Backdrop = P. If for some users that P is 2x the size and others it’s the same size, don’t I have to consider both possibilities, and if so, how? (I sort of know how, but whats the best way?) This is a little different than “it should just work” (although I know what you mean).

In other words, I think I understand how to deal with “constant coordinates” when working on a graphic in code, but when it comes down to Presentation - for some users that Picture is going to be one size, for others is a different size. How can I Present the graphic (e.g. assign it to a Canvas) consistently regardless if the user has a HiDPI display or not? It’s hard to debug because I’m only using one monitor (now a HiDPI one), so I have to really learn this so I can “see” what the non-HiDPI user is going to see.

As I recall, backdrop isn’t hidpi aware. Have you tried just drawing the picture in the paint event?

I’ll try that this weekend. Another question if you don’t mind - taking a complete step back… what is so special about a high-resolution display that is different than a “regular” display? You just said “HiDPI-aware” - why? Isn’t it the OS’s job to fully abstract this stuff for us? Isn’t a HiDPI monitor just a monitor with 3840 x 2160? Similarly, why wasn’t this a big deal when more people started using 1920x1080-capable displays up from 1280x1024? Forgive me if this is a stupid question, but I’m not birthed with the affection for catchphrases. I’m sure there’s a reason for it - tell me.

Confession: I don’t understand how Xojo handles hiDPI
This scaling malarky just leaves me going ‘huh’?


Isn’t a HiDPI monitor just a monitor with 3840 x 2160?

Based on my experience on a Retina Mac, that monitor has 3840 x 2160 PIXELS
But 1920 x 1080 is what the user sees.
Instead of tiny letters you get readable letters, which have ‘sub pixel’ rendering so they can have smoother edges.
One screen pixel is created using 4 ‘real’ pixels.

1 Like

Not just smoother, but crisper.

Our challenge when all of this started was to make it so in most cases your existing code would just work… and it does. If you go into any Canvas or Window paint event, you don’t need to be concerned with whether or not you are on a Retina display. The tricky part is that you need two or more instances of each picture to make things draw properly. One at the original size (let’s say 16x16 @72ppi), another at 2x the size with double pixel density (32x32 @144ppi) and if you’re on Windows, a 3rd image at 3x with triple pixel density (48x48 @216ppi). They all draw at exactly the same size at runtime, but the higher Rez pictures fill in all of those extra screen pixels instead of just blurring the tiny pic across them. FWIW, you don’t notice this as much with things like photos, but icons, particularly small ones really do look bad.

Xojo hides most of this from you with image sets. You put in multiple resolutions, we draw the best image at the right time. So if you had a multi Rez image on a 2x retina screen and you draw it larger than its intrinsic size, you might still get the 3x image if it will fill in the pixels better.

And FWIW, if you stare at a computer screen all day, the HiDPI screen makes all the difference in the world. I have both since I work on IDE graphics from time to time and I find that my old tired eyes don’t fatigue as quickly on the retina screens as they do on the non-retina ones.

Thanks for your answers - been busy with other things but thanks for the great answers. I’ll respond in a day or two.

OK, so I think we’ve established that the actual Picture returned from BitmapForCaching can be variable in size - it’ll be different for each user.

So, again, my question - when you are assigning that Picture to a Backdrop, or a MenuItem Icon - what am I supposed to do? For MenuItems I want the Picture to always be 16x16. For a Backdrop I always want the Picture to be the same size as the Canvas. It won’t matter what the Graphics object in the Picture is - if the Picture w/h is going to be variable, how do I ensure that the Picture is going to be that size?

Point size will stay the same, so if you ask for 16x16 you’ll get 16x16. However the pixel size may be 32 or 16.

So you can safely use this image as you would have before.

Sam, I think you are thinking conceptually and not practically.

I am assuming I’m missing some significant concept that I need, or should be, spelling out. See the quasi-code below, with the purpose of displaying a row-sized Icon (RowPicture) on a Listbox, viewed on a 4K monitor.

Dim P As Picture
Dim g As Graphics
Dim row As Integer

P = Self.BitmapForCaching(16, 16)
g = P.Graphics
// note: P.Width at this point is 32, not 16,
// so you saying “if you ask for 16 you’ll get 16” is incorrect)
// Sure, g.Width is 16, but that doesn’t make any difference below
g.DrawPicture(sf2, 0, 0, 16, 16, 0,0, sf2.Width, sf2.Height)

Listbox1.AddRow “”
row = Listbox1.ListCount - 1

Listbox1.Cell(row, 1) = “My Row”
Listbox1.RowPicture(row) = P

Only the upper left quadrant of the graphic appears. The problem is that P is actually 32x32 in this situation (it is 16 with a non-4K display), but Listbox.RowHeight is ALWAYS 16, regardless of display type.

Set me straight.

Shouldn’t this be

g.DrawPicture(sf2, 0, 0, g.width, g.height, 0,0, sf2.Width, sf2.Height)