working again

This commit is contained in:
Your Name
2026-03-16 23:40:30 +01:00
parent 31c10d456c
commit d030d9f069
10 changed files with 321 additions and 158 deletions

272
Cargo.lock generated
View File

@@ -33,12 +33,12 @@ dependencies = [
"anyhow",
"config",
"ctrlc",
"embed-resource",
"futures",
"grim-rs",
"image",
"image-compare",
"libc",
"okmain",
"oklab",
"png 0.17.16",
"reqwest",
"rgb",
"serde",
@@ -426,7 +426,7 @@ dependencies = [
"serde-untagged",
"serde_core",
"serde_json",
"toml",
"toml 1.0.6+spec-1.1.0",
"winnow",
"yaml-rust2",
]
@@ -680,6 +680,20 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "embed-resource"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d506610004cfc74a6f5ee7e8c632b355de5eca1f03ee5e5e0ec11b77d4eb3d61"
dependencies = [
"cc",
"memchr",
"rustc_version",
"toml 0.8.23",
"vswhom",
"winreg",
]
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -1076,12 +1090,6 @@ dependencies = [
"hashbrown 0.15.5",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -1343,18 +1351,6 @@ dependencies = [
"zune-jpeg",
]
[[package]]
name = "image-compare"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "176623a137baf75908084aff53578d6336cbd932bffaf12fabe26b343eb13338"
dependencies = [
"image",
"itertools",
"rayon",
"thiserror 2.0.18",
]
[[package]]
name = "image-webp"
version = "0.2.4"
@@ -1775,20 +1771,6 @@ dependencies = [
"rgb",
]
[[package]]
name = "okmain"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49e2519388a310524c60205a1321707d0e9790fa7da2d0a41cc627922cfd6933"
dependencies = [
"fast-srgb8",
"oklab",
"rand 0.10.0",
"rand_xoshiro",
"rgb",
"snafu",
]
[[package]]
name = "once_cell"
version = "1.21.4"
@@ -2057,7 +2039,7 @@ dependencies = [
"bytes",
"getrandom 0.3.4",
"lru-slab",
"rand 0.9.2",
"rand",
"ring",
"rustc-hash",
"rustls",
@@ -2105,16 +2087,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha",
"rand_core 0.9.5",
]
[[package]]
name = "rand"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
dependencies = [
"rand_core 0.10.0",
"rand_core",
]
[[package]]
@@ -2124,7 +2097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.5",
"rand_core",
]
[[package]]
@@ -2136,21 +2109,6 @@ dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "rand_core"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
[[package]]
name = "rand_xoshiro"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f0b2cc7bfeef8f0320ca45f88b00157a03c67137022d59393614352d6bf4312"
dependencies = [
"rand_core 0.10.0",
]
[[package]]
name = "rav1e"
version = "0.8.1"
@@ -2178,7 +2136,7 @@ dependencies = [
"num-traits",
"paste",
"profiling",
"rand 0.9.2",
"rand",
"rand_chacha",
"simd_helpers",
"thiserror 2.0.18",
@@ -2323,6 +2281,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "1.1.4"
@@ -2464,6 +2431,12 @@ dependencies = [
"libc",
]
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
@@ -2519,6 +2492,15 @@ dependencies = [
"zmij",
]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "1.0.4"
@@ -2582,27 +2564,6 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "snafu"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2"
dependencies = [
"snafu-derive",
]
[[package]]
name = "snafu-derive"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "socket2"
version = "0.6.3"
@@ -2844,6 +2805,18 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
"toml_edit",
]
[[package]]
name = "toml"
version = "1.0.6+spec-1.1.0"
@@ -2851,12 +2824,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc"
dependencies = [
"serde_core",
"serde_spanned",
"toml_datetime",
"serde_spanned 1.0.4",
"toml_datetime 1.0.0+spec-1.1.0",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "1.0.0+spec-1.1.0"
@@ -2866,6 +2848,20 @@ dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
"toml_write",
"winnow",
]
[[package]]
name = "toml_parser"
version = "1.0.9+spec-1.1.0"
@@ -2875,6 +2871,12 @@ dependencies = [
"winnow",
]
[[package]]
name = "toml_write"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "tower"
version = "0.5.3"
@@ -3045,6 +3047,26 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vswhom"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
dependencies = [
"libc",
"vswhom-sys",
]
[[package]]
name = "vswhom-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -3353,6 +3375,15 @@ dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@@ -3404,6 +3435,21 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@@ -3443,6 +3489,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@@ -3461,6 +3513,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@@ -3479,6 +3537,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -3509,6 +3573,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@@ -3527,6 +3597,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@@ -3545,6 +3621,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@@ -3563,6 +3645,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
@@ -3584,6 +3672,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"

View File

@@ -2,21 +2,24 @@
name = "ambiligth"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[dependencies]
anyhow = "1.0"
config = "0.15.21"
ctrlc = "3.5.2"
futures = "0.3"
image = "0.25.10"
image-compare = "0.5.0"
okmain = "0.2.0"
oklab = "1.1.2"
png = "0.17"
reqwest = { version = "0.13.2", features = ["json"] }
rgb = "0.8"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
tokio = { version = "1.50.0", features = ["full"] }
[build-dependencies]
embed-resource = "2.3"
[target.'cfg(unix)'.dependencies]
grim-rs = "0.1.6"
libc = "0.2.183"

7
build.rs Normal file
View File

@@ -0,0 +1,7 @@
#[cfg(target_os = "windows")]
fn main() {
embed_resource::compile("resources.rc", embed_resource::NONE);
}
#[cfg(not(target_os = "windows"))]
fn main() {}

View File

@@ -2,30 +2,30 @@
# The base URL of your Home Assistant instance.
# Example: "http://192.168.1.100:8123" or "https://ha.yourdomain.com"
ha_url = "https://homeassistant.pvv.ntnu.no:8123"
#ha_url = "https://homeassistant.pvv.ntnu.no:8123"
ha_url = "http://192.168.1.238:8123"
# A Long-Lived Access Token from Home Assistant.
# You can generate this in Home Assistant by going to your user profile.
ha_token = ""
ha_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJiMWU1ZmU2MWNlMjM0YzNkYjg2OWY1NTMzZGY5NGFjOCIsImlhdCI6MTc3MzY4ODMzOSwiZXhwIjoyMDg5MDQ4MzM5fQ.5dRwDrWakUeQk_3tCwurnqnsv3GLuukUEE3IyWnbK1g"
# Screenshot capture rate (FPS). How often to capture and analyze the screen.
screenshot_fps = 15
screenshot_fps = 10
# Maximum light update rate (FPS). Lights only update when color actually changes.
# This acts as a rate limiter to prevent spamming Home Assistant.
target_fps = 3
target_fps = 2
# Color smoothing factor (0.0 to 1.0)
# Higher values = slower, smoother transitions (0.0 = instant, 1.0 = no movement)
smoothing = 0.6
smoothing = 0.0
# Specific lights to control. If empty, all supported color lights are used.
# Specific lights to control. If empty, all supported color lights are used.https://docs.rs/oklab/1.1.2/oklab/
# Example: ["light.living_room", "light.bedroom"]
lights = ["light.fargelys"]
#lights = ["light.fargelys"]
# Restore lights to their original state/color when the program exits.
restore_on_exit = true
# Minimum percentage of difference required between frames to trigger an update.
# Helps prevent flickering on static screens due to non-deterministic color algorithm.
min_diff_percent = 10.0
min_diff_percent = 0.1

View File

@@ -57,7 +57,6 @@
rustfmt
clippy
rustPlatform.bindgenHook
pkgs.pkgsCross.mingwW64.windows.mingw_w64_headers
dbus
gtk3
glib

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -50,8 +50,20 @@ pub fn run_loop(
match active.as_ref() {
None => true,
Some(active_screenshot) => {
let diff = current_arc.diff_percent(active_screenshot);
diff >= settings_screenshot.min_diff_percent
let active_color = active_screenshot.average_color(
settings_screenshot.brightness_boost,
settings_screenshot.saturation_boost,
);
let _current_color = current_arc.average_color(
settings_screenshot.brightness_boost,
settings_screenshot.saturation_boost,
);
let color_diff = current_arc.color_diff(
&active_color,
settings_screenshot.brightness_boost,
settings_screenshot.saturation_boost,
);
color_diff >= settings_screenshot.min_diff_percent
}
}
};
@@ -104,7 +116,10 @@ pub fn run_loop(
};
if let Some(screenshot) = active_screenshot {
let color = screenshot.dominant_color();
let color = screenshot.average_color(
settings.brightness_boost,
settings.saturation_boost,
);
let new_target = RGB::new(color.r as f32, color.g as f32, color.b as f32);
{

View File

@@ -4,11 +4,28 @@ mod screenshot;
mod settings;
mod state;
use std::io::Cursor;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tray_item::{IconSource, TrayItem};
fn get_tray_icon() -> IconSource {
let icon_data = include_bytes!("../icon.png");
let cursor = Cursor::new(&icon_data[..]);
let mut decoder = png::Decoder::new(cursor);
decoder.set_transformations(png::Transformations::normalize_to_color8());
let mut reader = decoder.read_info().expect("Failed to read icon PNG");
let mut buf: Vec<u8> = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf).expect("Failed to decode icon PNG");
IconSource::Data {
data: buf,
width: info.width as i32,
height: info.height as i32,
}
}
fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
let rt_handle = rt.handle().clone();
@@ -71,16 +88,10 @@ fn main() {
);
});
// Create the tray application
// On Linux: empty string works as a default/no icon
// On Windows: use IDI_APPLICATION (default app icon) to avoid resource issues
#[cfg(unix)]
let icon_source = IconSource::Resource("");
#[cfg(windows)]
let icon_source = IconSource::Resource("#32512"); // IDI_APPLICATION
let icon_source = get_tray_icon();
let mut tray = TrayItem::new("Ambiligth", icon_source)
.expect("Failed to create tray icon. On Windows, this may require a valid icon resource.");
.expect("Failed to create tray icon");
let is_running_toggle = is_running.clone();
let restore_on_toggle = settings_arc.restore_on_exit;

