前段时间作了一个钉钉的Linux版本,因为是基于网页版作的,因此缺失了不少桌面应用程序的功能。因为使用的用户可能是Linux的用户,因此在Linux的截图功能没有,在几个用户的要求下决定作一个截图功能。javascript
项目目前支持显示器截图,在windows上运行效果比较理想,Linux上有必定的BUG,目前还不可以支持跨屏幕截图(一个截图横跨两个显示器)功能,本文也发布在了简书,也能够去简书阅读,传送门www.jianshu.com/p/276a29b28…html
在electron中提供了desktopCapturer模块,该模块只能在渲染进程使用。
该模块只提供了一个方法desktopCapturer.getSources(options, callback)
:java
ctrl+alt+a
来截图主进程代码以下git
// 引入各个模块
const {
globalShortcut,
ipcMain,
BrowserWindow,
clipboard,
nativeImage
} = require('electron')
// 保证函数只执行一次
let isRuned = false
// 截图时会出现截图界面,以下就是保存截图窗口的数组
const $windows = []
// 判断是否为快捷键退出,其余的退出方式都不被容许
let isClose = false
module.exports = mainWindow => {
if (isRuned) {
return
}
isRuned = true
// 注册全局快捷键
globalShortcut.register('ctrl+alt+a', function () {
mainWindow.webContents.send('shortcut-capture')
})
// 抓取截图以后显示窗口
ipcMain.on('shortcut-capture', (e, sources) => {
// 若是有之前的窗口就关闭之前的窗口
// 而后根据截图资源于屏幕数据生成窗口
closeWindow()
sources.forEach(source => {
createWindow(source)
})
})
// 有一个窗口关闭就关闭全部的窗口
ipcMain.on('cancel-shortcut-capture', closeWindow)
// 截图窗口确认截图时把数据传递到主进程
// 而后把数据写入到剪切板,并关闭窗口
// 没有直接在渲染进程把数据写入剪切板是由于在Linux上会报错
// 因此就把这一步改到主进程完成
ipcMain.on('set-shortcut-capture', (e, dataURL) => {
clipboard.writeImage(nativeImage.createFromDataURL(dataURL))
closeWindow()
})
}
// 建立窗口
function createWindow (source) {
// display为屏幕相关信息
// 特别再多屏幕的时候要定位各个窗口到对应的屏幕
const { display } = source
const $win = new BrowserWindow({
title: '截图',
width: display.size.width,
height: display.size.height,
x: display.bounds.x,
y: display.bounds.y,
frame: false,
show: false,
transparent: true,
resizable: false,
alwaysOnTop: true,
fullscreen: true,
skipTaskbar: true,
closable: true,
minimizable: false,
maximizable: false
})
// 全屏窗口
setFullScreen($win, display)
// 只能经过cancel-shortcut-capture的方式关闭窗口
$win.on('close', e => {
if (!isClose) {
e.preventDefault()
}
})
// 页面初始化完成以后再显示窗口
// 并检测是否有版本更新
$win.once('ready-to-show', () => {
$win.show()
$win.focus()
// 从新调整窗口位置和大小
setFullScreen($win, display)
})
// 当页面加载完成时通知截图窗口开始程序的执行
$win.webContents.on('dom-ready', () => {
$win.webContents.executeJavaScript(`window.source = ${JSON.stringify(source)}`)
$win.webContents.send('dom-ready')
$win.focus()
})
// 加载地址
$win.loadURL(`file://${__dirname}/window/shortcut-capture.html`)
$windows.push($win)
}
// 让窗口全屏
function setFullScreen ($win, display) {
$win.setBounds({
width: display.size.width,
height: display.size.height,
x: display.bounds.x,
y: display.bounds.y
})
$win.setAlwaysOnTop(true)
$win.setFullScreen(true)
}
// 关闭窗口
function closeWindow () {
isClose = true
while ($windows.length) {
const $winItem = $windows.pop()
$winItem.close()
}
isClose = false
}复制代码
webContents.executeJavaScript
方法以字符串的方式向页面注入js进行执行。// 主进程捕获到截图快捷键就让渲染进程截图
ipcRenderer.on('shortcut-capture', () => {
// 获取屏幕数量
// screen为electron的模块
const displays = screen.getAllDisplays()
// 每一个屏幕都截图一个
// desktopCapturer.getSources能够一次获取全部桌面的截图
// 但因为thumbnailSize不同因此就采用了每一个桌面尺寸都捕获一张
const getDesktopCapturer = displays.map((display, i) => {
return new Promise((resolve, reject) => {
desktopCapturer.getSources({
types: ['screen'],
thumbnailSize: display.size
}, (error, sources) => {
if (!error) {
return resolve({
display,
thumbnail: sources[i].thumbnail.toDataURL()
})
}
return reject(error)
})
})
})
Promise.all(getDesktopCapturer)
.then(sources => {
// 把数据传递到主进程
ipcRenderer.send('shortcut-capture', sources)
})
.catch(error => console.log(error))
})复制代码
webContents.executeJavaScript
的方法向页面传递了截图数据的ESC
按键的时候就关闭截图窗口退出截屏ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
方法
最后,若是有时间的话,可也在考虑能够把截图这个功能单独提取出来而后作成一个模块,可以在其余electron项目中直接引用便可。写得很差的地方请各位大佬包容,GitHub项目地址:github.com/nashaofu/di…github