HiDPI support

Xojo supports high dots per inch displays for Mac, Windows and Linux desktop apps. Apple calls these displays "Retina Displays", but the generic term is HiDPI. For most of your apps, you will likely only need to turn on the Supports Hi-DPI switch in the Inspector for the Shared Build Settings to enable your app to support HiDPI displays. When you do this, all UI elements will take advantage of HiDPI displays.

Xojo also supports HiDPI web apps.

On Windows, Microsoft's Writing DPI-Aware Desktop and Win32 Applications document is a useful reference.

To make it as easy as possibly for you to support HiDPI displays in your apps that have custom graphics, there are several changes to these desktop classes: DesktopApplication, Picture, Graphics, DesktopWindow and DesktopCanvas.

Overview

Enable HiDPI support for your web apps by turning on the "Supports HiDPI" property in the Shared Build Settings Inspector of the project.

When HiDPI is enabled, measurements are done in points rather than pixels. For example, if you set a ListBox Width property to 100, that means 100 points, which on a 2x HiDPI screen would actually be 200 pixels. By using points, this allows you UI elements to be the same relative size regardless of the display.

The most significant changes are to Picture, which now essentially can contain three different types of "pictures": Bitmap, Immutable Bitmap, Vector and Image.

Of these, the Image type is the one that supports HiDPI displays. The other Picture types work as they have before. To be precise, it breaks down like this

  • Bitmap: A mutable Picture object that is identical to what exists now.

  • Immutable Bitmap: A single-representation read-only bitmap. If the bitmap is RGB with 8, 16, 24, or 32 bits per pixel, there will be a read-only RGBSurface that can be used to access raw pixel data that hasn't gone through color conversion or pre-multiplied alpha (typically).

  • Image: An array of mutable or immutable bitmaps that can be loaded from an image set, a TIFF, or created at runtime. When drawn to a graphics object, the "best" bitmap (as described below) is chosen and drawn.

Image sets

An Image Set project item can contain pictures at three different scales: 1x, 2x and 3x. All images must have the same aspect ratio. For example if your 1x image is 64x64 @ 72DPI, then the 2x image must be the same ratio (1:1) and would typically be 128x128 @ 72DPI or 64x64 @ 144DPI. Make sure that that the tool you use to create or edit your images properly sets the image DPI (dots per inch). Some tools (such as Photoshop) do not properly set the DPI which can cause Xojo to interpret the image as the wrong size.

You can add Images to your projects by adding an Image Set from the Insert menu: Insert > Image.

Note

When the Supports HiDPI property is turned ON, dragging a picture file to the project creates an Image Set. When it is OFF, dragging a picture to the project adds it as a Picture. If you want to add a picture to an Image Set when Supports HiDPI is OFF, first add the Image Set to the project and then drag the picture file to the appropriate 1x, 2x or 3x slot.

Picture files added to the project in Image Sets are treated as Images and follow the rules described in the Image section.

Picture files in your existing projects are treated as 1x and will be scaled as necessary. Should you want to update your projects with multiple sizes for your pictures, you would create an Image Set with the same name as the original picture and add images to the 1x, 2x and 3x slots as necessary. Your code that refers to these images will continue to work without changes since the name used for the picture now refers to the Image Set.

Image

A Picture that is actually an Image type can consist of one or more bitmaps. When run on an HiDPI display, the image that best matches the display is used based on these rules:

  1. The algorithm iterates through the indexed images, first finding picture with the closest number of pixels to the destination, preferring the next largest image if no exact match is found.

  2. If multiple pictures match, the picture with the DPI closest to the destination scale is chosen.

The Picture class has many existing properties which have been updated to work with Images. This table shows you which properties can be used for the various types of pictures:

  • Not relevant for Vector Image

This table indicates which methods can be used for the various types of pictures:

Picture Property

Mutable Bitmap

Immutable Bitmap

Vector

Image

Graphics

Valid

Nil

Nil

Nil

Depth

User-specified

File-specified

0

0

HasAlphaChannel

User-specific

File-specified

False

False

Height

Pixels

Pixels

Points

Points

HorizontalResolution

User-specified

File-specified

72*

72

ImageCount

0

0

0

File-specified

Mask

User-specified

Nil

Nil

Nil

Objects

