enter image description here

我想采用任何形状,创建一个较小的版本,然后使用负片蒙版创建一个新形状,它类似于第一个对象的轮廓,但边框厚度为constant.据我所知,这通常是不可能的,如果不稍微扭曲较小的图像(例如,改变它的纵横比).因此,如果解决方案造成较小图像的一些扭曲,我可以接受.

我还知道如何制作底片面膜:

ctx.globalCompositeOperation = 'source-out'

不用担心给我在画布上画这些形状的代码.我有代码可以很好地做到这一点.我发现的问题是边框厚度不是恒定的,因为我需要扭曲较小的形状才能做到这一点.目前我还没有扭曲它,也不知道如何扭曲它.

我想到的一种方法可能是沿着大图的外边缘移动,对于每个点,向内画一个恒定距离的对应点,它将位于小图的边缘.实际上,当你在较大的图像周围移动时,会跟踪较小的图像.但我不知道如何确定Angular 是正确的.我必须使用某种曲率半径吗?

无论是某种数学解决方案、算法,还是指向我可以使用的库的指针,我都洗耳恭听!

先谢谢你了.

推荐答案

这里有一种可能性,使用destination-out在临时画布中一次切出一块,然后将它们组合在"主"画布中,这是最后的一个小代码.

我要用的图片是一朵向日葵

enter image description here

我认为这将是一个很好的开始,因为所有奇怪的形状边缘

var s = 10 // thickness scale

var img = new Image;
img.onload = draw;
img.src = "https://i.imgur.com/eKKoWVT.png"

var canvas = document.getElementById('c')
var t_canvas = document.createElement('canvas');
t_canvas.width = canvas.width
t_canvas.height = canvas.height

var ctx = canvas.getContext('2d')
var t_ctx = t_canvas.getContext('2d')

function draw() {
  for (i = 0; i < 8; i += Math.PI / 64) {
    t_ctx.globalCompositeOperation = "source-over";
    t_ctx.drawImage(img, 0, 0, 400, 400);
    t_ctx.globalCompositeOperation = "destination-out";
    t_ctx.drawImage(img, Math.sin(i) * s, Math.cos(i) * s, 400, 400);
    ctx.drawImage(t_canvas, 0, 0, 400, 400);
  }
}
<canvas id="c" width=400 height=400></canvas>


下面是一个"慢动作"过程,展示了如何从大图中提取内联绘图

var s = 50 // thickness scale
var i = 0

var img = new Image;
img.onload = draw
img.src = "https://i.imgur.com/eKKoWVT.png"

var canvas = document.getElementById('c')
var t_canvas = document.createElement('canvas');
t_canvas.width = canvas.width
t_canvas.height = canvas.height

var ctx = canvas.getContext('2d')
var t_ctx = t_canvas.getContext('2d')

function draw() {
  t_ctx.globalCompositeOperation = "source-over";
  t_ctx.drawImage(img, 0, 0, 400, 400);
  t_ctx.globalCompositeOperation = "destination-out";
  t_ctx.drawImage(img, Math.sin(i) * s, Math.cos(i) * s, 400, 400);
  
  ctx.globalCompositeOperation = "xor";
  ctx.drawImage(t_canvas, 0, 0, 400, 400);
  
  ctx.moveTo(200 + Math.sin(i) * 9, 200 + Math.cos(i) * 9)
  ctx.lineTo(200 + Math.sin(i) * s, 200 + Math.cos(i) * s)
  ctx.stroke()

  i += Math.PI / 64
  if (i < 8)
    setTimeout(draw, 100);
}
<canvas id="c" width=400 height=400></canvas>

Javascript相关问答推荐

使用print This时, map 容器已在LeafletJS中初始化

窗口.getComputedStyle()在MutationObserver中不起作用

在JavaScript中声明自定义内置元素不起作用

角色 map 集/spritebook动画,用户输入不停止在键上相位器3

使用JavaScript重新排序行

为什么我的列表直到下一次提交才更新值/onChange

Angular 17—每当一个布尔变量变为真时触发循环轮询,只要它保持为真

Google maps API通过API返回ZERO_RESULTS,以获得方向请求,但适用于Google maps

VUE 3捕获错误并呈现另一个组件

我可以使用空手道用户界面来获取网页的当前滚动位置吗?

如何在文本字段中输入变量?

Next.js服务器端组件请求,如何发送我的cookie token?

如何在Angular拖放组件中同步数组?

NG/Express API路由处理程序停止工作

在渲染turbo流之后滚动到元素

$GTE的mongoose 问题

material UI自动完成全宽

如果未定义,如何添加全局变量

用内嵌的含selenium的Java脚本抓取网站

使用JavaScript或PHP从div ID值创建锚标记和链接