use clap::Parser;
use image::ImageReader;
use image::DynamicImage;
use std::io::{stdin, stdout, Write};
use std::path::PathBuf;
use tilr::Mosaic;
#[derive(Debug, Parser)]
#[clap(
author,
version,
about,
long_about = r#"A program to build a mosaic of an image from a set of smaller image 'tiles'
Copyright (C) 2023 Charles German <5donuts@pm.me>
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
See the GNU General Public License for more details. You should have received a copy of the
GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>."#
)]
struct Args {
#[clap(value_parser)]
src_image: PathBuf,
#[clap(short, long, default_value = "tiles/", value_parser)]
tile_dir: PathBuf,
#[clap(short, long, default_value = "mosaic.png", value_parser)]
output: PathBuf,
#[clap(short, long, default_value = "1.0")]
scale: f32,
#[clap(long, default_value = "8")]
tile_size: u8,
}
fn main() {
let args = Args::parse();
let src_image = args.src_image;
let tile_dir = args.tile_dir;
let scale = args.scale;
let tile_size = args.tile_size;
let output = args.output;
eprint!("Loading input image...");
let img = ImageReader::open(&src_image).expect("Unable to read image file.");
let img = img.decode().expect("Unable to decode image file.");
let img = img.into_rgb8(); eprintln!("done.");
eprint!("Loading tiles...");
let tiles = tilr::load_tiles(&tile_dir).expect("Error loading tiles");
eprintln!("done.");
eprint!("Initializing mosaic canvas...");
let mosaic = Mosaic::new(DynamicImage::ImageRgb8(img), &tiles, scale, tile_size);
eprintln!("done.");
let (mos_x, mos_y) = mosaic.output_size();
if user_confirm(&*format!(
"Resulting mosaic will be a {}px x {}px image. Continue y/N? ",
mos_x, mos_y
)) {
let mosaic = mosaic.to_image();
eprint!("Saving image to {}...", &output.display());
mosaic.save(output).expect("Error saving mosaic.");
eprintln!("done.");
}
}
fn user_confirm(prompt: &str) -> bool {
print!("{}", prompt);
let _ = stdout().flush();
let mut s = String::new();
stdin().read_line(&mut s).unwrap();
let s = s.to_lowercase().chars().next().unwrap();
if s != 'y' && s != 'n' {
eprintln!("Unrecognized input; expected 'y' or 'n'.");
}
s == 'y'
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_cli() {
use clap::CommandFactory;
Args::command().debug_assert()
}
}