0

I'm trying to modify a pixbuf when the left mouse button is clicked but I don't think it's being modified. The modify_pixel function simply takes a specific pixel from the pixbuf and modifies it.

fn build_ui(application: &Application) {
    
    let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
    let pixbuf = Rc::new(RefCell::new(pixbuf));
    
    let gesture = GestureClick::new();

    let pixbuf_clone = Rc::clone(&pixbuf);

    
    gesture.connect_pressed(move |_gesture, _n_press, x, y| {
        let mut pixbuf = pixbuf_clone.borrow_mut();
        let position = [x as usize, y as usize];
        if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
            modify_pixel(&mut pixbuf, position);
        } else {
            println!("Out of bounds");
        }
    });

    let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("No se pudo crear el Picture"));


    let window = ApplicationWindow::builder()
        .application(application)
        .default_height(800)
        .default_width(800)
        .title("My GTK App")
        .build();
    window.set_child(Some(&picture));
    window.add_controller(gesture);
    window.present();
}
fn modify_pixel(pixbuf: &mut Pixbuf, position: [usize;2]){
    let pixels = unsafe {pixbuf.pixels()};
    let rowstride = pixbuf.rowstride() as usize;
    let n_channels = pixbuf.n_channels() as usize;

    
    let offset = position[1] * rowstride + position[0] * n_channels;

    let mut pixels = pixels.to_vec(); 
    pixels[offset] = 255;  
    pixels[offset + 1] = 0;  
    pixels[offset + 2] = 0;  
    *pixbuf = Pixbuf::from_mut_slice(
        pixels,
        Colorspace::Rgb,
        pixbuf.has_alpha(),
        8, 
        pixbuf.width(),
        pixbuf.height(),
        rowstride as i32,
    );
}

I'm also not sure if using a Gesture is the most appropriate option. I tried to modify the picture inside the clause but I had the same problem

1 Answer 1

0

You need to use set_pixbuf in order to update the Pixbuf like so:

fn build_ui(application: &Application) {
    let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
    let pixbuf = Rc::new(RefCell::new(pixbuf));
    let pixbuf_clone = Rc::clone(&pixbuf);
    
    let gesture = GestureClick::new();

    let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("Failed to load image."));

    let window = ApplicationWindow::builder()
        .application(application)
        .default_height(800)
        .default_width(800)
        .title("GTK Pixbuf test")
        .build();
    window.set_child(Some(&picture));

    gesture.connect_pressed(move |_gesture, _n_press, x, y| {
        let mut pixbuf = pixbuf_clone.borrow_mut();
        let position = [x as usize, y as usize];
        if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
            modify_pixel(&mut pixbuf, position);
            picture.set_pixbuf(Some(&pixbuf));
        } else {
            println!("Out of bounds");
        }
    });

    window.add_controller(gesture);
    window.present();
}

This will change the pixel to red when clicking on the image with the mouse.

I suppose this is not exactly what you would like to do though, for which reason, I would suggest looking into the DrawingArea example.

Pixbuf related methods are deprecated since GTK v4.12 btw. and should be replaced by paintable as can be seen below:

fn build_ui(application: &Application) {
    let pixbuf = Pixbuf::from_file("assets/blank.png").expect("msg");
    let pixbuf = Rc::new(RefCell::new(pixbuf));
    let pixbuf_clone = Rc::clone(&pixbuf);

    let gesture = GestureClick::new();

    let picture = Picture::for_paintable(&Texture::for_pixbuf(&pixbuf.borrow()));

    let window = ApplicationWindow::builder()
        .application(application)
        .default_height(800)
        .default_width(800)
        .title("GTK Pixbuf test")
        .build();
    window.set_child(Some(&picture));

    gesture.connect_pressed(move |_gesture, _n_press, x, y| {
        let mut pixbuf = pixbuf_clone.borrow_mut();
        let position = [x as usize, y as usize];
        if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
            modify_pixel(&mut pixbuf, position);
            picture.set_paintable(Some(&Texture::for_pixbuf(&pixbuf)));
        } else {
            println!("Out of bounds");
        }
    });

    window.add_controller(gesture);
    window.present();
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.