人人都会AI编程

13.5 屏幕捕获与截图:全屏捕获、区域捕获

更新时间:2026-07-11

屏幕捕获与截图是很多桌面应用(如远程协助、截图工具、录屏软件)的基础功能。Tauri 本身不直接提供截图 API,但可以通过 Rust 调用系统级库或第三方 crate 来实现高性能的屏幕捕获,再将图像数据传递给前端。下面给出两种实用方案:全屏捕获区域捕获,并说明如何在 Tauri 中落地。


全屏捕获

全屏捕获的核心是获取整个桌面的像素数据,通常通过操作系统原生 API 或跨平台库完成。

推荐方案:使用 scrap crate(跨平台)
scrap 是一个轻量的 Rust 屏幕捕获库,支持 Windows、macOS、Linux 的主要显示服务器(X11/Wayland)。它可以直接获取任意显示器的原始像素数据。

步骤示例:

  1. 添加依赖src-tauri/Cargo.toml):
   [dependencies]
   scrap = "0.5"
   image = "0.24"  # 用于 JPEG/PNG 编码
   base64 = "0.21" # 可选,方便前端展示
   
  1. 编写 Rust 命令,捕获屏幕并返回 Base64 图片:
   use scrap::{Capturer, Display};
   use std::io::ErrorKind::WouldBlock;
   use std::time::Duration;
   use std::thread;

   #[tauri::command]
   fn capture_full_screen() -> Result<String, String> {
       let display = Display::primary().map_err(|e| e.to_string())?;
       let mut capturer = Capturer::new(display).map_err(|e| e.to_string())?;
       let (w, h) = (display.width(), display.height());

       // 等待一帧有效数据(部分后端需要预热)
       loop {
           match capturer.frame() {
               Ok(frame) => {
                   // 将 BGRA 数据转为 RGB,然后用 image crate 编码为 PNG
                   let mut img = image::RgbaImage::new(w as u32, h as u32);
                   // 注意 scrap 默认返回 BGRA 格式
                   img.copy_from_slice(frame);
                   let mut buf = Vec::new();
                   let mut encoder = image::codecs::png::PngEncoder::new(&mut buf);
                   encoder.encode(&img, w as u32, h as u32, image::ExtendedColorType::Rgba8)
                       .map_err(|e| e.to_string())?;
                   let b64 = base64::encode(&buf);
                   return Ok(format!("data:image/png;base64,{}", b64));
               }
               Err(ref e) if e.kind() == WouldBlock => {
                   thread::sleep(Duration::from_millis(10));
               }
               Err(e) => return Err(e.to_string()),
           }
       }
   }
   
  1. 前端调用(如 React):
   const { invoke } = window.__TAURI__;
   const base64 = await invoke('capture_full_screen');
   document.getElementById('preview').src = base64;
   

注意事项:

  • macOS 需要录屏权限,应在 Info.plist 中声明 NSDesktopCaptureUsageDescription,并在首次调用时触发系统授权弹窗。
  • Linux 上可能需安装 libxcb/libwayland 等依赖;Wayland 的支持因发行版而异。
  • 性能优化:可以用 scrap 的另一模式直接捕获为 BGR 格式以减少转换开销,或对变化不大的场景做差分编码。

区域捕获

区域捕获通常需要用户交互选择矩形范围,然后只截取该区域的内容。这可以通过两种途径实现:

方案 A:先全屏截取,再用坐标裁剪(最简单)
先调用上面的全屏命令获得整个桌面的图像,前端通过拖拽控件让用户选取区域,然后前端用 canvas 裁剪后再上传或直接使用。
优点:实现快,无需额外 Rust 代码。缺点:每次截取都要传一次全屏图像数据,如果截图频繁(如实时标注)会增加内存和带宽压力。

方案 B:在 Rust 中直接按坐标裁剪(推荐)
扩展上面的命令,增加 x, y, width, height 参数,在 Rust 侧调用 capturer.frame() 拿到全屏原始帧后,使用 image crate 的 crop(或用 sub_image)裁剪,只返回目标区域的 Base64。这样可大幅减少前端数据传输量。

代码片段(核心逻辑)

#[tauri::command]
fn capture_region(x: u32, y: u32, width: u32, height: u32) -> Result<String, String> {
    // ... 获取全屏 frame 的代码同上 ...
    let frame = capturer.frame().map_err(|e| e.to_string())?;
    // 构建全尺寸 RgbaImage
    let full_img = image::RgbaImage::from_raw(w as u32, h as u32, frame.to_vec())
        .ok_or("Failed to create image")?;
    // 裁剪
    let cropped = full_img.view(x, y, width, height).to_image();
    // 编码为 PNG
    let mut buf = Vec::new();
    let encoder = image::codecs::png::PngEncoder::new(&mut buf);
    encoder.encode(&cropped, width, height, image::ExtendedColorType::Rgba8)
        .map_err(|e| e.to_string())?;
    Ok(format!("data:image/png;base64,{}", base64::encode(&buf)))
}

前端可以配合 Tauri 的窗口鼠标事件(或前端拖拽选择)来确定 x, y, width, height,然后调用该命令。


实用细节与兼容性

  • 性能考虑scrap 在每次调用 frame() 时都会返回最新的屏幕数据,没有硬件加速的情况下,高分辨率全屏捕获可能达到 100ms 以上。对于需要高帧率的场景(如录屏),建议使用更底层的库(如 Windows 的 DXGI、macOS 的 AVFoundation 或 ScreenCaptureKit),并通过 Tauri 的 Rust 插件集成。
  • 多显示器scrapDisplay::all() 可获取所有显示器,按索引选择或合并。
  • 安全权限:Tauri 的安全模型要求前端只能调用你注册的命令。截图命令本身不会泄露不安全数据,但应注意:若应用自动截取屏幕,需在隐私政策中明确说明,避免被系统或应用商店拒绝。
  • Tauri 插件:社区有 tauri-plugin-screenshots 等插件,但可能更新滞后。自己实现可更灵活控制。

一句话总结:借助 Rust 生态的 scrap 库,你可以在 Tauri 中轻松实现全屏与区域截图,用 Base64 或二进制流将图片传给前端显示或保存,全程体积小、无 Chromium 包袱。