Gtk.Image在HiDPI显示器上的显示问题

8
我使用一个由 GdkPixbuf.Pixbuf 支持的 Gtk.Image 来显示照片。我根据父部件的 size-allocate 信号来缩放照片以适应可用空间。问题是,在 HiDPI 显示器上,每个维度都是逻辑像素而不是设备像素,因此会出现以下一种情况:
  • 如果我将 GdkPixbuf.Pixbuf 缩放到从 size-allocate 信号中获得的尺寸,照片将占据所需的物理空间,但它只使用了显示器分辨率的一半(假设为2:1的设备像素比逻辑像素)。
  • 如果我将 GdkPixbuf.Pixbuf 缩放到 get_scale_factor() 倍于从size-allocate 信号中获得的尺寸,则照片将占用两倍的物理空间(即,它将无法适应窗口)。

如何让GTK知道我提供给Image的 Pixbuf 对应于设备像素而不是逻辑像素?

更新:这是我尝试过的(这些都是简单的示例,没有进行任何缩放,只是尝试显示未缩放的图像):

尝试1:

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

第二次尝试:
    surface = cairo.ImageSurface.create_from_png("subpixel.png")
    image = Gtk.Image()
    image.set_from_surface(surface)

第三次尝试:

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

第四次尝试:
    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)
1个回答

3

通常通过从像素数据创建cairo表面,然后使用gtk_image_set_from_surface()来完成。我不说Python,但在C中我会这样做:

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);
}

这里的代码可以正常使用。与gtk_image_set_from_file()不同,它不使用逻辑像素而是设备像素,因此永远不会应用缩放。


哇,我没想到一年多后还有回复。:) 不幸的是,我在Python中无法让这种方法工作,因为我没有找到与gdk_cairo_surface_create_from_pixbuf等效的东西。我尝试了一些类似的方法(添加到我的问题中),但它们都已经应用了缩放。 - Zoltan
@Zoltan:你可以查看gdk_cairo_surface_create_from_pixbuf如何设置cairo表面,并尝试在Python中复制它。我上面的代码绝对可以解决问题。我发现你的问题是因为我和你有同样的问题,只是我使用的是C而不是Python。 - Andreas
1
@Andreas,我无法感谢你的足够,这个问题让我疯狂了,几周前我发现这个问题时没有答案。这个解决方案完美地修复了我的应用程序在HiDPI显示器上的缺陷。 - Scoopta
我自己还没有尝试过这个答案,但基于@Scoopta的评论,我打算接受它。 - Zoltan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接