feat: 改进配置方式,重写逻辑。

This commit is contained in:
2022-11-28 00:09:18 +08:00
parent 7e1c4dd245
commit 479fdba9f6
10 changed files with 444 additions and 182 deletions

View File

@@ -0,0 +1,58 @@
#[derive(Clone, Copy)]
pub struct LedStripConfig {
pub index: usize,
pub global_start_position: usize,
pub global_end_position: usize,
}
#[derive(Clone, Copy)]
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,
}
#[derive(Clone, Copy)]
pub enum LedFlowX {
LR, // from left to right
RL, // from right to left
}
#[derive(Clone, Copy)]
pub enum LedFlowY {
TB, // from top to bottom
BT, // from bottom to top
}
impl DisplayConfig {
pub fn default(index_of_display: usize, display_width: usize, display_height: usize) -> Self {
Self {
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,
},
}
}
}

View File

@@ -0,0 +1,51 @@
use paris::info;
use scrap::{Capturer, Display};
use super::{config::DisplayConfig, screen::Screen, screenshot::Screenshot};
pub struct DisplayPicker {
pub screen: Screen,
pub config: DisplayConfig,
}
impl DisplayPicker {
pub fn new(screen: Screen, config: DisplayConfig) -> Self {
Self { screen, config }
}
pub fn from_config(config: DisplayConfig) -> anyhow::Result<Self> {
let displays = Display::all()
.map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
let display = displays
.into_iter()
.skip(config.index_of_display)
.next();
match display {
Some(display) => {
let height = display.height();
let width = display.width();
info!("dw: {}, cw: {}", width, config.display_height);
assert_eq!(width, config.display_width);
let capturer = Capturer::new(display)?;
let screen = Screen::new(capturer, width, height);
Ok(Self { screen, config })
}
None => {
anyhow::bail!("Index out of displays range.")
}
}
}
pub fn take_screenshot(&mut self) -> anyhow::Result<Screenshot> {
let bitmap = self
.screen
.take()
.map_err(|error| anyhow::anyhow!("take screenshot for display failed. {}", error))?;
// info!("bitmap size {}", bitmap.len());
let screenshot = Screenshot::new(bitmap, self.config);
Ok(screenshot)
}
}

View File

