画布图像蒙版/重叠

问题描述 投票:30回答:2

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

重叠的图像应更改为另一种选择的颜色。我的问题是使用画布有什么办法,我们可以更改由画布绘制的图像颜色,或者我们需要始终使用不同的图像并与CSS / jQuery结合使用。

我了解了画布图像的遮罩和重叠。但是无法理解我的图像,因为它们不是正方形或圆形,那么第一件事就是我如何在单个图像上绘制多个波形。我不知道我搜索过什么,但是找不到完美的解决方案。

我需要的是在画布上绘制一个波浪图像,并通过单击功能更改其颜色,并使用背景图像设置另一个div,另外两个画布将重叠。这可能吗?

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

javascript canvas html5-canvas composition
2个回答
47
投票

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

例如,如果您已经有这个蓝色徽标作为图像:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9zNVZBNS5wbmcifQ==” alt =“在此处输入图像说明”>

任何您想要徽标的顶部被涂成紫色:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9JQ2M4Qy5wbmcifQ==” alt =“在此处输入图像描述”>

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

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

剩下的叫做叠加层。

图像的此覆盖部分是我们将以编程方式重新着色的部分。

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS82MlczbS5wbmcifQ==” alt =“在此处输入图像描述”>

此覆盖图可以通过编程方式重新着色为任何颜色。

“在这里输入的图像描述” “在此处输入图片描述”

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

  1. 在空的画布上绘制覆盖。
  2. 将合成模式设置为“ source-in”。
  3. 效果:仅替换现有像素-透明像素保持透明
  4. 现在在画布上绘制任何颜色的矩形
  5. ((请记住,只有现有的覆盖层会被替换为新颜色)

如何使用更改后的叠加色完成徽标

  1. 将合成模式设置为“目的地优先”
  2. 效果:仅替换透明像素-现有像素保持不变
  3. 现在绘制原始徽标
  4. ((请注意,现有的彩色叠加层将不会被替换)

这种“目的地上方”的合成效果有时称为“下方绘制”。

此覆盖层甚至可以替换为纹理!

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9ZeFVPai5wbmcifQ==” alt =“在此处输入图像说明”>

这里是代码和小提琴: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>

55
投票

目前的问题是,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,这意味着将在现有实体数据的[[inside中绘制源图像(我们将在目标旁边绘制的图像)。什么都不会吸引到透明区域。

如果我们的剪贴蒙版看起来像这样(来自网络的随机

合理使用

:]“剪贴簿”

以及我们的图像如下:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS91VlEwWC5qcGcifQ==” alt =“主图像”>

结果将是这样:

“合成图像”“>

方法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设置了剪切蒙版,接下来将绘制到画布上的所有内容都将被剪切以适合该形状(注意,我们确保形状可以在其开始处结束):

“路径已剪切图像”“ >>

© www.soinside.com 2019 - 2024. All rights reserved.