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

HTML Canvas中如何将黑白蒙版转为黑透明蒙版?(规避慢像素操作)

在Canvas中如何将黑白蒙版转换为黑透明蒙版?

我想把黑白蒙版(白色背景+黑白渐变区域)转换为黑透明蒙版(透明背景+黑到透明的渐变区域),目前找到的方法只有像素操作,但速度太慢。目标效果如下:

目标效果示例

HTML

Convert this:<canvas id="a" width="100" height="100"></canvas>
to this:<canvas id="b" width="100" height="100"></canvas>

CSS

body {
  background-color: pink;
}

canvas {
  outline: 1px solid cyan;
}

JS

var ac = a.getContext('2d');
var g = ac.createLinearGradient(25, 0, 75, 0);
g.addColorStop(0, 'black');
g.addColorStop(1, 'white');
ac.fillStyle = 'white';
ac.fillRect(0, 0, 100, 100);
ac.fillStyle = g;
ac.fillRect(25, 25, 50, 50);

var bc = b.getContext('2d');
var g = bc.createLinearGradient(25, 0, 75, 0);
g.addColorStop(0, 'black');
g.addColorStop(1, '#00000000');
bc.fillStyle = g;
bc.fillRect(25, 25, 50, 50);

尝试过的Multiply混合模式方案

我试过用multiply混合模式实现,但这个方法只能直接得到应用蒙版后的图像,没法单独获取中间的黑透明蒙版画布,代码如下:

HTML

Green image:
<canvas id="a" width=100 height=100 style="outline: 1px solid cyan;"></canvas>
Black and white mask:
<canvas id="m" width=100 height=100 style="outline: 1px solid cyan;"></canvas>
Result:
<canvas id="c" width=100 height=100 style="outline: 1px solid cyan;"></canvas>

CSS

body {
  background-color: cyan;
}

JS

var a = document.getElementById('a'),
    m = document.getElementById('m'),
    c = document.getElementById('c');

// green image
a.context = a.getContext('2d');
a.context.fillStyle = 'green';
a.context.fillRect(0, 0, 100, 100);

// black and white mask
m.context = m.getContext('2d');
m.context.fillStyle = 'white';
m.context.fillRect(0, 0, 100, 100);

var g = m.context.createLinearGradient(25, 0, 75, 0);
g.addColorStop(0, 'black');
g.addColorStop(1, 'white');

m.context.fillStyle = g;
m.context.fillRect(25, 25, 50, 50);

// result
c.context = c.getContext('2d');
c.context.drawImage(a, 0, 0);
c.context.globalCompositeOperation = "multiply";
c.context.drawImage(m, 0, 0);

可行的优化方案

如果不想用原生像素操作的低效方式,可以用TypedArray直接操作像素缓冲区,速度会提升很多。这个方法直接处理32位整数形式的像素,避免逐个操作RGBA四个通道的开销:

function convertBWToBlackTransparent(sourceCanvas) {
  const ctx = sourceCanvas.getContext('2d');
  const { width, height } = sourceCanvas;
  const imageData = ctx.getImageData(0, 0, width, height);
  // 用Uint32Array直接操作像素缓冲区,一次处理一个32位像素
  const pixelData = new Uint32Array(imageData.data.buffer);

  for (let i = 0; i < pixelData.length; i++) {
    // 提取像素的红色通道值(黑白图的RGB通道值一致)
    const grayValue = (pixelData[i] >> 16) & 0xff;
    // 计算alpha值:黑色(0)对应完全不透明(255),白色(255)对应完全透明(0)
    const alpha = 255 - grayValue;
    // 构造目标像素:黑色RGB(0,0,0) + 计算出的alpha
    pixelData[i] = (alpha << 24) | 0x000000;
  }

  // 创建目标画布并写入处理后的图像数据
  const targetCanvas = document.createElement('canvas');
  targetCanvas.width = width;
  targetCanvas.height = height;
  targetCanvas.getContext('2d').putImageData(imageData, 0, 0);
  return targetCanvas;
}

// 使用示例:转换id为"a"的黑白蒙版
const source = document.getElementById('a');
const resultMask = convertBWToBlackTransparent(source);
// 可以将resultMask插入到页面中查看效果
document.body.appendChild(resultMask);

如果需要纯Canvas合成模式实现(不操作像素),可以结合两步合成近似实现,但效果精度和性能不如TypedArray优化方案:

function convertBWToBlackTransparentComposite(sourceCanvas) {
  const { width, height } = sourceCanvas;
  const targetCanvas = document.createElement('canvas');
  targetCanvas.width = width;
  targetCanvas.height = height;
  const ctx = targetCanvas.getContext('2d');

  // 第一步:绘制黑色背景
  ctx.fillStyle = 'black';
  ctx.fillRect(0, 0, width, height);

  // 第二步:保留蒙版区域的黑色
  ctx.globalCompositeOperation = 'destination-in';
  ctx.drawImage(sourceCanvas, 0, 0);

  // 第三步:反转alpha通道,实现白→透明、黑→不透明的效果
  ctx.globalCompositeOperation = 'destination-out';
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, width, height);

  // 恢复默认合成模式
  ctx.globalCompositeOperation = 'source-over';

  return targetCanvas;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:49:58