feat: 支持将色彩校准的值写入本地配置文件。

This commit is contained in:
Ivan Li 2023-04-16 18:17:49 +08:00
parent fc8b3164d8
commit 6e6160fc0a
10 changed files with 145 additions and 19 deletions

View File

@ -2,7 +2,8 @@
"files.autoSave": "onWindowChange", "files.autoSave": "onWindowChange",
"cSpell.words": [ "cSpell.words": [
"Itertools", "Itertools",
"Leds" "Leds",
"unlisten"
], ],
"idf.customExtraVars": { "idf.customExtraVars": {
"OPENOCD_SCRIPTS": "/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20211220/openocd-esp32/share/openocd/scripts" "OPENOCD_SCRIPTS": "/Users/ivan/.espressif/tools/openocd-esp32/v0.11.0-esp32-20211220/openocd-esp32/share/openocd/scripts"

7
.vscode/tasks.json vendored
View File

@ -14,7 +14,12 @@
], ],
"problemMatcher": [ "problemMatcher": [
"$eslint-stylish" "$eslint-stylish"
] ],
"options": {
"env": {
"RUST_LOG": "info"
}
}
}, },
{ {
"label": "ui:dev", "label": "ui:dev",

View File

@ -5,7 +5,7 @@ use paris::{error, info};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::api::path::config_dir; use tauri::api::path::config_dir;
use crate::screenshot::{self, LedSamplePoints}; use crate::screenshot::LedSamplePoints;
const CONFIG_FILE_NAME: &str = "cc.ivanli.ambient_light/led_strip_config.toml"; const CONFIG_FILE_NAME: &str = "cc.ivanli.ambient_light/led_strip_config.toml";
@ -26,10 +26,18 @@ pub struct LedStripConfig {
pub len: usize, pub len: usize,
} }
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct ColorCalibration {
r: f32,
g: f32,
b: f32,
}
#[derive(Clone, Serialize, Deserialize, Debug)] #[derive(Clone, Serialize, Deserialize, Debug)]
pub struct LedStripConfigGroup { pub struct LedStripConfigGroup {
pub strips: Vec<LedStripConfig>, pub strips: Vec<LedStripConfig>,
pub mappers: Vec<SamplePointMapper>, pub mappers: Vec<SamplePointMapper>,
pub color_calibration: ColorCalibration,
} }
impl LedStripConfigGroup { impl LedStripConfigGroup {
@ -115,7 +123,17 @@ impl LedStripConfigGroup {
}) })
} }
} }
Ok(Self { strips, mappers }) let color_calibration = ColorCalibration {
r: 1.0,
g: 1.0,
b: 1.0,
};
Ok(Self {
strips,
mappers,
color_calibration,
})
} }
} }

View File

@ -5,7 +5,7 @@ use tokio::sync::OnceCell;
use crate::ambient_light::{config, LedStripConfigGroup}; use crate::ambient_light::{config, LedStripConfigGroup};
use super::{Border, SamplePointMapper}; use super::{Border, SamplePointMapper, ColorCalibration};
pub struct ConfigManager { pub struct ConfigManager {
config: Arc<RwLock<LedStripConfigGroup>>, config: Arc<RwLock<LedStripConfigGroup>>,
@ -223,4 +223,15 @@ impl ConfigManager {
) -> tokio::sync::watch::Receiver<LedStripConfigGroup> { ) -> tokio::sync::watch::Receiver<LedStripConfigGroup> {
self.config_update_receiver.clone() self.config_update_receiver.clone()
} }
pub async fn set_color_calibration(&self, color_calibration: ColorCalibration) -> anyhow::Result<()> {
let config = self.config.write().await;
let mut cloned_config = config.clone();
cloned_config.color_calibration = color_calibration;
drop(config);
self.update(&cloned_config).await
}
} }

View File

@ -192,7 +192,7 @@ impl LedColorsPublisher {
warn!("Failed to send sorted colors: {}", err); warn!("Failed to send sorted colors: {}", err);
} }
}; };
log::info!("tick: {}ms", start.elapsed().as_millis()); log::debug!("tick: {}ms", start.elapsed().as_millis());
start = tokio::time::Instant::now(); start = tokio::time::Instant::now();
} }
} }

