npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rust-rpa

v0.1.7

Published

Rust-based RPA automation library for Node.js

Downloads

382

Readme

rust-rpa

基于 Rust 的高性能 Node.js RPA(机器人流程自动化)库。

特性

  • 🚀 高性能: 使用 Rust 编写,追求极致速度和效率
  • 🔄 跨平台: 支持 Windows 和 macOS
  • 📦 易于使用: 简洁的面向对象 API,支持 TypeScript
  • 非阻塞: 异步操作不会阻塞 Node.js 事件循环
  • 🔒 类型安全: 完整的 TypeScript 类型定义
  • 🖱️ 输入自动化: Mouse 和 Keyboard 类,完整的输入控制
  • 🪟 窗口管理: 基于 XCap 的窗口枚举和信息获取
  • 🖥️ 多显示器支持: Monitor 类,支持多显示器设置
  • 📸 屏幕截图: 支持全屏和窗口截图,多种图片格式
  • 🔑 权限管理: Permission 类,自动检测并弹出系统权限授权对话框

安装

npm install rust-rpa

支持的平台:

  • Windows (x64, x86)
  • macOS (Intel x64, Apple Silicon ARM64)

注意: 当前版本不支持 Linux。

系统要求

Windows

  • Windows 10 或更高版本 (x64 或 x86)
  • 某些操作可能需要管理员权限

macOS

  • macOS 10.13 或更高版本 (Intel 或 Apple Silicon)
  • 需要辅助功能权限(见下文)

命令行工具

安装后可通过 rpa 命令直接使用,无需编写代码:

# 查看帮助
rpa --help

# 检查权限(macOS 自动弹出授权)
rpa permission --prompt

# 列出所有窗口
rpa window:list

# 将窗口置于最前
rpa window:focus Chrome

# 设置窗口位置和大小
rpa window:bounds Chrome 100 100 800 600

# 截取主显示器
rpa screenshot -o desktop.png

# 截取指定窗口
rpa screenshot --window Chrome -o chrome.png

# 鼠标操作
rpa mouse:position
rpa mouse:move 500 300
rpa mouse:click right
rpa mouse:scroll 0 -3

# 键盘操作
rpa keyboard:type "Hello World"
rpa keyboard:press enter
rpa keyboard:press ctrl+c

# 剪贴板
rpa clipboard:read
rpa clipboard:write "Hello"
rpa clipboard:paste

# 列出所有显示器
rpa monitor:list

所有命令支持 --help 查看详细用法,如 rpa screenshot --help

示例代码

项目提供了丰富的示例代码,位于 examples/ 目录中:

  • permission-demo.js - 权限检查演示
  • list-windows.js - 窗口管理演示
  • screenshot-demo.js - 屏幕截图功能演示
  • clipboard-demo.js - 剪贴板操作演示
  • image-processing-demo.js - 图像处理功能演示
  • find-icon-demo.js - 完整的 findIcon 功能演示
  • find-icon-basic.js - findIcon 基础用法示例

运行示例:

node examples/permission-demo.js
node examples/list-windows.js

使用方法

JavaScript

const { Window, Monitor, Mouse, Keyboard, Permission } = require('rust-rpa');

async function main() {
  try {
    // 检查权限(macOS 上无权限会自动弹出授权对话框)
    Permission.checkAccessibility();
    Permission.checkScreenCapture();

    // 获取所有窗口
    const windows = Window.all();
    console.log(`Found ${windows.length} windows`);
    
    windows.forEach(win => {
      console.log(`${win.appName()}: ${win.title()}`);
      console.log(`  PID: ${win.pid()}, Parent PID: ${win.parentId()}`);
      console.log(`  Position: (${win.x()}, ${win.y()}), Size: ${win.width()}x${win.height()}`);
    });
    
    // 将窗口置于最前
    await windows[0].bringToFront();
    
    // 获取所有显示器
    const monitors = Monitor.all();
    const primaryMonitor = monitors.find(m => m.isPrimary());
    
    // 截图
    const image = await primaryMonitor.captureImage();
    const pngBuffer = await image.toPng();
    
    // 鼠标和键盘控制
    await Mouse.moveTo(100, 100);
    await Mouse.click('left');
    await Keyboard.typeText('Hello World!');
  } catch (error) {
    console.error('Error:', error.message);
  }
}

