SHOULD have a handler for config/CLI parses

This commit is contained in:
2026-05-28 18:55:03 +02:00
parent 54e8a265d0
commit d098375da6
3 changed files with 116 additions and 88 deletions
-2
View File
@@ -10,12 +10,10 @@ pub struct Config {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EffectsConfig { pub struct EffectsConfig {
pub mode: String,
pub corner_radius: f32, pub corner_radius: f32,
pub drop_shadow: bool, pub drop_shadow: bool,
pub rounded_corners: bool, pub rounded_corners: bool,
pub shadow_blur_radius: f32, pub shadow_blur_radius: f32,
pub shadow_blur_passes: u32,
pub shadow_color: [u8; 4], pub shadow_color: [u8; 4],
pub shadow_offset_x: f32, pub shadow_offset_x: f32,
pub shadow_offset_y: f32, pub shadow_offset_y: f32,
+2 -3
View File
@@ -16,7 +16,6 @@ pub fn apply_effects(img: RgbaImage, cfg: &EffectsConfig) -> RgbaImage {
cfg.shadow_blur_radius, cfg.shadow_blur_radius,
cfg.shadow_offset_x, cfg.shadow_offset_x,
cfg.shadow_offset_y, cfg.shadow_offset_y,
cfg.shadow_blur_passes,
cfg.shadow_color, cfg.shadow_color,
) )
} else { } else {
@@ -53,12 +52,12 @@ pub fn apply_drop_shadow(
blur_radius: f32, blur_radius: f32,
offset_x: f32, offset_x: f32,
offset_y: f32, offset_y: f32,
blur_passes: u32, // blur_passes: u32,
shadow_color: [u8; 4], shadow_color: [u8; 4],
) -> RgbaImage { ) -> RgbaImage {
let (iw, ih) = img.dimensions(); let (iw, ih) = img.dimensions();
let br = blur_radius.ceil() as u32; let br = blur_radius.ceil() as u32;
let bp = blur_passes; let bp = 1;
// Original idea // Original idea
// let spread = br * bp; // let spread = br * bp;
// Claude is hallucinating but let's try it **Worked btw** // Claude is hallucinating but let's try it **Worked btw**
+114 -83
View File
@@ -11,7 +11,6 @@ struct CliOverrides {
corner_radius: Option<f32>, corner_radius: Option<f32>,
drop_shadow: Option<bool>, drop_shadow: Option<bool>,
shadow_blur_radius: Option<f32>, shadow_blur_radius: Option<f32>,
shadow_blur_passes: Option<u32>,
shadow_offset_x: Option<f32>, shadow_offset_x: Option<f32>,
shadow_offset_y: Option<f32>, shadow_offset_y: Option<f32>,
// Accepted as four comma-separated u8 values, e.g. `255,0,0,200` // Accepted as four comma-separated u8 values, e.g. `255,0,0,200`
@@ -50,7 +49,24 @@ fn parse_shadow_color(s: &str) -> Result<[u8; 4]> {
Ok([r, g, b, a]) Ok([r, g, b, a])
} }
fn main() -> Result<()> { fn extract_image_path() -> Option<String> {
let args: Vec<String> = std::env::args().skip(1).collect();
args.windows(2)
.find(|w| w[0] == "--image")
.map(|w| w[1].clone())
}
fn main() {
let image_path = extract_image_path();
if let Some(path) = image_path {
if let Err(e) = run() {
eprintln!("Error: {}", e);
push_image(&path).ok();
}
}
}
fn run() -> Result<()> {
let args: Vec<String> = std::env::args().skip(1).collect(); let args: Vec<String> = std::env::args().skip(1).collect();
let mut image_path: Option<String> = None; let mut image_path: Option<String> = None;
@@ -61,125 +77,97 @@ fn main() -> Result<()> {
while i < args.len() { while i < args.len() {
match args[i].as_str() { match args[i].as_str() {
"--image" => { "--image" => {
i += 1; image_path = Some(next_arg(&args, &mut i, "--image")?);
image_path = Some(
args.get(i)
.cloned()
.context("Expected a path after --image")?,
);
} }
"--rounded-corners" => { "--corner" => {
i += 1; let val = next_arg(&args, &mut i, "--corners")?;
let val = args overrides.rounded_corners = Some(parse_bool(&val)?);
.get(i)
.context("Expected true/false after --rounded-corners")?;
overrides.rounded_corners = Some(parse_bool(val)?);
} }
"--corner-radius" => { "--corner-radius" => {
i += 1; let val = next_arg(&args, &mut i, "--corner-radius")?;
let val = args
.get(i)
.context("Expected a number after --corner-radius")?;
overrides.corner_radius = Some( overrides.corner_radius = Some(
val.parse::<f32>() val.parse::<f32>()
.context("--corner-radius must be a number")?, .context("--corner-radius must be a number")?,
); );
} }
"--drop-shadow" => { "--shadow" => {
i += 1; let val = next_arg(&args, &mut i, "--shadow")?;
let val = args overrides.drop_shadow = Some(parse_bool(&val)?);
.get(i)
.context("Expected true/false after --drop-shadow")?;
overrides.drop_shadow = Some(parse_bool(val)?);
} }
"--shadow-blur-radius" => { "--shadow-blur" => {
i += 1; let val = next_arg(&args, &mut i, "--shadow-blur")?;
let val = args
.get(i)
.context("Expected a number after --shadow-blur-radius")?;
overrides.shadow_blur_radius = Some( overrides.shadow_blur_radius = Some(
val.parse::<f32>() val.parse::<f32>()
.context("--shadow-blur-radius must be a number")?, .context("--shadow-blur-radius must be a number")?,
); );
} }
"--shadow-offset-x" => { "--shadow-offset-x" => {
i += 1; let val = next_arg(&args, &mut i, "--shadow-offset-x")?;
let val = args
.get(i)
.context("Expected a number after --shadow-offset-x")?;
overrides.shadow_offset_x = Some( overrides.shadow_offset_x = Some(
val.parse::<f32>() val.parse::<f32>()
.context("--shadow-offset-x must be a number")?, .context("--shadow-offset-x must be a number")?,
); );
} }
"--shadow-offset-y" => { "--shadow-offset-y" => {
i += 1; let val = next_arg(&args, &mut i, "--shadow-offset-y")?;
let val = args
.get(i)
.context("Expected a number after --shadow-offset-y")?;
overrides.shadow_offset_y = Some( overrides.shadow_offset_y = Some(
val.parse::<f32>() val.parse::<f32>()
.context("--shadow-offset-y must be a number")?, .context("--shadow-offset-y must be a number")?,
); );
} }
"--shadow-blur-passes" => {
i += 1;
let val = args
.get(i)
.context("Expected a number after --shadow-blur-passes")?;
overrides.shadow_blur_passes = Some(
val.parse::<u32>()
.context("--shadow-blur-passes must be a number")?,
);
}
"--shadow-color" => { "--shadow-color" => {
i += 1; let val = next_arg(&args, &mut i, "--shadow-color")?;
let val = args overrides.shadow_color = Some(parse_shadow_color(&val)?);
.get(i)
.context("Expected r,g,b,a after --shadow-color")?;
overrides.shadow_color = Some(parse_shadow_color(val)?);
} }
"--scale" => { "--scale" => {
i += 1; let val = next_arg(&args, &mut i, "--scale")?;
let val = args.get(i).context("Expected a number after --scale")?;
scale = Some(val.parse::<f32>().context("--scale must be a number")?); scale = Some(val.parse::<f32>().context("--scale must be a number")?);
} }
unknown => bail!("Unknown argument: {unknown}"), unknown => bail!("Unknown argument: {}", unknown),
} }
i += 1; i += 1;
} }
let image_path = image_path.context("Missing --image <path>")?; let image_path = image_path.context("Missing --image <path>")?;
let config = config::Config::load().context("Failed to load config")?; // Check if any arguments were provided
let cli_args_provided = overrides.rounded_corners.is_some()
let mut effects = config.screenshot; || overrides.corner_radius.is_some()
if effects.mode == "auto" { || overrides.drop_shadow.is_some()
if let Some(v) = overrides.rounded_corners { || overrides.shadow_blur_radius.is_some()
effects.rounded_corners = v; || overrides.shadow_offset_x.is_some()
} || overrides.shadow_offset_y.is_some()
if let Some(v) = overrides.corner_radius { || overrides.shadow_color.is_some();
effects.corner_radius = v; let mut effects = if cli_args_provided {
} // If all args provided
if let Some(v) = overrides.drop_shadow { let rounded_corners = overrides.rounded_corners.context("Missing --corner")?;
effects.drop_shadow = v; let corner_radius = overrides.corner_radius.context("Missing --corner-radius")?;
} let drop_shadow = overrides.drop_shadow.context("Missing --shadow")?;
if let Some(v) = overrides.shadow_blur_radius { let shadow_blur_radius = overrides
effects.shadow_blur_radius = v; .shadow_blur_radius
} .context("Missing --shadow-blur")?;
if let Some(v) = overrides.shadow_offset_x { let shadow_offset_x = overrides
effects.shadow_offset_x = v; .shadow_offset_x
} .context("Missing --shadow-offset-x")?;
if let Some(v) = overrides.shadow_offset_y { let shadow_offset_y = overrides
effects.shadow_offset_y = v; .shadow_offset_y
} .context("Missing --shadow-offset-y")?;
if let Some(v) = overrides.shadow_blur_passes { let shadow_color = overrides.shadow_color.context("Missing --shadow-color")?;
effects.shadow_blur_passes = v; config::EffectsConfig {
} rounded_corners,
if let Some(v) = overrides.shadow_color { corner_radius,
effects.shadow_color = v; drop_shadow,
} shadow_blur_radius,
shadow_offset_x,
shadow_offset_y,
shadow_color,
} }
} else {
// If not all args were provided use config file
let config = config::Config::load()?;
config.screenshot
};
// if scale is set do // if scale is set do
if let Some(scale) = scale.filter(|&s| s != 1.0) { if let Some(scale) = scale.filter(|&s| s != 1.0) {
@@ -196,6 +184,49 @@ fn main() -> Result<()> {
Ok(()) Ok(())
} }
fn next_arg(args: &[String], i: &mut usize, flag: &str) -> Result<String> {
*i += 1;
let val = args
.get(*i)
.context(format!("Expected value after {}", flag))?;
if val.starts_with('-') {
bail!("Expected value after {}, found flag {}", flag, val);
}
Ok(val.clone())
}
fn push_image(path: &str) -> Result<()> {
let img = image::open(path)
.with_context(|| format!("Failed to open image '{path}'"))?
.into_rgba8();
let mut png_bytes: Vec<u8> = Vec::new();
image::DynamicImage::ImageRgba8(img)
.write_to(
&mut std::io::Cursor::new(&mut png_bytes),
image::ImageFormat::Png,
)
.context("Failed to encode processed image as PNG")?;
let mut child = Command::new("swappy")
.args(["-f", "-"])
.stdin(Stdio::piped())
.spawn()
.context("Failed to spawn swappy. Is it installed and in PATH?")?;
// Writes the PNG bytes to swappy's stdin and then closes
if let Some(mut stdin) = child.stdin.take() {
stdin
.write_all(&png_bytes)
.context("Failed to write image data to swappy")?;
}
Ok(())
}
fn process_image(path: &str, effects: &config::EffectsConfig) -> Result<()> { fn process_image(path: &str, effects: &config::EffectsConfig) -> Result<()> {
let img = image::open(path) let img = image::open(path)
.with_context(|| format!("Failed to open image '{path}'"))? .with_context(|| format!("Failed to open image '{path}'"))?