gtk3pygtkhidpi

Gtk.Image on HiDPI displays


I use a Gtk.Image backed by a GdkPixbuf.Pixbuf to display a photo. I scale the photo to fit the available space in response to the size-allocate signal of the parent widget. The problem is that on HiDPI displays, every dimension is in logical pixels and not device pixels, therefore one the following happens:

How can I let GTK know that the Pixbuf I supply to the Image corresponds to device pixels and not logical pixels?

Update: This is what I have tried (these are simplified examples without any scaling on my part, just trying to display an image unscaled):

Attempt 1:

    image = Gtk.Image()
    image.set_from_file("subpixel.png")

Attempt 2:

    surface = cairo.ImageSurface.create_from_png("subpixel.png")
    image = Gtk.Image()
    image.set_from_surface(surface)

Attempt 3:

    pb = GdkPixbuf.Pixbuf.new_from_file("subpixel.png")
    image = Gtk.Image.new_from_pixbuf(pb)
    self.add(image)

Attempt 4:

    pb = GdkPixbuf.Pixbuf.new_from_file("subpixel.png")
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, pb.get_width(), pb.get_height())
    context = cairo.Context(surface)

    Gdk.cairo_set_source_pixbuf(context, pb, 0, 0)
    context.paint()

    image = Gtk.Image()
    image.set_from_surface(surface)

Solution

  • This is typically done by creating a cairo surface from the pixel data and then using gtk_image_set_from_surface(). I don't speak Python, but in C I do it like this:

    GdkPixbuf *pb = gdk_pixbuf_new_from_file(file, NULL);
    
    if(pb) {
    
        cairo_surface_t *s = gdk_cairo_surface_create_from_pixbuf(pb, 0, gtk_widget_get_window(w));
    
        if(s) {
            gtk_image_set_from_surface(GTK_IMAGE(w), s);
            cairo_surface_destroy(s);       
        }
    
        g_object_unref(pb);
    }
    

    This works fine here. In contrast to gtk_image_set_from_file() it won't use logical pixels but device pixels so no scaling will ever be applied.