feat: 完善项目。

- 后端代码结构调整;
- 所有屏幕截屏;
- 前端增加 tailwind;
- 前端 style lint。
This commit is contained in:
2022-11-19 15:28:34 +08:00
parent fbb222ad23
commit 9814247f4e
14 changed files with 1319 additions and 83 deletions

9
src-tauri/Cargo.lock generated
View File

@ -1742,6 +1742,12 @@ dependencies = [
"system-deps 6.0.3",
]
[[package]]
name = "paris"
version = "1.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eaf2319cd71dd9ff38c72bebde61b9ea657134abcf26ae4205f54f772a32810"
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -2289,8 +2295,11 @@ dependencies = [
name = "screen-bg-light-desktop"
version = "0.0.0"
dependencies = [
"anyhow",
"base64",
"bmp",
"once_cell",
"paris",
"repng",
"scrap",
"serde",

View File

@ -22,6 +22,9 @@ repng = "0.2.2"
bmp = "0.5.0"
webp = "0.2.2"
base64 = "0.13.1"
anyhow = "1.0.66"
once_cell = "1.16.0"
paris = { version = "1.5", features = ["timestamps", "macros"] }
[features]
# by default Tauri runs in production mode

View File

@ -3,13 +3,11 @@
windows_subsystem = "windows"
)]
use bmp::{Image, Pixel};
use scrap::{Capturer, Display};
use std::io::ErrorKind::WouldBlock;
use std::path::Path;
use std::thread;
use std::time::Duration;
use std::{fs, time::Instant};
mod screen_color_picker;
use paris::*;
use screen_color_picker::{Screen, ScreenColorPicker};
use std::time::Instant;
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
@ -18,65 +16,77 @@ fn greet(name: &str) -> String {
}
#[tauri::command]
fn take_snapshot() -> String {
let one_second = Duration::new(1, 0);
let one_frame = one_second / 60;
fn refresh_displays() {
match ScreenColorPicker::global().refresh_displays() {
Ok(_) => {}
Err(error) => {
error!("{}", error)
}
}
}
let display = Display::primary().expect("Couldn't find primary display.");
let mut capturer = Capturer::new(display).expect("Couldn't begin capture.");
let (w, h) = (capturer.width(), capturer.height());
#[tauri::command]
fn take_snapshot() -> Vec<String> {
let start = Instant::now();
loop {
// Wait until there's a frame.
let start = Instant::now();
let buffer = match capturer.frame() {
Ok(buffer) => buffer,
Err(error) => {
if error.kind() == WouldBlock {
// Keep spinning.
thread::sleep(one_frame);
continue;
} else {
panic!("Error: {}", error);
let screenshots = match ScreenColorPicker::global().take_screenshots_for_all() {
Ok(bitmaps) => {
info!("bitmaps len: {}", bitmaps.len());
match ScreenColorPicker::global().screens.lock() {
Ok(screens) => Vec::from_iter(
screens
.iter()
.enumerate()
.map(|(index, screen)| bitmap_to_webp_base64(screen, &bitmaps[index])),
),
Err(error) => {
error!("can not lock screens. {}", error);
Vec::<String>::new()
}
}
};
println!("Captured! Saving...");
// Flip the ARGB image into a BGRA image.
let mut bitflipped = Vec::with_capacity(w * h * 3);
let stride = buffer.len() / h;
let mut img = Image::new(w as u32, h as u32);
for y in 0..h {
for x in 0..w {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[buffer[i + 2], buffer[i + 1], buffer[i]]);
// img.set_pixel(
// x as u32,
// y as u32,
// Pixel::new(buffer[i + 2], buffer[i + 1], buffer[i]),
// );
}
}
Err(error) => {
error!("can not take screenshots for all. {}", error);
Vec::<String>::new()
}
};
println!("运行耗时: {:?}", start.elapsed());
screenshots
}
let webp_memory =
webp::Encoder::from_rgb(bitflipped.as_slice(), w as u32, h as u32).encode(100.0);
let encode_text = base64::encode(&*webp_memory);
// let output_path = Path::new("assets").join("lake").with_extension("webp");
// std::fs::write(&output_path, &*webp_memory).unwrap();
println!("运行耗时: {:?}", start.elapsed());
return encode_text;
fn bitmap_to_webp_base64(screen: &Screen, bitmap: &Vec<u8>) -> String {
let mut bitflipped = Vec::with_capacity(screen.width * screen.height * 3);
let stride = bitmap.len() / screen.height;
// let mut img = Image::new(w as u32, h as u32);
for y in 0..screen.height {
for x in 0..screen.width {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[bitmap[i + 2], bitmap[i + 1], bitmap[i]]);
// img.set_pixel(
// x as u32,
// y as u32,
// Pixel::new(buffer[i + 2], buffer[i + 1], buffer[i]),
// );
}
}
let webp_memory = webp::Encoder::from_rgb(
bitflipped.as_slice(),
screen.width as u32,
screen.height as u32,
)
.encode(100.0);
return base64::encode(&*webp_memory);
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet, take_snapshot])
.invoke_handler(tauri::generate_handler![
greet,
take_snapshot,
refresh_displays
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -0,0 +1,96 @@
use once_cell::sync::OnceCell;
use scrap::{Capturer, Display};
use std::{
io,
sync::{Arc, Mutex},
};
use paris::*;
pub struct Screen {
bitmap: Option<Vec<u8>>,
capturer: Option<Capturer>,
init_error: Option<io::Error>,
pub height: usize,
pub width: usize,
}
unsafe impl Send for Screen {}
pub struct ScreenColorPicker {
pub screens: Arc<Mutex<Vec<Screen>>>,
}
impl ScreenColorPicker {
pub fn global() -> &'static ScreenColorPicker {
static SCREEN_COLOR_PICKER: OnceCell<ScreenColorPicker> = OnceCell::new();
SCREEN_COLOR_PICKER.get_or_init(|| ScreenColorPicker {
screens: Arc::new(Mutex::new(Vec::<Screen>::new())),
})
}
pub 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()
.map_err(|error| anyhow::anyhow!("lock screens failed. {}", error))?;
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 {
bitmap: None,
capturer: Some(capturer),
init_error: None,
height,
width,
}),
Err(error) => screens.push(Screen {
bitmap: None,
capturer: None,
init_error: Some(error),
height,
width,
}),
}
}
Ok(())
}
pub fn take_screenshots_for_all(&self) -> anyhow::Result<Vec<Vec<u8>>> {
let mut screens = self
.screens
.lock()
.map_err(|error| anyhow::anyhow!("lock screens failed. {}", error))?;
let mut screenshots = Vec::<Vec<u8>>::new();
for screen in screens.iter_mut() {
let screenshot = screen.take().map_err(|error| {
anyhow::anyhow!("take screenshot for display failed. {}", error)
})?;
screenshots.push(screenshot);
}
anyhow::Ok(screenshots)
}
}
impl Screen {
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))?;
self.bitmap = Some(buffer.to_vec());
anyhow::Ok(buffer.to_vec())
}
None => anyhow::bail!("Do not initialized"),
}
}
}