Working With HiDPI Images

Is there a general guide to working with images in HiDPI? In Fractal we have an issue where all of the images we show are blurry on HiDPI screens. Our code for displaying images is here.

If I could learn how to adjust things properly for HiDPI that would be wonderful :slight_smile:

a) Do not draw pixbufs every frame. They are just being converted to a cairo surface and then rendered
b) I think the problem is just that the draw function here is doing scaling itself, but in application pixels?
c) Please don’t call set_size_request() in draw.

The only one I know, is an How Do I wiki page on HiDPI.

In general, though, what you want when dealing with drawing assets at different scales are… assets at different scales, unless you’re rendering an SVG.

If you have a raster asset, you could store it as the maximum possible scale and then render downscaled it at the actual scale of the widget—though that will end up with some blurriness caused by the bilinear filtering. Of course, you cannot upscale any asset because any interpolating filter we have cannot make up information it doesn’t have.

If you don’t control the assets then there isn’t anything you can do: small images upscaled will look blurry. It’s a fact of life.

Looking at the code, and adding on top of what Timm already said:

  • HiDPI means that the sizes will remain constant across different scaling factors; a widget size will stay at (say) 128x128 pixels regardless of scale=1 or scale=2. What HiDPI really does is changing the size of a pixel. This means that if you have an asset that is sized at 128x128 pixels at scale=1 you will need an asset sized at 256x256 pixels as scale=2. As I said above, we don’t have an interpolation filter that can make up information that isn’t there, which means that you will need to ship N assets for any scaling factor you wish to support
  • don’t use GdkPixbuf except to load data; shove the image data into a Cairo image surface and keep the surface around
  • reload the image data whenever the scaling factor changes; GdkPixbuf has no concept of a scale except when loading the image data, which means it’s up to you to reload the data when the scale changes
  • seriously: don’t use GdkPixbuf except to load data, and make sure when loading to tell both GdkPixbuf and the image surface what kind of device scale you’re going to use
  • if you create an image surface using Gdk.Window.create_similar_image_surface() then you’ll be able to tell Cairo the scaling factor for the surface. This will ensure that the rendering is kept in sync with the expectations of GTK

So, in short, to deal with HiDPI:

  • if you ship assets, you need to have different ones for each scaling factor
  • you need to load your assets depending on the scaling factor of the widget
  • you need to reload your assets if the scaling factor changes
  • use Cairo, not GdkPixbuf, and keep the device scale in sync between Cairo surface and GTK widget
  • never upscale assets, only downscale them
1 Like

Thanks for the detailed response :slight_smile: I appreciate it.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.