From 26b3301a043abf56d1530d06c3ed4ba0b42398e6 Mon Sep 17 00:00:00 2001 From: markichnich Date: Sun, 17 Mar 2024 20:41:35 +0100 Subject: [PATCH] add arg parsing for previously hardcoded variables --- Cargo.lock | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/cli.rs | 45 +++++++++++++++ src/main.rs | 51 +++++++++++------ 4 files changed, 241 insertions(+), 16 deletions(-) create mode 100644 src/cli.rs diff --git a/Cargo.lock b/Cargo.lock index f891b85..a515d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,54 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -54,12 +102,45 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "crc32fast" version = "1.4.0" @@ -268,6 +349,7 @@ dependencies = [ name = "pic2string" version = "0.1.0" dependencies = [ + "clap", "image", ] @@ -340,6 +422,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "tiff" version = "0.9.1" @@ -351,6 +439,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "webp" version = "0.2.6" @@ -366,6 +460,72 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "zune-inflate" version = "0.2.54" diff --git a/Cargo.toml b/Cargo.toml index d72b9a7..6864838 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.5.3", features = ["cargo"] } image = { version = "0.24.9", features = ["libwebp"] } diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..a9c7438 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,45 @@ +use clap::{command, value_parser, Arg, ArgAction, Command, ValueHint}; + +pub fn new() -> Command { + command!() + .about("Simply convert images to ASCII art") + .arg( + Arg::new("input") + .help("Input image file") + .action(ArgAction::Set) + .value_name("INPUT_FILE") + .value_parser(value_parser!(std::path::PathBuf)) + .value_hint(ValueHint::FilePath) + .required(true), + ) + .arg( + Arg::new("output") + .short('o') + .long("output") + .help("Optional output text file - If omitted, writes to stdout") + .action(ArgAction::Set) + .value_name("FILE") + .value_parser(value_parser!(std::path::PathBuf)) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("size") + .short('s') + .long("size") + .help("Output size in characters along the larger of the images dimensions") + .action(ArgAction::Set) + .value_name("INTEGER") + .value_parser(value_parser!(u32)) + .default_value("25"), + ) + .arg( + Arg::new("x-stretch") + .short('x') + .long("x-stretch") + .help("Factor to stretch the image by along its horizontal") + .action(ArgAction::Set) + .value_name("FLOAT") + .value_parser(value_parser!(f64)) + .default_value("2.3"), + ) +} diff --git a/src/main.rs b/src/main.rs index bd5fdd6..c288286 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,28 @@ -use std::env; use image::GenericImageView; +use std::{fmt, fs::File, io, path::PathBuf}; + +mod cli; const SYMBOLS: &[char] = &[' ', '.', ':', '-', '=', '+', '*', '#', '%', '@']; -const PIXEL_SIZE: f64 = 25.0; -const X_STRETCH: f64 = 2.0; fn main() -> Result<(), &'static str> { - let filename: String; - match env::args().into_iter().nth(1) { - None => return Err("No filename provided."), - Some(arg) => filename = arg, - } + let matches = cli::new().get_matches(); - let img = image::open(filename).unwrap(); + let input_file: &PathBuf = matches.get_one("input").unwrap(); + let x_stretch: f64 = *matches.get_one("x-stretch").unwrap(); + let size: u32 = *matches.get_one("size").unwrap(); + + let img = image::open(input_file).unwrap(); let (w, h) = img.dimensions(); - let a = u32::max(h, w) as f64 / PIXEL_SIZE; - let w = (w as f64 / a * X_STRETCH) as u32; - let h = (h as f64 / a) as u32; + let scale = size as f64 / u32::max(h, w) as f64; + let w = (w as f64 * scale * x_stretch) as u32; + let h = (h as f64 * scale) as u32; let resized = img.resize_exact(w, h, image::imageops::FilterType::Nearest); - resized.pixels() + let data = resized + .pixels() .map(|(_, _, color)| { let sum: u16 = color.0.iter().take(3).map(|&v| v as u16).sum::(); let normalized = sum as f64 / (3.0 * 255.0); @@ -31,9 +32,27 @@ fn main() -> Result<(), &'static str> { }) .collect::>() .chunks(w as usize) - .for_each(|chunk| { - println!("{}", chunk.iter().collect::()) - }); + .fold( + String::with_capacity((size as usize).pow(2)), + |mut s, line| { + fmt::Write::write_str(&mut s, &line.iter().chain(&['\n']).collect::()) + .unwrap(); + s + }, + ); + + match matches.get_one::("output") { + None => print!("{data}"), + Some(path) => { + let mut file = File::create(path).unwrap_or_else(|_| { + panic!( + "Failed to open output file: '{}'", + path.to_str().unwrap_or_default() + ) + }); + io::Write::write(&mut file, data.as_bytes()).unwrap(); + } + } Ok(()) }