【问题标题】:Canvas: How to modify ImageData pixels that exist within a custom path?Canvas:如何修改自定义路径中存在的 ImageData 像素?
【发布时间】:2021-11-21 18:44:03
【问题描述】:

我正在尝试创建一种用户可以将自定义光标移动到图像上并更改该自定义光标内的像素的体验。

mousemove 事件中,我尝试重新创建此自定义光标路径并使用isPointInPath 确定自定义光标是否“超过”主画布上下文中的给定点。

代码确实改变了主画布中的一些像素。但是,下面列出了以下意外行为:

  • 移动光标会改变主画布中多个区域的像素
  • 主画布的 x 和 y 坐标(源自 imageData)不正确

(见下图)

为什么会这样?如何更改代码以使自定义光标(又名圆形)仅更改与主画布的该部分对应的像素?

let image;
let imageData;

const cursorCanvas = document.createElement("canvas");
const cursorCanvasContext = cursorCanvas.getContext("2d");
cursorCanvas.width = 100;
cursorCanvas.height = 100;
drawCursor();

const imageCanvas = document.querySelector("canvas");
imageCanvas.width = window.innerWidth;
imageCanvas.height = window.innerHeight;
const imageCanvasContext = imageCanvas.getContext("2d");

document.querySelector("img").addEventListener("load", (event) => {
  image = event.target;
  image.crossOrigin = "Anonymous";
  drawBackground();
  imageData = imageCanvasContext.getImageData(
    0,
    0,
    imageCanvas.width,
    imageCanvas.height
  );
});

window.addEventListener("mousemove", (event) => {
  requestAnimationFrame(() => {
    if (imageData) {
      imageCanvasContext.beginPath();
      imageCanvasContext.arc(
        event.clientX,
        event.clientY,
        cursorCanvas.width / 2,
        0,
        2 * Math.PI
      );
      imageCanvasContext.closePath();

      for (let i = 0; i < imageData.data.length; i += 4) {
        const y = Math.floor(i / imageData.width);
        const x = i - y * imageData.width;

        if (imageCanvasContext.isPointInPath(x, y)) {
          imageData.data[i] = 40;
          imageData.data[i + 1] = 40;
          imageData.data[i + 2] = 40;
        }
      }
      imageCanvasContext.putImageData(imageData, 0, 0);
    }

    imageCanvasContext.drawImage(
      cursorCanvas,
      event.clientX - cursorCanvas.width / 2,
      event.clientY - cursorCanvas.height / 2
    );
  });
});

function drawBackground() {
  imageCanvasContext.clearRect(
    0,
    0,
    imageCanvas.width,
    imageCanvas.height
  );

  if (image) {
    const ratio =
      window.innerWidth > window.innerHeight ?
      window.innerWidth / window.innerHeight :
      window.innerHeight / window.innerWidth;

    imageCanvasContext.drawImage(
      image,
      0,
      0,
      image.width,
      image.height,
      0,
      0,
      ratio * imageCanvas.width,
      ratio * imageCanvas.height
    );
  }
}

function drawCursor() {
  cursorCanvasContext.beginPath();
  cursorCanvasContext.arc(
    cursorCanvas.width / 2,
    cursorCanvas.width / 2,
    cursorCanvas.width / 2,
    0,
    2 * Math.PI
  );
  cursorCanvasContext.stroke();
  cursorCanvasContext.closePath();
}
html,
body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

body {
  font-family: sans-serif;
  margin: 0;
}

img {
  visibility: hidden;
  position: absolute;
}

canvas {
  cursor: none;
}
<img src="https://i.imgur.com/vzGhITt.jpeg" />
<canvas />

【问题讨论】:

    标签: javascript canvas getimagedata putimagedata


    【解决方案1】:

    啊,好像是我计算错了imageData的x和y坐标。

    不正确:

    const y = Math.floor(i / imageData.width);
    const x = i - y * imageData.width;
    

    正确:

    const x = (i / 4) % imageData.width;
    const y = Math.floor(i / 4 / imageData.width);
    

    let image;
    let imageData;
    
    const cursorCanvas = document.createElement("canvas");
    const cursorCanvasContext = cursorCanvas.getContext("2d");
    cursorCanvas.width = 100;
    cursorCanvas.height = 100;
    drawCursor();
    
    const imageCanvas = document.querySelector("canvas");
    imageCanvas.width = window.innerWidth;
    imageCanvas.height = window.innerHeight;
    const imageCanvasContext = imageCanvas.getContext("2d");
    
    document.querySelector("img").addEventListener("load", (event) => {
      image = event.target;
      image.crossOrigin = "Anonymous";
      drawBackground();
      imageData = imageCanvasContext.getImageData(
        0,
        0,
        imageCanvas.width,
        imageCanvas.height
      );
    });
    
    window.addEventListener("mousemove", (event) => {
        if (imageData) {
          imageCanvasContext.beginPath();
          imageCanvasContext.arc(
            event.clientX,
            event.clientY,
            cursorCanvas.width / 2,
            0,
            2 * Math.PI
          );
          imageCanvasContext.closePath();
    
          for (let i = 0; i < imageData.data.length; i += 4) {
            const x = (i / 4) % imageData.width;
            const y = Math.floor(i / 4 / imageData.width);
    
            if (imageCanvasContext.isPointInPath(x, y)) {
              imageData.data[i] = 40;
              imageData.data[i + 1] = 40;
              imageData.data[i + 2] = 40;
            }
          }
          imageCanvasContext.putImageData(imageData, 0, 0);
        }
    
        imageCanvasContext.drawImage(
          cursorCanvas,
          event.clientX - cursorCanvas.width / 2,
          event.clientY - cursorCanvas.height / 2
        );
    });
    
    function drawBackground() {
      imageCanvasContext.clearRect(
        0,
        0,
        imageCanvas.width,
        imageCanvas.height
      );
    
      if (image) {
        const ratio =
          window.innerWidth > window.innerHeight ?
          window.innerWidth / window.innerHeight :
          window.innerHeight / window.innerWidth;
    
        imageCanvasContext.drawImage(
          image,
          0,
          0,
          image.width,
          image.height,
          0,
          0,
          ratio * imageCanvas.width,
          ratio * imageCanvas.height
        );
      }
    }
    
    function drawCursor() {
      cursorCanvasContext.beginPath();
      cursorCanvasContext.arc(
        cursorCanvas.width / 2,
        cursorCanvas.width / 2,
        cursorCanvas.width / 2,
        0,
        2 * Math.PI
      );
      cursorCanvasContext.stroke();
      cursorCanvasContext.closePath();
    }
    html,
    body {
      width: 100vw;
      height: 100vh;
      overflow: hidden;
    }
    
    body {
      font-family: sans-serif;
      margin: 0;
    }
    
    img {
      visibility: hidden;
      position: absolute;
    }
    
    canvas {
      cursor: none;
    }
    <img src="https://i.imgur.com/vzGhITt.jpeg" />
    <canvas />

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      • 1970-01-01
      • 1970-01-01
      • 2019-01-04
      • 2018-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多