【问题标题】:HTML5 Canvas: Filling transparent image with color and drawing on topHTML5 Canvas:用颜色填充透明图像并在顶部绘图
【发布时间】:2020-04-21 15:33:33
【问题描述】:

我正在尝试在另一个充满颜色的图像上绘制透明图像。我有一个这样的代码结构,有一个基本图像,另一个透明的image_1 乘以它,然后image_2 应该被颜色填充和绘制。无法使用 fillStylefillRect 使其工作。

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?

【问题讨论】:

    标签: javascript canvas html5-canvas


    【解决方案1】:

    简单的解决方案:使用第二个画布。

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

    【讨论】:

    • 谢谢你的回答和sn-ps,我去了第二个临时画布解决方案。我希望有一种方法可以使用 globalCompositeOperation 值直接执行此操作。
    • @Sarge 好吧 -> 第二个 sn-p。但如果您需要多个预混合,则需要在第二张画布上完成。
    • 问题是我只能在前一个的 onload 运行后加载一张图片,就像一步一步加载一样。
    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 2013-06-27
    • 2014-05-08
    • 2015-05-23
    • 2017-06-18
    相关资源
    最近更新 更多