基于Canvas实现稿定设计版智能抠图的擦除画笔和修补画笔

先贴下demo地址(备用demo地址)吧,大家可以打开体验一下,操作说明参考demo源码(备用源码地址)中readme介绍。这个功能是好久之前做的一个需求了,是公司产品借鉴😂稿定设计智能抠图编辑器(旧版)提的需求,由于是比较冷门的功能,所以当时没找到任何可供参考的方案(近期搜了下好像还是没有),因此做这个需求那段时间前期压力还比较大(主要是做之前没接触过Canvas API)。而最近刚好在空档期,就写篇文章总结下实现思路, 就当做个纪念吧。

1. 实现思路

擦除画笔和修补画笔主要基于Canvas API中CanvasRenderingContext2D.globalCompositeOperation这个选项来实现的,理解了核心思路后就会发现具体的实现其实也挺简单的,而且还可以做一些其它图像混合相关的功能。当然,用WebGL实现也可以,但是会更麻烦一些,而且性能不见得会更好。

1.1 画笔实现思路

画笔是基于鼠标事件监听器和Canvas API实现的,画笔的工作流程如下:

  1. 在画布上触发mousedown事件时开始调用画笔进行绘制并绑定/激活mousemove监听器,每次绘制的图形都是一个圆形,即填充一个圆弧,填充样式使用渐变以实现画笔硬度(详情参考demo源码)。
  2. 在画布上拖动时,即触发mousemove事件时,连续地绘制画笔圆点,但是需要基于鼠标事件对象的movementX/movementY进行节流——movementX/movementY中的较大值达到一个阈值才进行绘制, 否则会导致绘制过于频繁而无法实现画笔的硬度效果。
  3. 在画布上触发mouseup事件时停止绘制并解绑/关闭mousemove监听器。

1.2 图像擦除实现思路

图像擦除——擦除画笔的核心功能,实际的效果就将图像上指定区域(由擦除画笔绘制而来)的像素擦除掉,这个功能其实比较简单,直接通过globalCompositeOperation中"destination-out"这个选项就能实现。 具体就是在进行绘制之前将ctx.globalCompositeOperation设置为"destination-out",然后再进行绘制,此时绘制的区域中之前绘制的图像的像素就会被擦除掉。

1.3 图像修补实现思路

图像修补——修补画笔的核心功能,实际的效果就是进行抠图,也就是将图像指定区域(由修补画笔绘制而来)的像素抠出来,这个功能要比图像擦除麻烦一点,主要是通过globalCompositeOperation中"destination-in"和"source-over"两个选项来实现,另外,在处理流程中需要额外的隐藏画布(canvas)去进行一些中间绘制,具体流程如下:

  1. 准备一张隐藏画布hidden1,将要修补的区域,即画笔绘制的形状绘制到hidden1上。
  2. 准备一张隐藏画布hidden2, 先将其ctx.globalCompositeOperation设置为"source-over", 然后将原始图像(要修补的图像)绘制到hidden2上。
  3. 将hidden2的ctx.globalCompositeOperation设置为"destination-in", 然后将hidden1的内容绘制到hidden2上(即hidden2的ctx以hidden1为绘制源调用drawImage),这样就将图像上目标区域修补(抠)出来了。
  4. 以hidden2作为绘制源就可以将原始图像上修补出的部分绘制到最终呈现的画布上。此外,还可以加一层隐藏画布hidden3,将hidden2的内容绘制到hidden3上,hidden3尺寸保持与原始图像大小一致(若原始图片尺寸过大也应该进行一定缩放,否则会影响性能),由此保证图像放大后的清晰度,而最终呈现的画布则以hidden3为绘制源进行绘制。

2. 其它说明

正如开头所述,由于是不太常用的前端需求,加上完整的demo中在实现上涉及诸多细节,所以暂时未对demo源码中任何部分进行展开。有感兴趣或者有相关需求的朋友可以看一下源码(注释还算详细),觉得不错的话还请给个星吧,如有疑问欢迎评论区留言或联系我。

posted @ 2022-03-22 21:10  科学家丶  阅读(1114)  评论(1编辑  收藏  举报