手动绘制仿qq截屏效果

        因我司业务需要,现在在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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343