前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MarsCode 助力:Canvas 上的素描变色魔法✨

MarsCode 助力:Canvas 上的素描变色魔法✨

原创
作者头像
BLACK595
修改2024-09-17 21:53:52
1180
修改2024-09-17 21:53:52

😎嘿!首先,先来看超酷的效果哦😃!🎨素描图在用户鼠标按下后,就像被施了魔法一样🧙‍♂️,将鼠标范围内的素描像素神奇地转换成有色像素🌈。

GIF 2024-9-4 14-52-14.gif
GIF 2024-9-4 14-52-14.gif

原理

  1. 设置原图A在底层
  2. 将模糊过或者另一张图片B覆盖遮挡原图A
  3. 监听鼠标按下移动事件,抹除B相应部分,露出原图A 也就是橡皮擦效果,即鼠标点下去移动所经过位置擦除,鼠标松开不清除。
image.png
image.png

关于绘制图形,图形操作,前端一般都是用Canvas进行处理。

最近抖音豆包AI的插件MarsCode也进入了插件市场,咱们拿来用用,提升下速度,自己也可以少敲点代码。

实现

滑动画线

首先,先来实现鼠标按下滑动后画出线条,先来让AI助手来生成下代码。

image.png
image.png

这里我们必须要把需求描述清楚,要说使用Canvas来实现,不然AI理解不了你要干嘛。

先把代码粘贴进来试下。结果报错了。

image.png
image.png

onMouseMove方法重复了,这里它给的代码有点小bug,在引入时引入了onMouseMoveonMouseUp,但vue中并没有这两个方法,我们把这两个引入删除。除了这个bug,效果还是可以的。

image.png
image.png
GIF 2024-9-2 21-51-51.gif
GIF 2024-9-2 21-51-51.gif

擦除

现在完成了滑动时画出内容,但是我们需要的是滑动时清除内容,这里就要用到cavas的一个神奇的属性-globalCompositeOperation,该属性定义了我们在绘制图形时如何将新内容合成现有图形,合成为新图形。

常用的混合结果如下:

  • source-over:默认设置,在现有画布上下文之上绘制新图形。
image.png
image.png
  • source-in:新图形只在新图形和目标画布重叠的地方绘制。其他的都是透明的。
image.png
image.png
  • source-out:在不与现有画布内容重叠的地方绘制新图形。
image.png
image.png
  • destination-over:在现有的画布内容后面绘制新的图形。
image.png
image.png
  • destination-in:现有的画布内容保持在新图形和现有画布内容重叠的位置。其他的都是透明的。
image.png
image.png
  • destination-out:现有内容保持在新图形不重叠的地方。
image.png
image.png

可以看到,我们需要的效果正是destination-out,画笔划过的地方将原有内容擦除。ctx.globalCompositeOperation = 'destination-out'

填充原图背景

接着我们将原图的背景填充上,先来个灰色背景试试。问问AI,代码少写点

image.png
image.png

根据它的代码,我们再加上destination-out的设置,写一个初始化Canvas的方法init()。

代码语言:js
复制
    function init() {
      const canvas = myCanvas.value;
      const ctx =canvas.getContext('2d');
      //填充整个画布为灰色
      ctx.fillStyle ='gray';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.globalCompositeOperation = 'destination-out'
    }
GIF 2024-9-3 20-39-14.gif
GIF 2024-9-3 20-39-14.gif

有效像素计算

擦除效果有了后,我们还需要考虑在擦除的时候我们并不需要将全部的的遮挡都擦除,因此需要设置当擦除完大部分的灰色前景后就自动将全部的灰色抹除,也就需要判断当前擦除面积是否达到一定百分比

Canvas中擦除实际是改变已有图像的透明度,Canvas给我们提供了getImageData()查看当前图像的像素信息,通过在onMouseMove中统计图像当前有效像素比,看是否需要直接清空前景。

有了思路后,让AI给我们生成代码,我们再来看合不合适。

image.png
image.png

给我们生成了checkAndClearForeground方法,这里这个方法我们不太清楚,让豆包MarsCode给我们注释下。

代码语言:js
复制
/**
 * 检查并清空前景
 * @param {number} x - 鼠标在画布上的 x 坐标
 * @param {number} y - 鼠标在画布上的 y 坐标
 */
function checkAndClearForeground(x, y) {
  // 获取对当前画布元素的引用
  const canvas = myCanvas.value;
  // 从画布上获取图像数据
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  // 初始化有效像素计数为 0
  let validPixels = 0;

  // 遍历图像数据中的每个像素点
  // rgba 显示的模式,所以一个像素表示有 4 个分量,透明度是最后一个分量
  for (let i = 0; i < imageData.data.length; i += 4) {
    // 提取当前像素点的 alpha 通道值
    const alpha = imageData.data[i + 3];
    // 判断 alpha 通道值是否大于 0,若大于 0 则表示当前像素点有效
    if (alpha > 0) {
      validPixels++;
    }
  }

  // 计算有效像素比例(有效像素数除以总像素数)
  const validPixelRatio = validPixels / (imageData.data.length / 4);

  // 判断有效像素比例是否小于 50%
  if (validPixelRatio < 0.5) {
    // 将填充样式设置为灰色
    ctx.fillStyle = 'gray';
    // 用灰色填充整个画布
    ctx.fillRect(0, 0, canvas.width, canvas.height);
  }
}

计算的关键原来在于,在rgba模式下,一个像素有4个分量,最后一个分量表示透明度,当透明度的分量大于0时,表示这个像素点就是有效的,通过计算有效的像素点就能知道百分比了

设置背景

有了基本的功能,我们再让UI小姐姐将我们的原图转为素描图,来替换之前的灰色前景。

代码语言:js
复制
function init() {
  const canvas = myCanvas.value;
  const ctx =canvas.getContext('2d');
  const image = new Image();
  image.src = imagePath;
  // 图片加载完成后执行
  image.onload = function() {
    //填充画布为图像
    ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = 'destination-out'
  };
}
GIF 2024-9-4 14-50-42.gif
GIF 2024-9-4 14-50-42.gif

因为gif帧率的问题,擦除完毕后,清空页面后感觉像变成了白色的,但其实清空后屏幕就透明了。

接着,我们把有色原图设置到Canvas的背景上,这样擦除后,显示的就是有色背景了。

代码语言:css
复制
    canvas {
      background-image: url('@/assets/erase/back.jpg');
      background-size: cover;
      background-position: center;
    }

最终效果:

GIF 2024-9-4 14-52-14.gif
GIF 2024-9-4 14-52-14.gif

扩展

基于此原理,我们还可以做擦除原本模糊的图像,露出清晰的原图。

或者给前景写上文字后,擦除后露出内容的刮刮卡效果。

image.png
image.png

在线体验:http://bulibuli.top:11083/

源码地址:(gitee.com)

结尾

有了MarsCode帮助我们生成代码后,确实可以减少我们开发的难度和成本,但目前AI给我们的代码也不一定是完全正确的😏,对于部分bug还是需要我们手动去处理。不过当我们有了思路与具体的实现方法后,让AI给我们生成代码后我们就只需要大体看下代码,再改一些参数配置后就能很方便的和我们项目适配,目前AI时代已经来临,我们程序员应该尽快找到一个自己喜欢顺手的AI,辅助开发,加快我们开发效率🎈。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原理
  • 实现
    • 滑动画线
      • 擦除
        • 填充原图背景
          • 有效像素计算
          • 设置背景
          • 最终效果:
          • 扩展
          • 结尾
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档