Can create & save an image; but can't load, modify & save one


#1

Here is some code that works fine:

extern crate image;
extern crate imageproc;

use std::path::Path;
use image::{Rgba, RgbaImage};
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();
}

However, when I add this code at the end:

    let mut img = image::open(path).unwrap();
    draw_filled_rect_mut(&mut img,
                         imageproc::rect::Rect::at(75, 75).of_size(25, 25),
                         blue);
    img.save(path).unwrap();

I get this error:

error[E0061]: this function takes 2 parameters but 1 parameter was supplied
  --> src/main.rs:28:9
   |
28 |     img.save(path).unwrap();
   |         ^^^^ expected 2 parameters

What I’m trying to do is load in a .png image, then draw some semi-transparent rectangles on it, then save it back again under the original name.


#2

Your using two different data types so there are two different functions.
Just add the format to save


#3

I tried img.save(path, ImageFormat::PNG) but it doesn’t work because it expects an image buffer not a path.


#4

More accurately, the function expects a writer. Ergo, you need to open the corresponding file before writing to it, the save() function will not open it for you (unlike with the other image type).

It might be a good idea to open a ticket about this interface inconsistency.


#5

Thanks, your hint allowed me to create this which works:

    let mut img = image::open(path).unwrap();
    draw_filled_rect_mut(
        &mut img, imageproc::rect::Rect::at(75, 75).of_size(25, 25),
        blue);

    let mut file = File::create(path).unwrap();
    img.save(&mut file, ImageFormat::PNG).unwrap();

#6

I have now discovered that when I paint a semi-transparent rectangle, it completely obliterates what it covers rather than allowing what was there before to show through in the places the rectangle is semi-transparent. Here’s an example:

extern crate image;
extern crate imageproc;

use std::fs::File;
use std::path::Path;
use image::{ImageFormat, Rgba, RgbaImage};
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 magenta = Rgba([255u8, 0u8, 255u8, 127u8]);

    let mut img = image::open("1.png").unwrap();
    draw_filled_rect_mut(
        &mut img, imageproc::rect::Rect::at(10, 10).of_size(75, 75),
        magenta);

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

The 2.png has 2 rectangles, the second (magenta) one is semi-transparent and overlaps the first (red) one. And the red one should also show-through some of the white background so really ought to appear to be pink.

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