Skip to content

Commit

Permalink
Merge pull request #195 from flick0/colour
Browse files Browse the repository at this point in the history
option to use hexcodes instead of img path
  • Loading branch information
LGFae authored Jun 11, 2024
2 parents f751621 + e6b5b46 commit ceb6306
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 61 deletions.
25 changes: 23 additions & 2 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ impl CliPosition {
}
}

#[derive(Clone)]
pub enum CliImage {
Path(PathBuf),
/// Single rgb color
Color([u8; 3]),
}

#[derive(Parser)]
#[command(version, name = "swww")]
///A Solution to your Wayland Wallpaper Woes
Expand Down Expand Up @@ -246,8 +253,9 @@ pub struct Restore {

#[derive(Parser)]
pub struct Img {
/// Path to the image to display
pub path: PathBuf,
/// Path of image or hexcode (starting with 0x) to display
#[arg(value_parser = parse_image)]
pub image: CliImage,

/// Comma separated list of outputs to display the image at.
///
Expand Down Expand Up @@ -423,6 +431,19 @@ fn parse_bezier(raw: &str) -> Result<(f32, f32, f32, f32), String> {
Ok(parsed)
}

pub fn parse_image(raw: &str) -> Result<CliImage, String> {
let path = PathBuf::from(raw);
if path.exists() {
return Ok(CliImage::Path(path));
}
if let Some(color) = raw.strip_prefix("0x") {
if let Ok(color) = from_hex(color) {
return Ok(CliImage::Color(color));
}
}
Err(format!("Path '{}' does not exist", raw))
}

// parses Percents and numbers in format of "<coord1>,<coord2>"
fn parse_coords(raw: &str) -> Result<CliPosition, String> {
let coords = raw.split(',').map(|s| s.trim()).collect::<Vec<&str>>();
Expand Down
144 changes: 85 additions & 59 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clap::Parser;
use std::{path::PathBuf, process::Stdio, time::Duration};
use std::{process::Stdio, time::Duration};

use utils::{
cache,
Expand All @@ -10,7 +10,7 @@ mod imgproc;
use imgproc::*;

mod cli;
use cli::{ResizeStrategy, Swww};
use cli::{CliImage, ResizeStrategy, Swww};

fn main() -> Result<(), String> {
let swww = Swww::parse();
Expand Down Expand Up @@ -137,8 +137,10 @@ fn make_request(args: &Swww) -> Result<Option<RequestSend>, String> {
Swww::Img(img) => {
let requested_outputs = split_cmdline_outputs(&img.outputs);
let (format, dims, outputs) = get_format_dims_and_outputs(&requested_outputs)?;
let imgbuf = ImgBuf::new(&img.path)?;
let img_request = make_img_request(img, &imgbuf, &dims, format, &outputs)?;
// let imgbuf = ImgBuf::new(&img.path)?;

let img_request = make_img_request(img, &dims, format, &outputs)?;

Ok(Some(RequestSend::Img(img_request)))
}
Swww::Init { no_cache, .. } => {
Expand All @@ -154,73 +156,97 @@ fn make_request(args: &Swww) -> Result<Option<RequestSend>, String> {

fn make_img_request(
img: &cli::Img,
imgbuf: &ImgBuf,
dims: &[(u32, u32)],
pixel_format: ipc::PixelFormat,
outputs: &[Vec<String>],
) -> Result<ipc::Mmap, String> {
let img_raw = imgbuf.decode(pixel_format)?;
let transition = make_transition(img);
let mut img_req_builder = ipc::ImageRequestBuilder::new(transition);
for (&dim, outputs) in dims.iter().zip(outputs) {
let path = match img.path.canonicalize() {
Ok(p) => p.to_string_lossy().to_string(),
Err(e) => {
if let Some("-") = img.path.to_str() {
"STDIN".to_string()
} else {
return Err(format!("failed no canonicalize image path: {e}"));
}

match &img.image {
CliImage::Color(color) => {
for (&dim, outputs) in dims.iter().zip(outputs) {
img_req_builder.push(
ipc::ImgSend {
img: image::RgbImage::from_pixel(dim.0, dim.1, image::Rgb(*color))
.to_vec()
.into_boxed_slice(),
path: format!("0x{:02x}{:02x}{:02x}", color[0], color[1], color[2]),
dim,
format: pixel_format,
},
outputs,
None,
);
}
};
}
CliImage::Path(img_path) => {
let imgbuf = ImgBuf::new(img_path)?;
let img_raw = imgbuf.decode(pixel_format)?;

let animation = if !imgbuf.is_animated() {
None
} else if img.resize == ResizeStrategy::Crop {
match cache::load_animation_frames(&img.path, dim, pixel_format) {
Ok(Some(animation)) => Some(animation),
otherwise => {
if let Err(e) = otherwise {
eprintln!("Error loading cache for {:?}: {e}", img.path);
for (&dim, outputs) in dims.iter().zip(outputs) {
let path = match img_path.canonicalize() {
Ok(p) => p.to_string_lossy().to_string(),
Err(e) => {
if let Some("-") = img_path.to_str() {
"STDIN".to_string()
} else {
return Err(format!("failed no canonicalize image path: {e}"));
}
}
};

Some({
ipc::Animation {
animation: compress_frames(
imgbuf.as_frames()?,
dim,
pixel_format,
make_filter(&img.filter),
img.resize,
&img.fill_color,
)?
.into_boxed_slice(),
let animation = if !imgbuf.is_animated() {
None
} else if img.resize == ResizeStrategy::Crop {
match cache::load_animation_frames(img_path, dim, pixel_format) {
Ok(Some(animation)) => Some(animation),
otherwise => {
if let Err(e) = otherwise {
eprintln!("Error loading cache for {:?}: {e}", img_path);
}

Some({
ipc::Animation {
animation: compress_frames(
imgbuf.as_frames()?,
dim,
pixel_format,
make_filter(&img.filter),
img.resize,
&img.fill_color,
)?
.into_boxed_slice(),
}
})
}
})
}
}
} else {
None
};
}
} else {
None
};

let img = match img.resize {
ResizeStrategy::No => img_pad(&img_raw, dim, &img.fill_color)?,
ResizeStrategy::Crop => img_resize_crop(&img_raw, dim, make_filter(&img.filter))?,
ResizeStrategy::Fit => {
img_resize_fit(&img_raw, dim, make_filter(&img.filter), &img.fill_color)?
}
};
let img = match img.resize {
ResizeStrategy::No => img_pad(&img_raw, dim, &img.fill_color)?,
ResizeStrategy::Crop => {
img_resize_crop(&img_raw, dim, make_filter(&img.filter))?
}
ResizeStrategy::Fit => {
img_resize_fit(&img_raw, dim, make_filter(&img.filter), &img.fill_color)?
}
};

img_req_builder.push(
ipc::ImgSend {
img,
path,
dim,
format: pixel_format,
},
outputs,
animation,
);
img_req_builder.push(
ipc::ImgSend {
img,
path,
dim,
format: pixel_format,
},
outputs,
animation,
);
}
}
}

Ok(img_req_builder.build())
Expand Down Expand Up @@ -332,7 +358,7 @@ fn restore_from_cache(requested_outputs: &[String]) -> Result<(), String> {
.map_err(|e| format!("failed to get previous image path: {e}"))?;
#[allow(deprecated)]
if let Err(e) = process_swww_args(&Swww::Img(cli::Img {
path: PathBuf::from(img_path),
image: cli::parse_image(&img_path)?,
outputs: output.to_string(),
no_resize: false,
resize: ResizeStrategy::Crop,
Expand Down

0 comments on commit ceb6306

Please sign in to comment.