使用electron截图、裁剪转化成file上传至服务器

  • 邢毅彪
  • 12 Minutes
  • 2018年11月15日

前言

最近在使用electron制作桌面客户端, 其中有个需求是截图并上传, 截图只截应用内部分区域, 上传接口只接受文件类型。 由于此前并没有这方面经验, 在此记录一下实现方式。

实现

  1. 使用electron截图
    首先使用electron本身提供的能力进行截图,此处使用渲染进程desktopCapturer方法抓取应用当前状态屏幕显示内容,具体实现为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const { desktopCapturer } = require('electron')

// 开始截图
desktopCapturer.getSources({types: ['window'], (error, sources) => {
if (error) throw error
let imgSrc = null
for(let i = 0; i < sources.length; i++) {
if(sources[i].name === 'Electron') {
imgSrc = sources[i].thumbnail.toDataURL() // 此处返回的是base64 src
break
}
}

if (imgSrc) {
const canvas$ = document.createElement('canvas') // 创建canvas元素
const img$ = document.createElement('img') // 创建img元素
const ctx = canvas$.getContext('2d')
canvas$.setAttribute('width', 1220)
canvas$.setAttribute('height', 634)
img$.src = imgSrc

img$.onload = () => {
canvas$.drawImage(img$) // 将图片绘制到画布
// TODO 进行图片裁剪


}
}
}})
  1. 使用canvas裁剪图片
    之前想到的裁剪方法都是使用drawImage方法进行裁剪, 但是一直不能达到想要的后果, 后来查到canvas还有一对getImageData 和 putImageData的方法,更加适合来做图片裁剪, 故此处使用此方法进行裁剪
1
2
3
4
5
6
7
8
9
const imgData = canvas$.getImageData(0, 44, 960, 540) // 使用getImageData方法获得画布制定区域像素内容
canvas$.clearRect(0, 0, 1220, 634) // 将画布清空
canvas$.setAttribute('width', 960) // 设置画布大小
canvas$.setAttribute('height', 540)
canvas$.putImageData(imgData, 0, 0) // 将刚才制定区域的像素内容绘制到画布

const imgUrl = canvas$.toDataURL('image/png') // 将canvas转化成图片,此时仍然是base64
// 开始上传图片
uploadHandler(imgUrl)
  1. 将base64转化为file文件上传至服务器
    base64利用h5新特性Blob FormData等属性进行文件上传
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import axios from 'axios'

function base64UrlToBlob(imgUrl) {
const bytes = window.atob(imgUrl.split(',')[1]) // 去掉base64的头部type, 并转化为byte

// 处理异常, 将ascii码小于0的转化为0
const arrayBuffer = new ArrayBuffer(bytes.length)
const unitArray = new Uint8Array(arrayBuffer)

for (let i = 0; i < bytes.length; i++) {
unitArray[i] = bytes[i].charCodeAt(i)
}

return new Blob([arrayBuffer], { type: 'image/png' })
}

const uploadHandler = async (imgUrl) => {
const formData = new FormData()

const file = base64UrlToBlob(imgUrl)

formData.append('file', file, 'image.png') // 注意,第三个参数为文件名称, 如果不传默认为blob, 此时后台可能因为拿不到后缀会报错。

try {
const { data } = await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})

console.log(data) // 处理成功回调
} catch (e) {
console.error(e) // 处理异常
}
}

写到最后

此功能虽然为小功能, 但是在客户端开发中还是比较常见的一个需求, 对自己的技术盲点也是一次查漏补缺。

访问量