GTK4 How to properly display a huge image

I need to display an image that could potentially have a very large height >30_000 pixels.
To check if GTK can render such an image, I generated it with imagemagick:
convert -size 2000x80000 xc:green green.png.

When I try to open an image, I get the following message:
gdk_memory_texture_new_subtexture: assertion 'x < 0 || x >= GDK_TEXTURE (source)->width' failed.

After some attempts, I came to the conclusion that there is no error only if the image size fits into 32768x32768.
If you dig even deeper, this number can be seen by running in the terminal: glxinfo -l | grep GL_MAX_TEXTURE_SIZE.

Now I have a few questions.

How can you get a similar or similar GL_MAX_TEXTURE_SIZE value in GTK4 taking into account that there is OpenGL and Vulkan?

How to properly display images with such a high resolution in GTK4?

Test code:

int main(string[] args) {
  var app = new Gtk.Application(null, GLib.ApplicationFlags.FLAGS_NONE);

  app.activate.connect(() => {
    var win = new Gtk.ApplicationWindow(app);
    var sw = new Gtk.ScrolledWindow();
    var picture = new Gtk.Picture.for_filename("./green.png");

    with(sw) {
      hexpand = true;
      vexpand = true;
      child = picture;
    }

    win.child = sw;
    win.present();
  });

  return app.run(args);
}

That’s the maximum size for a Cairo image surface.

The maximum texture size is more likely going to be 8k or 16k pixels maximum, given that it’s generally related to the hardware.

You should not load the whole image into a single texture: you should tile it into multiple buffers, instead.

For large image data, I recommend using Gegl, which is meant to be used for that role.

@ebassi Thanks for the answer.
I tried to upload an image via Gegl, but it didn’t work and I couldn’t find the right example.

Could you see what I’m doing wrong or show an example of rendering an image in GTK4 using Gegl?

int main(string[] args) {
  Gegl.init(ref args);

  var path = "/path/to/green.png";

  var app = new Gtk.Application(null, GLib.ApplicationFlags.FLAGS_NONE);

  app.activate.connect(() => {
    var win = new Gtk.ApplicationWindow(app);
    var sw = new Gtk.ScrolledWindow();

    int w, h;

    Gdk.Pixbuf.get_file_info(path, out w, out h);
    var pb = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, w, h);
    
    var root = new Gegl.Node();
    var to_pixbuf = root.new_child("operation", "gegl:pixbuf", "pixbuf", pb, null);
    var load = to_pixbuf.new_child("operation", "gegl:load", "path", path, null);

    root.link_many(to_pixbuf, load, null);

    var picture = new Gtk.Picture.for_pixbuf(pb);

    with(sw) {
      hexpand = true;
      vexpand = true;
      child = picture;
    }

    win.child = sw;
    win.present();
  });

  return app.run(args);
}

You are just taking the image from the Gegl buffer and then putting it into a GdkPixbuf in order to draw: you are not going to get around the limits on texture size.

You will need to write a widget that renders each tile in the Gegl buffer independently.

Alternatively, you’ll need to scale the Gegl buffer and compute its contents at different zoom factors.

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