image-rs / image

Encoding and decoding images in Rust
Apache License 2.0
4.85k stars 596 forks source link

Iterating over grayscale image returns RGBA8 #771

Open medakk opened 6 years ago

medakk commented 6 years ago

I'm a bit confused by the API of this package. I loaded an image from a JPEG file, used grayscale() to convert it to grayscale, and then iterated over it. But the iterator function returns Rgba pixels. Should it not return a single value per pixel, now that it is grayscale?

extern crate image;

use image::GenericImage;

fn main() {
    let mut args = std::env::args();
    args.next();

    let filename: String = args.next().unwrap();
    let image = image::open(filename).unwrap();

    let width = image.width() as f32;
    let height = image.height() as f32; 

    let image = image.resize_exact(
        (width * 0.25) as u32,
        (height * 0.25) as u32,
        image::Nearest,
    );

    let image = image.grayscale();

    for (x, y, pixel) in image.pixels() {
        // pixel is Rgba<u8>
    }
}
noblehelm commented 6 years ago

Might be a bug with the grayscale() function (should it return a GrayImage or ImageBuffer<Luma> instead of DynamicImage?). In the meantime, try using the .to_luma() function to see if it works.

peterbraden commented 4 years ago

I think there's an underlying bug with the luma image, see:

  137         let mut img = image::DynamicImage::new_luma_a8(self.width as u32, self.height as u32); |  ~
  138         for x in 0..self.width {                                                               |  ~
  139             for y in 0..self.height {                                                          |  ~
  140                 let val = 255 * self.data[x * self.width + y] as u8;                           |  ~
  141                 img.put_pixel(x as u32, y as u32, image::LumaA([val, val]));                   |  ~
  142             }                                                                                  |  ~
  143         }                                                                                      |  ~
  144         let mut buf = Vec::new();                                                              |  ~
  145         img.write_to(&mut buf, image::ImageOutputFormat::Png).expect("Unable to write");       |  ~
  146         return buf;

and I get:

error[E0308]: mismatched types
   --> src/heatmap.rs:142:51
    |
142 |                 img.put_pixel(x as u32, y as u32, image::LumaA([val, val]));
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `image::color::Rgba`, found struct `image::color::LumaA`
    |
    = note: expected struct `image::color::Rgba<u8>`
               found struct `image::color::LumaA<u8>`
aschampion commented 4 years ago

DynamicImage::put_pixel always takes an Rgba. If you want to use a particular image type, use it directly (like GrayAlphaImage), and it will use ImageBuffer::put_pixel, which takes the particular pixel type for that image.

fintelia commented 4 years ago

Also, you can convert a DynamicImage to a specific ImageBuffer type by matching on the enum