如何在 Vala 中将图像调整为 window 大小

How to resize an Image to window size in Vala

我正在尝试创建一个小应用程序来显示您在文件选择器中选择的图像os。当用户调整 window.

大小时,它应该会调整大小

我的应用程序可以正常工作,我将此代码添加到 class 的构造函数中,这应该使图像能够在 window 调整大小时调整大小。

window.size_allocate.connect(() => {

        resize_image(); //<-- a problem

    });

这个 "should" 在 window 改变它的大小时调用方法 resize_image 但是每次我添加这段代码时,我的虚拟机 运行 elementary os 崩溃并停止工作(我每次尝试 运行 我的程序时都必须重新启动)。

方法 resize_image() 的工作原理如下:

public void resize_image()
{
    try
    {       if(buf.get_width() < window.get_allocated_width()){
            buf = buf.scale_simple(window.get_allocated_width(), window.get_allocated_width(), Gdk.InterpType.NEAREST); 
            image.set_from_pixbuf(buf);
            }      
    }catch(Error e)
    {
    }
}

(我知道我的调整大小 "alogrithm" 还不是最好的,但我只是用这种方法进行测试。)

现在我的问题是: 为什么我的程序崩溃了?从 pixbuf 到图像的转换对用户来说太慢了吗? 有没有其他方法可以将图像调整为 window 大小?

任何帮助将不胜感激:)

这里的技巧是添加布局并将调整大小回调设置为布局而不是 window。它并不完美,它有点脏但有效。初始定位效果不佳,但仍有改进空间。 必须检查 Gtk.Widget 和 Gtk.Containers 请求、分配和自然大小,甚至使用 Gdk 方法。来晚了,希望这会引导你朝着正确的方向前进。

PS:我正在使用 endless.png 图片,但您可以随意使用另一张图片,只需更改代码以反映它。

using Gtk;

public int main (string[] args) {
    Gtk.Image image;
    Gtk.Layout layout;
    Gtk.Window window;
    Gdk.Pixbuf pixbuf;

    Gtk.init (ref args);

    window = new Gtk.Window ();
    layout = new Gtk.Layout (); 
    image  = new Gtk.Image ();

    try {
        pixbuf = new Gdk.Pixbuf.from_file ("endless.png");
        image = new Gtk.Image.from_pixbuf (pixbuf); 
        layout.put (image, 0,0);
        window.add (layout);

        layout.size_allocate.connect ((allocation) => {
            print ("Width: %d Height: %d\n", allocation.width, allocation.height);
            var pxb = pixbuf.scale_simple (allocation.width, allocation.height, Gdk.InterpType.BILINEAR);
            image.set_from_pixbuf (pxb);
        });

        window.destroy.connect (Gtk.main_quit);

        window.show_all ();

        Gtk.main ();

        return 0;
    } catch (Error e) {
        stderr.printf ("Could not load file...exit (%s)\n", e.message);
        return 1;
    }
}

编辑:

一个简单的开罗版本:

using Gtk;
using Cairo;

public int main (string[] args) {
    Cairo.ImageSurface image;

    image = new Cairo.ImageSurface.from_png ("endless.png");

    Gtk.init (ref args);

    var window = new Gtk.Window ();
    var darea  = new DrawingArea ();
    window.add (darea);
    window.show_all ();

    darea.draw.connect ((cr) => {
        float xscale;
        float yscale;

        cr.save ();

        xscale = (float) darea.get_allocated_width () / image.get_width ();
        yscale = (float) darea.get_allocated_height () / image.get_height ();

        cr.scale (xscale, yscale);
        cr.set_source_surface (image, 0, 0);
        cr.paint ();

        cr.restore ();
        return true;
    });

    window.destroy.connect (Gtk.main_quit);

    Gtk.main ();

    return 0;
}

编辑 2: 我已经创建了另一个版本来在 2 个图像之间切换并检查是否在执行此操作时多次并检查内存是否增加,但它没有。添加了几个框,并添加了 2 个按钮。

using Gtk;
using Cairo;

public int main (string[] args) {
    Cairo.ImageSurface image;

    image = new Cairo.ImageSurface.from_png ("endless.png");

    Gtk.init (ref args);

    var window = new Gtk.Window ();
    var box1   = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); 
    var box2   = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 
    var b1     = new Gtk.Button.with_label ("Image1");
    var b2     = new Gtk.Button.with_label ("Image2");
    box2.pack_start (b1, true, true, 0);
    box2.pack_end (b2, true, true, 0);
    var darea  = new DrawingArea ();
    box1.pack_start (box2, false, false, 0);
    box1.pack_end (darea, true, true, 0);
    window.add (box1);
    window.show_all ();

    b1.clicked.connect (() => {
        image = new Cairo.ImageSurface.from_png ("endless.png");
        darea.queue_draw ();
    });

    b2.clicked.connect (() => {
        image = new Cairo.ImageSurface.from_png ("Gnome-logo.png");
        darea.queue_draw ();
    });

    darea.draw.connect ((cr) => {
        float xscale;
        float yscale;

        cr.save ();

        xscale = (float) darea.get_allocated_width () / image.get_width ();
        yscale = (float) darea.get_allocated_height () / image.get_height ();

        cr.scale (xscale, yscale);
        cr.set_source_surface (image, 0, 0);
        cr.paint ();

        cr.restore ();
        return true;
    });

    window.destroy.connect (Gtk.main_quit);

    Gtk.main ();

    return 0;
}