HTML5 Canvas: заливка прозрачного изображения цветом и нанесение сверху - PullRequest
0 голосов
/ 21 апреля 2020

Я пытаюсь нарисовать прозрачное изображение поверх другого, заполненного цветом. У меня есть такая структура кода, есть базовое изображение, поверх него умножается еще один прозрачный image_1, а затем image_2 должен быть закрашен и нарисован цветом. Не удалось заставить его работать, используя fillStyle & fillRect.

image_1.src = 'image_1_url';
image_1.onload = () => {
  context.globalCompositeOperation = 'multiply';
  context.drawImage(image_1, 0, 0, canvas.width, canvas.height);

  image_2.src = 'image_2_url';
  image_2.onload = () => {
    //fill image_2 with a color and draw it on top of canvas
  }
}

. В каком порядке я должен использовать заливку цветом и globalCompositeOperations?

enter image description here

1 Ответ

0 голосов
/ 21 апреля 2020

Простое решение: используйте второй холст.

(async () => {
  const [ cat, star, hex ] = await Promise.all( loadImages( [ "kNpEG.jpg", "PPfrd.png", "Vcc8C.png" ], 'https://i.stack.imgur.com/' ) );

  // the visible canvas
  const canvas = document.getElementById( 'canvas' );
  const ctx = canvas.getContext( '2d' );
  // create an offcreen copy
  const canvas2 = canvas.cloneNode();
  const ctx2 = canvas2.getContext( '2d' );
  
  // on the visible canvas 
  // we can apply simply the first step source-over operation
  ctx.drawImage( cat, 0, 0 );
  ctx.drawImage( star, 0, 0 );

  // on the offsreen canvas we apply the color blending
  ctx2.fillStyle = "red";
  ctx2.fillRect( 0, 0, 200, 200 );
  ctx2.globalCompositeOperation = "destination-in";
  ctx2.drawImage( hex, 0, 0 );

  // now we can draw it on the visible canvas, still as source-over
  ctx.drawImage( canvas2, 0, 0 );
  
})().catch( console.error );

function loadImages( filenames, path = "" ) {
  return filenames.map( filename => new Promise( (res, rej ) => {
    const img = new Image();
    img.onload = (evt) => res( img );
    img.onerror = rej;
    img.src = path + filename;
  } ) );
}
<canvas id="canvas" width="200" height="200"></canvas>

Не всегда возможно: рисовать спереди назад.

(async () => {
  const [ cat, star, hex ] = await Promise.all( loadImages( [ "kNpEG.jpg", "PPfrd.png", "Vcc8C.png" ], 'https://i.stack.imgur.com/' ) );

  // the only canvas
  const canvas = document.getElementById( 'canvas' );
  const ctx = canvas.getContext( '2d' );

  // we start with the color blending
  ctx.fillStyle = "red";
  ctx.fillRect( 0, 0, 200, 200 );
  ctx.globalCompositeOperation = "destination-in";
  ctx.drawImage( hex, 0, 0 );

  // and now we draw from behind
  ctx.globalCompositeOperation = "destination-over";

  // so we need to inverse these two
  ctx.drawImage( star, 0, 0 );
  ctx.drawImage( cat, 0, 0 );

})().catch( console.error );

function loadImages( filenames, path = "" ) {
  return filenames.map( filename => new Promise( (res, rej ) => {
    const img = new Image();
    img.onload = (evt) => res( img );
    img.onerror = rej;
    img.src = path + filename;
  } ) );
}
<canvas id="canvas" width="200" height="200"></canvas>
...