View File

@@ -17,62 +17,78 @@ pub struct Screenshot {
}
impl Screenshot {
pub fn dominant_color(&self) -> rgb::Rgb<u8> {
let mut rgb_data = vec![0u8; self.data.len() * 3];
pub fn average_color(&self, brightness_boost: f32, saturation_boost: f32) -> rgb::Rgb<u8> {
let mut sum_l = 0.0f32;
let mut sum_a = 0.0f32;
let mut sum_b = 0.0f32;
for (i, p) in self.data.iter().enumerate() {
let offset = i * 3;
rgb_data[offset] = p.r;
rgb_data[offset + 1] = p.g;
rgb_data[offset + 2] = p.b;
for pixel in &self.data {
if pixel.a == 0 {
continue;
}
let r = pixel.r as f32 / 255.0;
let g = pixel.g as f32 / 255.0;
let b = pixel.b as f32 / 255.0;
let linear_rgb = oklab::LinearRgb::new(r, g, b);
let oklab_color = oklab::linear_srgb_to_oklab(linear_rgb);
sum_l += oklab_color.l;
sum_a += oklab_color.a;
sum_b += oklab_color.b;
}
let input =
okmain::InputImage::from_bytes(self.width as u16, self.height as u16, &rgb_data)
.expect("Failed to create okmain InputImage");
let palette = okmain::colors(input);
palette
.into_iter()
.next()
.map(|c| rgb::Rgb {
r: c.r,
g: c.g,
b: c.b,
})
.unwrap_or(rgb::Rgb { r: 0, g: 0, b: 0 })
let count = self.data.len() as f32;
let avg_l = sum_l / count;
let avg_a = sum_a / count;
let avg_b = sum_b / count;
let target_l = brightness_boost;
let boosted_l = (avg_l + target_l) / 2.0;
let boosted_a = avg_a * saturation_boost;
let boosted_b = avg_b * saturation_boost;
let oklab_avg = oklab::Oklab {
l: boosted_l,
a: boosted_a,
b: boosted_b,
};
let linear_rgb = oklab::oklab_to_linear_srgb(oklab_avg);
rgb::Rgb {
r: (linear_rgb.r * 255.0).clamp(0.0, 255.0) as u8,
g: (linear_rgb.g * 255.0).clamp(0.0, 255.0) as u8,
b: (linear_rgb.b * 255.0).clamp(0.0, 255.0) as u8,
}
}
/// Compares this screenshot against another and returns the percentage of difference (0.0 to 100.0)
pub fn diff_percent(&self, other: &Screenshot) -> f32 {
if self.width != other.width || self.height != other.height {
return 100.0;
}
pub fn color_diff(
&self,
color: &rgb::Rgb<u8>,
brightness_boost: f32,
saturation_boost: f32,
) -> f32 {
let avg_color = self.average_color(brightness_boost, saturation_boost);
let mut rgb_data1 = vec![0u8; self.data.len() * 3];
let mut rgb_data2 = vec![0u8; other.data.len() * 3];
let r1 = avg_color.r as f32 / 255.0;
let g1 = avg_color.g as f32 / 255.0;
let b1 = avg_color.b as f32 / 255.0;
for (i, (p1, p2)) in self.data.iter().zip(other.data.iter()).enumerate() {
let offset = i * 3;
rgb_data1[offset] = p1.r;
rgb_data1[offset + 1] = p1.g;
rgb_data1[offset + 2] = p1.b;
let r2 = color.r as f32 / 255.0;
let g2 = color.g as f32 / 255.0;
let b2 = color.b as f32 / 255.0;
rgb_data2[offset] = p2.r;
rgb_data2[offset + 1] = p2.g;
rgb_data2[offset + 2] = p2.b;
}
let oklab1 = oklab::linear_srgb_to_oklab(oklab::LinearRgb::new(r1, g1, b1));
let oklab2 = oklab::linear_srgb_to_oklab(oklab::LinearRgb::new(r2, g2, b2));
let img1 = image::RgbImage::from_vec(self.width as u32, self.height as u32, rgb_data1)
.expect("Failed to create image1 buffer");
let img2 = image::RgbImage::from_vec(other.width as u32, other.height as u32, rgb_data2)
.expect("Failed to create image2 buffer");
let delta_l = (oklab1.l - oklab2.l).abs();
let delta_a = (oklab1.a - oklab2.a).abs();
let delta_b = (oklab1.b - oklab2.b).abs();
let algo = image_compare::Algorithm::MSSIMSimple;
if let Ok(res) = image_compare::rgb_similarity_structure(&algo, &img1, &img2) {
((1.0 - res.score) * 100.0) as f32
} else {
100.0
}
let delta_e = (delta_l * delta_l + delta_a * delta_a + delta_b * delta_b).sqrt();
(delta_e * 1000.0).clamp(0.0, 100.0) as f32
}
}
@@ -212,8 +228,8 @@ mod ffi {
#![allow(non_snake_case, dead_code)]
use super::{Pixel, ScreenResult, Screenshot};
use std::ffi::c_void;
use std::os::raw::{c_int, c_long, c_uint};
use std::mem::size_of;
use std::os::raw::{c_int, c_long, c_uint};
type PVOID = *mut c_void;
type LPVOID = *mut c_void;

View File

@@ -26,12 +26,26 @@ pub struct Settings {
#[serde(default = "default_min_diff_percent")]
pub min_diff_percent: f32,
#[serde(default = "default_brightness_boost")]
pub brightness_boost: f32,
#[serde(default = "default_saturation_boost")]
pub saturation_boost: f32,
}
fn default_min_diff_percent() -> f32 {
1.0
}
fn default_brightness_boost() -> f32 {
0.5
}
fn default_saturation_boost() -> f32 {
2.0
}
fn default_restore_on_exit() -> bool {
true
}