前段時間作了一個釘釘的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