canvas如何对png图片进行描边?

我现在想给一张png图片描边,使它可以在背景中看的更加清楚。因为之后背景颜色也会变化,所以我希望描边是沿图片边缘扣一个透明的边。我的想法是将图片复制八份,通过设置context.globalCompositeOperation = "xor"并将他们沿八个角度移动2px来进行一个描边,代码实现如下

    <div id="canvas-warp">
      <canvas id="canvas"></canvas>
    </div>
    <script>
      var context;
      var canvas = document.getElementById("canvas");
      canvas.width = 600;
      canvas.height = 600;
      context = canvas.getContext("2d");
      context.fillStyle = "#000";
      context.fillRect(0, 0, 800, 600);
      context.globalCompositeOperation = "xor";
      const image1 = new Image();
      image1.src = "./images/one1.png";
      image1.onload = function () {
        const list = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1];
        for (let i = 0; i < list.length; i += 2) {
          context.drawImage(
            image1,
            canvas.width / 2 - (this.width * 1.1) / 2 - list[i] * 2,
            canvas.height / 2 - (this.height * 1.1) / 2 - list[i + 1] * 2,
            180,
            180
          );
        }
      };


但是图片的描边效果并不是很好,希望求教更好的方法

9/9更新

我又想到一种方法,将图片用getImageData变成数组,在数组循环成点阵的时候扩充点阵的边缘,但是经过测试,这种方法太耗性能了,渲染一张图需要5s以上,代码如下

<div id="canvas-warp">
      <canvas id="canvas"></canvas>
    </div>
    <script>
      const canvas = document.querySelector("#canvas");
      const ctx = canvas.getContext("2d");
      const image = new Image();
      image.src = "./images/one1.png";
      image.onload = function () {
        main();
      };
      function main() {
        data = new Date()
        console.log(data)
        const { width, height } = image;
        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(image, 0, 0);
        const imageData = ctx.getImageData(0, 0, width, height).data;
        ctx.fillStyle = "#ffffff";
        ctx.fillRect(0, 0, width, height);
        const gap = 1;
        for (let h = 1; h < height*2; h += gap) {
          for (let w = 1; w < width*20; w += gap) {
            const position = (width * h + w) * 4;
            const r = imageData[position+1];
            const g = imageData[position + 2];
            const b = imageData[position + 3];
            if (r < 180 || b < 180 || g < 180) {
              ctx.fillStyle = "#6cf";
              ctx.fillRect(w+1, h+1, 1, 1);
            //   ctx.fillRect(w-1, h-1, 1, 1);
            //   ctx.fillRect(w, h-1, 1, 1);
            //   ctx.fillRect(w, h, 1, 1);
            //   ctx.fillRect(w, h-1, 1, 1);
            //   ctx.fillRect(w, h-1, 1, 1);
            }
          }
        }
        data1 = new Date()
        console.log(data1-data)
      }
    </script>
阅读 2.9k
2 个回答

通过 d3-contour 可以计算出描边多边形,之后用 canvas 或者 svg 等方式绘制都可以

import simplify from '@turf/simplify';
import * as d3 from 'd3-contour';

const contours = d3
  .contours()
  .size([width, height])
  .smooth(false)
  .thresholds([1]);
const [lines] = contours(imageData);
const { coordinates } = simplify(lines, {
  tolerance: 1,
  highQuality: false,
});
const polyline = coordinates.flat(1); // 描边多边形组成的数组
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