How do I copy contents of image into an image buffer?

I'm trying to extract the pixels of an image and write each pixel into a different set of coordinates on an Image buffer. Right now I'm just trying to copy them verbatim

use image::{GenericImageView, ImageBuffer, DynamicImage, ImageResult, Pixel, Rgb};
use std::path::Path;

pub fn load_image<P> (path: P) -> ImageResult<DynamicImage> where P: AsRef<Path> {
    image::open(path)
}


/*
    creates a new image buffer to 
ImageBuffer<T::Pixel, Vec<<<T as image::GenericImageView>::Pixel as Trait>::Subpixel> 
*/
pub fn mount_image<T: GenericImageView, P: Pixel>((x, y): (u32, u32), input: T, clearValue: P) {
    let mut imageBuffer = ImageBuffer::new(x, y);
    for (x, y, pixel) in imageBuffer.enumerate_pixels_mut() {
        *pixel = clearValue.clone();
    }

    for (x, y, pixel) in input.pixels() {
        //let img_pixel = input.get_pixel(x, y);
        imageBuffer.put_pixel(x, y, pixel.clone());
    }

    imageBuffer;
}


I'm currently getting this error

error[E0308]: mismatched types
 --> src/raybar/examples/isomorph.rs:21:37
  |
21|         imageBuffer.put_pixel(x, y, pixel.clone());
  |                                     ^^^^^^^^^^^^^ expected type parameter, found associated type
  |
  = note: expected type `P`
             found type `<T as image::GenericImageView>::Pixel`
  = note: you might be missing a type parameter or trait bound

I don't quite know how to act on this. as I understand it, a DynamicImage in the image crate implements GenericView which is why I'm putting it in there.

Basically I just want to copy each pixel into the second image buffer and return it.

I also tried replacing P with T::Pixel


pub fn mount_image<T: GenericImageView>((x, y): (u32, u32), input: T, clearValue: T::Pixel) {
    let mut imageBuffer = ImageBuffer::new(x, y);
    for (x, y, pixel) in imageBuffer.enumerate_pixels_mut() {
        *pixel = clearValue.clone();
    }

    for (x, y, pixel) in input.pixels() {
        //let img_pixel = input.get_pixel(x, y);
        imageBuffer.put_pixel(x, y, pixel.clone());
    }

    imageBuffer;
}


instead I'm now getting an error refering to lifetimes

error[E0310]: the associated type `<T as image::GenericImageView>::Pixel` may not live long enough
  --> src/raybar/examples/isomorph.rs:15:38
   |
15 |     for (x, y, pixel) in imageBuffer.enumerate_pixels_mut() {
   |                                      ^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as image::GenericImageView>::Pixel: 'static`...
note: ...so that the type `<T as image::GenericImageView>::Pixel` will meet its required lifetime bounds
  --> src/raybar/examples/isomorph.rs:15:38
   |
15 |     for (x, y, pixel) in imageBuffer.enumerate_pixels_mut() {
   |                                      ^^^^^^^^^^^^^^^^^^^^

Many of ImageBuffer's methods require that P is 'static. Follow the advice and add the 'static bound and you may get farther. In your most recent example, without an explicit P, that would look like:

where T::Pixel: 'static

THANKYOU @cbiffle this solved my issue. for other,s here's what the final code looked like

pub fn mount_image<T: GenericImageView>((x, y): (u32, u32), input: T, clearValue: T::Pixel) -> ImageBuffer<T::Pixel, Vec<<<T as image::GenericImageView>::Pixel as image::Pixel>::Subpixel>> where T::Pixel: 'static {
    let mut imageBuffer = ImageBuffer::new(x, y);
    for (x, y, pixel) in imageBuffer.enumerate_pixels_mut() {
        *pixel = clearValue.clone();
    }

    for (x, y, pixel) in input.pixels() {
        //let img_pixel = input.get_pixel(x, y);
        imageBuffer.put_pixel(x, y, pixel.clone());
    }

    imageBuffer
}


You are doing a lot of manual work, if I read the definitions right, something like this should do the same thing:

use image::GenericImage;
pub fn mount_image<T: GenericImageView>(
    (x, y): (u32, u32),
    input: T,
    clearValue: T::Pixel,
) -> ImageBuffer<T::Pixel, Vec<<T::Pixel as Pixel>::Subpixel>>
where
    T::Pixel: 'static,
{
    let mut imageBuffer = ImageBuffer::from_pixel(x, y, clearValue);
    imageBuffer.copy_from(&input, 0, 0);
    imageBuffer
}

ah I see, what exactly is the purpose of the as Pixel part anyway? is there a place I can read about how this works? is it somehow looking into the Pixel definition I imported from the image crate?

According to the error, it's to tell the compiler the exact associated type you are referring to (in case T::Pixel implements two traits with an associate type named Subpixel).

But I guess the compiler could find out on its own. So maybe I'm wrong and it can't, or it's to speed up compilation a bit (the compiler doesn't have to chase down the trait) or to increase readability and avoid having to chase down the trait.

1 Like