main();

TypeScript

import { Window, Monitor, Mouse, Keyboard } from 'rust-rpa';

async function main(): Promise<void> {
  try {
    // 获取所有窗口
    const windows = Window.all();
    console.log(`Found ${windows.length} windows`);
    
    windows.forEach((win) => {
      console.log(`${win.appName()}: ${win.title()}`);
    });
    
    // 截图
    const monitors = Monitor.all();
    const image = await monitors[0].captureImage();
    
    // 输入控制
    await Mouse.moveTo(100, 100);
    await Keyboard.typeText('Hello!');
  } catch (error) {
    console.error('Error:', error);
  }
}

main();

API

Window 类

窗口管理类,基于 XCap 实现。

静态方法

Window.all(): Window[]

获取所有可见窗口列表。

const windows = Window.all();

实例方法

  • id(): number - 获取窗口 ID
  • pid(): number - 获取窗口进程 ID
  • parentId(): number - 获取窗口所属进程的父进程 ID
  • title(): string - 获取窗口标题
  • appName(): string - 获取应用程序名称
  • x(): number - 获取窗口 X 坐标
  • y(): number - 获取窗口 Y 坐标
  • width(): number - 获取窗口宽度
  • height(): number - 获取窗口高度
  • getSize(): WindowSize - 获取窗口尺寸(宽度和高度)
  • isMinimized(): boolean - 是否最小化
  • isMaximized(): boolean - 是否最大化
  • isFocused(): boolean - 是否聚焦
  • bringToFront(): Promise<void> - 将窗口置于最前(激活并置顶)
  • currentMonitor(): Monitor - 获取窗口所在显示器
  • currentMonitorId(): number - 获取窗口所在显示器的 ID
  • getBounds(): WindowBounds - 获取窗口边界(位置和大小)
  • setBounds(bounds): Promise<void> - 设置窗口边界(位置和大小)
  • toJSON(): WindowToJson - 转为 JSON 可序列化对象
  • captureImage(options?: CaptureImageOptions): Promise<ImageData> - 截取窗口图像;可选 options.size 指定目标宽高并自动缩放;options.from'screen' 时截取窗口所在显示器整屏;options.region 指定仅截取逻辑像素区域;options.autoSize 为 true 时在 Windows 高 DPI 下自动缩放到逻辑像素尺寸

Monitor 类

显示器管理类。

静态方法

Monitor.all(): Monitor[]

获取所有显示器列表。

const monitors = Monitor.all();
const primary = monitors.find(m => m.isPrimary());

实例方法

  • id(): number - 获取显示器 ID
  • name(): string - 获取显示器名称
  • x(): number - 获取显示器 X 坐标
  • y(): number - 获取显示器 Y 坐标
  • width(): number - 获取显示器宽度
  • height(): number - 获取显示器高度
  • scaleFactor(): number - 获取缩放因子
  • isPrimary(): boolean - 是否主显示器
  • captureImage(options?: CaptureImageOptions): Promise<ImageData> - 截取显示器图像;可选 options.size 指定目标宽高并自动缩放

ImageData 类

图像数据类,用于截图和图像处理操作。

静态工厂方法

  • ImageData.fromFile(filePath): Promise<ImageData> - 从文件加载图片
  • ImageData.fromBuffer(buffer): Promise<ImageData> - 从 Buffer 解码图片

属性

  • width: number - 图像宽度(只读)
  • height: number - 图像高度(只读)

方法

格式转换与保存

  • toPng(): Promise<Buffer> - 转换为 PNG 格式
  • toJpeg(): Promise<Buffer> - 转换为 JPEG 格式
  • toBmp(): Promise<Buffer> - 转换为 BMP 格式
  • toFile(filePath): Promise<void> - 保存到文件(根据扩展名自动识别格式:.png/.jpg/.jpeg/.bmp)

