使用 context.putImageData html canvas 中的阴影

Dropshadow in html canvas using context.putImageData

在 html canvas 中,我试图在包含透明片段的图像上生成阴影。此图像由代码生成,然后使用 ctx.putImageData(dst, 0, 0);

绘制到 canvas

问题是以下代码没有生成任何阴影:

ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 15;
ctx.shadowColor = 'rgba(0,0,0,1)';

ctx.putImageData(dst, 0, 0);

如有任何帮助,我们将不胜感激

ctx.putImageData() 会将上下文中的像素替换为您放置的 ImageData 中包含的像素。
没有像 shadowBlur 这样的上下文 属性,也没有过滤器,也没有 globalCompositeOperation,甚至没有矩阵变换会影响它。即使 ImageData 中的透明像素在上下文中也是透明的。

const ctx = canvas.getContext('2d');
ctx.fillStyle = 'salmon';
ctx.fillRect(0,0,300,150);

ctx.translate(120, 50);
ctx.rotate(Math.PI/3);
ctx.translate(-25, -25);
ctx.filter = 'blur(5px)';
ctx.globalCompositeOperation = 'lighter';

ctx.fillStyle = '#0000FF';
ctx.fillRect(0,0,50,50);

setTimeout(() => {
  // at this time, all previous filters, transform, gCO are still active 
  const bluerect = ctx.createImageData(50,50);
  const data = new Uint32Array(bluerect.data.buffer);
  data.fill(0xFFFF0000); // blue
  ctx.putImageData(bluerect, 0, 0); // same as our previous fillRect();
  // a transparent ImageData (smaller)
  const transrect = ctx.createImageData(25, 25);
  ctx.putImageData(transrect, 170, 50); // push a bit farther;
}, 1500);
body {
  background: lightblue;
}
<canvas id="canvas"></canvas>

那么,如何处理 ImageData 并且仍然能够在其上应用上下文的属性? 通过第二个离屏 canvas,您将在其上放置 ImageData,然后您将在主 canvas 上绘制。 drawImage 接受 HTMLCanvasElement 作为源,它受 shadowBlur 等上下文属性的影响:

const ctx = canvas.getContext('2d');
ctx.shadowBlur = 12;
ctx.shadowColor = "red";
// our ImageData
const bluerect = ctx.createImageData(50,50);
const data = new Uint32Array(bluerect.data.buffer);
data.fill(0xFFFF0000); // blue
// create a new canvas, the size of our ImageData
const offscreen = document.createElement('canvas');
offscreen.width = bluerect.width;
offscreen.height = bluerect.height;
// put our ImageData on it
offscreen.getContext('2d')
  .putImageData(bluerect, 0, 0);
// draw it on main canvas
ctx.drawImage(offscreen, 50, 50);
<canvas id="canvas"></canvas>

现在,新的浏览器也可以在不使用第二个浏览器的情况下通过从 ImageData 生成 ImageBitmap 来执行此操作,但此操作是异步的,因此您可能仍然更喜欢旧方法.

const ctx = canvas.getContext('2d');
ctx.shadowBlur = 12;
ctx.shadowColor = "red";
// our ImageData
const bluerect = ctx.createImageData(50,50);
const data = new Uint32Array(bluerect.data.buffer);
data.fill(0xFFFF0000); // blue

// create an ImageBitmap from our ImageData
createImageBitmap(bluerect)
.then(bitmap => { // later
  ctx.drawImage(bitmap, 50, 50);
});
<canvas id="canvas"></canvas>