思路
electron截图工具,其实是通过desktopCapturer捕捉一张全屏的底图放在一个新的窗口上,然后监听鼠标事件记录鼠标点击滑动的区域,在底图上进行裁剪的过程。
创建一个透明的全屏窗口,用来操作截图
import {ipcMain, desktopCapturer, screen , nativeImage, globalShortcut } from 'electron'
//用于保存屏幕底图
let screenImage = ''
//初始化截图界面
const useScreenshot = () => {
//用于获取屏幕的参数
let screenSize = screen.getPrimaryDisplay().size;
//提前创建窗口防止闪屏
const captureWin = winTool.createWin({
fullscreen: true,
transparent: true,
frame: false,
resizable: false,
show: false,
router:'capture',
id:'capture',
alwaysOnTop: true,
})
//在linux中fullscreen可能会失效,所以要设置窗口大小
if(os.platform()==='linux'){
captureWin.setSize(screenSize.width,screenSize.height)
}
//默认隐藏窗口
captureWin.hide()
//快捷键方式
globalShortcut.register('ctrl+shift+a', () => {
captureScreen(captureWin)
})
}
//在主进程创建中使用
useScreenshot()
隐藏截图窗口
const closeScreenshot = function(){
if (captureWin && !captureWin?.isDestroyed()){
captureWin?.close()
captureWin = null
useScreenshot()
}
}
操作截图的方法
const captureScreen = (captureWin) => {
//执行等待,怕截图窗口还没加载好
wait(800)
let screenSize = screen.getPrimaryDisplay().size;
const scaleFactor = screen.getPrimaryDisplay().scaleFactor;
// //创建一个全屏大小的Buffer
const { width, height } = screenSize;
const size = { width: Math.round(width * scaleFactor), height: Math.round(height * scaleFactor) };
//捕获屏幕截图
desktopCapturer.getSources({
types: ['screen'],
thumbnailSize: size
}).then(imgs => {
let imageData=imgs[0].thumbnail.toDataURL()
screenImage = imageData
if (captureWin && !captureWin.isDestroyed()) {
captureWin.show();
captureWin.on('ready-to-show',()=>{
captureWin.webContents.send("imageData", imageData,scaleFactor)
})
}
主进程监听用户操作截图事件
ipcMain.on('captureScreen', (e) => {
captureScreen()
})
ipcMain.on('closeScreenshot', (e,data:any) => {
closeScreenshot()
captureImg(data)
})
将地图裁成截图的屏幕大小,在传给截图的工具页面
function captureImg(data:any){
const scaleFactor = screen.getPrimaryDisplay().scaleFactor;
let newData={
x:Math.round(data.x * scaleFactor),
y:Math.round(data.y * scaleFactor),
width:Math.round(data.width * scaleFactor),
height:Math.round(data.height * scaleFactor),
img:''
}
if(screenImage){
let img = nativeImage.createFromDataURL(screenImage)
let image = img.crop({x:newData.x,y:newData.y,width:newData.width,height:newData.height}).toDataURL()
newData.img = image
//截图工具窗口页面
if(imgTool && !imgTool.isDestroyed()){
sendImgTool(newData)
}else{
createImgTool(newData)
}
}
}
渲染进程中的截图界面
<template>
<div id="box" class="box">
<div id="div-box" class="div-box"></div>
<img id="imgBase" :src="data.imageData" draggable="false" />
</div>
</template>
<script setup>
const ipcRenderer = window.ipcRenderer;
let data = reactive({
x:0,
y:0,
width:0,
height:0,
status:false,
imageData:'',
scaleFactor:0
})
onMounted(()=>{
init()
ipcRenderer.on('imageData',(_,imageData: string,scaleFactor:number)=>{
data.imageData = imageData
data.scaleFactor = scaleFactor
})
})
//移除鼠标事件
onUnmounted(()=>{
document.removeEventListener('mousedown',handleDown)
document.removeEventListener('mouseup',handleUp)
document.removeEventListener('mousemove',handleMove)
})
//监听鼠标事件
const init=()=>{
document.addEventListener('mousedown',handleDown)
document.addEventListener('mousemove',handleMove)
document.addEventListener('mouseup', handleUp)
}
//鼠标按起
const handleUp=(e:any)=>{
console.log('mouseup',data)
data.status = false
if(data.width===window.innerWidth){
data.x = 0
data.y = 0
}
done()
}
//鼠标移动
const handleMove=(event:any)=>{
let div = document.getElementById('div-box')
if(!data.status){
return
}
//这次的宽高
let width = event.pageX - data.x
let height = event.pageY - data.y
//如果等于屏幕的高度
if (
data.width === width &&
data.height === height
) {
return;
}
//移动的位置小与初始位置
if(event.offsetX < width || event.offsetY < height){
return
}
//移动的位置=截图的位置
data.width = width >= 0 ? width : 0;
data.height = height >= 0 ? height : 0;
if(width>0){
div.style.width = width + 'px'
}
if(height>0){
div.style.height = height + 'px'
}
}
//鼠标按下--设置截图的初始位置
const handleDown=(e:any)=>{
let div = document.getElementById('div-box')
//是否正在截图
if (data.status) {
return
}
div.style.width= '0px'
div.style.height='0px'
data.x = e.pageX
data.y = e.pageY
div.style.left = data.x + 'px'
div.style.top = data.y + 'px'
div.style.position = 'absolute'
div.style.display='block'
data.status = true
}
//裁剪截图大小
const done = ()=>{
let params = {}
//图片的宽度
if(data.width===0){
params = {
x:0,
y:0,
width:window.innerWidth,
height:window.innerHeight
}
}else{
params = {
x:Math.round(data.x)+4,
y:Math.round(data.y)+4,
width:data.width-4,
height:data.height-4
}
}
//截图结束,把截图的大小传到主进程
ipcRenderer.send('closeScreenshot', params)
}
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
user-select: none;
-webkit-user-drag: none;
}
.box{
cursor: crosshair;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.div-box{
position: absolute;
width: 0px;
height: 0px;
left: 0;
top:0;
box-shadow: 0 0 0 20000px rgba(0, 0, 0, 0.4);
justify-content: center;
flex-direction: column;
align-items: center;
display: none;
border:1px solid #fff;
// transition: all 0.1s;
}
#imgBase {
position: absolute;
width: 100%;
z-index: -1;
image-rendering: -webkit-optimize-contrast;
}
</style>