因我司业务需要,现在在electron端需要开发仿qq截屏功能,(其实window端已经实现,具体实现方案可以看前面一篇文章~),现在需要手动使用canvas做一个仿qq截图功能的截屏效果,不说了,直接入正题。。。。
其中有部分效果参考了其他博客文章 https://www.cnblogs.com/ygtq-island/p/7676564.html,(部分算法实在是写起来麻烦,于是就把人家的源码拿过来用啦~嘿嘿)先看一个效果图
其中马赛克和箭头的部分实现起来是花费了挺多时间的,首先是截取全屏,通过调用electron的api截取全屏图片数据:
然后在当前屏幕里面创建遮罩层区域,根据在鼠标点击遮罩层事件开始划分截图的矩形并生成同样大小的canvas画布,根据矩形的起始坐标和宽高可以算出画布在全屏截图中的位置,并通过canvas的drawImage属性将图片画到canvas中去,并同时在画布下创建按钮区域,接下来就是开始做各种编辑操作了编辑
本次案例中一共使用了两块画布,也就是说生成了2个canvas,先生成canvas01,这个是基本的canvas,最后获取截图数据就是通过它来获取的,文字编辑功能和马赛克功能目前是在此canvas01上完成
文字编辑功能:
createTextEvent(target) { // 绘制文字事件
this.btnFn(target).then(() => {
let that = this;
let textX, textY;
let nowColor = '#FF0F00'
that.canvasResult.onmousedown = function(ev) {
let input_dx = ev.clientX
let input_dy = ev.clientY
textX = input_dx
textY = input_dy-15
$("body").append(`
<div class="font-group" style="left: ${input_dx}px; top: ${input_dy-15}px">
<input class="draw-text" value="默认文字" />
<span class="draw-text-move"></span>
<span class="draw-text-define"></span>
</div>
`)
sendDom()
}
that.canvasResult.onmouseup = function(ev) {
that.canvasResult.onmousedown = null
}
let sendDom = function() {
$('.text-color-choose ul li').click(function() {
nowColor = $(this).attr('colors')
console.log(nowColor)
$(this).addClass('on').siblings().removeClass('on')
$('.font-group .draw-text').css({color: nowColor})
})
$('.font-group .draw-text-move').mousedown(function(ev) {
ev.stopPropagation()
let dx = ev.clientX - that.canvasResult.offsetLeft
let dy = ev.clientY - that.canvasResult.offsetTop
let input_dx = $('.font-group').offset().left
let input_dy = $('.font-group').offset().top
document.onmousemove = function(ev) {
let mx = ev.clientX - dx - that.canvasResult.offsetLeft
let my = ev.clientY - dy - that.canvasResult.offsetTop
textX = input_dx+mx
textY = input_dy+my
$('.font-group').css({left: input_dx+mx+'px', top: input_dy+my+'px'})
}
document.onmouseup = function(ev) {
document.onmousemove = null
document.onmouseup = null
}
})
$('.font-group .draw-text-define').click(function(ev) {
let input_test = $('.font-group .draw-text').val()
that.ctx.strokeStyle=nowColor;
that.ctx.font="18px Arial";
console.log(textX)
console.log(textY)
that.ctx.strokeText(input_test, textX - that.canvasResult.offsetLeft, textY - that.canvasResult.offsetTop+15);
let fontGroup = document.getElementsByClassName('font-group')[0]
if (!fontGroup) return
document.getElementsByTagName('body')[0].removeChild(fontGroup)
})
}
})
}
在canvas中生成一个文字编辑区块,也可以自行选择颜色,最终获取到input中的val,通过ctx.strokeText绘制到canvas中;
马赛克功能:
this.btnFn(target).then(() => {
let that = this
var lastImgArr = []; //修改缓存
canvasResult.onmousedown = function(ev) {
var modifyImgData = that.ctx.getImageData(0, 0, that.canvasResult.width, that.canvasResult.height);
lastImgArr.push(modifyImgData); //每次下笔前先保存
var ev=ev || window.event;
var dx = ev.clientX-canvasResult.offsetLeft;
var dy = ev.clientY-canvasResult.offsetTop;
drawLine(that.Img,dx,dy, that.ctx, that.canvasResult, that.quan, that.num);
document.onmousemove = function(ev) {
var ev = ev || window.event;
var mx = ev.clientX - that.canvasResult.offsetLeft;
var my = ev.clientY - that.canvasResult.offsetTop;
if (
Math.pow(dx - mx, 2) + Math.pow(dy - my, 2) >=
Math.pow(that.quan * that.num, 2)
) {
//(quan*马赛克个数*2)的平方
drawLine(that.Img, mx, my, that.ctx, that.canvasResult, that.quan, that.num);
dx = mx;
dy = my;
}
};
document.onmouseup = function() {
document.onmousemove = null;
document.onmouseup = null;
};
}
})
function drawLine(obj, dx, dy, context, canvas, quan, num) {
//原始图像
var originalImgData = context.getImageData(
0,
0,
canvas.width,
canvas.height
);
var originalPxData = originalImgData.data;
//用于循环修改
var modifyImgData = context.getImageData(
0,
0,
canvas.width,
canvas.height
);
var modifyPxData = modifyImgData.data;
for (
var i = dx - quan * num;
i < dx + quan * num;
i = i + 2 * quan + 1
) {
for (
var j = dy - quan * num;
j < dy + quan * num;
j = j + 2 * quan + 1
) {
//中心点(dx,dy)
// if(Math.pow(i-dx,2)+Math.pow(j-dy,2) <= Math.pow(quan*num/2,2)){
if (
!(
(i == dx - quan * num && j == dy - quan * num) ||
(i == dx - quan * num &&
j == dy - quan * num + 2 * quan + 1) ||
(i == dx - quan * num &&
j == dy - quan * num + 4 * quan + 2) ||
(i == dx - quan * num &&
j == dy - quan * num + 12 * quan + 6) ||
(i == dx - quan * num &&
j == dy - quan * num + 14 * quan + 7) ||
(i == dx - quan * num &&
j == dy - quan * num + 16 * quan + 8) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num + 2 * quan + 1) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num + 4 * quan + 2) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num + 12 * quan + 6) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num + 14 * quan + 7) ||
(i == dx - quan * num + 16 * quan + 8 &&
j == dy - quan * num + 16 * quan + 8) ||
(i == dx - quan * num + 2 * quan + 1 &&
j == dy - quan * num) ||
(i == dx - quan * num + 4 * quan + 2 &&
j == dy - quan * num) ||
(i == dx - quan * num + 12 * quan + 6 &&
j == dy - quan * num) ||
(i == dx - quan * num + 14 * quan + 7 &&
j == dy - quan * num) ||
(i == dx - quan * num + 2 * quan + 1 &&
j == dy - quan * num + 16 * quan + 8) ||
(i == dx - quan * num + 4 * quan + 2 &&
j == dy - quan * num + 16 * quan + 8) ||
(i == dx - quan * num + 12 * quan + 6 &&
j == dy - quan * num + 16 * quan + 8) ||
(i == dx - quan * num + 14 * quan + 7 &&
j == dy - quan * num + 16 * quan + 8)
)
) {
var sumR = 0;
var sumG = 0;
var sumB = 0;
//找他周围的元素
for (var x = -quan; x <= quan; x++) {
for (var y = -quan; y <= quan; y++) {
var xx = i + x;
var yy = j + y;
var pp = yy * canvas.width + xx; //周围的元素。
sumR += originalPxData[pp * 4 + 0];
sumG += originalPxData[pp * 4 + 1];
sumB += originalPxData[pp * 4 + 2];
}
}
var totlal = (2 * quan + 1) * (2 * quan + 1);
var avgR = sumR / totlal;
var avgG = sumG / totlal;
var avgB = sumB / totlal;
for (var x = -quan; x <= quan; x++) {
for (var y = -quan; y <= quan; y++) {
var xx = i + x;
var yy = j + y;
var pp = yy * canvas.width + xx; //周围的元素。
modifyPxData[pp * 4 + 0] = avgR;
modifyPxData[pp * 4 + 1] = avgG;
modifyPxData[pp * 4 + 2] = avgB;
}
}
}
}
}
context.putImageData(
modifyImgData,
0,
0,
0,
0,
canvas.width,
canvas.height
);
}
其中绘制马赛克的算法借助了drawLine,是从其他途径获取的,主要实现方式看代码即可;
绘制箭头,矩形方法参考了文章(https://www.cnblogs.com/ygtq-island/p/7676564.html)中使用的Ypaint.js,在需要绘制箭头矩形等功能时新创建一块矩形区域并生成canvas02,将绘制成功的canvas02通过toDataURL("image/png")方法获取到图片数据,在通过drawImage方法渲染到canvas01中即可
源代码地址:https://download.csdn.net/download/lbn2676043895/11275821