How do I let Picture track rgb bytes change?

I create a Picture from static RGB bytes via Pixbuf, and I hope the Picture can be re-rendered when RGB bytes change. Seems Picture can’t do this automatically, is there any way to do that?
Here was my code:

const SIZE: usize = 300 * 200;
const LEN: usize = SIZE * 3;
static mut RGB_BYTES: [u8; LEN] = [0; LEN];

fn main() {
    let app = Application::builder().application_id("com.pixbuf").build();

    app.connect_activate(build_ui);

    app.run();
}

fn change_rgb() {
    unsafe {
        for i in 0..LEN {
            RGB_BYTES[i] = match RGB_BYTES[i] {
                255 => 0,
                rgb => rgb + 1,
            };
        }
        println!("Rgb bytes changed.")
    }
}

fn build_ui(app: &Application) {
    unsafe {
        let pixbuf = Pixbuf::from_bytes(
            &Bytes::from_static(&RGB_BYTES),
            gtk::gdk_pixbuf::Colorspace::Rgb,
            false,
            8,
            300,
            200,
            300 * 3,
        );

        let picture = Picture::for_pixbuf(&pixbuf);
        picture.set_can_shrink(false);
        picture.set_halign(gtk::Align::Start);
        picture.set_valign(gtk::Align::Start);

        let window = ApplicationWindow::builder()
            .application(app)
            .title("Pixbuf")
            .child(&picture)
            .build();

        timeout_add_local(Duration::from_millis(100), || {
            change_rgb();
            Continue(true)
        });

        window.present();
    }
}

GdkPixbuf does not keep track of its contents, and it definitely does not know that you poked at its pixel buffer. GdkPixbuf is mostly just a simple linear buffer of RGB(A) pixels, with some additional code around it that lets you turn image data from various formats into that buffer of pixels.

After that point in your code, you would queue a redraw of the Picture widget. You will need to pass the widget to the change_rgb handler.

In addition to what @ebassi wrote, simply changing the pixel data in the background while something else is using the same data is generally a good idea unless you make sure there’s proper synchronization between both parts.

All the unsafe in this code should’ve been a red flag already :slight_smile:

Does this mean I should create a custom Picture and implements its snapshot() function, and do some operation in there to redraw the Picture? I simply put picture.queue_draw() after println macro, but nothing happened.

No, but I was wrong: queueing a redraw won’t work. I forgot that GtkPicture takes a copy of the Pixbuf to an immutable storage internally, so you will have to replace the GdkPixbuf inside the Picture widget by calling set_pixbuf() on it.

It works now. Thanks a lot!

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