HiDPI / Retina

HiDPI/Retina is not clear to me.

It seems that Xojo uses images in 72 dpi but at double (and triple) points, see below.

So that’s what I did, but with different images (showing other things besides the size difference). Which lets me know which image was loaded (that my code is good).

I load the image in 2x, but it does not fit in the canvas which is at 1x size…
1x: 220 x 101 in 72 dpi
2x: 440 x 202 in 72 dpi
3x: 660 x 303 in 72 dpi

The destination Canvas is 220 x 101 in size. When loaded, my x2 image is a bit truncated.

The documentation doesn’t seem to agree…more or less…and I’m not talking about the Forum.

The question is: what can Xojo do behind my back to correctly display my image.

The sign at is not welcome by the forum software, so I replaced it with a ‘x’.

Here’s the result (the image is 2x, green):

And here is the image from a set (standard size, 2x, 3x) applied to the Canvas Backdrop in the IDE:

You can see the difference. And this is the same image (the green one, 2x; 1x is red and 3x is blue…).

Are you using an Image set or are you using separate images?
Creating Image sets by using the Image Set Editor should handle the correct sizing of the images for you when running the application.

1 Like

Should be:
2x 440 X 202 @ 144 dpi
3x 660 x 303 @ 216 dpi

When drawing a picture you are recommended to use the rect that it will be displayed in (even Apple says this is you use their API, which Xojo do).

g.drawPicture feather, 0, 0, 220, 101, 0, 0, feather.width, feather.height

That is what I think, but reading this forum leads me to what I wrote above; the LR also says that, but recently adds 72 /144 / 216 dpi.

But this does not solve the problem.

In the screen shot where the feather is incomplete, the images comes from the hard disk.
In the other screen shot, taken from the IDE, the image comes from the Image Set Editor:

The screen shot was far larger (w=3360), so I keep only the relevant part.

Also, I assigned the loaded image from disk into the Canvas Backdrop… (the imageset is done in the IDE).

But it is the same image in both case !

If those images were drawn two different ways that’s your problem. It’s your code, not Xojo.

This is correct. Drawing at scale is not automatic. If pulling the images from disk, you’ll either want to load them into a multi-resolution picture, or use DrawPicture with the full scale parameters to draw it at the size you need. For a 2x image, you’d want to draw it at half the size. As counter intuitive as it sounds, it’ll maintain the high resolution. In my opinion an image set or multi red picture (which is all an image set is) is much easier to work with.

Wait, what?
If the OP has an image set, can they not just draw the image and Xojo (using Apple’s API) draws the correct image for the display?

Almost all of my image drawing code uses declares and NSImages, which auto handles this, but it is still important to include the full draw rect and not just a draw point.
A lot of the UI images you see in my apps are imagewells (with declares to hide the frame and control the image scaling), with setting a NSImage into the ImageWell.

Correct, if you have an image set, you can draw it like any other picture and it’ll work fine.

I loaded the correct image with code and get wrong results.

To be sure it is not me, I created a Picture set and get the correct result.


This is simple.

And I do nothing fancy: not MY bug !

Here’s the used code:

Var Image_FI   As FolderItem
Var Image_Name As String

Select Case Self.ScaleFactor
Case 1
  Image_Name = "sqlite370_banner.png"
Case 2
  Image_Name = "sqlite370_banner@2.png"
Case 3
  Image_Name = "sqlite370_banner@3.png"
  Image_Name = "sqlite370_banner.png"
End Select

// Get a Reference to the Resources Folder
Image_FI = App.ExecutableFile.Parent.Parent.Child("Resources")

// Get a Reference to the Images Folder
Image_FI = Image_FI.Child("Images")

// Get a Reference to the correct image
Image_FI = Image_FI.Child(Image_Name)

// Assign l’image
Me.Backdrop = Picture.Open(Image_FI)

// Force a refresh to display the image (in case…)

You missed this part.

Here’s an example.

Method 1: Load into multi-res picture.

Var ResourcesFolder As FolderItem = App.ExecutableFile.Parent.Parent.Child("Resources")
Var BaseImage As Picture = Picture.Open(ResourcesFolder.Child("sqlite370_banner.png"))
Var Images() As Picture
Me.Backdrop = New Picture(BaseImage.Width, BaseImage.Height, Images)

Method 2: Draw the picture at the desired size

Var BestFactor As Integer = Min(3, Ceiling(Self.ScaleFactor))
Var ImageName As String = "sqlite370_banner" + If(BestFactor = 1, "", "@" + BestFactor.ToString(Locale.Raw, "0")) + ".png"
Var Source As Picture = Picture.Open(App.ExecutableFile.Parent.Parent.Child("Resources").Child(ImageName))
Var Image As New Picture(Source.Width / BestFactor, Source.Height / BestFactor)
Image.Graphics.DrawPicture(Source, 0, 0, Image.Width, Image.Height, 0, 0, Source.Width, Source.Height)
Me.Backdrop = Image

Oh and also, you can’t count on ScaleFactor being whole numbers.

Edit: I’m writing code from memory, it may be necessary to set the resolution properties of the Image variable in the second example.

1 Like

If you simply load the image from disk w/o using an image set and use it as a Canvas backdrop, make sure to set the images’ properties HorizontalResolution and VerticalResolution correctly. Simply multiply 72 with the current scaling for both. That should work.

Thank you Thom.

I will read your answer carefully later today (when coll & calm).

@Carsten_Belling Thank you.

Nota: I do not played with the screen value, but the scale factor (here) is 2.

Monitor Control Panel (set the default size).

I do not know how the ScaleFactor can be a number with a decimal part on MacOS: the “values” are predefined by icons… (we cannot use a % value).

But you are correct, I do not have made my home work thinking “this is easy”…

The difference in size from my code vs the Picture Set is not 2 times, but some by few %… (after all, the image is twice the size of the Canvas area).

Thank you Thom, works fine.

Xojo must do something special when it get a multi-parts image, because I do not changed anything to my images and that works.

The only difference with my code is… I pass the correct image instead of a multi-parts image (array)…

However, your code works fine and it is OK.