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

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.

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

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

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.

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();

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?