chore: 重构配置文件结构和灯条色彩获取逻辑。

This commit is contained in:
Ivan Li 2022-12-18 18:10:21 +08:00
parent 5042ff8bfb
commit 4ad78ae5cc
6 changed files with 278 additions and 133 deletions

View File

@ -118,16 +118,21 @@ impl CoreManager {
let mut global_colors = HashMap::new();
while let Some(screenshot) = rx.recv().await {
let start_at = Instant::now();
match screenshot.get_top_colors().await {
Ok(colors) => {
let start = screenshot.get_top_of_led_start_at().min(screenshot.get_top_of_led_end_at());
let colors = screenshot.get_top_colors();
let start = screenshot
.get_top_of_led_start_at()
.min(screenshot.get_top_of_led_end_at());
let colors_len = colors.len();
for (index, color) in colors.into_iter().enumerate() {
global_colors.insert(index + start, color);
}
info!("led count: {}, spend: {:?}", global_colors.len(), start_at.elapsed());
info!(
"led count: {}, spend: {:?}",
global_colors.len(),
start_at.elapsed()
);
if global_colors.len() == 60 {
let mut colors = vec![];
@ -148,9 +153,6 @@ impl CoreManager {
}
}
}
Err(_) => {}
};
}
});
join_all(futs).await;

View File

@ -2,6 +2,7 @@
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
#![feature(bool_to_option)]
mod core;
mod picker;
@ -11,10 +12,11 @@ use crate::core::AmbientLightMode;
use crate::core::CoreManager;
use paris::*;
use picker::manager::Picker;
use picker::screenshot::ScreenshotDto;
use std::vec;
#[tauri::command]
async fn take_snapshot() -> Vec<String> {
async fn take_snapshot() -> Vec<ScreenshotDto> {
let manager = Picker::global();
let start = time::Instant::now();
@ -29,7 +31,7 @@ async fn take_snapshot() -> Vec<String> {
vec![]
}
};
info!("截图花费 {} s", start.elapsed().as_seconds_f32());
info!("截图耗时 {} s", start.elapsed().as_seconds_f32());
base64_bitmap_list
}

View File

@ -12,10 +12,10 @@ pub struct DisplayConfig {
pub index_of_display: usize,
pub display_width: usize,
pub display_height: usize,
pub top_led_strip: LedStripConfig,
pub bottom_led_strip: LedStripConfig,
pub left_led_strip: LedStripConfig,
pub right_led_strip: LedStripConfig,
pub top_led_strip: Option<LedStripConfig>,
pub bottom_led_strip: Option<LedStripConfig>,
pub left_led_strip: Option<LedStripConfig>,
pub right_led_strip: Option<LedStripConfig>,
}
impl DisplayConfig {
@ -24,26 +24,10 @@ impl DisplayConfig {
index_of_display,
display_width,
display_height,
top_led_strip: LedStripConfig {
index: 0,
global_start_position: 0,
global_end_position: 0,
},
bottom_led_strip: LedStripConfig {
index: 0,
global_start_position: 0,
global_end_position: 0,
},
left_led_strip: LedStripConfig {
index: 0,
global_start_position: 0,
global_end_position: 0,
},
right_led_strip: LedStripConfig {
index: 0,
global_start_position: 0,
global_end_position: 0,
},
top_led_strip: None,
bottom_led_strip: None,
left_led_strip: None,
right_led_strip: None,
}
}
}

View File

@ -1,7 +1,7 @@
use color_space::{Hsv, Rgb};
use serde::Serialize;
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub struct LedColor {
bits: [u8; 3],
}

View File

