javascript 画布图像遮罩/重叠

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18379818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 11:41:32  来源:igfitidea点击:

Canvas image masking / overlapping

javascriptcanvashtml5-canvascomposition

提问by Anup

In my project i have to implement one different color image on the other same size and pattern image using canvas and images are not in round or rectangle shapes. That all are in waves shape and it will apply on a single main background image for showing multiple graphics on every onclickfunction.

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

Overlapped image should be change in another selected color. My question Is there any way with using canvas from that we can change the image color which is draw by canvas or we need to use different images always and apply with CSS/jQuery.

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

I read about canvas image masking and overlapping. But cant understand with my images because that are not in square or circle shape then first thing is how i draw multiple wave shapes on a single image. I have no idea about that i searched but fail to search perfect solution.

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

My need is just draw one wave image on canvas and change its color from on click function and also set an another div with background-image and also more then two canvas will overlapped. Is this possible?

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

(That means : This functionality is for create or set multiple graphics on a car, for that each graphic image need to set in a canvas and for another graphic need to overlapped on div and first canvas)

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

回答by

The question as it stands is a bit unclear IMO. To give a more general answer that you can apply to a scenario where you need clipping you can use (at least) two approaches:

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

Method 1 - Using composite mode to clip

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

Composite mode is the simplest way but also the least flexible as you need to pre-define the clipping mask as an image with a transparent background (usually PNG).

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

You can either use the solid parts of the image to clip the next drawn thing, or use the transparent areas to fill in.

您可以使用图像的实心部分来剪辑下一个绘制的东西,或者使用透明区域来填充。

Here is an approach where we use the solid parts to clip the next drawn shape/image:

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

/// 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);

Here the globalCompositeOperationis changed to source-inwhich means that the source image (the one we are gonna draw next to destination) will be drawn insidethe existing solid data. Nothing will be drawn to transparent areas.

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

If our clipping mask looks like this (random fair-usefrom the net):

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

Clip mask

剪辑蒙版

And our image like this:

而我们的形象是这样的:

Main image

主图

The result will be this:

结果将是这样的:

Composited image

合成图像

Method 2 - Using a Path to clip

方法 2 - 使用路径进行剪辑

You can also define a Path for the clipping. This is very flexible as you can adjust the path or animate it if you desire.

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

Note: Just have in mind that clipping using Path is currently a bit "fragile" in the browsers so you should consider using save()and restore()before and after setting and using a clip path as the browsers are unable to reset clip at the moment (restorewill restore the default clip = full canvas);

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

Lets define a simple zig-zag path (this will be your waves in your case):

让我们定义一个简单的锯齿形路径(这将是您的波浪):

/// 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();

Now that we have set the clipping mask using clipanything drawn to the canvas next will be clipped to fit inside that shape (note that we make sure the shape can end where it begun):

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

Path clipped image

路径剪切图像

回答by markE

You can use context compositing to replace part of an image.

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

For example, if you have this blue logo already as an image:

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

enter image description here

在此处输入图片说明

Any you want the top part of the logo to be colored purple:

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

enter image description here

在此处输入图片说明

You can use compositing to recolor the top part of the image.

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

First, use your favorite image editor to crop away any part you don'twant recolored.

首先,用你最喜爱的图像编辑器来裁剪掉你的任何一部分希望重新着色。

What's left is called an overlay.

剩下的称为叠加层。

This overlay part of the image is what we will programmatically recolor.

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

enter image description here

在此处输入图片说明

This overlay can be programatically recolored to any color.

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

enter image description hereenter image description here

在此处输入图片说明在此处输入图片说明

How the overlay was programatically recolored:

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

  1. Draw the overlay on an empty canvas.
  2. Set the compositing mode to “source-in”.
  3. The Effect: Only existing pixels are replaced—transparent pixels remain transparent
  4. Now draw a rectangle of any color the covering the canvas
  5. (remember, only the existing overlay will be replaced with the new color)
  1. 在空白画布上绘制叠加层。
  2. 将合成模式设置为“source-in”。
  3. 效果:仅替换现有像素——透明像素保持透明
  4. 现在绘制一个覆盖画布的任何颜色的矩形
  5. (请记住,只有现有的叠加层会被新颜色替换)

How to complete the logo with the changed overlay color

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

  1. Set the compositing mode to “destination-atop”
  2. The Effect: Only transparent pixels are replaced—existing pixels remain unchanged
  3. Now draw the original logo
  4. (remember, the existing colored overlay will not be replaced)
  1. 将合成模式设置为“destination-atop”
  2. 效果:仅替换透明像素——现有像素保持不变
  3. 现在绘制原始标志
  4. (请记住,现有的彩色叠加层不会被替换)

This "destination-atop" compositing effect is sometimes called “drawing under”.

这种“destination-atop”合成效果有时被称为“drawing under”。

This overlay can even be replace with textures!

这种覆盖甚至可以用纹理代替!

enter image description here

在此处输入图片说明

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/bfUPr/

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