mirror of
https://github.com/waveplate/img2irc.git
synced 2024-12-22 05:36:37 +00:00
add new CLI options for crop, rotate, flip, filter, scale, and aspect ratio
This commit is contained in:
parent
492079af6c
commit
703000e68a
275
src/args.rs
275
src/args.rs
@ -1,173 +1,300 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[derive(clap::ValueEnum, Clone, Debug)]
|
||||
pub enum SamplingFilter {
|
||||
Nearest,
|
||||
Triangle,
|
||||
CatmullRom,
|
||||
Gaussian,
|
||||
Lanczos3,
|
||||
}
|
||||
|
||||
#[derive(clap::ValueEnum, Clone, Debug)]
|
||||
pub enum ColourSpace {
|
||||
HSL,
|
||||
HSV,
|
||||
HSLUV,
|
||||
LCH,
|
||||
}
|
||||
|
||||
#[derive(Parser, Clone, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
/// image url or file path
|
||||
#[arg(index = 1)]
|
||||
pub image: String,
|
||||
|
||||
/// irc
|
||||
/// output image width in columns
|
||||
#[arg(short, long)]
|
||||
pub width: Option<u32>,
|
||||
|
||||
/// output image height in rows
|
||||
#[arg(short, long)]
|
||||
pub height: Option<u32>,
|
||||
|
||||
/// scaling factors (x:y, e.g., "2:2")
|
||||
#[arg(long, value_parser = parse_xy_pair)]
|
||||
pub scale: Option<(f32, f32)>,
|
||||
|
||||
/// final aspect ratio (x:y, e.g., "2:1")
|
||||
#[arg(long, value_parser = parse_xy_pair)]
|
||||
pub aspect: Option<(f32, f32)>,
|
||||
|
||||
/// crop image (x1,y1,x2,y2)
|
||||
#[arg(long, value_parser = parse_crop_coordinates)]
|
||||
pub crop: Option<(u32, u32, u32, u32)>,
|
||||
|
||||
/// sampling filter
|
||||
#[arg(long, value_enum, default_value_t = SamplingFilter::Nearest)]
|
||||
pub filter: SamplingFilter,
|
||||
|
||||
/// rotate degrees
|
||||
#[arg(long, default_value_t = 0)]
|
||||
pub rotate: i32,
|
||||
|
||||
/// flip horizontal
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub fliph: bool,
|
||||
|
||||
/// flip vertical
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub flipv: bool,
|
||||
|
||||
/// use IRC99 colours
|
||||
#[arg(long, default_value_t = false, group = "colour", required_unless_present_any = ["ansi", "ansi24"])]
|
||||
pub irc: bool,
|
||||
|
||||
/// 8-bit ansi
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// use 8-bit ANSI colours
|
||||
#[arg(long, default_value_t = false, group = "colour", required_unless_present_any = ["irc", "ansi24"])]
|
||||
pub ansi: bool,
|
||||
|
||||
/// 24-bit ansi
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// use 24-bit ANSI colours
|
||||
#[arg(long, default_value_t = false, group = "colour", required_unless_present_any = ["irc", "ansi"])]
|
||||
pub ansi24: bool,
|
||||
|
||||
/// quarterblock
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub qb: bool,
|
||||
/// use braille pixels
|
||||
#[arg(long, default_value_t = false, group = "pixel")]
|
||||
pub braille: bool,
|
||||
|
||||
/// image width to resize to
|
||||
#[arg(short, long, default_value_t = 50)]
|
||||
pub width: u32,
|
||||
/// use halfblock pixels
|
||||
#[arg(long, alias = "halfblock", default_value_t = true, group = "pixel")]
|
||||
pub hb: bool,
|
||||
|
||||
/// brightness (-255 to 255)
|
||||
#[arg(short, long, require_equals = true, default_value_t = 0.0)]
|
||||
/// use quarterblocks pixels
|
||||
#[arg(long, alias = "quarterblock", default_value_t = false, group = "pixel")]
|
||||
pub qb: bool,
|
||||
|
||||
/// adjust brightness (0 = no change)
|
||||
#[arg(short = 'b', long, default_value_t = 0.0, allow_hyphen_values = true)]
|
||||
pub brightness: f32,
|
||||
|
||||
/// contrast (-255 to 255)
|
||||
#[arg(short, long, require_equals = true, default_value_t = 0.0)]
|
||||
/// adjust contrast (0 = no change)
|
||||
#[arg(short = 'c', long, default_value_t = 0.0, allow_hyphen_values = true)]
|
||||
pub contrast: f32,
|
||||
|
||||
/// saturation (-255 to 255)
|
||||
#[arg(short, long, require_equals = true, default_value_t = 0.0)]
|
||||
pub saturation: f32,
|
||||
|
||||
/// hue (0 to 360)
|
||||
#[arg(short = 'H', long, default_value_t = 0.0)]
|
||||
pub hue: f32,
|
||||
|
||||
/// gamma (0 to 255)
|
||||
#[arg(short, long, default_value_t = 0.0)]
|
||||
/// adjust gamma (0 to 255)
|
||||
#[arg(short = 'g', long, default_value_t = 0.0, allow_hyphen_values = true)]
|
||||
pub gamma: f32,
|
||||
|
||||
/// dither (1 to 8)
|
||||
#[arg(long, default_value_t = 0)]
|
||||
/// adjust saturation (0 = no change)
|
||||
#[arg(short = 's', long, default_value_t = 0.0, allow_hyphen_values = true)]
|
||||
pub saturation: f32,
|
||||
|
||||
/// rotate hue (0 to 360)
|
||||
#[arg(short = 'u', long, default_value_t = 0.0)]
|
||||
pub hue: f32,
|
||||
|
||||
/// colors are inverted, opposite on the color wheel
|
||||
#[arg(short = 'i', long, default_value_t = false)]
|
||||
pub invert: bool,
|
||||
|
||||
/// dithering (1 to 8)
|
||||
#[arg(long, short = 'd', long, default_value_t = 0)]
|
||||
pub dither: u32,
|
||||
|
||||
/// pixelize size
|
||||
/// adjust luma brightness (braille only)
|
||||
#[arg(short = 'B', long, default_value_t = 0.0, allow_hyphen_values = true, requires = "braille")]
|
||||
pub luma_brightness: f32,
|
||||
|
||||
/// adjust luma contrast (braille only)
|
||||
#[arg(short = 'C', long, default_value_t = 0.0, allow_hyphen_values = true, requires = "braille")]
|
||||
pub luma_contrast: f32,
|
||||
|
||||
/// adjust luma gamma (braille only)
|
||||
#[arg(short = 'G', long, default_value_t = 0.0, allow_hyphen_values = true, requires = "braille")]
|
||||
pub luma_gamma: f32,
|
||||
|
||||
/// adjust luma saturation (braille only)
|
||||
#[arg(short = 'S', long, default_value_t = 0.0, allow_hyphen_values = true, requires = "braille")]
|
||||
pub luma_saturation: f32,
|
||||
|
||||
/// luminance is inverted
|
||||
#[arg(short = 'I', long, default_value_t = false, requires = "braille")]
|
||||
pub luma_invert: bool,
|
||||
|
||||
/// colour space
|
||||
#[arg(long, value_enum, default_value_t = ColourSpace::HSV)]
|
||||
pub colorspace: ColourSpace,
|
||||
|
||||
/// converts image to black and white
|
||||
#[arg(long, default_value_t = false, group = "grayscale_opts")]
|
||||
pub grayscale: bool,
|
||||
|
||||
/// exclude grayscale colours from the palette
|
||||
#[arg(long, default_value_t = false, group = "grayscale_opts")]
|
||||
pub nograyscale: bool,
|
||||
|
||||
/// pixelize pixel size
|
||||
#[arg(long, default_value_t = 0)]
|
||||
pub pixelize: i32,
|
||||
|
||||
/// simple average of all the neighboring pixels surrounding a given pixel
|
||||
#[arg(long="boxblur", default_value_t = false)]
|
||||
pub box_blur: bool,
|
||||
|
||||
/// gaussian blur radius
|
||||
#[arg(long, default_value_t = 0)]
|
||||
#[arg(long="gaussianblur", default_value_t = 0)]
|
||||
pub gaussian_blur: i32,
|
||||
|
||||
/// oil ("<radius>,<intensity>")
|
||||
/// oil filter ("[radius],[intensity]")
|
||||
#[arg(long)]
|
||||
pub oil: Option<String>,
|
||||
|
||||
/// grayscale
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub grayscale: bool,
|
||||
|
||||
/// no grayscale
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub nograyscale: bool,
|
||||
|
||||
/// halftone
|
||||
/// made up of small dots creating a continuous-tone illusion
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub halftone: bool,
|
||||
|
||||
/// sepia
|
||||
/// brownish, aged appearance like old photographs
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub sepia: bool,
|
||||
|
||||
/// normalize
|
||||
/// adjusts brightness and contrast for better image quality
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub normalize: bool,
|
||||
|
||||
/// noise
|
||||
/// random variations in brightness and color like film grain
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub noise: bool,
|
||||
|
||||
/// emboss
|
||||
/// gives a raised, 3d appearance
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub emboss: bool,
|
||||
|
||||
/// box_blur
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub box_blur: bool,
|
||||
|
||||
/// identity
|
||||
/// no modifications, unchanged image
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub identity: bool,
|
||||
|
||||
/// laplace
|
||||
/// enhances edges and boundaries in an image
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub laplace: bool,
|
||||
|
||||
/// noise reduction
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// reduces noise for a cleaner, clearer image
|
||||
#[arg(long="denoise", default_value_t = false)]
|
||||
pub noise_reduction: bool,
|
||||
|
||||
/// sharpen
|
||||
/// increases clarity and definition, making edges and details more distinct
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub sharpen: bool,
|
||||
|
||||
/// cali
|
||||
/// cool blue tone with increased contrast
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub cali: bool,
|
||||
|
||||
/// dramatic
|
||||
/// high contrast and vivid colors for a dramatic effect
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub dramatic: bool,
|
||||
|
||||
/// firenze
|
||||
/// warm, earthy tones reminiscent of tuscan landscapes
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub firenze: bool,
|
||||
|
||||
/// golden
|
||||
/// warm, golden glow like sunset light
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub golden: bool,
|
||||
|
||||
/// lix
|
||||
/// high-contrast black and white appearance with increased sharpness
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub lix: bool,
|
||||
|
||||
/// lofi
|
||||
/// low-fidelity, retro appearance like old photographs or film
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub lofi: bool,
|
||||
|
||||
/// neue
|
||||
/// clean, modern appearance with neutral colors and simple design
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub neue: bool,
|
||||
|
||||
/// obsidian
|
||||
/// dark, monochromatic appearance with black and gray shades
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub obsidian: bool,
|
||||
|
||||
/// pastel_pink
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// soft, delicate pink tint like pastel colors
|
||||
#[arg(long="pastelpink", default_value_t = false)]
|
||||
pub pastel_pink: bool,
|
||||
|
||||
/// ryo
|
||||
/// bright, high-contrast appearance with vivid colors and sharp details
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub ryo: bool,
|
||||
|
||||
/// invert
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub invert: bool,
|
||||
|
||||
/// frosted glass
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// blurred, frosted appearance as if viewed through semi-transparent surface
|
||||
#[arg(long="frostedglass", default_value_t = false)]
|
||||
pub frosted_glass: bool,
|
||||
|
||||
/// solarize
|
||||
/// strange, otherworldly appearance with inverted colors and surreal atmosphere
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub solarize: bool,
|
||||
|
||||
/// edge detection
|
||||
#[arg(long, default_value_t = false)]
|
||||
/// highlights edges and boundaries in an image
|
||||
#[arg(long="edgedetection", default_value_t = false)]
|
||||
pub edge_detection: bool,
|
||||
}
|
||||
|
||||
pub fn parse_args() -> Args {
|
||||
Args::parse()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_xy_pair(s: &str) -> Result<(f32, f32), String> {
|
||||
let parts: Vec<&str> = s.split(':').collect();
|
||||
if parts.len() != 2 {
|
||||
return Err(format!(
|
||||
"Invalid format. Expected 'value1:value2', got '{}'",
|
||||
s
|
||||
));
|
||||
}
|
||||
|
||||
let first = parts[0].parse::<f32>().map_err(|e| {
|
||||
format!(
|
||||
"Failed to parse the first value ('{}') as f32: {}",
|
||||
parts[0], e
|
||||
)
|
||||
})?;
|
||||
let second = parts[1].parse::<f32>().map_err(|e| {
|
||||
format!(
|
||||
"Failed to parse the second value ('{}') as f32: {}",
|
||||
parts[1], e
|
||||
)
|
||||
})?;
|
||||
|
||||
if first <= 0.0 || second <= 0.0 {
|
||||
return Err("Both values must be positive numbers.".to_string());
|
||||
}
|
||||
|
||||
Ok((first, second))
|
||||
}
|
||||
|
||||
fn parse_crop_coordinates(s: &str) -> Result<(u32, u32, u32, u32), String> {
|
||||
let coords: Vec<&str> = s.split(',').collect();
|
||||
if coords.len() != 4 {
|
||||
return Err(format!(
|
||||
"Invalid crop format '{}'. Expected 'x1,y1,x2,y2' (e.g., '50,50,200,200').",
|
||||
s
|
||||
));
|
||||
}
|
||||
|
||||
let x1 = coords[0].parse::<u32>().map_err(|_| format!("Invalid x1 value '{}'.", coords[0]))?;
|
||||
let y1 = coords[1].parse::<u32>().map_err(|_| format!("Invalid y1 value '{}'.", coords[1]))?;
|
||||
let x2 = coords[2].parse::<u32>().map_err(|_| format!("Invalid x2 value '{}'.", coords[2]))?;
|
||||
let y2 = coords[3].parse::<u32>().map_err(|_| format!("Invalid y2 value '{}'.", coords[3]))?;
|
||||
|
||||
Ok((x1, y1, x2, y2))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user