working again
This commit is contained in:
@@ -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);
|
||||
|
||||
{
|
||||
|
||||
27
src/main.rs
27
src/main.rs
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user