截图模块调整

This commit is contained in:
2026-08-01 22:24:33 +08:00
parent 89e5b7bed5
commit f51a7f894e
13 changed files with 2408 additions and 527 deletions
+133 -12
View File
@@ -1,8 +1,10 @@
//! Tauri 命令:截图模块
//!
//! 命令清单:
//! - screenshot_capture_fullscreen:捕获虚拟屏并存入静态,返回元数据 + base64
//! - screenshot_take_fullscreen:取出并清除静态存储的全屏捕获
//! - screenshot_capture_fullscreen:捕获虚拟屏并存入静态(不做 PNG 编码)
//! - screenshot_get_fullscreen_bmp:取出全屏捕获的 BMP 原始字节(raw IPC,覆盖层显示用,不移除)
//! - screenshot_fullscreen_png:全屏捕获编码 PNG base64 并清除(全屏截图进编辑器用)
//! - screenshot_clear_fullscreen:清除静态全屏捕获(覆盖层关闭时)
//! - screenshot_crop_stored:按物理像素裁剪已存储的全屏捕获
//! - screenshot_window_from_point:拾取指定屏幕坐标下的顶层窗口
//! - screenshot_enum_windows:枚举可见顶层窗口
@@ -10,21 +12,68 @@
//! - screenshot_set_editor_image / screenshot_get_editor_image:编辑器图片传递
//! - screenshot_copy_image:写入剪贴板(CF_DIB
//! - screenshot_save_png:写入文件
//! - screenshot_disable_transitions:禁用窗口显示/隐藏过渡动画(消除覆盖层缩放动画)
use super::{CaptureData, WindowInfo};
use tauri::Manager;
/// 捕获整个虚拟屏(多显示器拼接),存入静态供后续裁剪,并返回 base64
/// 禁用指定窗口(按 label 查找)的显示/隐藏过渡动画,消除覆盖层出现/消失时的缩放动画
#[tauri::command]
pub async fn screenshot_capture_fullscreen() -> Result<CaptureData, String> {
pub async fn screenshot_disable_transitions(
app: tauri::AppHandle,
label: String,
) -> Result<(), String> {
#[cfg(windows)]
{
use raw_window_handle::HasWindowHandle;
let win = app
.get_webview_window(&label)
.ok_or_else(|| format!("窗口不存在: {}", label))?;
let handle = win
.window_handle()
.map_err(|e| format!("获取窗口句柄失败: {}", e))?;
match handle.as_raw() {
raw_window_handle::RawWindowHandle::Win32(h) => {
super::capture::disable_window_transitions(h.hwnd.get() as isize)
}
_ => Ok(()),
}
}
#[cfg(not(windows))]
{
let _ = (app, label);
Ok(())
}
}
/// 注册(或切换)截图全局快捷键。传入空字符串则禁用快捷键。
#[tauri::command]
pub async fn screenshot_register_shortcut(
app: tauri::AppHandle,
shortcut: String,
) -> Result<(), String> {
super::shortcut::register_shortcut(&app, &shortcut)
}
/// 注销截图全局快捷键
#[tauri::command]
pub async fn screenshot_unregister_shortcut(app: tauri::AppHandle) -> Result<(), String> {
super::shortcut::unregister_shortcut(&app);
Ok(())
}
/// 捕获整个虚拟屏(多显示器拼接)存入静态,不做 PNG 编码
#[tauri::command]
pub async fn screenshot_capture_fullscreen() -> Result<(), String> {
#[cfg(windows)]
{
// 屏幕捕获涉及 GDI 调用,放线程池避免阻塞 async 调度
let img = tauri::async_runtime::spawn_blocking(|| {
super::capture::capture_virtual_screen()
tauri::async_runtime::spawn_blocking(|| {
let img = super::capture::capture_virtual_screen()?;
super::capture::store_fullscreen(img)
})
.await
.map_err(|e| format!("捕获任务失败: {}", e))??;
Ok(super::capture::store_fullscreen(img))
.map_err(|e| format!("捕获任务失败: {}", e))?
}
#[cfg(not(windows))]
{
@@ -32,16 +81,50 @@ pub async fn screenshot_capture_fullscreen() -> Result<CaptureData, String> {
}
}
/// 取出并清除静态存储的全屏捕获(覆盖层取消时清理用)
/// 取出全屏捕获的 BMP 原始字节(raw IPC → 前端 ArrayBuffer),不移除
#[tauri::command]
pub async fn screenshot_take_fullscreen() -> Result<Option<CaptureData>, String> {
pub async fn screenshot_get_fullscreen_bmp() -> Result<tauri::ipc::Response, String> {
#[cfg(windows)]
{
Ok(super::capture::take_fullscreen())
tauri::async_runtime::spawn_blocking(|| {
let bmp = super::capture::fullscreen_bmp()?;
Ok(tauri::ipc::Response::new(bmp))
})
.await
.map_err(|e| format!("读取捕获失败: {}", e))?
}
#[cfg(not(windows))]
{
Ok(None)
Err("截图仅支持 Windows".into())
}
}
/// 全屏捕获编码为 PNG base64 并清除(全屏截图直接进编辑器)
#[tauri::command]
pub async fn screenshot_fullscreen_png() -> Result<CaptureData, String> {
#[cfg(windows)]
{
tauri::async_runtime::spawn_blocking(|| super::capture::fullscreen_png())
.await
.map_err(|e| format!("编码任务失败: {}", e))?
}
#[cfg(not(windows))]
{
Err("截图仅支持 Windows".into())
}
}
/// 清除静态全屏捕获(覆盖层关闭/取消时释放内存)
#[tauri::command]
pub async fn screenshot_clear_fullscreen() -> Result<(), String> {
#[cfg(windows)]
{
super::capture::clear_fullscreen();
Ok(())
}
#[cfg(not(windows))]
{
Ok(())
}
}
@@ -68,6 +151,29 @@ pub async fn screenshot_crop_stored(
}
}
/// 裁剪已存储的全屏捕获并直接写入剪贴板(一次 IPC 完成"裁剪+复制"
#[tauri::command]
pub async fn screenshot_crop_copy_stored(
x: i32,
y: i32,
w: i32,
h: i32,
) -> Result<CaptureData, String> {
#[cfg(windows)]
{
tauri::async_runtime::spawn_blocking(move || {
super::capture::crop_copy_stored(x, y, w, h)
})
.await
.map_err(|e| format!("裁剪复制任务失败: {}", e))?
}
#[cfg(not(windows))]
{
let _ = (x, y, w, h);
Err("截图仅支持 Windows".into())
}
}
/// 拾取指定物理屏幕坐标下的顶层窗口
#[tauri::command]
pub async fn screenshot_window_from_point(
@@ -89,6 +195,21 @@ pub async fn screenshot_window_from_point(
}
}
/// 获取当前鼠标物理屏幕坐标(覆盖层打开时定位初始悬停窗口)
#[tauri::command]
pub async fn screenshot_cursor_pos() -> Result<(i32, i32), String> {
#[cfg(windows)]
{
tauri::async_runtime::spawn_blocking(super::capture::cursor_pos)
.await
.map_err(|e| format!("查询任务失败: {}", e))?
}
#[cfg(not(windows))]
{
Err("截图仅支持 Windows".into())
}
}
/// 枚举所有可见顶层窗口
#[tauri::command]
pub async fn screenshot_enum_windows() -> Result<Vec<WindowInfo>, String> {