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

@open-snapora/electron

v1.0.7

Published

Electron host adapter and plugin for open-snapora

Downloads

1,141

Readme

@open-snapora/electron

面向 Electron 桌面应用的高性能多屏幕截图、Canvas 标注与桌面置顶贴图管理器。

English | 简体中文 | 日本語 | Español | 한국어

npm version npm downloads bundle size TypeScript license Electron >= 30 CI


概述

@open-snapora/electron 为 Electron 桌面端应用提供生产级的多显示器屏幕采集、全套交互式标注以及桌面置顶贴图能力。它抹平了跨屏幕全局坐标系换算、HiDPI 高分屏缩放与色彩失真问题,内置零闪烁的透明全屏遮罩缓存复用机制,并提供了兼具安全性与灵活性的 IPC 跨进程通信桥梁。


核心特性

  • 🖥️ 原生多显示器画面捕获:基于 Electron 底层 desktopCapturer 与屏幕服务,精准统一多屏幕逻辑/物理坐标系,无缝适配各类高分屏 Retina 缩放。
  • ⚡ 零白屏与窗口缓存复用:内置智能透明全屏遮罩窗口缓存池,支持静默预加载与实例复用,告别频繁创建 BrowserWindow 的性能损耗与白屏闪烁。
  • 🪟 窗口智能吸附 (Window Snapping):鼠标移动时自动探测并吸附高亮当前应用内所有可见窗口边缘;开放 getWindowSnapRegions 接口,支持注入操作系统底层原生窗口坐标。
  • 📌 独立置顶贴图浮窗 (Pin to Desktop):一键将截图固定到桌面最顶层(Always-on-top)。生成的独立无边框贴图窗口支持鼠标拖拽平移、边缘手柄自由缩放、一键再次复制到剪贴板、另存为本地文件,并自动跟随宿主页面生命周期同步销毁。
  • 🎨 专业级标注画布工具箱:
    • 几何工具:矩形、椭圆、箭头、直线。
    • 画笔涂鸦与敏感脱敏:自由笔触画笔,以及可自由调节马赛克块大小与模糊强度的脱敏滤镜。
    • 富文本与水印:支持字号、色板、文字描边与背景填充的文本输入,以及半透明防伪水印。
    • 完整历史栈:支持无限制步骤的撤销与重做(Undo / Redo)。
    • 精细样式调节:预设色盘 + 自由 HEX 颜色拾取、线宽滑块、透明度调节。
  • 🛡️ 现代企业级安全架构:
    • 全面基于 Context Isolation(上下文隔离),绝不依赖任何不安全的 remote 模块。
    • 内置 validateSender 校验来源,自动拦截非法跨域 iframe 与未受信任的伪造 IPC 截图请求。
  • 🚥 并发冲突与排队策略 (busyPolicy):支持 'queue'(自动按先进先出 FIFO 队列缓冲并发截图请求)或 'reject'(拒绝重复并发点击),可设置队列最大容量 maxQueuedCaptures。
  • 🔌 可插拔输出管线 (outputAdapter):可完全接管输出阶段,将截图二进制流直接上传至阿里云 OSS、腾讯云 COS、AWS S3 或内部业务接口。
  • 📊 阶段级微秒耗时诊断 (onDiagnostic):提供精确到阶段(capture -> overlay -> edit -> output)的微秒级耗时追踪与异常诊断遥测。
  • 🌐 多语言开箱即用 (i18n):内置简体中文(zh-CN)、英语(en-US)、日语(ja-JP)、韩语(ko-KR)、西班牙语(es-ES),支持字段级自定义词条覆盖。
  • 🎨 深浅色主题深度定制:支持 Dark/Light 双主题,工具栏、遮罩层、选区高亮色与手柄均可自定义配置。

安装说明

npm install @open-snapora/electron
# 或者
pnpm add @open-snapora/electron
# 或者
yarn add @open-snapora/electron

环境依赖:需要 electron >= 30.0.0。


快速上手(一键集成方案)

1. 主进程配置 (main.js / main.ts)

使用 setupElectronSnapora 即可一键完成管理器创建、IPC 通道注册与标准 Preload 路径解析:

const { app, BrowserWindow, globalShortcut } = require('electron');
const path = require('path');
const { setupElectronSnapora, resolveHostPreloadPath } = require('@open-snapora/electron');

// 1. 在主进程中初始化 Snapora 控制器
const snapora = setupElectronSnapora({
  busyPolicy: 'queue', // 截图进行中时,后续请求自动排队
});

let mainWindow = null;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1024,
    height: 768,
    webPreferences: {
      preload: resolveHostPreloadPath(), // 安全注入 window.electronSnapora
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  mainWindow.loadFile('index.html');
}

app.whenReady().then(() => {
  createWindow();

  // 2. 注册全局截图快捷键(例如 Windows: Ctrl+Alt+A / macOS: Command+Alt+A)
  const shortcut = process.platform === 'darwin' ? 'Command+Alt+A' : 'Ctrl+Alt+A';
  globalShortcut.register(shortcut, () => {
    // 也可以直接在主进程中发起截图
    snapora.manager.capture({
      locale: 'zh-CN',
      showCopyFeedback: true,
    });
  });
});

app.on('will-quit', () => {
  globalShortcut.unregisterAll();
  snapora.unregister(); // 清理 IPC 监听器与后台缓存窗口
});

2. 渲染进程调用 (renderer.js / 前端框架页面)

页面中通过全局对象 window.electronSnapora 即可唤起全功能截屏:

async function handleTakeScreenshot() {
  try {
    const result = await window.electronSnapora.capture({
      locale: 'zh-CN',
      showCopyFeedback: true,
      defaultTool: 'select',
      tools: ['rectangle', 'ellipse', 'arrow', 'brush', 'text', 'mosaic', 'watermark'],
      theme: {
        mode: 'dark',
        accentColor: '#3b82f6',
      },
    });

    if (result.status === 'completed') {
      console.log('截图已成功完成!');
      console.log('触发动作:', result.output.action); // 'copy' | 'save' | 'pin'
      console.log('选区边界:', result.bounds);         // { x, y, width, height }
      console.log('屏幕 ID:', result.displayId);
      console.log('图片大小:', result.data.byteLength, 'bytes');

      if (result.output.action === 'save') {
        console.log('文件保存路径:', result.output.filePath);
      }
    } else if (result.status === 'cancelled') {
      console.log('用户取消了截图流程(按 Esc 或取消按钮)');
    } else {
      console.error('截图失败:', result.code, result.message);
    }
  } catch (error) {
    console.error('调用过程捕获到异常:', error);
  }
}

自定义 Preload 集成(进阶方案)

若您的项目已有自定义 Preload 脚本,可通过 exposeScreenshotApi 手动接入:

在您的 preload.ts 中:

import { contextBridge, ipcRenderer } from 'electron';
import { exposeScreenshotApi } from '@open-snapora/electron/preload';

exposeScreenshotApi({
  contextBridge,
  ipcRenderer,
  globalName: 'myScreenshotApi', // 可选,默认为 'electronSnapora'
});

在您的前端页面中:

const result = await window.myScreenshotApi.capture({
  locale: 'zh-CN',
});

API 参考手册

主进程导出对象与函数

setupElectronSnapora(options?: SetupElectronSnaporaOptions): SetupElectronSnaporaResult

一站式集成辅助工具。实例化 ScreenshotManager、绑定 IPC 并输出官方 Preload 路径。

export interface SetupElectronSnaporaOptions {
  busyPolicy?: 'reject' | 'queue';
  managerOptions?: ScreenshotManagerOptions;
  resourceLimits?: ScreenshotResourceLimitOptions;
  channel?: string;        // 默认: 'plugin:snapora|capture'
  cancelChannel?: string;  // 默认: 'plugin:snapora|cancel'
  validateSender?: (event: IpcMainInvokeEvent) => boolean;
}

export interface SetupElectronSnaporaResult {
  manager: ScreenshotManager;
  preloadPath: string;
  unregister: () => void;
}

class ScreenshotManager

截图底层核心协调器,管理屏幕捕获会话、透明遮罩生命周期、窗口吸附与输出分发。

  • capture(options?: ScreenshotOptions, context?: ScreenshotJobContext): Promise<ScreenshotResult>
  • cancel(senderWebContentsId?: number): boolean
  • dispose(): void

registerScreenshotIpc(options: RegisterScreenshotIpcOptions): () => void

将 IPC 监听绑定到现有的 ScreenshotManager 实例,并返回支持在应用退出或热重载时调用的清理函数。

resolveHostPreloadPath(): string

返回 @open-snapora/electron 内置标准 Preload 文件的绝对路径。


Preload 导出函数 (@open-snapora/electron/preload)

exposeScreenshotApi(options: ExposeScreenshotApiOptions): ScreenshotRendererApi

通过 Electron 的 contextBridge 安全地将 capture() 和 cancel() 挂载到渲染进程的 window 对象。


核心配置与类型定义

ScreenshotOptions 截图调用选项

| 属性 | 类型 | 默认值 | 描述 | | :--- | :--- | :--- | :--- | | display | 'cursor' \| 'primary' \| string | 'cursor' | 截取目标屏幕:鼠标所在屏、主屏或指定显示器 ID | | tools | ScreenshotTool[] | 全部工具 | 工具栏上可见的标注工具列表 | | defaultTool | 'select' \| ScreenshotTool | 'select' | 唤起时默认选中的标注工具 | | showCopyFeedback | boolean | false | 复制到剪贴板成功后是否展示屏幕悬浮 Toast | | locale | ScreenshotLocale | 'zh-CN' | 界面语言:'en-US' | 'zh-CN' | 'ja-JP' | 'ko-KR' | 'es-ES' | | messages | ScreenshotMessageOverrides | undefined | 覆盖界面默认词条字典 | | theme | ScreenshotTheme | undefined | 界面色彩与视觉样式配置 |

ScreenshotResult 截图结果定义

export type ScreenshotResult =
  | (ScreenshotImageResult & { output: ScreenshotOutputMetadata })
  | { status: 'cancelled' }
  | { status: 'failed'; code: ScreenshotErrorCode; message: string };

export interface ScreenshotImageResult {
  status: 'completed';
  data: Uint8Array; // PNG 二进制数据
  mimeType: 'image/png';
  bounds: { x: number; y: number; width: number; height: number };
  displayId: string;
}

export type ScreenshotOutputMetadata =
  | { action: 'copy' }
  | { action: 'save'; filePath: string }
  | { action: 'pin' };

进阶实战案例

1. 接管保存逻辑并上传至云存储 (outputAdapter)

如果需要将截图直接上传至云端图床而不是写入本地硬盘,可注入自定义 outputAdapter:

import { ScreenshotManager, registerScreenshotIpc } from '@open-snapora/electron';

const manager = new ScreenshotManager({
  outputAdapter: {
    execute: async (payload, context) => {
      if (payload.action === 'save') {
        // 自定义上传逻辑
        const cloudUrl = await uploadToOSS(payload.result.data);
        return {
          status: 'completed',
          output: { action: 'save', filePath: cloudUrl },
        };
      }
      return null; // 返回 null 则走默认本地存储/剪贴板管线
    },
  },
});

2. 注入操作系统原生窗口坐标实现全局窗口吸附

默认情况下 Snapora 会吸附当前 Electron 应用内的所有可见窗口。若您集成了原生窗口枚举扩展,可注入 getWindowSnapRegions:

const snapora = setupElectronSnapora({
  managerOptions: {
    getWindowSnapRegions: () => {
      // 借助 Node 原生扩展获取全局窗口列表
      return [
        { x: 0, y: 0, width: 1920, height: 1080 },
        { x: 100, y: 100, width: 800, height: 600 },
      ];
    },
  },
});

3. 性能诊断与阶段耗时统计

精确追踪截图全链路耗时,协助排查客户端卡顿:

const snapora = setupElectronSnapora({
  managerOptions: {
    onDiagnostic: (event) => {
      console.log(`[Snapora阶段:${event.stage}:${event.phase}] 耗时: ${event.durationMs ?? 0}ms`, event);
    },
  },
});

完整示例

本仓库在 demos/electron 目录中提供了完整的 Electron 参考工程,欢迎查阅与运行。


开源协议

MIT © open-snapora authors