You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript Canvas中恢复globalCompositeOperation=destination-out的遮罩区域?

Canvas遮罩恢复问题的解决方案

你现在的问题出在:用destination-out在交互画布上绘制时,是把画布对应区域的像素擦成透明(露出下方的原图),但切换到source-over时,你用橙色笔触去画,相当于在透明区域覆盖橙色,这当然不是你要的“恢复遮罩”效果——你要的是把之前挖开的洞补上,重新遮住原图。

完全不需要引入第三块Canvas,调整Konva的图层逻辑和合成模式就能解决:

核心实现思路

  • 把遮罩操作单独放在交互画布的独立Layer里(Konva的Layer本质就是独立的Canvas),原图放在这个遮罩Layer的下方。
  • 绘制遮罩(挖洞露原图):用destination-out在遮罩Layer上绘制,相当于把遮罩层的对应像素擦除,露出下方原图。
  • 擦除遮罩(补洞遮原图):切换到source-over,用和遮罩Layer初始底色一致的不透明颜色(比如白色)绘制,把之前擦除的区域补回来,重新遮住原图。

调整后的核心代码

if (event.target.name() === "baseImage") {
    isDrawingMask.value = true;

    if (konvaStage.value) {
      currentLineMask.value = [];
      const pointerPosition = konvaStage.value.getNode().getPointerPosition();
      const scale = konvaStage.value.getNode().scale();
      const stagePosition = konvaStage.value.getNode().position();

      if (pointerPosition && scale) {
        const calculatedX = (pointerPosition.x - stagePosition.x) / scale.x;
        const calculatedY = (pointerPosition.y - stagePosition.y) / scale.y;

        const isDrawMask = props.tool === "draw-mask";
        currentLineMask.value = {
          stroke: isDrawMask ? "#df4b26" : "#ffffff", // 擦除时用遮罩层底色填充
          strokeWidth: 60,
          globalCompositeOperation: isDrawMask ? "destination-out" : "source-over",
          lineCap: "round",
          lineJoin: "round",
          points: [calculatedX, calculatedY, calculatedX, calculatedY],
        };
      }
    }
  }

关键注意点

  • 确保遮罩Layer的初始状态是完全不透明(比如给Layer填充白色),这样一开始原图是被完全遮住的,destination-out绘制时才会挖洞露出原图。
  • 不要把遮罩操作和原图绘制放在同一个Layer,否则destination-out会直接擦除原图像素,后续无法恢复。

内容的提问来源于stack exchange,提问作者muzak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 06:17:29