Add solar wallpaper support
parent
f2853d4513
commit
79470ca392
|
@ -17,9 +17,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.39"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
@ -210,9 +210,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.88"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "libheif-rs"
|
||||
|
@ -310,9 +310,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -359,18 +359,18 @@ checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.124"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -385,9 +385,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
use std::path::Path;
|
||||
|
||||
use libheif_rs::HeifContext;
|
||||
use anyhow::Result;
|
||||
use crate::util::png;
|
||||
use crate::schema::xml::{Background, Image::{Static, Transition}};
|
||||
use colored::*;
|
||||
use crate::serializer::GnomeXMLBackgroundSerializer;
|
||||
use crate::DAY_SECS;
|
||||
use std::io::BufWriter;
|
||||
|
||||
pub struct ImagePoint<'a> {
|
||||
pub image_ctx: &'a HeifContext,
|
||||
pub img_id: u32,
|
||||
pub index: usize,
|
||||
pub background: &'a mut Background,
|
||||
pub parent_directory: &'a Path,
|
||||
pub start_time: f32,
|
||||
pub time: f32,
|
||||
pub next_time: f32,
|
||||
}
|
||||
|
||||
pub fn process_img(pt: ImagePoint) -> Result<()> {
|
||||
let prim_image = pt.image_ctx.image_handle(pt.img_id).unwrap();
|
||||
let number_of_images = pt.image_ctx.number_of_top_level_images();
|
||||
png::write_png(
|
||||
format!("{}/{}.png", pt.parent_directory.to_string_lossy(), pt.index).as_str(),
|
||||
prim_image,
|
||||
)?;
|
||||
|
||||
// Add to Background Structure
|
||||
pt.background.images.push(Static {
|
||||
duration: 1 as f32,
|
||||
file: format!("{}/{}.png", pt.parent_directory.to_string_lossy(), pt.index),
|
||||
idx: pt.index,
|
||||
});
|
||||
|
||||
pt.background.images.push(Transition {
|
||||
kind: "overlay".to_string(),
|
||||
duration: {
|
||||
if pt.index < number_of_images - 1 {
|
||||
(pt.time - pt.next_time).abs() * DAY_SECS - 1.0
|
||||
} else {
|
||||
(((pt.time - 1.0).abs() + pt.start_time) * DAY_SECS - 1.0).ceil()
|
||||
}
|
||||
},
|
||||
from: format!("{}/{}.png", pt.parent_directory.to_string_lossy(), pt.index),
|
||||
to: format!("{}/{}.png", pt.parent_directory.to_string_lossy(), {
|
||||
if pt.index < number_of_images - 1 {
|
||||
pt.index + 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}),
|
||||
idx: pt.index,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_xml(xml: &mut Background, parent_directory: &Path) -> Result<()> {
|
||||
println!("{}: {}", "Conversion".yellow(), "Done!");
|
||||
|
||||
println!("{}: {}", "Conversion".green(), "Creating xml description for new wallpaper");
|
||||
xml.images.sort_by(|a, b| match (a, b) {
|
||||
(
|
||||
Static {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Transition {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Static {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Static {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Transition {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Static {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Transition {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Transition {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
});
|
||||
|
||||
println!("{}: {}", "Conversion".green(), "Writing wallpaper description");
|
||||
let result_file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(format!(
|
||||
"{}/default.xml",
|
||||
parent_directory.to_string_lossy()
|
||||
))?;
|
||||
let mut result = BufWriter::new(result_file);
|
||||
let mut ser = GnomeXMLBackgroundSerializer::new(&mut result);
|
||||
ser.serialize(&xml)?;
|
||||
println!("{}", "Done".green());
|
||||
Ok(())
|
||||
}
|
|
@ -8,10 +8,13 @@ mod metadata;
|
|||
mod schema;
|
||||
mod serializer;
|
||||
mod timebased;
|
||||
mod solar;
|
||||
mod util;
|
||||
mod image;
|
||||
|
||||
const INPUT: &str = "IMAGE";
|
||||
const DIR: &str = "DIR";
|
||||
const DAY_SECS: f32 = 86400.0;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let matches = App::new("heic-to-dynamic-gnome-wallpaper")
|
||||
|
@ -67,10 +70,9 @@ fn main() -> Result<()> {
|
|||
println!("{}: {}", "Preparation".bright_blue(), "Detected time-based wallpaper");
|
||||
timebased::compute_time_based_wallpaper(image_ctx, content, &parent_directory)
|
||||
}
|
||||
metadata::WallPaperMode::Solar(_content) => {
|
||||
metadata::WallPaperMode::Solar(content) => {
|
||||
println!("{}: {}", "Preparation".bright_blue(), "Detected solar-based wallpaper");
|
||||
eprintln!("Solar is not supported at the moment, please use wallpapers only with time based changes.");
|
||||
std::process::exit(1)
|
||||
solar::compute_solar_based_wallpaper(image_ctx, content, &&parent_directory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
|||
use libheif_rs::HeifContext;
|
||||
use quick_xml::{events::Event, Reader};
|
||||
|
||||
use crate::schema::plist::WallpaperMetaTime;
|
||||
use crate::schema::plist::{WallpaperMetaSun, WallpaperMetaTime};
|
||||
|
||||
pub enum WallPaperMode {
|
||||
H24(String),
|
||||
|
@ -68,3 +68,9 @@ pub fn get_time_plist_from_base64(input: &String) -> Result<WallpaperMetaTime> {
|
|||
let plist = plist::from_bytes(&decoded)?;
|
||||
Ok(plist)
|
||||
}
|
||||
|
||||
pub fn get_solar_plist_from_base64(input: &String) -> Result<WallpaperMetaSun> {
|
||||
let decoded = base64::decode(input)?;
|
||||
let plist = plist::from_bytes(&decoded)?;
|
||||
Ok(plist)
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ pub struct TimeSlice {
|
|||
pub struct WallpaperMetaSun {
|
||||
#[serde(rename = "si")]
|
||||
pub solar_slices: Vec<SolarSlice>,
|
||||
#[serde(rename = "ap")]
|
||||
pub appearance: Appearance,
|
||||
// #[serde(rename = "ap")]
|
||||
// pub appearance: Appearance,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -38,8 +38,8 @@ pub struct SolarSlice {
|
|||
pub altitude: f32,
|
||||
#[serde(rename = "i")]
|
||||
pub idx: usize,
|
||||
#[serde(rename = "o")]
|
||||
pub light_mode: usize,
|
||||
// #[serde(rename = "o")]
|
||||
// pub light_mode: usize,
|
||||
#[serde(rename = "z")]
|
||||
pub azimuth: f32,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
use std::path::Path;
|
||||
use crate::{image::process_img, metadata};
|
||||
use anyhow::Result;
|
||||
use libheif_rs::HeifContext;
|
||||
use std::cmp::Ordering;
|
||||
use crate::image::ImagePoint;
|
||||
use crate::schema::xml::{Background, StartTime};
|
||||
use crate::util::time;
|
||||
use crate::DAY_SECS;
|
||||
use indicatif::{ProgressIterator, ProgressBar, ProgressStyle};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SolarToHourSlice {
|
||||
time: f32,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
const HOUR_PER_DEGREE:f32 = 24f32/360f32;
|
||||
|
||||
pub fn compute_solar_based_wallpaper(
|
||||
image_ctx: HeifContext,
|
||||
content: String,
|
||||
parent_directory: &Path,
|
||||
) -> Result<()> {
|
||||
let mut plist = metadata::get_solar_plist_from_base64(&content)?;
|
||||
|
||||
plist.solar_slices.sort_by(|x, y| x.azimuth.partial_cmp(&y.azimuth).unwrap_or(Ordering::Equal));
|
||||
let time_slices: Vec<SolarToHourSlice> = plist.solar_slices.iter().map(|elem|{
|
||||
SolarToHourSlice {
|
||||
time: elem.azimuth / 360f32,
|
||||
index: elem.idx,
|
||||
}
|
||||
}).collect();
|
||||
let mut img_ids = vec![0; image_ctx.number_of_top_level_images()];
|
||||
image_ctx.top_level_image_ids(&mut img_ids);
|
||||
|
||||
let start_time = time_slices.get(0).expect("No image has been found").time;
|
||||
let start_seconds = (start_time * DAY_SECS) as u16;
|
||||
let mut background_definition = Background {
|
||||
starttime: StartTime {
|
||||
year: 2011,
|
||||
month: 10,
|
||||
day: 1,
|
||||
hour: time::to_rem_hours(start_seconds),
|
||||
minute: time::to_rem_min(start_seconds),
|
||||
second: time::to_rem_sec(start_seconds),
|
||||
},
|
||||
images: vec!(),
|
||||
};
|
||||
|
||||
let pb = ProgressBar::new(image_ctx.number_of_top_level_images() as u64).with_style(ProgressStyle::default_bar()
|
||||
.template("Conversion: {wide_bar} {pos}/{len} [ETA: {eta_precise}]")
|
||||
.progress_chars("## "));
|
||||
for (idx, SolarToHourSlice { time, index }) in time_slices.iter().enumerate().progress_with(pb) {
|
||||
let img_id = img_ids[*index];
|
||||
let pt = ImagePoint {
|
||||
image_ctx: &image_ctx,
|
||||
img_id,
|
||||
index: idx,
|
||||
background: &mut background_definition,
|
||||
parent_directory,
|
||||
start_time,
|
||||
time: *time,
|
||||
next_time: time_slices.get(idx + 1).map(|elem| elem.time).unwrap_or(0f32),
|
||||
};
|
||||
process_img(pt)?;
|
||||
}
|
||||
crate::image::save_xml(&mut background_definition, parent_directory)
|
||||
}
|
121
src/timebased.rs
121
src/timebased.rs
|
@ -1,20 +1,20 @@
|
|||
use std::{io::BufWriter, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::metadata;
|
||||
use crate::schema::plist::TimeSlice;
|
||||
use crate::schema::xml::{
|
||||
Background,
|
||||
Image::{Static, Transition},
|
||||
StartTime,
|
||||
};
|
||||
use crate::serializer::GnomeXMLBackgroundSerializer;
|
||||
use crate::util::{png, time};
|
||||
use crate::DAY_SECS;
|
||||
use crate::image::{ImagePoint, process_img, save_xml};
|
||||
|
||||
use crate::util::time;
|
||||
use anyhow::Result;
|
||||
use libheif_rs::HeifContext;
|
||||
use indicatif::{ProgressIterator, ProgressBar, ProgressStyle};
|
||||
use colored::*;
|
||||
|
||||
const DAY_SECS: f32 = 86400.0;
|
||||
|
||||
pub fn compute_time_based_wallpaper(
|
||||
image_ctx: HeifContext,
|
||||
|
@ -27,22 +27,22 @@ pub fn compute_time_based_wallpaper(
|
|||
plist
|
||||
.time_slices
|
||||
.sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
|
||||
let first_time = plist.time_slices.get(0).unwrap().time as u16;
|
||||
let start_time = plist.time_slices.get(0).unwrap().time;
|
||||
let start_seconds = (start_time * DAY_SECS) as u16;
|
||||
let mut xml_background = Background {
|
||||
images: Vec::new(),
|
||||
starttime: StartTime {
|
||||
year: 2011,
|
||||
month: 10,
|
||||
day: 1,
|
||||
hour: time::to_rem_hours(first_time),
|
||||
minute: time::to_rem_min(first_time),
|
||||
second: time::to_rem_sec(first_time),
|
||||
hour: time::to_rem_hours(start_seconds),
|
||||
minute: time::to_rem_min(start_seconds),
|
||||
second: time::to_rem_sec(start_seconds),
|
||||
},
|
||||
};
|
||||
|
||||
let number_of_images = image_ctx.number_of_top_level_images();
|
||||
println!("{}: {} {} {}", "Preparation".bright_blue(), "Found", number_of_images, "images");
|
||||
// Has to be initialized
|
||||
let mut image_ids = vec![0u32; number_of_images];
|
||||
image_ctx.top_level_image_ids(&mut image_ids);
|
||||
println!("{}: {}", "Conversion".yellow(), "Converting embedded images to png format");
|
||||
|
@ -52,95 +52,18 @@ pub fn compute_time_based_wallpaper(
|
|||
for (time_idx, TimeSlice{time, idx}) in plist.time_slices.iter().enumerate().progress_with(pb) {
|
||||
let img_id = *image_ids.get(*idx).expect("Could not fetch image id described in metadata");
|
||||
//println!("Image ID: {:?}", img_id);
|
||||
let prim_image = image_ctx.image_handle(img_id).unwrap();
|
||||
png::write_png(
|
||||
format!("{}/{}.png", parent_directory.to_string_lossy(), time_idx).as_str(),
|
||||
prim_image,
|
||||
)?;
|
||||
|
||||
// Add to Background Structure
|
||||
xml_background.images.push(Static {
|
||||
duration: 1 as f32,
|
||||
file: format!("{}/{}.png", parent_directory.to_string_lossy(), time_idx),
|
||||
idx: time_idx,
|
||||
});
|
||||
|
||||
xml_background.images.push(Transition {
|
||||
kind: "overlay".to_string(),
|
||||
duration: {
|
||||
if time_idx < number_of_images - 1 {
|
||||
(time - plist.time_slices.get(time_idx + 1).unwrap().time).abs() * DAY_SECS
|
||||
- 1.0
|
||||
} else {
|
||||
let first_time = plist.time_slices.get(0).unwrap().time;
|
||||
(((time - 1.0).abs() + first_time) * DAY_SECS - 1.0).ceil()
|
||||
}
|
||||
},
|
||||
from: format!("{}/{}.png", parent_directory.to_string_lossy(), time_idx),
|
||||
to: format!("{}/{}.png", parent_directory.to_string_lossy(), {
|
||||
if time_idx < number_of_images - 1 {
|
||||
time_idx + 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}),
|
||||
idx: time_idx,
|
||||
});
|
||||
let pt = ImagePoint{
|
||||
image_ctx: &image_ctx,
|
||||
img_id,
|
||||
index: time_idx,
|
||||
background: &mut xml_background,
|
||||
parent_directory,
|
||||
start_time,
|
||||
time: *time,
|
||||
next_time: plist.time_slices.get(time_idx + 1).map(|elem| elem.time).unwrap_or(0f32),
|
||||
};
|
||||
process_img(pt)?;
|
||||
}
|
||||
println!("{}: {}", "Conversion".yellow(), "Done!");
|
||||
|
||||
println!("{}: {}", "Conversion".green(), "Creating xml description for new wallpaper");
|
||||
xml_background.images.sort_by(|a, b| match (a, b) {
|
||||
(
|
||||
Static {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Transition {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Static {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Static {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Transition {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Static {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
(
|
||||
Transition {
|
||||
idx: static_idx, ..
|
||||
},
|
||||
Transition {
|
||||
idx: transition_idx,
|
||||
..
|
||||
},
|
||||
) => static_idx.cmp(&transition_idx),
|
||||
});
|
||||
|
||||
println!("{}: {}", "Conversion".green(), "Writing wallpaper description");
|
||||
let result_file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.open(format!(
|
||||
"{}/default.xml",
|
||||
parent_directory.to_string_lossy()
|
||||
))?;
|
||||
let mut result = BufWriter::new(result_file);
|
||||
let mut ser = GnomeXMLBackgroundSerializer::new(&mut result);
|
||||
ser.serialize(&xml_background)?;
|
||||
println!("{}", "Done".green());
|
||||
Ok(())
|
||||
save_xml(&mut xml_background, parent_directory)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue