Electron屏幕捕获功能:基于gh_mirrors/el/electron-quick-start实现截图工具
引言:截图工具的痛点与解决方案
你是否还在为寻找一款轻量、高效且可定制的截图工具而烦恼?传统截图工具要么功能单一,要么体积庞大,难以满足开发者的个性化需求。本文将带你基于Electron框架,从零开始打造一款功能完备的截图工具,解决截图、编辑、保存全流程的痛点。
读完本文,你将能够:
- 掌握Electron桌面捕获API的核心用法
- 实现区域选择、全屏截图等基础功能
- 了解截图工具的架构设计与实现原理
- 学会如何打包和分发Electron应用
项目准备与环境搭建
1. 项目克隆与依赖安装
首先,克隆项目仓库并安装依赖:
git clone https://gitcode.com/gh_mirrors/el/electron-quick-start
cd electron-quick-start
npm install
2. 安装截图相关依赖
为了实现截图功能,我们需要安装以下依赖:
npm install electron-screenshot-app --save
核心功能实现
1. 主进程代码修改(main.js)
首先,我们需要修改主进程代码,引入必要的模块并实现截图功能:
// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, desktopCapturer } = require('electron')
const path = require('node:path')
const fs = require('fs')
const { writeFile } = require('fs')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// 实现截图功能
ipcMain.on('capture-screen', async (event, args) => {
try {
const { width, height, x, y } = args;
// 获取所有可用的桌面源
const sources = await desktopCapturer.getSources({ types: ['screen'] })
// 创建截图窗口
const captureWindow = new BrowserWindow({
width: width,
height: height,
x: x,
y: y,
frame: false,
transparent: true,
alwaysOnTop: true,
skipTaskbar: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
// 加载截图页面
captureWindow.loadFile('capture.html')
// 发送截图区域信息
captureWindow.webContents.on('did-finish-load', () => {
captureWindow.webContents.send('capture-info', {
sources: sources,
bounds: { width, height, x, y }
})
})
} catch (error) {
console.error('截图失败:', error)
}
})
// 保存截图
ipcMain.on('save-screenshot', (event, args) => {
const { imageData, filePath } = args;
const base64Data = imageData.replace(/^data:image\/png;base64,/, '');
fs.writeFile(filePath, base64Data, 'base64', (err) => {
if (err) {
console.error('保存截图失败:', err);
event.reply('save-status', { success: false, error: err.message });
} else {
event.reply('save-status', { success: true, path: filePath });
}
});
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
2. 预加载脚本修改(preload.js)
接下来,修改预加载脚本,添加与主进程通信的接口:
/**
* The preload script runs before `index.html` is loaded
* in the renderer. It has access to web APIs as well as
* Electron's renderer process modules and some polyfilled
* Node.js functions.
*
* https://www.electronjs.org/docs/latest/tutorial/sandbox
*/
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
captureScreen: (bounds) => ipcRenderer.send('capture-screen', bounds),
saveScreenshot: (imageData, filePath) => ipcRenderer.invoke('save-screenshot', { imageData, filePath }),
onSaveStatus: (callback) => ipcRenderer.on('save-status', callback)
});
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
3. 创建截图页面(capture.html)
创建一个新的HTML文件,用于显示截图区域和提供编辑功能:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>截图工具</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="screenshot-container"></div>
<div id="toolbar">
<button id="save-btn">保存</button>
<button id="cancel-btn">取消</button>
</div>
<script src="renderer.js"></script>
</body>
</html>
4. 渲染进程代码修改(renderer.js)
修改渲染进程代码,实现截图区域选择和处理:
/**
* This file is loaded via the <script> tag in the index.html file and will
* be executed in the renderer process for that window. No Node.js APIs are
* available in this process because `nodeIntegration` is turned off and
* `contextIsolation` is turned on. Use the contextBridge API in `preload.js`
* to expose Node.js functionality from the main process.
*/
const { ipcRenderer } = require('electron');
document.addEventListener('DOMContentLoaded', () => {
// 添加截图按钮点击事件
const screenshotBtn = document.createElement('button');
screenshotBtn.textContent = '截图';
screenshotBtn.id = 'screenshot-btn';
document.body.appendChild(screenshotBtn);
screenshotBtn.addEventListener('click', () => {
// 获取屏幕尺寸
const { screen } = require('electron');
const primaryDisplay = screen.getPrimaryDisplay();
const { width, height } = primaryDisplay.workAreaSize;
// 发送截图请求到主进程
window.electronAPI.captureScreen({
width,
height,
x: 0,
y: 0
});
});
// 监听保存状态
window.electronAPI.onSaveStatus((event, args) => {
if (args.success) {
alert(`截图已保存至: ${args.path}`);
} else {
alert(`保存失败: ${args.error}`);
}
});
});
功能扩展与优化
1. 快捷键支持
为了提升用户体验,我们可以添加快捷键支持:
// 在main.js中添加
const { globalShortcut } = require('electron');
app.whenReady().then(() => {
// 注册快捷键 Ctrl+Shift+A 用于截图
const ret = globalShortcut.register('Ctrl+Shift+A', () => {
console.log('Ctrl+Shift+A is pressed');
// 触发截图功能
const mainWindow = BrowserWindow.getAllWindows()[0];
if (mainWindow) {
mainWindow.webContents.send('trigger-screenshot');
}
});
if (!ret) {
console.log('registration failed');
}
// 检查快捷键是否注册成功
console.log(globalShortcut.isRegistered('Ctrl+Shift+A'));
});
app.on('will-quit', () => {
// 注销快捷键
globalShortcut.unregister('Ctrl+Shift+A');
globalShortcut.unregisterAll();
});
2. 图片编辑功能
可以集成简单的图片编辑功能,如添加文字、箭头等:
// 在renderer.js中添加编辑功能
function initEditor() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.getElementById('screenshot-container').appendChild(canvas);
// 实现简单的绘图功能
let isDrawing = false;
let lastX = 0;
let lastY = 0;
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
});
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
function draw(e) {
if (!isDrawing) return;
ctx.strokeStyle = '#ff0000';
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
}
应用打包与分发
1. 安装打包工具
npm install electron-packager --save-dev
2. 添加打包脚本
在package.json中添加打包脚本:
"scripts": {
"start": "electron .",
"package": "electron-packager . screenshot-tool --platform=win32 --arch=x64 --out=dist"
}
3. 执行打包命令
npm run package
总结与展望
通过本文的学习,我们基于Electron框架实现了一个基础的截图工具,包括区域选择、全屏截图、保存等核心功能。当然,这只是一个起点,你可以根据需求进一步扩展功能,如添加图片编辑、OCR文字识别、云同步等高级特性。
Electron框架为桌面应用开发提供了极大的便利,结合Web技术栈的优势,可以快速构建跨平台的桌面应用。希望本文能够帮助你更好地理解Electron的应用开发,为你的项目带来启发。
下期预告
下一篇文章,我们将深入探讨Electron应用的性能优化技巧,包括内存管理、启动速度优化等关键话题,敬请期待!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