图像处理

  • crop(x, y, width, height): Promise<ImageData> - 裁剪图像
  • resize(width, height): Promise<ImageData> - 缩放图像(使用 Lanczos3 高质量算法)
  • grayscale(): Promise<ImageData> - 转换为灰度图(使用标准加权算法:0.299R + 0.587G + 0.114B)
  • findIcon(template, options?): Promise<MatchResult> - 查找模板图标(模板匹配)

数据访问

  • getRawData(): Buffer - 获取原始像素数据(RGBA 格式,每像素 4 字节)
  • metadata(): ImageMetadata - 获取图片元信息

findIcon 参数:

  • template: ImageData - 模板图片(要查找的图标)
  • options?: MatchOptions - 可选的匹配选项对象
    • threshold?: number - 匹配阈值 (0.0-1.0),默认 0.8
    • regions?: Array<{x, y, width, height}> - 可选的搜索区域列表,默认为空(全图搜索)
      • 区域可超出图片边界,会自动裁剪为与图片的交集范围进行查找

MatchOptions 说明:

  1. threshold(匹配阈值)

    • 取值范围:0.0 - 1.0
    • 默认值:0.8
    • 说明:相似度分数必须大于此阈值才算匹配成功
    • 建议:0.8 是个好的起点,根据实际效果调整
  2. regions(搜索区域)

    • 格式:[{x: number, y: number, width: number, height: number}]
    • 默认:空数组(全图搜索)
    • 说明:限定在指定区域内搜索,可提高效率和准确性
    • 示例:[{x: 0, y: 0, width: 100, height: 100}]

使用建议:

  • 大多数情况使用默认参数即可:findIcon(template)
  • 需要调整灵敏度时指定阈值:findIcon(template, { threshold: 0.9 })
  • 在特定区域查找可提高性能:findIcon(template, { threshold: 0.8, regions: [...] })

MatchResult 类型:

interface MatchResult {
  found: boolean;      // 是否找到匹配
  score: number;       // 相似度分数 (0.0-1.0)
  x: number;           // 匹配位置 x 坐标
  y: number;           // 匹配位置 y 坐标
  width: number;       // 模板宽度
  height: number;      // 模板高度
}

ImageMetadata 类型:

interface ImageMetadata {
  width: number;           // 图片宽度
  height: number;          // 图片高度
  channels: number;        // 通道数(固定为 4,RGBA)
  bytesPerPixel: number;   // 每像素字节数(固定为 4)
  dataSize: number;        // 数据总字节数
}

captureImage 选项(Monitor / Window):

// 截取区域(逻辑像素),仅对 Window.captureImage 有效
interface CaptureRegion {
  x: number;      // 区域左上角 x(相对截图画布左上角)
  y: number;      // 区域左上角 y
  width: number;  // 区域宽度
  height: number; // 区域高度
}

interface CaptureImageOptions {
  size?: { width: number; height: number };  // 可选,截取后缩放到指定宽高
  // 以下仅对 Window.captureImage 有效:
  from?: 'window' | 'screen';  // 默认 'window' 截窗口;'screen' 截窗口所在显示器整屏(可配合 getBounds 与 image.crop 裁剪出窗口)
  region?: CaptureRegion | null;  // 仅截取该逻辑像素区域,不填则截全图
  autoSize?: boolean | null;     // 为 true 时在 Windows 存在 DPI 缩放时自动将图像缩放到逻辑像素宽高(与 getSize/getBounds 一致)
}

Mouse 类

鼠标控制类,所有方法都是静态的。

静态方法

  • Mouse.moveTo(x, y, duration?): Promise<void> - 移动鼠标到指定坐标。duration 可选,移动动画持续时间(秒),默认为 0(瞬间移动)。如果设置 > 0,鼠标将以平滑动画的方式移动到目标点,动画过程中会触发 mouseMove 事件
  • Mouse.click(button?): Promise<void> - 点击鼠标。button 可选,可用枚举 MouseButton.Left / MouseButton.Right 或字符串 'left' / 'right' 等,默认左键
  • Mouse.doubleClick(button?): Promise<void> - 双击鼠标,button 同上
  • Mouse.down(button?): Promise<void> - 按下鼠标按钮,button 同上
  • Mouse.up(button?): Promise<void> - 释放鼠标按钮,button 同上
  • MouseButton 枚举:MouseButton.Left | Right | Middle | Back | Forward,用于上述 button 参数
  • Mouse.scroll(deltaX?, deltaY?): Promise<void> - 滚动鼠标滚轮。方向deltaY 正数向上、负数向下;deltaX 正数向右、负数向左。如 scroll(0, 3) 向上滚、scroll(0, -3) 向下滚
  • Mouse.position(): Promise<{ x: number, y: number }> - 获取当前鼠标位置

