滚动截图,细节调整
This commit is contained in:
@@ -10,13 +10,14 @@
|
||||
//! - screenshot_show_overlay:一次 IPC 完成覆盖层 show + focus(关键路径减少往返)
|
||||
//! - screenshot_enum_windows:枚举可见顶层窗口
|
||||
//! - screenshot_capture_window:按 hwnd 捕获指定窗口
|
||||
//! - screenshot_set_editor_image / screenshot_get_editor_image:编辑器图片传递
|
||||
//! - screenshot_take_editor_image_raw:取出编辑器图片(raw IPC,滚动截图会话直接写入)
|
||||
//! - screenshot_compose_png / screenshot_compose_copy:raw RGBA → PNG(仅编码 / 剪贴板+编码)
|
||||
//! - screenshot_copy_image:写入剪贴板(CF_DIB)
|
||||
//! - screenshot_save_png:写入文件
|
||||
//! - screenshot_disable_transitions:禁用窗口显示/隐藏过渡动画(消除覆盖层缩放动画)
|
||||
|
||||
use super::{CaptureData, CaptureStart, WindowInfo};
|
||||
use tauri::{Emitter, Manager};
|
||||
use tauri::{AppHandle, Emitter, Manager};
|
||||
|
||||
/// 禁用指定窗口(按 label 查找)的显示/隐藏过渡动画,消除覆盖层出现/消失时的缩放动画
|
||||
#[tauri::command]
|
||||
@@ -297,19 +298,90 @@ pub async fn screenshot_capture_window(hwnd: isize) -> Result<CaptureData, Strin
|
||||
}
|
||||
}
|
||||
|
||||
/// 存入编辑器图片(base64 PNG)
|
||||
/// 滚动截图:从窗口当前滚动位置向下拼接到底部,返回超长 PNG。
|
||||
/// `region` 为 Some 时仅在框选区域(屏幕物理坐标)内捕捉,宽 = 选区宽;
|
||||
/// 为 None 时捕捉整个客户区。结束后会把窗口滚回起始位置,不打扰用户。
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn screenshot_set_editor_image(png_base64: String) -> Result<(), String> {
|
||||
super::set_editor_image(png_base64);
|
||||
Ok(())
|
||||
pub async fn screenshot_scroll_capture(
|
||||
hwnd: isize,
|
||||
region: Option<super::ScrollRegion>,
|
||||
) -> Result<CaptureData, String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
super::scroll_capture::scroll_capture(hwnd, region)
|
||||
})
|
||||
.await
|
||||
.map_err(|e| format!("滚动截图任务失败: {}", e))?
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = hwnd;
|
||||
let _ = region;
|
||||
Err("截图仅支持 Windows".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 取出编辑器图片(编辑器窗口加载时调用,取出即清除)
|
||||
/// 启动滚动截图会话(后台线程持续捕捉拼接,实时推进度事件)。
|
||||
/// `auto = true` 为自动滚动(线程主动下滚拼到底部);`false` 为手动(等用户滚动窗口)。
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn screenshot_get_editor_image() -> Result<Option<String>, String> {
|
||||
Ok(super::take_editor_image())
|
||||
pub fn screenshot_scroll_start(
|
||||
app: AppHandle,
|
||||
hwnd: isize,
|
||||
region: Option<super::ScrollRegion>,
|
||||
auto: bool,
|
||||
) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
super::scroll_session::start(app, hwnd, region, auto)
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = (app, hwnd, region, auto);
|
||||
Err("截图仅支持 Windows".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 结束滚动截图会话并导出结果。
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub fn screenshot_scroll_finish() -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
super::scroll_session::finish()
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
Err("截图仅支持 Windows".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 取消滚动截图会话(不导出)。
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub fn screenshot_scroll_cancel() -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
super::scroll_session::cancel_now()
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
Err("截图仅支持 Windows".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 取出编辑器图片(原始 PNG 字节,raw IPC → 前端 ArrayBuffer → Blob URL,取出即清除)
|
||||
///
|
||||
/// 长图(滚动截图)可达数十 MB:raw IPC 相比 base64 JSON 事件传输省 ~33% 体积,
|
||||
/// 且避免 JSON 序列化/多次广播。注:返回 ipc::Response,specta 无法生成,豁免标注。
|
||||
#[tauri::command]
|
||||
pub async fn screenshot_take_editor_image_raw() -> Result<tauri::ipc::Response, String> {
|
||||
match super::take_editor_image_raw() {
|
||||
Some(bytes) => Ok(tauri::ipc::Response::new(bytes)),
|
||||
None => Err("无待编辑的截图".into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 将 PNG base64 写入系统剪贴板(转 CF_DIB)
|
||||
@@ -339,6 +411,39 @@ pub async fn screenshot_copy_image(png_base64: String) -> Result<(), String> {
|
||||
#[tauri::command]
|
||||
pub async fn screenshot_compose_copy(
|
||||
request: tauri::ipc::Request<'_>,
|
||||
) -> Result<super::CaptureData, String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let body = match request.body() {
|
||||
tauri::ipc::InvokeBody::Raw(data) => data.clone(),
|
||||
_ => return Err("需要 raw body(ArrayBuffer)".into()),
|
||||
};
|
||||
if body.len() < 8 {
|
||||
return Err("数据不足:缺少尺寸头".into());
|
||||
}
|
||||
let width = i32::from_le_bytes([body[0], body[1], body[2], body[3]]);
|
||||
let height = i32::from_le_bytes([body[4], body[5], body[6], body[7]]);
|
||||
let rgba = body[8..].to_vec();
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
super::capture::compose_copy_rgba(&rgba, width, height)
|
||||
})
|
||||
.await
|
||||
.map_err(|e| format!("合成复制任务失败: {}", e))?
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = request;
|
||||
Err("截图仅支持 Windows".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 有标注导出(仅编码):接收 raw RGBA(前端 canvas.getImageData 直传),一次完成 PNG 编码。
|
||||
/// 与 screenshot_compose_copy 的区别:不写剪贴板(编辑器「保存到文件」用)。
|
||||
/// body 格式:前 8 字节 = width(i32 LE) + height(i32 LE),之后为 raw RGBA 像素。
|
||||
/// 注:参数为 tauri::ipc::Request(原始 body),specta 无法生成,豁免标注。
|
||||
#[tauri::command]
|
||||
pub async fn screenshot_compose_png(
|
||||
request: tauri::ipc::Request<'_>,
|
||||
) -> Result<super::CaptureData, String> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
@@ -353,10 +458,10 @@ pub async fn screenshot_compose_copy(
|
||||
let height = i32::from_le_bytes([body[4], body[5], body[6], body[7]]);
|
||||
let rgba = body[8..].to_vec();
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
super::capture::compose_copy_rgba(&rgba, width, height)
|
||||
super::capture::compose_png_rgba(&rgba, width, height)
|
||||
})
|
||||
.await
|
||||
.map_err(|e| format!("合成复制任务失败: {}", e))?
|
||||
.map_err(|e| format!("合成编码任务失败: {}", e))?
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user