性能优化

This commit is contained in:
zhongluofeng
2026-08-06 10:33:16 +08:00
parent c7578a2e6b
commit e66c53e66d
105 changed files with 7273 additions and 5002 deletions
+99 -3
View File
@@ -15,10 +15,11 @@
//! - screenshot_disable_transitions:禁用窗口显示/隐藏过渡动画(消除覆盖层缩放动画)
use super::{CaptureData, WindowInfo};
use tauri::Manager;
use tauri::{Emitter, Manager};
/// 禁用指定窗口(按 label 查找)的显示/隐藏过渡动画,消除覆盖层出现/消失时的缩放动画
#[tauri::command]
#[specta::specta]
pub async fn screenshot_disable_transitions(
app: tauri::AppHandle,
label: String,
@@ -48,22 +49,27 @@ pub async fn screenshot_disable_transitions(
/// 注册(或切换)截图全局快捷键。传入空字符串则禁用快捷键。
#[tauri::command]
#[specta::specta]
pub async fn screenshot_register_shortcut(
app: tauri::AppHandle,
shortcut: String,
) -> Result<(), String> {
super::shortcut::register_shortcut(&app, &shortcut)
crate::shortcut::register_shortcut(&app, "截图", &shortcut, |a| {
let _ = a.emit(crate::constants::events::SCREENSHOT_SHORTCUT, ());
})
}
/// 注销截图全局快捷键
#[tauri::command]
#[specta::specta]
pub async fn screenshot_unregister_shortcut(app: tauri::AppHandle) -> Result<(), String> {
super::shortcut::unregister_shortcut(&app);
crate::shortcut::unregister_shortcut(&app, "截图");
Ok(())
}
/// 捕获整个虚拟屏(多显示器拼接)存入静态,不做 PNG 编码
#[tauri::command]
#[specta::specta]
pub async fn screenshot_capture_fullscreen() -> Result<(), String> {
#[cfg(windows)]
{
@@ -101,6 +107,7 @@ pub async fn screenshot_get_fullscreen_bmp() -> Result<tauri::ipc::Response, Str
/// 全屏捕获编码为 PNG base64 并清除(全屏截图直接进编辑器)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_fullscreen_png() -> Result<CaptureData, String> {
#[cfg(windows)]
{
@@ -116,6 +123,7 @@ pub async fn screenshot_fullscreen_png() -> Result<CaptureData, String> {
/// 清除静态全屏捕获(覆盖层关闭/取消时释放内存)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_clear_fullscreen() -> Result<(), String> {
#[cfg(windows)]
{
@@ -130,6 +138,7 @@ pub async fn screenshot_clear_fullscreen() -> Result<(), String> {
/// 按物理像素坐标裁剪已存储的全屏捕获
#[tauri::command]
#[specta::specta]
pub async fn screenshot_crop_stored(
x: i32,
y: i32,
@@ -153,6 +162,7 @@ pub async fn screenshot_crop_stored(
/// 裁剪已存储的全屏捕获并直接写入剪贴板(一次 IPC 完成"裁剪+复制"
#[tauri::command]
#[specta::specta]
pub async fn screenshot_crop_copy_stored(
x: i32,
y: i32,
@@ -176,6 +186,7 @@ pub async fn screenshot_crop_copy_stored(
/// 拾取指定物理屏幕坐标下的顶层窗口
#[tauri::command]
#[specta::specta]
pub async fn screenshot_window_from_point(
x: i32,
y: i32,
@@ -197,6 +208,7 @@ pub async fn screenshot_window_from_point(
/// 获取当前鼠标物理屏幕坐标(覆盖层打开时定位初始悬停窗口)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_cursor_pos() -> Result<(i32, i32), String> {
#[cfg(windows)]
{
@@ -212,6 +224,7 @@ pub async fn screenshot_cursor_pos() -> Result<(i32, i32), String> {
/// 枚举所有可见顶层窗口
#[tauri::command]
#[specta::specta]
pub async fn screenshot_enum_windows() -> Result<Vec<WindowInfo>, String> {
#[cfg(windows)]
{
@@ -227,6 +240,7 @@ pub async fn screenshot_enum_windows() -> Result<Vec<WindowInfo>, String> {
/// 按 hwnd 捕获指定窗口
#[tauri::command]
#[specta::specta]
pub async fn screenshot_capture_window(hwnd: isize) -> Result<CaptureData, String> {
#[cfg(windows)]
{
@@ -250,6 +264,7 @@ pub async fn screenshot_capture_window(hwnd: isize) -> Result<CaptureData, Strin
/// 存入编辑器图片(base64 PNG
#[tauri::command]
#[specta::specta]
pub async fn screenshot_set_editor_image(png_base64: String) -> Result<(), String> {
super::set_editor_image(png_base64);
Ok(())
@@ -257,12 +272,14 @@ pub async fn screenshot_set_editor_image(png_base64: String) -> Result<(), Strin
/// 取出编辑器图片(编辑器窗口加载时调用,取出即清除)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_get_editor_image() -> Result<Option<String>, String> {
Ok(super::take_editor_image())
}
/// 将 PNG base64 写入系统剪贴板(转 CF_DIB)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_copy_image(png_base64: String) -> Result<(), String> {
#[cfg(windows)]
{
@@ -283,6 +300,7 @@ pub async fn screenshot_copy_image(png_base64: String) -> Result<(), String> {
///
/// 省去前端 toDataURL(PNG 编码+base64) → Rust base64 解码 → PNG 解码 三次往返。
/// body 格式:前 8 字节 = width(i32 LE) + height(i32 LE),之后为 raw RGBA 像素。
/// 注:参数为 tauri::ipc::Request(原始 body),specta 无法生成,豁免标注。
#[tauri::command]
pub async fn screenshot_compose_copy(
request: tauri::ipc::Request<'_>,
@@ -314,6 +332,7 @@ pub async fn screenshot_compose_copy(
/// 将 PNG base64 写入文件
#[tauri::command]
#[specta::specta]
pub async fn screenshot_save_png(png_base64: String, path: String) -> Result<(), String> {
tauri::async_runtime::spawn_blocking(move || {
#[cfg(windows)]
@@ -329,3 +348,80 @@ pub async fn screenshot_save_png(png_base64: String, path: String) -> Result<(),
.await
.map_err(|e| format!("保存任务失败: {}", e))?
}
// ===== 截图历史缓存:完整 PNG 落盘缓存目录,内存只保留缩略图 =====
/// 历史缓存根目录(app_cache_dir/screenshot/history
fn history_cache_dir(app: &tauri::AppHandle) -> Result<std::path::PathBuf, String> {
let dir = app
.path()
.app_cache_dir()
.map_err(|e| format!("获取缓存目录失败: {}", e))?
.join("screenshot")
.join("history");
std::fs::create_dir_all(&dir).map_err(|e| format!("创建缓存目录失败: {}", e))?;
Ok(dir)
}
/// 校验 path 属于历史缓存目录(防止路径穿越/任意文件读写)
fn ensure_in_history_dir(app: &tauri::AppHandle, path: &str) -> Result<std::path::PathBuf, String> {
let dir = history_cache_dir(app)?;
let p = std::path::PathBuf::from(path);
if !p.starts_with(&dir) {
return Err("非法路径:不在截图历史缓存目录内".into());
}
Ok(p)
}
/// 将完整 PNG 写入历史缓存目录,返回文件路径
#[tauri::command]
#[specta::specta]
pub async fn screenshot_save_cache(
app: tauri::AppHandle,
png_base64: String,
) -> Result<String, String> {
tauri::async_runtime::spawn_blocking(move || {
let dir = history_cache_dir(&app)?;
// 时间戳微秒命名(避免引入额外依赖;并发截图的同微秒碰撞可忽略)
let ts = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_micros())
.unwrap_or(0);
let path = dir.join(format!("{}.png", ts));
super::capture::save_png_to_file(&png_base64, &path.to_string_lossy())?;
Ok(path.to_string_lossy().into_owned())
})
.await
.map_err(|e| format!("缓存任务失败: {}", e))?
}
/// 从历史缓存目录读取 PNG 并返回 base64(点击历史项复制/保存时一次性加载,不常驻内存)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_load_cache(
app: tauri::AppHandle,
path: String,
) -> Result<String, String> {
tauri::async_runtime::spawn_blocking(move || {
let p = ensure_in_history_dir(&app, &path)?;
let bytes = std::fs::read(&p).map_err(|e| format!("读取缓存失败: {}", e))?;
use base64::Engine as _;
Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
})
.await
.map_err(|e| format!("读取缓存任务失败: {}", e))?
}
/// 删除历史缓存文件(历史项移除/清空时调用,静默忽略不存在文件)
#[tauri::command]
#[specta::specta]
pub async fn screenshot_delete_cache(app: tauri::AppHandle, path: String) -> Result<(), String> {
tauri::async_runtime::spawn_blocking(move || {
if let Ok(p) = ensure_in_history_dir(&app, &path) {
let _ = std::fs::remove_file(p);
}
Ok(())
})
.await
.map_err(|e| format!("删除缓存任务失败: {}", e))?
}