Keyboard 类

键盘控制类,所有方法都是静态的。

静态方法

  • Keyboard.typeText(text): Promise<void> - 输入文本
  • Keyboard.click(key): Promise<void> - 按下并释放按键
  • Keyboard.down(key): Promise<void> - 按下按键
  • Keyboard.up(key): Promise<void> - 释放按键
  • Keyboard.sequence(keys): Promise<void> - 按键序列(如 [Key.Ctrl, Key.C]

key 参数:可使用 Key 枚举(如 Key.EnterKey.CtrlKey.F1)或字符串(如 'enter''ctrl')。Key 提供字母 A–Z、数字 Num0–Num9、功能键 F1–F12、修饰键 Control/Ctrl/Shift/Alt/Meta/Command/Win、控制键 Enter/Escape/Tab/Space/Backspace/Delete/Insert、方向键 Left/Right/Up/Down、Home/End/PageUp/PageDown、数字键盘 Numpad0–Numpad9、NumpadAdd/NumpadEnter 等。

Clipboard 类

剪贴板控制类,所有方法都是静态的。

静态方法

  • Clipboard.readText(): Promise<string> - 读取剪贴板文本内容
  • Clipboard.writeText(text): Promise<void> - 将文本写入剪贴板
  • Clipboard.writeImage(source): Promise<void> - 将图片写入剪贴板,source 支持文件路径(string)、base64 字符串、data URI 或 Buffer
  • Clipboard.writeFile(paths): Promise<void> - 将文件路径写入剪贴板,粘贴时在资源管理器/访达中为文件(paths 可为单个路径字符串或路径数组)
  • Clipboard.paste(): Promise<void> - 执行粘贴操作(使用 Cmd/Ctrl+V 快捷键)
  • Clipboard.pasteText(text): Promise<void> - 将文本写入剪贴板并粘贴,完成后自动恢复剪贴板原始内容
  • Clipboard.pasteImage(source): Promise<void> - 将图片写入剪贴板并粘贴,完成后自动恢复剪贴板原始内容(sourcewriteImage
  • Clipboard.pasteFile(paths): Promise<void> - 将文件路径写入剪贴板并粘贴,不会自动恢复剪贴板原始内容

Permission 类

权限检查工具类,所有方法都是静态的。

静态方法

  • Permission.checkAccessibility(prompt?): boolean - 检查辅助功能权限(鼠标、键盘、窗口操作等需要此权限)
  • Permission.checkScreenCapture(prompt?): boolean - 检查屏幕录制权限(截图功能需要此权限)

参数说明:

  • prompt(可选,默认 true):无权限时是否自动弹出系统授权对话框(仅 macOS 生效)

平台行为差异:

| 平台 | checkAccessibility | checkScreenCapture | |------|--------------------|--------------------| | macOS | 调用 AXIsProcessTrustedWithOptions,prompt=true 时弹出辅助功能授权对话框 | 调用 CGRequestScreenCaptureAccess,prompt=true 时弹出屏幕录制授权对话框 | | Windows | 检查是否以管理员身份运行(管理员即有权限) | 检查是否以管理员身份运行 |

const { Permission } = require('rust-rpa');

// 检查并弹出授权(推荐在应用启动时调用)
const hasAccessibility = Permission.checkAccessibility();
const hasScreenCapture = Permission.checkScreenCapture();

console.log('辅助功能权限:', hasAccessibility);
console.log('屏幕录制权限:', hasScreenCapture);

// 仅检查,不弹窗
const check = Permission.checkAccessibility(false);

macOS 权限要求

辅助功能权限(输入控制)

在 macOS 上使用鼠标和键盘控制功能时,需要授予辅助功能权限:

  1. 打开 系统偏好设置
  2. 进入 安全性与隐私 > 隐私 > 辅助功能
  3. 点击锁图标进行更改
  4. 将您的终端应用程序或 IDE 添加到列表中
  5. 重启应用程序

屏幕录制权限(截图功能)

使用截图功能时,需要授予屏幕录制权限:

  1. 打开 系统偏好设置
  2. 进入 安全性与隐私 > 隐私 > 屏幕录制
  3. 点击锁图标进行更改
  4. 勾选您的终端应用程序或 IDE
  5. 重启应用程序

示例

窗口管理

const { Window } = require('rust-rpa');

// 获取所有窗口
const windows = Window.all();
console.log(`Found ${windows.length} windows`);

// 遍历窗口
windows.forEach(win => {
  console.log(`${win.appName()}: ${win.title()}`);
  console.log(`  PID: ${win.pid()}, Parent PID: ${win.parentId()}`);
  console.log(`  Position: (${win.x()}, ${win.y()})`);
  console.log(`  Size: ${win.width()}x${win.height()}`);
  console.log(`  Minimized: ${win.isMinimized()}, Focused: ${win.isFocused()}`);
});

// 将窗口置于最前
const target = windows.find(w => w.appName().includes('Chrome'));
if (target) {
  await target.bringToFront();
}

// 获取/设置窗口边界
const bounds = windows[0].getBounds();
console.log(`Bounds: ${JSON.stringify(bounds)}`);
await windows[0].setBounds({ x: 100, y: 100, width: 800, height: 600 });

// 获取窗口所在显示器
const monitor = windows[0].currentMonitor();
console.log(`Window is on monitor: ${monitor.name()}`);

// 转为 JSON 对象
console.log(JSON.stringify(windows[0].toJSON(), null, 2));

显示器管理

const { Monitor } = require('rust-rpa');

// 获取所有显示器
const monitors = Monitor.all();
monitors.forEach(m => {
  console.log(`Monitor: ${m.name()}`);
  console.log(`  Resolution: ${m.width()}x${m.height()}`);
  console.log(`  Scale: ${m.scaleFactor()}x`);
  console.log(`  Primary: ${m.isPrimary()}`);
});

// 获取主显示器
const primary = monitors.find(m => m.isPrimary());

屏幕截图

const fs = require('fs');
const { Monitor, Window, ImageData } = require('rust-rpa');

// 截取显示器
const monitors = Monitor.all();
const image = await monitors[0].captureImage();

// 截取时指定目标尺寸(自动缩放,便于后续扩展其他选项)
const imageResized = await monitors[0].captureImage({ size: { width: 800, height: 600 } });

// 保存为不同格式(方式 1:转换为 Buffer)
const pngBuffer = await image.toPng();
fs.writeFileSync('screenshot.png', pngBuffer);

const jpegBuffer = await image.toJpeg();
fs.writeFileSync('screenshot.jpg', jpegBuffer);

// 保存为不同格式(方式 2:直接保存文件)
await image.toFile('screenshot.png');
await image.toFile('screenshot.jpg');
await image.toFile('screenshot.bmp');

// 裁剪图像
const cropped = await image.crop(0, 0, 800, 600);
await cropped.toFile('cropped.png');

// 截取窗口
const windows = Window.all();
if (windows.length > 0) {
  const windowImage = await windows[0].captureImage();
  await windowImage.toFile('window.png');
}

截图选项captureImage(options?) 接受可选对象 CaptureImageOptions

  • size?: { width, height }:截取后缩放到指定宽高,不传则返回原始尺寸。
  • Window 专用from?: 'window' | 'screen' 默认截窗口,设为 'screen' 可截窗口所在显示器整屏再配合 getBounds()image.crop() 裁剪;region?: { x, y, width, height } 仅截取该逻辑像素区域;autoSize?: true 在 Windows 高 DPI 下自动将图像缩放到逻辑像素宽高(与 getSize/getBounds 一致)。

输入自动化

const { Mouse, MouseButton, Keyboard, Key } = require('rust-rpa');

// 鼠标操作
await Mouse.moveTo(100, 200);              // 瞬间移动鼠标
await Mouse.moveTo(100, 200, 0.5);         // 平滑动画移动,持续 0.5 秒
await Mouse.click(MouseButton.Left);       // 左键点击
await Mouse.click(MouseButton.Right);      // 右键点击
await Mouse.doubleClick();                 // 双击
await Mouse.scroll(0, 3);          // 向上滚动(正值 = 远离用户)
await Mouse.scroll(0, -3);         // 向下滚动(负值 = 朝向用户)

// 获取鼠标位置
const { x, y } = await Mouse.position();
console.log(`Mouse at (${x}, ${y})`);

// 键盘操作(key 可用 Key 枚举或字符串)
await Keyboard.typeText('Hello World!');  // 输入文本
await Keyboard.click(Key.Enter);          // 按 Enter

// 组合键
await Keyboard.sequence([Key.Ctrl, Key.A]);  // Ctrl+A (全选)
await Keyboard.sequence([Key.Ctrl, Key.C]);  // Ctrl+C (复制)
await Keyboard.sequence([Key.Meta, Key.V]);  // Cmd+V (粘贴,macOS)

// 按键按下和释放
await Keyboard.down(Key.Shift);
await Keyboard.click(Key.A);
await Keyboard.up(Key.Shift);

剪贴板操作

const path = require('path');
const { Clipboard, ImageData } = require('rust-rpa');

// 读取剪贴板
const text = await Clipboard.readText();
console.log('剪贴板内容:', text);

// 写入剪贴板
await Clipboard.writeText('Hello, Clipboard!');

// 写入图片到剪贴板(支持文件路径、Buffer、base64)
await Clipboard.writeImage(path.join(__dirname, 'test/images/ding_copy.png'));

// 写入文件到剪贴板(粘贴时为文件)
await Clipboard.writeFile(path.join(__dirname, 'rust-rpa.darwin-x64.node'));

// 执行粘贴操作(使用 Cmd/Ctrl+V)
await Clipboard.paste();

// pasteText / pasteImage 会自动恢复剪贴板;pasteFile 不会自动恢复
await Clipboard.pasteText('直接粘贴文本');
await Clipboard.pasteImage('image.png');
await Clipboard.pasteFile('/path/to/file.pdf');

图像处理

const fs = require('fs');
const { Monitor, ImageData } = require('rust-rpa');

// 方式 1: 从截图获取图片
const monitors = Monitor.all();
const screenshot = await monitors[0].captureImage();

// 方式 2: 从文件加载图片
const image = await ImageData.fromFile('input.png');

// 方式 3: 从 Buffer 加载图片
const buffer = fs.readFileSync('input.png');
const imageFromBuffer = await ImageData.fromBuffer(buffer);

// 缩放图片
const resized = await image.resize(800, 600);

// 裁剪图片
const cropped = await image.crop(100, 100, 400, 300);

// 转换为灰度图
const grayscale = await image.grayscale();

// 保存图片(自动根据扩展名识别格式)
await resized.toFile('output.png');      // 保存为 PNG
await grayscale.toFile('gray.jpg');      // 保存为 JPEG
await cropped.toFile('cropped.bmp');     // 保存为 BMP

// 转换为 Buffer(用于进一步处理)
const pngBuffer = await image.toPng();
fs.writeFileSync('screenshot.png', pngBuffer);

const jpegBuffer = await image.toJpeg();
fs.writeFileSync('screenshot.jpg', jpegBuffer);

// 获取原始像素数据
const rawData = image.getRawData();  // Buffer,RGBA 格式
console.log(`Data size: ${rawData.length} bytes`);
console.log(`First pixel: R=${rawData[0]}, G=${rawData[1]}, B=${rawData[2]}, A=${rawData[3]}`);

// 获取图片元信息
const meta = image.metadata();
console.log(`Size: ${meta.width}x${meta.height}`);
console.log(`Channels: ${meta.channels}, Data: ${meta.dataSize} bytes`);

// 链式操作
const processed = await ImageData.fromFile('input.png')
  .then(img => img.resize(800, 600))
  .then(img => img.grayscale())
  .then(img => img.crop(100, 100, 400, 300));
await processed.toFile('processed.png');

// 查找图标(模板匹配)
const template = await ImageData.fromFile('icon.png');

// 使用默认参数(threshold=0.8,全图搜索)
const result = await image.findIcon(template);

if (result.found) {
  console.log(`找到匹配!`);
  console.log(`  相似度: ${(result.score * 100).toFixed(2)}%`);
  console.log(`  位置: (${result.x}, ${result.y})`);
} else {
  console.log('未找到匹配');
}

// 自定义阈值
const result1 = await image.findIcon(template, { threshold: 0.9 });

// 在指定区域内查找
const result2 = await image.findIcon(template, {
  threshold: 0.8,
  regions: [
    { x: 0, y: 0, width: 800, height: 600 }  // 只在左上角区域搜索
  ]
});

更多示例请查看 examples/test/ 目录:

# 运行截屏示例
node examples/screenshot-demo.js

# 运行窗口列表示例
node examples/list-windows.js

# 运行剪贴板示例
node examples/clipboard-demo.js

# 运行图像处理示例
node examples/image-processing-demo.js

# 运行测试
npm test

平台支持

| 平台 | 架构 | 状态 | 备注 | |----------|-------------|--------|-------| | Windows | x64 | ✅ 支持 | 可能需要管理员权限 | | Windows | x86 (32位) | ✅ 支持 | 可能需要管理员权限 | | macOS | x64 (Intel) | ✅ 支持 | 需要辅助功能权限 | | macOS | ARM64 (Apple Silicon) | ✅ 支持 | 需要辅助功能权限 | | Linux | 全部 | ❌ 不支持 | 当前版本无计划 |

性能

  • 窗口枚举通常在 < 100ms 内完成
  • 异步操作不会阻塞 Node.js 事件循环
  • 最小的内存开销

开发

从源码构建和开发指南请参阅 dev.md

路线图

  • [x] 窗口枚举和信息获取(基于 XCap)
  • [x] 鼠标和键盘自动化(Mouse/Keyboard 类)
  • [x] 屏幕截图(Monitor/Window 截图)
  • [x] 多显示器支持
  • [x] 图像格式转换(PNG/JPEG/BMP)
  • [x] 图像裁剪功能
  • [x] 图像缩放功能(Lanczos3 高质量算法)
  • [x] 图像识别(模板匹配)
  • [x] 图像灰度化
  • [x] 图像数据访问(原始像素、元信息)
  • [x] 图像保存到文件
  • [x] 剪贴板操作
  • [x] 窗口操作(置顶、移动、调整大小、父进程查询)
  • [ ] 定位文字findText(text, {prompt: '', model: '', timeout: number})
  • [ ] 等待文字、图标、指定时间
  • [ ] 点击文字、图标等操作
  • [ ] 进程管理

更新日志

0.1.7

BREAKCHANGE

  • Mouse.scroll 滚动单位改为像素: Mouse.scroll(dx, dy)dxdy 参数现在表示像素值,而非滚动行数
    • 此前 Windows 和 macOS 使用不同的滚动单位,行为不一致
    • 现在统一按像素处理:传入 200 表示尝试滚动约 200 像素
    • Windows: 30 像素 ≈ 1 个 WHEEL_DELTA (120)
    • macOS: 20 像素 ≈ 1 行滚动
  • Windows 平台 Mouse.scroll 方向调整: dy 正数现在表示向下滚动(与 macOS 保持一致)
    • 此前 Windows 上正数向上滚动,与 macOS 相反
    • 现在双平台方向一致:正数向下,负数向上

0.1.6

BREAKCHANGE

  • Windows 平台鼠标坐标统一为逻辑像素: Mouse.moveTo()Mouse.position() 现在统一使用逻辑像素坐标,与 Window.getBounds() 等 API 保持一致
    • 此前 Windows 平台上鼠标操作使用物理像素,在高 DPI 缩放环境下与窗口坐标不一致
    • 现在 Windows 平台会自动处理 DPI 缩放,传入和返回的坐标均为逻辑像素
    • macOS 平台不受影响(原本就使用逻辑像素)

0.1.5

功能

  • Mouse.moveTo 增强: 新增可选 duration 参数,支持平滑动画移动
    • duration 为移动动画持续时间(秒),默认为 0(瞬间移动)
    • duration > 0 时,鼠标以平滑动画方式移动到目标点,使用 easeInOutCubic 缓动函数
    • 动画过程中会触发 mouseMove 事件,网页等应用可正常响应鼠标移动
  • findIcon 参数优化: options 参数中的 thresholdregions 字段均改为可选
    • threshold 不传时默认使用 0.8
    • regions 中的区域可超出图片边界,会自动裁剪为与图片的交集范围进行查找
  • Window.captureImage 选项 from:新增 'window'(默认)与 'screen'。设为 'screen' 时先截取窗口所在显示器整屏,再自动裁剪为当前窗口与显示器的交集区域(超出显示器的部分忽略)。
  • Window.captureImage 选项 region:新增可选参数,仅截取指定逻辑像素区域 { x, y, width, height },不填则截取全图。
  • Window.captureImage 选项 auto:新增可选参数。为 true 时,在 Windows 存在 DPI 缩放的情况下自动将图像缩放到逻辑像素宽高(与 getSize/getBounds 一致)。
  • CaptureImageOptions 处理顺序:内部先执行 autoSize(缩放到逻辑像素),再执行 region(按逻辑像素裁剪),最后应用 size(若有)。启用 autoSize 后,region 与逻辑像素坐标一一对应。

0.1.4

BREAKCHANGE

  • toJson()改为toJSON()
  • window toJSON() 返回对象中取消bounds
  • Window 数据一致性修复: 统一 getBounds()toJSON()setBounds() 中屏幕宽高和窗口大小位置都使用逻辑像素,解决 Windows 环境下坐标不一致问题。

0.1.3

功能

  • 新增 Window.getSize() 方法: 返回 {width, height} 对象,提供便捷的窗口尺寸获取方式
  • 新增 Window.currentMonitorId() 方法: 获取窗口所在显示器的 ID,比 currentMonitor() 更轻量
  • Window.toJSON() 增强: 现在包含 monitorId 字段,提供窗口所在显示器的 ID 信息

修复

  • bringToFront在mac中仅将当前窗口顶置,避免顶置其父窗口
  • windows缩放后,应用程序大小和屏幕大小使用的逻辑像素逻辑不一致,都改为使用真实逻辑像素,减少后续处理

0.1.2

修复

  • windows上的.node文件调用失败修复

0.1.1

新增

  • CLI 命令行工具:安装后可通过 rpa 命令直接使用,支持窗口/鼠标/键盘/剪贴板/截图/显示器/权限等全部功能
  • Permission 类:新增 checkAccessibility()checkScreenCapture(),macOS 自动弹出系统授权对话框,Windows 检查管理员权限
  • Window.parentId():获取窗口所属进程的父进程 ID
  • Window.bringToFront():将窗口置于最前,改为异步方法返回 Promise<void>
  • Window.setBounds():设置窗口位置和大小,改为异步方法返回 Promise<void>
  • Clipboard.pasteText(text):写入文本并粘贴,完成后自动恢复剪贴板原始内容
  • Clipboard.pasteImage(source):写入图片并粘贴,完成后自动恢复剪贴板原始内容
  • Clipboard.pasteFile(paths):写入文件并粘贴,不会自动恢复剪贴板原始内容
  • ImageData.fromBase64(base64):从 base64 字符串或 data URI 创建 ImageData 对象

BreakChange

  • Clipboard.writeImage(source):简化接口,不再需要手动传 width/height,支持文件路径、Buffer、base64 字符串、data URI 四种输入方式
  • bringWindowToFrontById:已移除公开暴露,改为 bringToFront() 实例方法内部调用
  • WindowToJson / MonitorToJson:修正 TypeScript 定义中的字段命名为 camelCase(与 napi-rs 实际输出一致)
  • Node.js 版本要求:最低版本从 14 提升至 18

许可证

MIT

致谢

构建基于以下项目: