1use crate::backends::*;
12use std::process::Command;
13use std::str;
14use palette::Srgb;
15use palette::cast::AsComponents;
16use std::fmt;
17
18enum IMcmd {
19 Magick,
20 Convert,
21}
22
23impl fmt::Display for IMcmd {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 match self {
26 IMcmd::Magick => write!(f, "magick"),
27 IMcmd::Convert => write!(f, "convert"),
28 }
29 }
30}
31
32
33pub fn wal(f: &Path) -> Result<Vec<u8>> {
35 let mut cols: Vec<Srgb<u8>> = Vec::with_capacity(16); let magick_command = has_im()?.to_string();
38
39 let mut raw_colors = String::new();
40
41 for i in 0..20 {
43 raw_colors = imagemagick(16 + i, f, &magick_command)?;
44
45 if raw_colors.lines().count() > 16 { break }
46
47 if i == 19 {
48 anyhow::bail!("Imagemagick couldn't generate a suitable palette.");
49 }
50 }
56
57 for line in raw_colors.lines().skip(1) {
58 let mut s = line.split_ascii_whitespace().skip(1);
59 let hex = s.next().expect("Should always be present, without spaces in between e.g. (0,0,0)");
60 let hex = &hex[1..hex.len() - 1];
62 let rgbs: Vec<u8> = hex
63 .split(',')
64 .map(|x| x.parse::<u8>().expect("Should be a number"))
65 .collect();
66 let hex = Srgb::new(rgbs[0], rgbs[1], rgbs[2]);
67 cols.push(hex);
68 }
69
70 Ok(cols.as_components().to_vec())
71}
72
73fn imagemagick(color_count: u8, img: &Path, magick_command: &str) -> Result<String> {
74 let im = Command::new(magick_command)
75 .args([
76 &format!("{}[0]", img.display()), "-resize", "25%",
78 "-colors", &color_count.to_string(),
79 "-unique-colors",
80 "-colorspace", "srgb", "-depth", "8", "txt:-",
83 ])
84 .output()
85 .expect("This should run, given that `has_im()` should fail first, unless IM flags are deprecated.");
86
87 Ok(str::from_utf8(&im.stdout)?.to_owned())
88}
89
90fn has_im() -> Result<IMcmd> {
92 let m = "magick";
93 let c = "convert";
94
95 match Command::new(m).output() {
97 Ok(_) => Ok(IMcmd::Magick),
98 Err(e) => {
99 match Command::new(c).output() {
100 Ok(_) => Ok(IMcmd::Convert),
101 Err(e2) => Err(anyhow::anyhow!("Neither `magick` nor `convert` is invokable:\n{e} {e2}")),
102 }
103 },
109 }
110}