How can I pass a GenericImage?


#1

I often hit a problem when trying to refactor in Rust: I often don’t know the types of the values I need to pass to my refactored function. I normally solve this by setting the type to u8 and then usually the Rust compiler tells me what it wants.

However, I am finding it impossible to pass a GenericImage. I tried copying from the source code of one of the imageproc’s draw functions, but still I can’t get this to compile:

extern crate conv;
extern crate image;
extern crate imageproc;

use conv::ValueInto;
use std::fs::File;
use std::path::Path;
use image::{GenericImage, ImageFormat, Pixel, Rgba, RgbaImage};
use imageproc;
use imageproc::drawing::draw_filled_rect_mut;

fn main() {
    let path = Path::new("1.png");

    let white = Rgba([255u8, 255u8, 255u8, 255u8]);
    let red = Rgba([255u8, 0u8, 0u8, 127u8]);
    let blue = Rgba([0u8, 0u8, 255u8, 127u8]);

    let mut img = RgbaImage::new(200, 200);
    draw_filled_rect_mut(&mut img,
                         imageproc::rect::Rect::at(0, 0).of_size(200, 200),
                         white);
    draw_filled_rect_mut(&mut img,
                         imageproc::rect::Rect::at(50, 50).of_size(50, 50),
                         red);
    img.save(path).unwrap();

    let mut img = image::open("1.png").unwrap();
    draw_rect(&mut img);

    let mut file = File::create("2.png").unwrap();
    img.save(&mut file, ImageFormat::PNG).unwrap();
}

fn draw_rect<'a, I>(img: &'a mut I)
    where I: GenericImage,
          <I::Pixel as Pixel>::Subpixel: ValueInto<f32> + 
          imageproc::definitions::Clamp<f32> {
    let magenta = Rgba([255u8, 0u8, 255u8, 127u8]);
    draw_filled_rect_mut(
        &mut img, imageproc::rect::Rect::at(10, 10).of_size(75, 75),
        magenta);
}

The error is:

error[E0277]: the trait bound `&'a mut I: image::GenericImage` is not satisfied
  --> src/main.rs:39:5
   |
39 |     draw_filled_rect_mut(
   |     ^^^^^^^^^^^^^^^^^^^^ the trait `image::GenericImage` is not implemented for `&'a mut I`
   |error[E0277]: the trait bound `&'a mut I: image::GenericImage` is not satisfied
  --> src/main.rs:39:5
   |
39 |     draw_filled_rect_mut(
   |     ^^^^^^^^^^^^^^^^^^^^ the trait `image::GenericImage` is not implemented for `&'a mut I`
   |
   = note: required by `imageproc::drawing::draw_filled_rect_mut`

For the moment my workaround is to refactor everything except the draw*() call, but I’d prefer to do it right.

BTW Is semi-transparent drawing possible using image & imageproc, & if so, how?


#2

In the call to draw_filled_rect_mut() in the function draw_rect() you dont need &mut img only img


#3

That just produces a different error. In my experience so far if you want to change something in rust you must pass it as &mut.


#4

This works for me:

fn draw_rect(img: &mut DynamicImage) {

    let magenta = Rgba([255u8, 0u8, 255u8, 127u8]);
    draw_filled_rect_mut(
        img, imageproc::rect::Rect::at(10, 10).of_size(75, 75),
        magenta);
}


#5

The problem here is that in your draw_rect, img is already a &mut I. Which means that what you are passing to draw_filled_rect_mut is a &mut &mut I, and that doesn’t fulfill the trait requirement.

So as @elsuizo says, pass in img. If it still produces an error, please let us know the exact code you tried and the exact error.


#6

@elsuizo thank you – that worked perfectly (& was much simpler than my original)!