View File

@ -8,7 +8,9 @@ mod rpc;
pub mod screenshot; pub mod screenshot;
mod screenshot_manager; mod screenshot_manager;
use ambient_light::{Border, LedColorsPublisher, LedStripConfig, LedStripConfigGroup}; use ambient_light::{
Border, ColorCalibration, LedColorsPublisher, LedStripConfig, LedStripConfigGroup,
};
use core_graphics::display::{ use core_graphics::display::{
kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay, kCGNullWindowID, kCGWindowImageDefault, kCGWindowListOptionOnScreenOnly, CGDisplay,
}; };
@ -145,14 +147,14 @@ async fn send_colors(buffer: Vec<u8>) -> Result<(), String> {
} }
#[tauri::command] #[tauri::command]
async fn move_strip_part(display_id: u32, border: Border, target_start: usize) -> Result<(), String> { async fn move_strip_part(
display_id: u32,
border: Border,
target_start: usize,
) -> Result<(), String> {
let config_manager = ambient_light::ConfigManager::global().await; let config_manager = ambient_light::ConfigManager::global().await;
config_manager config_manager
.move_strip_part( .move_strip_part(display_id, border, target_start)
display_id,
border,
target_start,
)
.await .await
.map_err(|e| { .map_err(|e| {
error!("can not move strip part: {}", e); error!("can not move strip part: {}", e);
@ -172,6 +174,18 @@ async fn reverse_led_strip_part(display_id: u32, border: Border) -> Result<(), S
}) })
} }
#[tauri::command]
async fn set_color_calibration(calibration: ColorCalibration) -> Result<(), String> {
let config_manager = ambient_light::ConfigManager::global().await;
config_manager
.set_color_calibration(calibration)
.await
.map_err(|e| {
error!("can not set color calibration: {}", e);
e.to_string()
})
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
env_logger::init(); env_logger::init();
@ -194,6 +208,7 @@ async fn main() {
send_colors, send_colors,
move_strip_part, move_strip_part,
reverse_led_strip_part, reverse_led_strip_part,
set_color_calibration,
]) ])
.register_uri_scheme_protocol("ambient-light", move |_app, request| { .register_uri_scheme_protocol("ambient-light", move |_app, request| {
let response = ResponseBuilder::new().header("Access-Control-Allow-Origin", "*"); let response = ResponseBuilder::new().header("Access-Control-Allow-Origin", "*");
@ -359,6 +374,7 @@ async fn main() {
.unwrap(); .unwrap();
} }
}); });
let app_handle = app.handle().clone(); let app_handle = app.handle().clone();
tokio::spawn(async move { tokio::spawn(async move {
let publisher = ambient_light::LedColorsPublisher::global().await; let publisher = ambient_light::LedColorsPublisher::global().await;

View File

@ -1,13 +1,18 @@
import { Component, JSX } from 'solid-js'; import { Component, JSX } from 'solid-js';
type Props = {} & JSX.HTMLAttributes<HTMLInputElement>; type Props = {
value?: number;
} & JSX.HTMLAttributes<HTMLInputElement>;
export const ColorSlider: Component<Props> = (props) => { export const ColorSlider: Component<Props> = (props) => {
return ( return (
<input <input
type="range" type="range"
value="50"
{...props} {...props}
max={1}
min={0}
step={0.01}
value={props.value}
class={ class={
'w-full h-2 bg-gradient-to-r rounded-lg appearance-none cursor-pointer dark:bg-gray-700 drop-shadow ' + 'w-full h-2 bg-gradient-to-r rounded-lg appearance-none cursor-pointer dark:bg-gray-700 drop-shadow ' +
props.class props.class

View File

@ -1,7 +1,38 @@
import { listen } from '@tauri-apps/api/event';
import { createEffect, onCleanup } from 'solid-js';
import { ColorCalibration, LedStripConfigContainer } from '../../models/led-strip-config';
import { ledStripStore, setLedStripStore } from '../../stores/led-strip.store';
import { ColorSlider } from './color-slider'; import { ColorSlider } from './color-slider';
import { TestColorsBg } from './test-colors-bg'; import { TestColorsBg } from './test-colors-bg';
import { invoke } from '@tauri-apps/api';
export const WhiteBalance = () => { export const WhiteBalance = () => {
// listen to config_changed event
createEffect(() => {
const unlisten = listen('config_changed', (event) => {
const { strips, mappers, color_calibration } =
event.payload as LedStripConfigContainer;
console.log(event.payload);
setLedStripStore({
strips,
mappers,
colorCalibration: color_calibration,
});
});
onCleanup(() => {
unlisten.then((unlisten) => unlisten());
});
});
const updateColorCalibration = (field: keyof ColorCalibration, value: number) => {
const calibration = { ...ledStripStore.colorCalibration, [field]: value };
console.log(field, calibration);
invoke('set_color_calibration', {
calibration,
}).catch((error) => console.log(error));
};
const exit = () => { const exit = () => {
window.history.back(); window.history.back();
}; };
@ -14,15 +45,42 @@ export const WhiteBalance = () => {
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10/12 max-w-lg bg-stone-200 p-5 rounded-xl drop-shadow"> <div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-10/12 max-w-lg bg-stone-200 p-5 rounded-xl drop-shadow">
<label class="flex items-center gap-2"> <label class="flex items-center gap-2">
<span class="w-3 block">R:</span> <span class="w-3 block">R:</span>
<ColorSlider class="from-cyan-500 to-red-500" /> <ColorSlider
class="from-cyan-500 to-red-500"
value={ledStripStore.colorCalibration.r}
onInput={(ev) =>
updateColorCalibration(
'r',
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
)
}
/>
</label> </label>
<label class="flex items-center gap-2"> <label class="flex items-center gap-2">
<span class="w-3 block">G:</span> <span class="w-3 block">G:</span>
<ColorSlider class="from-pink-500 to-green-500" /> <ColorSlider
class="from-pink-500 to-green-500"
value={ledStripStore.colorCalibration.g}
onInput={(ev) =>
updateColorCalibration(
'g',
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
)
}
/>
</label> </label>
<label class="flex items-center gap-2"> <label class="flex items-center gap-2">
<span class="w-3 block">B:</span> <span class="w-3 block">B:</span>
<ColorSlider class="from-yellow-500 to-blue-500" /> <ColorSlider
class="from-yellow-500 to-blue-500"
value={ledStripStore.colorCalibration.b}
onInput={(ev) =>
updateColorCalibration(
'b',
(ev.target as HTMLInputElement).valueAsNumber ?? 1,
)
}
/>
</label> </label>
<label class="flex items-center gap-2"> <label class="flex items-center gap-2">
<span class="w-3 block">W:</span> <span class="w-3 block">W:</span>

View File

@ -6,9 +6,16 @@ export type LedStripPixelMapper = {
pos: number; pos: number;
}; };
export class ColorCalibration {
r: number = 1;
g: number = 1;
b: number = 1;
}
export type LedStripConfigContainer = { export type LedStripConfigContainer = {
strips: LedStripConfig[]; strips: LedStripConfig[];
mappers: LedStripPixelMapper[]; mappers: LedStripPixelMapper[];
color_calibration: ColorCalibration;
}; };
export class LedStripConfig { export class LedStripConfig {

View File

@ -1,9 +1,14 @@
import { createStore } from 'solid-js/store'; import { createStore } from 'solid-js/store';
import { LedStripConfig, LedStripPixelMapper } from '../models/led-strip-config'; import {
ColorCalibration,
LedStripConfig,
LedStripPixelMapper,
} from '../models/led-strip-config';
export const [ledStripStore, setLedStripStore] = createStore({ export const [ledStripStore, setLedStripStore] = createStore({
strips: new Array<LedStripConfig>(), strips: new Array<LedStripConfig>(),
mappers: new Array<LedStripPixelMapper>(), mappers: new Array<LedStripPixelMapper>(),
colorCalibration: new ColorCalibration(),
colors: new Uint8ClampedArray(), colors: new Uint8ClampedArray(),
sortedColors: new Uint8ClampedArray(), sortedColors: new Uint8ClampedArray(),
get totalLedCount() { get totalLedCount() {