Nil

Nil

Valid

Nil

RGBSurface

Valid

Nil

Valid

Nil

Transparent

User-specified

0

0

0

VerticalResolution

User-specified

File-specified

72*

72

Width

Pixels

Pixels

Points

Points

  • Not relevant for Vector pictures.

This table indicates which methods can be used for the various types of pictures:

Picture Method

Bitmap

Immutable Bitmap

Vector

Image

ApplyMask

Valid

IllegalOperationException

IllegalOperationException

IllegalOperationException

CopyMask

Valid

Valid

IllegalOperationException

IllegalOperationException

CopyOSHandle

Valid

Valid

IllegalOperationException

IllegalOperationException if not an NSImage

GetData

Valid

Valid

IllegalOperationException

IllegalOperationException if lossy

Save

Valid

Valid

Valid

IllegalOperationException if lossy

Picture notes

  • Pictures in the project, loaded from disk, received from drag and drop, or loaded from data will be loaded as Images if the format supports it. This better preserves color spaces, loads multiple resolutions if the format supports it, and reduces memory usage. Simple bitmap formats will load as Immutable Bitmaps.

  • The ImageCount and IndexedImage properties provide a way to access the different bitmaps that comprise an image. It is possible for this to be zero.

  • Pictures in the project will be composited at build time if they have a mask or transparent property set. At runtime the picture will be loaded as an image.

  • Use Image Sets to add multi-resolution Images (with the same aspect ration) to a project.

  • When a Picture is drawn via DrawPicture or used in a UI element like a menu item, the best available representation is used. Vectors are rasterized (converted to bitmap) at the required size.

  • For Pictures that are used in user interface elements like menu items or bevel buttons, the chosen image representation is automatically recalculated when the backing store scale factor changes.

  • To convert from an Image to a Bitmap, a bitmap can be created with the desired pixel dimensions and then the source image drawn into it. This mirrors how a bitmap with a mask can be converted to a bitmap with an alpha channel.

  • Using DrawInto may result in scaling the image up or down if the backing store scale factor for the control's window does not match the targel's backing store scale factor.

Framework API changes

Application

SupportsHiDPI As Boolean (read-only)

You can only set this property in the Inspector for the Shared Build Settings. Set to ON to make the app HiDPI-aware. This is set to ON by default.

Picture

Constructor(width As Integer, height As Integer, bitmaps() As Picture)

This constructor creates an Image from one or more bitmap pictures.

Property Type As Types (read-only)

The type of this Picture. Used with the Types Enum.

Enum Types

An enumeration that contains all the valid picture types.

Enum HandleType.NSImage

An NSImage object that has been autoreleased, so an explicit release is not necessary. This is supported for all kinds of Pictures, including vector images. Supported in Mac GUI applications.

BestRepresentation(width As Integer, height As Integer, scale As Double) As Picture

Calculates which picture is the best to use for drawing at the requested size.

CopyOSHandle(width As Integer, height As Integer, scale As Double, type As Picture.HandleType) As Ptr

Returns a platform-specific image handle that is the best match for drawing at the given resolution, using the same logic as BestRepresentation.

Graphics

The Graphics class has the following changes.

Property ScaleX As Double

Property ScaleY As Double

The scale factor used when converting user space coordinates to backing store coordinates. These can be modified at runtime and must be greater than zero.

Graphics.Pixel

This is now deprecated. Use Picture as a replacement.

Window

The DesktopWindow class has the following changes.

Event Sub ScaleFactorChanged

The backing store scale factor has changed for this Window and the application should invalidate any cached bitmaps or other relevant state. This is only called for Mac apps.

Property ScaleFactor As Double (read-only)

The scale factor used when converting user space coordinates to backing store coordinates for this Window.

BitmapForCaching(width As Integer, height As Integer) As Picture

Returns a bitmap that is configured correctly for using as a cache for content to be drawn to this Window. Raises exceptions in the following cases:

  • InvalidArgumentException if width, height, or scale are less than or equal to zero.

  • OutOfMemoryException if the picture could not be allocated.

Canvas

Event Sub ScaleFactorChanged

The backing store scale factor has changed and the canvas should invalidate any cached bitmaps or other relevant state. This only gets called for Mac apps.

Other information

Windows HiDPI known issues