Dropshadow в html canvas, используя context.putImageData - PullRequest
0 голосов
/ 15 марта 2019

В HTML-холсте я пытаюсь создать тени на изображении с прозрачными кусочками в нем. Это изображение генерируется кодом и затем рисуется на холсте, используя: ctx.putImageData(dst, 0, 0);

Проблема в том, что следующий код не генерирует тени:

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

ctx.putImageData(dst, 0, 0);

Любая помощь будет оценена

1 Ответ

2 голосов
/ 15 марта 2019

ctx.putImageData() заменит пиксели в вашем контексте на пиксели, содержащиеся в помещаемых вами данных ImageData.
Нет таких свойств контекста, как shadowBlur, filter, globalCompositeOperation и даже matrix.трансформации, которые будут влиять на это.Даже прозрачные пиксели в ваших 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 и при этом иметь возможность применять к нему свойства контекста?Пройдите второй закадровый холст, на котором вы поместите свои ImageData, и затем будете рисовать на своем основном холсте.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>

Теперь новые браузеры также имеют возможность делать это без использования второго браузера, генерируя ImageBitmap из ImageData, но эта операция асинхронная, поэтому вы все равно можете предпочесть старый способ.

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>
...