@ -2,12 +2,16 @@ use futures::{stream::FuturesUnordered, StreamExt};
use once_cell::sync::OnceCell;
use paris::info;
use scrap::Display;
use std::{sync::Arc, borrow::Borrow};
use std::{borrow::Borrow, sync::Arc};
use tokio::{sync::Mutex, task};
use crate::picker::{config, screen::Screen};
use super::{config::DisplayConfig, display_picker::DisplayPicker, screenshot::Screenshot};
use super::{
config::DisplayConfig,
display_picker::DisplayPicker,
screenshot::{Screenshot, ScreenshotDto},
};
pub struct Picker {
pub screens: Arc<Mutex<Vec<Screen>>>,
@ -28,7 +32,7 @@ impl Picker {
})
}
pub async fn list_displays(&self) -> anyhow::Result<Vec<String>> {
pub async fn list_displays(&self) -> anyhow::Result<Vec<ScreenshotDto>> {
let mut configs = self.display_configs.lock().await;
let displays = Display::all()
@ -64,12 +68,12 @@ impl Picker {
Ok(bitmap_string_list)
}
pub async fn preview_display_by_config(config: DisplayConfig) -> anyhow::Result<String> {
pub async fn preview_display_by_config(config: DisplayConfig) -> anyhow::Result<ScreenshotDto> {
let start = time::Instant::now();
let mut picker = DisplayPicker::from_config(config)?;
let screenshot = picker.take_screenshot()?;
info!("Take Screenshot Spend: {}", start.elapsed());
anyhow::Ok(screenshot.to_webp_base64().await)
anyhow::Ok(screenshot.to_dto().await)
}
}

View File

@ -1,101 +1,233 @@
use std::ops::Range;
use std::iter;
use color_space::{Hsv, Rgb};
use either::Either;
use serde::{Deserialize, Serialize};
use super::{
config::{DisplayConfig, LedStripConfig},
led_color::LedColor,
};
#[derive(Clone)]
type Point = (usize, usize);
type LedSamplePoints = Vec<Point>;
#[derive(Clone, Serialize, Deserialize, Debug)]
struct ScreenSamplePoints {
pub top: Vec<LedSamplePoints>,
pub bottom: Vec<LedSamplePoints>,
pub left: Vec<LedSamplePoints>,
pub right: Vec<LedSamplePoints>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Screenshot {
bitmap: Vec<u8>,
config: DisplayConfig,
sample_points: ScreenSamplePoints,
}
impl Screenshot {
pub fn new(bitmap: Vec<u8>, config: DisplayConfig) -> Self {
Self { bitmap, config }
Self {
bitmap,
config,
sample_points: Self::get_sample_points(config),
}
}
pub async fn get_top_colors(&self) -> anyhow::Result<Vec<LedColor>> {
self.get_x_colors(XPosition::Top, self.config.top_led_strip)
.await
}
pub async fn get_bottom_colors(&self) -> anyhow::Result<Vec<LedColor>> {
self.get_x_colors(XPosition::Bottom, self.config.bottom_led_strip)
.await
}
pub fn get_top_of_led_start_at(&self) -> usize {
self.config.top_led_strip.global_start_position
}
pub fn get_top_of_led_end_at(&self) -> usize {
self.config.top_led_strip.global_end_position
}
async fn get_x_colors(
&self,
position: XPosition,
strip_config: LedStripConfig,
) -> anyhow::Result<Vec<LedColor>> {
let bitmap = &self.bitmap;
let number_of_leds = strip_config
fn get_sample_points(config: DisplayConfig) -> ScreenSamplePoints {
let top = match config.top_led_strip {
Some(led_strip_config) => Self::get_one_edge_sample_points(
config.display_height / 8,
config.display_width,
led_strip_config
.global_start_position
.abs_diff(strip_config.global_end_position)
+ 1;
if number_of_leds == 0 {
return Ok(vec![]);
.abs_diff(led_strip_config.global_end_position),
5,
),
None => {
vec![]
}
let cell_size_x = self.config.display_width / number_of_leds;
let cell_size_y = self.config.display_height / 8;
let cell_size = cell_size_x * cell_size_y;
let y_range = match position {
XPosition::Top => 20..cell_size_y + 20,
XPosition::Bottom => {
self.config.display_height - 20 - cell_size_y..self.config.display_height - 20
}
}
.step_by(5);
let x_range = if strip_config.global_start_position < strip_config.global_end_position {
Either::Left(strip_config.global_start_position..=strip_config.global_end_position)
} else {
Either::Right(
(strip_config.global_end_position..=strip_config.global_start_position).rev(),
)
};
let mut colors = Vec::new();
let stride = bitmap.len() / self.config.display_height;
let bottom: Vec<LedSamplePoints> = match config.top_led_strip {
Some(led_strip_config) => {
let points = Self::get_one_edge_sample_points(
config.display_height / 9,
config.display_width,
led_strip_config
.global_start_position
.abs_diff(led_strip_config.global_end_position),
5,
);
points
.into_iter()
.map(|groups| -> Vec<Point> {
groups
.into_iter()
.map(|(x, y)| (x, config.display_height - y))
.collect()
})
.collect()
}
None => {
vec![]
}
};
for pos in x_range {
let left: Vec<LedSamplePoints> = match config.top_led_strip {
Some(led_strip_config) => {
let points = Self::get_one_edge_sample_points(
config.display_width / 16,
config.display_height,
led_strip_config
.global_start_position
.abs_diff(led_strip_config.global_end_position),
5,
);
points
.into_iter()
.map(|groups| -> Vec<Point> {
groups.into_iter().map(|(x, y)| (y, x)).collect()
})
.collect()
}
None => {
vec![]
}
};
let right: Vec<LedSamplePoints> = match config.top_led_strip {
Some(led_strip_config) => {
let points = Self::get_one_edge_sample_points(
config.display_width / 16,
config.display_height,
led_strip_config
.global_start_position
.abs_diff(led_strip_config.global_end_position),
5,
);
points
.into_iter()
.map(|groups| -> Vec<Point> {
groups
.into_iter()
.map(|(x, y)| (y, config.display_width - x))
.collect()
})
.collect()
}
None => {
vec![]
}
};
ScreenSamplePoints {
top,
bottom,
left,
right,
}
}
fn get_one_edge_sample_points(
width: usize,
length: usize,
leds: usize,
single_axis_points: usize,
) -> Vec<LedSamplePoints> {
let cell_size_x = length as f64 / single_axis_points as f64 / leds as f64;
let cell_size_y = width / single_axis_points;
let point_start_y = cell_size_y / 2;
let point_start_x = cell_size_x / 2.0;
let point_y_list: Vec<usize> = (point_start_y..width).step_by(cell_size_y).collect();
let point_x_list: Vec<usize> = iter::successors(Some(point_start_x), |i| {
let next = i + cell_size_x;
(next < (width as f64)).then_some(next)
})
.map(|i| i as usize)
.collect();
let points: Vec<Point> = point_x_list
.into_iter()
.zip(point_y_list.into_iter())
.collect();
points
.chunks(single_axis_points * single_axis_points)
.into_iter()
.map(|points| Vec::from(points))
.collect()
}
pub fn get_colors(&self) -> DisplayColorsOfLedStrips {
let top = self
.get_one_edge_colors(&self.sample_points.top)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let bottom = self
.get_one_edge_colors(&self.sample_points.bottom)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let left = self
.get_one_edge_colors(&self.sample_points.left)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
let right = self
.get_one_edge_colors(&self.sample_points.right)
.into_iter()
.flat_map(|color| color.get_rgb())
.collect();
DisplayColorsOfLedStrips {
top,
bottom,
left,
right,
}
}
pub fn get_one_edge_colors(
&self,
sample_points_of_leds: &Vec<LedSamplePoints>,
) -> Vec<LedColor> {
let mut colors = vec![];
for led_points in sample_points_of_leds {
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
let mut count = 0;
for x in (pos * cell_size_x..(pos + 1) * cell_size_x).step_by(5) {
for y in y_range.to_owned() {
let i = stride * y + 4 * x;
r += bitmap[i + 2] as f64;
g += bitmap[i + 1] as f64;
b += bitmap[i] as f64;
count+=1;
let len = led_points.len() as f64;
for (x, y) in led_points {
let position = (x + y * self.config.display_width) * 4;
r += self.bitmap[position + 2] as f64;
g += self.bitmap[position + 1] as f64;
b += self.bitmap[position] as f64;
}
}
let rgb = Rgb::new(
r / count as f64,
g / count as f64,
b / count as f64,
);
let hsv = Hsv::from(rgb);
// info!("HSV: {:?}", [hsv.h, hsv.s, hsv.v]);
let color = LedColor::from_hsv(hsv.h, hsv.s, hsv.v);
let color = LedColor::new((r / len) as u8, (g / len) as u8, (b / len) as u8);
// paris::info!("color: {:?}", color.get_rgb());
colors.push(color);
}
return Ok(colors);
colors
}
pub fn get_top_colors(&self) -> Vec<LedColor> {
self.get_one_edge_colors(&self.sample_points.top)
}
pub fn get_top_of_led_start_at(&self) -> usize {
self.config
.top_led_strip
.and_then(|c| Some(c.global_start_position))
.unwrap_or(0)
}
pub fn get_top_of_led_end_at(&self) -> usize {
self.config
.top_led_strip
.and_then(|c| Some(c.global_end_position))
.unwrap_or(0)
}
pub async fn to_webp_base64(&self) -> String {
@ -119,9 +251,30 @@ impl Screenshot {
.encode(100.0);
return base64::encode(&*webp_memory);
}
pub async fn to_dto(&self) -> ScreenshotDto {
let encode_image = self.to_webp_base64().await;
let config = self.config.clone();
let colors = self.get_colors();
ScreenshotDto {
encode_image,
config,
colors,
}
}
}
enum XPosition {
Top,
Bottom,
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ScreenshotDto {
pub config: DisplayConfig,
pub encode_image: String,
pub colors: DisplayColorsOfLedStrips,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct DisplayColorsOfLedStrips {
pub top: Vec<u8>,
pub bottom: Vec<u8>,
pub left: Vec<u8>,
pub right: Vec<u8>,
}