画布图像遮罩/重叠

时间:2013-08-22 11:59:40

标签: javascript canvas html5-canvas composition

在我的项目中,我必须使用画布在另一个相同尺寸和图案图像上实现一个不同的彩色图像,而图像不是圆形或矩形形状。这些都是波浪形状,它将应用于单个主背景图像,以在每个onclick函数上显示多个图形。

重叠图像应更改为其他所选颜色。我的问题是否有任何使用画布的方法我们可以改变画布绘制的图像颜色,或者我们需要总是使用不同的图像并应用CSS / jQuery。

我读到了关于画布图像遮罩和重叠的内容。但不能理解我的图像,因为它不是方形或圆形,那么首先是我如何在单个图像上绘制多个波形。我不知道我搜索过但却未能找到完美的解决方案。

我需要的是在画布上绘制一个波形图像并从点击功能中更改其颜色,并设置另一个具有背景图像的div,并且还将重叠两个画布。这可能吗?

(这意味着:此功能用于在汽车上创建或设置多个图形,因为每个图形图像需要在画布中设置,而另一个图形需要在div和第一个画布上重叠)

2 个答案:

答案 0 :(得分:51)

目前的问题是IMO有点不清楚。要给出一个更通用的答案,你可以应用于你需要裁剪的场景,你可以使用(至少)两种方法:

方法1 - 使用复合模式剪辑

复合模式是最简单的方法,但也是最不灵活的,因为您需要将剪贴蒙版预先定义为具有透明背景的图像(通常为PNG)。

您可以使用图像的实体部分剪辑下一个绘制的内容,也可以使用透明区域填充。

这是一种方法,我们使用实体部分剪切下一个绘制的形状/图像:

/// draw the shape we want to use for clipping
ctx1.drawImage(imgClip, 0, 0);

/// change composite mode to use that shape
ctx1.globalCompositeOperation = 'source-in';

/// draw the image to be clipped
ctx1.drawImage(img, 0, 0);

此处globalCompositeOperation更改为source-in,这意味着源图像(我们将在目标旁边绘制的图像)将在内部绘制现有的实体数据。透明区域不会被吸引。

如果我们的剪贴蒙版看起来像这样(从网上随机合理使用):

Clip mask

我们的形象是这样的:

Main image

结果将是:

Composited image

方法2 - 使用剪辑路径

您还可以为剪辑定义路径。这非常灵活,因为您可以根据需要调整路径或设置动画。

注意:请记住,使用Path的剪辑目前在浏览器中有点“脆弱”,因此您应该考虑在设置和使用剪辑路径之前和之后使用save()restore()作为浏览器暂时无法重置剪辑(restore将恢复默认剪辑=完整画布);

让我们定义一个简单的之字形路径(这将是你的波浪):

/// use save when using clip Path
ctx2.save();

ctx2.beginPath();
ctx2.moveTo(0, 20);
ctx2.lineTo(50,0);
/// ... more here - see demo
ctx2.lineTo(400, 20);
ctx2.lineTo(400, 100);
ctx2.lineTo(0, 100);
ctx2.closePath();

/// define this Path as clipping mask
ctx2.clip();

/// draw the image
ctx2.drawImage(img, 0, 0);

/// reset clip to default
ctx2.restore();

现在我们已经使用clip设置了剪贴蒙版,下一个绘制到画布的任何内容都会被剪裁以适合该形状(注意我们确保形状可以在它开始的地方结束):

Path clipped image

<强> See online demo of these methods here

答案 1 :(得分:42)

您可以使用上下文合成来替换部分图片。

例如,如果您已将此蓝色徽标作为图像:

enter image description here

任何您希望徽标的顶部都是紫色的:

enter image description here

您可以使用合成来重新着色图像的顶部。

首先,使用您喜欢的图像编辑器裁剪掉想要重新着色的任何部分。

剩下的内容称为叠加层。

图像的叠加部分是我们将以编程方式重新着色的部分。

enter image description here

此叠加层可以以编程方式重新着色为任何颜色。

enter image description here enter image description here

叠加层是如何以编程方式重新着色的:

  1. 在空白画布上绘制叠加层。
  2. 将合成模式设置为“source-in”。
  3. 效果:仅替换现有像素 - 透明像素保持透明
  4. 现在绘制一个覆盖画布的任何颜色的矩形
  5. (请记住,只有现有的叠加层将替换为新的颜色)
  6. 如何使用更改的叠加颜色完成徽标

    1. 将合成模式设置为“destination-atop”
    2. 效果:仅替换透明像素 - 现有像素保持不变
    3. 现在绘制原始徽标
    4. (请记住,现有的彩色叠加层不会被替换)
    5. 这种“目的地 - 顶部”合成效果有时被称为“绘图下”。

      此叠加层甚至可以替换为纹理!

      enter image description here

      这是代码和小提琴:http://jsfiddle.net/m1erickson/bfUPr/

      <!doctype html>
      <html>
      <head>
      <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
      <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
      
      <style>
          body{ background-color: ivory; padding:20px; }
          #canvas{border:1px solid red;}
      </style>
      
      <script>
      $(function(){
      
          var canvas=document.getElementById("canvas");
          var ctx=canvas.getContext("2d");
      
          var truck,logo,overlay;
          var newColor="red";
      
          var imageURLs=[];
          var imagesOK=0;
          var imgs=[];
          imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/boxTruck.png");
          imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/TVlogoSmall.png");
          imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/TVlogoSmallOverlay.png");
          loadAllImages();
      
          function loadAllImages(){
              for (var i = 0; i < imageURLs.length; i++) {
                var img = new Image();
                imgs.push(img);
                img.onload = function(){ imagesOK++; imagesAllLoaded(); };
                img.src = imageURLs[i];
              }      
          }
      
          var imagesAllLoaded = function() {
            if (imagesOK==imageURLs.length ) {
               // all images are fully loaded an ready to use
               truck=imgs[0];
               logo=imgs[1];
               overlay=imgs[2];
               start();
            }
          };
      
      
          function start(){
      
              // save the context state
              ctx.save();
      
              // draw the overlay
              ctx.drawImage(overlay,150,35);
      
              // change composite mode to source-in
              // any new drawing will only overwrite existing pixels
              ctx.globalCompositeOperation="source-in";
      
              // draw a purple rectangle the size of the canvas
              // Only the overlay will become purple
              ctx.fillStyle=newColor;
              ctx.fillRect(0,0,canvas.width,canvas.height);
      
              // change the composite mode to destination-atop
              // any new drawing will not overwrite any existing pixels
              ctx.globalCompositeOperation="destination-atop";
      
              // draw the full logo
              // This will NOT overwrite any existing purple overlay pixels
              ctx.drawImage(logo,150,35);
      
              // draw the truck
              // This will NOT replace any existing pixels
              // The purple overlay will not be overwritten
              // The blue logo will not be overwritten
              ctx.drawImage(truck,0,0);
      
              // restore the context to it's original state
              ctx.restore();
      
          }
      
      
      }); // end $(function(){});
      </script>
      
      </head>
      
      <body>
          <canvas id="canvas" width=500 height=253></canvas>
      </body>
      </html>