@@ -1,16 +1,24 @@
use futures::{stream::FuturesUnordered, StreamExt};
use once_cell::sync::OnceCell;
use paris::*;
use scrap::{Capturer, Display};
use paris::info;
use scrap::Display;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::{sync::Mutex, task};
use crate::picker::screen::Screen;
use crate::picker::{
config::{LedFlowX, LedFlowY, LedStripConfig},
screen::Screen,
};
use super::{led_color::LedColor, screenshot::Screenshot};
use super::{
config::DisplayConfig, display_picker::DisplayPicker, led_color::LedColor,
screenshot::Screenshot,
};
pub struct Picker {
pub screens: Arc<Mutex<Vec<Screen>>>,
pub screenshots: Arc<Mutex<Vec<Screenshot>>>,
pub display_configs: Arc<Mutex<Vec<DisplayConfig>>>,
}
impl Picker {
@@ -20,46 +28,144 @@ impl Picker {
SCREEN_COLOR_PICKER.get_or_init(|| Picker {
screens: Arc::new(Mutex::new(vec![])),
screenshots: Arc::new(Mutex::new(vec![])),
display_configs: Arc::new(Mutex::new(vec![
DisplayConfig {
index_of_display: 1,
display_width: 1920,
display_height: 1200,
top_led_strip: LedStripConfig {
index: 1,
global_start_position: 32,
global_end_position: 60,
},
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,
},
},
DisplayConfig {
index_of_display: 0,
display_width: 3008,
display_height: 1692,
top_led_strip: LedStripConfig {
index: 0,
global_start_position: 0,
global_end_position: 32,
},
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,
},
},
])),
})
}
pub async fn refresh_displays(&self) -> anyhow::Result<()> {
pub async fn list_displays(&self) -> anyhow::Result<Vec<String>> {
let mut configs = self.display_configs.lock().await;
let screenshots = self.screenshots.lock().await;
let displays = Display::all()
.map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
let mut screens = self.screens.lock().await;
let mut screenshots = self.screenshots.lock().await;
screens.clear();
info!("number of displays: {}", displays.len());
for display in displays {
configs.clear();
let mut futs = FuturesUnordered::new();
for (index, display) in displays.iter().enumerate() {
let height = display.height();
let width = display.width();
match Capturer::new(display) {
Ok(capturer) => screens.push(Screen::new(capturer, width, height)),
Err(error) => screens.push(Screen::new_failed(
anyhow::anyhow!("{}", error),
width,
height,
)),
};
screenshots.push(Screenshot::new(width, height));
let config = DisplayConfig::default(index, width, height);
configs.push(config);
}
screens.reverse();
screenshots.reverse();
screenshots[0].set_number_of_leds(22, 0);
screenshots[1].set_number_of_leds(38, 0);
for (index, display) in displays.iter().enumerate() {
let height = display.height();
let width = display.width();
let config = configs[index];
futs.push(async move {
let join = task::spawn(Self::preview_display_by_config(config));
join.await?
});
}
let mut bitmap_string_list = vec![];
while let Some(bitmap_string) = futs.next().await {
match bitmap_string {
Ok(bitmap_string) => {
bitmap_string_list.push(bitmap_string);
}
Err(error) => {
anyhow::bail!("can not convert to base64 image. {}", error);
}
}
}
Ok(bitmap_string_list)
}
pub async fn preview_display_by_config(config: DisplayConfig) -> anyhow::Result<String> {
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)
}
pub async fn refresh_displays(&self) -> anyhow::Result<()> {
// let displays = Display::all()
// .map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
// let mut screens = self.screens.lock().await;
// let mut screenshots = self.screenshots.lock().await;
// screens.clear();
// info!("number of displays: {}", displays.len());
// for display in displays {
// let height = display.height();
// let width = display.width();
// match Capturer::new(display) {
// Ok(capturer) => screens.push(Screen::new(capturer, width, height)),
// Err(error) => screens.push(Screen::new_failed(
// anyhow::anyhow!("{}", error),
// width,
// height,
// )),
// };
// screenshots.push(Screenshot::new(width, height));
// }
// screens.reverse();
// screenshots.reverse();
Ok(())
}
pub async fn take_screenshots_for_all(&self) -> anyhow::Result<Vec<Screenshot>> {
let mut screens = self.screens.lock().await;
let mut screenshots = self.screenshots.lock().await;
let screenshots = self.screenshots.lock().await;
for (index, screen) in screens.iter_mut().enumerate() {
let bitmap = screen.take().map_err(|error| {
anyhow::anyhow!("take screenshot for display failed. {}", error)
})?;
screenshots[index].set_bitmap(bitmap).await
}
Ok(screenshots.to_vec())
}

View File

@@ -1,4 +1,6 @@
pub mod led_color;
pub mod screen;
pub mod manager;
pub mod screenshot;
pub mod screenshot;
pub mod display_picker;
pub mod config;

View File

@@ -1,5 +1,5 @@
use scrap::Capturer;
use std::{io::ErrorKind::WouldBlock, time::Duration, thread};
pub struct Screen {
capturer: Option<Capturer>,
@@ -29,15 +29,24 @@ impl Screen {
pub fn take(&mut self) -> anyhow::Result<Vec<u8>> {
match self.capturer.as_mut() {
Some(capturer) => {
let buffer = capturer
.frame()
.map_err(|error| anyhow::anyhow!("failed to frame of display. {}", error))?;
anyhow::Ok(buffer.to_vec())
}
Some(capturer) => loop {
match capturer.frame() {
Ok(buffer) => {
return anyhow::Ok(buffer.to_vec());
}
Err(error) => {
if error.kind() == WouldBlock {
thread::sleep(Duration::from_millis(16));
continue;
} else {
anyhow::bail!("failed to frame of display. {}", error);
}
}
}
},
None => anyhow::bail!("Do not initialized"),
}
}
}
unsafe impl Send for Screen {}
unsafe impl Send for Screen {}

View File

@@ -1,126 +1,106 @@
use color_space::{Hsv, Rgb};
use paris::info;
use std::sync::Arc;
use tokio::sync::Mutex;
use super::led_color::LedColor;
use std::ops::Range;
use color_space::{Hsv, Rgb};
use super::{
config::{DisplayConfig, LedStripConfig},
led_color::LedColor,
};
#[derive(Clone)]
pub struct Screenshot {
bitmap: Arc<Mutex<Option<Vec<u8>>>>,
width: usize,
height: usize,
led_number_of_x: usize,
led_number_of_y: usize,
bitmap: Vec<u8>,
config: DisplayConfig,
}
impl Screenshot {
pub fn new(width: usize, height: usize) -> Self {
Self {
bitmap: Arc::new(Mutex::new(None)),
led_number_of_x: 0,
led_number_of_y: 0,
width,
height,
}
pub fn new(bitmap: Vec<u8>, config: DisplayConfig) -> Self {
Self { bitmap, config }
}
pub fn get_size(&self) -> (usize, usize) {
(self.width, self.height)
}
pub fn get_number_of_leds(&self) -> (usize, usize) {
(self.led_number_of_x, self.led_number_of_y)
}
pub fn set_number_of_leds(&mut self, led_number_of_x: usize, led_number_of_y: usize) {
self.led_number_of_x = led_number_of_x;
self.led_number_of_y = led_number_of_y;
}
pub async fn get_top_colors(&self) -> anyhow::Result<Vec<LedColor>> {
self.get_x_colors(XPosition::Top).await
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).await
self.get_x_colors(XPosition::Bottom, self.config.bottom_led_strip)
.await
}
async fn get_x_colors(&self, position: XPosition) -> anyhow::Result<Vec<LedColor>> {
if self.led_number_of_x == 0 {
return Ok(vec![]);
}
pub fn get_top_of_led_strip_range(&self) -> Range<usize> {
self.config.top_led_strip.global_start_position
..self.config.top_led_strip.global_end_position
}
let bitmap = self.bitmap.lock().await;
match bitmap.as_ref() {
Some(bitmap) => {
let cell_size_x = self.width / self.led_number_of_x;
let cell_size_y = self.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.height - 20 - cell_size_y..self.height - 20,
};
let mut colors = Vec::new();
let stride = bitmap.len() / self.height;
for pos in 0..self.led_number_of_x {
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
for x in pos * cell_size_x..(pos + 1) * cell_size_x {
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;
}
}
let rgb = Rgb::new(
r / cell_size as f64,
g / cell_size as f64,
b / cell_size 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);
// info!("color: {:?}", color.get_rgb());
colors.push(color);
}
return Ok(colors);
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
.global_start_position
.abs_diff(strip_config.global_end_position);
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
}
None => Ok(vec![]),
}
}
};
pub async fn set_bitmap(&mut self, bitmap: Vec<u8>) {
let mut self_bitmap = self.bitmap.lock().await;
*self_bitmap = Some(bitmap);
let mut colors = Vec::new();
let stride = bitmap.len() / self.config.display_height;
for pos in strip_config.global_start_position..strip_config.global_end_position {
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
for x in pos * cell_size_x..(pos + 1) * cell_size_x {
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;
}
}
let rgb = Rgb::new(
r / cell_size as f64,
g / cell_size as f64,
b / cell_size 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);
// info!("color: {:?}", color.get_rgb());
colors.push(color);
}
return Ok(colors);
}
pub async fn to_webp_base64(&self) -> String {
let bitmap = self.bitmap.lock().await;
match bitmap.to_owned() {
Some(bitmap) => {
let mut bitflipped = Vec::with_capacity(self.width * self.height * 3);
let stride = bitmap.len() / self.height;
let bitmap = &self.bitmap;
let mut bitflipped =
Vec::with_capacity(self.config.display_width * self.config.display_height * 3);
let stride = bitmap.len() / self.config.display_height;
for y in 0..self.height {
for x in 0..self.width {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[bitmap[i + 2], bitmap[i + 1], bitmap[i]]);
}
}
let webp_memory = webp::Encoder::from_rgb(
bitflipped.as_slice(),
self.width as u32,
self.height as u32,
)
.encode(100.0);
return base64::encode(&*webp_memory);
for y in 0..self.config.display_height {
for x in 0..self.config.display_width {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[bitmap[i + 2], bitmap[i + 1], bitmap[i]]);
}
None => "".to_owned(),
}
let webp_memory = webp::Encoder::from_rgb(
bitflipped.as_slice(),
self.config.display_width as u32,
self.config.display_height as u32,
)
.encode(100.0);
return base64::encode(&*webp_memory);
}
}