前言
尽管可以通过操作系统自带的截图工具进行截图(Win11下快捷键Win
+Shift
+S
),在前端截取图像的分辨率还是存在不同(基于HTMLCanvasElement.width
和HTMLCanvasElement.height
),且可以进行额外处理(如去除背景)
流程
从\<canvas\>截图到\<img\>
在对图像进行裁剪之前,需要先从不断变化的<canvas>
中截取静止的一帧,这里使用HTMLCanvasElement.toBlob()
方法,它相比另一个方法HTMLCanvasElement.toDataURL()
性能更好
canvas.toBlob(function (blob) {
var url = URL.createObjectURL(blob);
$('#screenshot>img').attr('src', url);
});
其中url
即为截图的链接
如果在使用
webgl
绘图时截取的图片为全黑,请在获取<canvas>
的webgl
上下文时传入参数preserveDrawingBuffer: true
,意为保留缓冲区canvas = document.getElementById('canvas'); gl = canvas.getContext('webgl', { preserveDrawingBuffer: true })
在\<img\>上进行裁剪
裁剪的动作为拖动光标画出一个矩形框,并以框选区与未选区的明暗差异作为实时反馈
拖动鼠标
在按下左键后再绑定拖动鼠标事件,在松开左键时移除该事件,并添加右键的退出事件
通过设置元素的CSS
变量来传递参数,在CSS
中通过函数var()
获取
$('#screenshot').on('mousedown', function (e) {
if (e.which == 1) {
e.preventDefault();
var sx, sy, ex, ey;
sx = e.clientX, sy = e.clientY;
$(this).css({
'--sx': sx + 'px',
'--sy': sy + 'px'
}).on('mousemove', function (e) {
ex = e.clientX, ey = e.clientY;
$(this).css({
'--ex': ex + 'px',
'--ey': ey + 'px'
});
}).on('mouseup', function () {
// crop
// ...
$(this).attr('style', '').off('mousemove').off('mouseup');
});
}
else if (e.which == 3) {
$(this).css('display', 'none');
}
});
其中e.preventDefault()
用于阻止默认事件(此处为拖动<img>
元素)
在结束动作后通过$(this).attr('style', '')
可以同时隐藏截图界面和清除设置的CSS
变量
绘制选框
框选的区域为原图,未选的区域颜色加深,这种效果可以通过遮罩(mask)实现mask
的值mask-image
接受一个图像,该值可以是gradient
(渐变图像)
因此可以通过CSS
函数linear-gradient()
(线性渐变)绘制选框,参数说明参看MDN
#{
mask: linear-gradient(to right, #000 40%, #0000 40%, #0000 60%, #000 60%);
background: #0008;
}
这段代码创建了一个从左到右的渐变图像(渐变长度为0),同理可以创建一个从上到下(to bottom
)的渐变图像,两者叠加即为选框
为了简洁,直接通过伪元素绘制选框,由于<img>
元素没有伪元素(因为无内容物),用一个<div>
将其包裹
<div id="screenshot">
<img>
</div>
#screenshot::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
mask: linear-gradient(to right, #000 var(--sx), #0000 var(--sx), #0000 var(--ex), #000 var(--ex)),
linear-gradient(to bottom, #000 var(--sy), #0000 var(--sy), #0000 var(--ey), #000 var(--ey));
background: #0008;
}
- 在Chrome中需要使用属性名
-webkit-mask
裁剪图像
选定裁剪范围后需要再次绘制到<canvas>
之后再生成图片
使用CanvasRenderingContext2D.drawImage()
方法在绘制时进行裁剪,参数说明参看MDN
// crop
var cvs = $('<canvas></canvas>')[0];
var ctx = cvs.getContext('2d');
var dx = Math.abs(ex - sx), dy = Math.abs(ey - sy);
cvs.width = dx, cvs.height = dy;
ctx.drawImage($(this).children()[0], sx, sy, dx, dy, 0, 0, dx, dy);
cvs.toBlob(function (blob) {
var url = URL.createObjectURL(blob);
// download
// ...
});
下载截图
创建<a>
并通过模拟点击事件进行下载
// download
var a = $('<a></a>').attr({
'href': url,
'download': screenshot
});
a[0].click();
- 如果不设置
download
(文件名),浏览器的行为将是打开该链接,而不是下载
示例
点击demo左上角截图按钮