如何在HTML5画布中剪切INSIDE形状?

时间:2013-09-24 17:22:52

标签: canvas clipping

我发现了许多用于剪切弧的外部区域的示例(例如:this example)。我似乎无法弄清楚如何在内部中剪切

以下是我当前如何裁剪外部区域的示例,这与我想要的完全相反:

ctx.save();

ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.clip();

ctx.beginPath();
ctx.lineWidth     = 1;
ctx.shadowBlur    = 10;
ctx.shadowOffsetX = shadowOffset;
ctx.shadowColor   = '#000000';
ctx.strokeStyle   = '#000000';
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
ctx.stroke();

ctx.restore();

3 个答案:

答案 0 :(得分:13)

可用选项

对于不规则形状,您可以使用两种技术:

  1. 复合模式
  2. 剪辑
  3. 恕我直言,最好选择使用实际剪辑模式或复合模式destination-out

    正如markE在他的回答xor中所说的那样,但xor只反转了alpha像素并且没有删除RGB像素。这适用于没有透明度的实体图像,但是如果现有像素具有透明度,则这些像素可能会产生相反的效果(变为可见),或者如果稍后使用xor模式并在顶部绘制其他内容,则“剪切”区域将再次显示。

    剪辑

    通过使用剪辑,您只需使用clearRect清除路径定义的区域。

    示例:

    /// save context for clipping
    ctx.save();
    
    /// create path
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.closePath();
    
    /// set clipping mask based on shape
    ctx.clip();
    
    /// clear anything inside it
    ctx.clearRect(0, 0, offset, offset);
    
    /// remove clipping mask
    ctx.restore();
    

    <强> ONLINE DEMO FOR CLIPPING

    源图像:具有部分半透明像素且完全透明的图像,其中背景中的白色通过 -

    Source image

    <强>结果:

    我们打了一个洞,背景显示:

    clipping

    复合模式:目标输出

    使用复合模式destination-out将清除像素一样的像素:

    ctx.beginPath();
    ctx.arc(offset * 0.5, offset * 0.5, offset * 0.3, 0, 2 * Math.PI);
    ctx.closePath();
    
    /// set composite mode
    ctx.globalCompositeOperation = 'destination-out';
    ctx.fill();
    
    /// reset composite mode to default
    ctx.globalCompositeOperation = 'source-over';
    

    <强> ONLINE DEMO FOR COMPOSITE MODE

    <强>结果:

    destination out

    与裁剪相同,因为destination-out会移除像素。

    复合模式:xor

    在存在透明像素(see online example here)的情况下使用xor

    xor mode

    仅反转了alpha值。由于我们没有实体像素,因此alpha不会从255变为0(255 - 255)而是255 - actual value,这会导致使用此模式的非清除背景。

    (如果您使用相同模式第二次绘制,则“已删除”像素将被恢复,因此可以通过其他方式使用这些像素。)

答案 1 :(得分:9)

你肯定可以使用你的风格的“倒”剪辑形状进行剪辑:先画一下 屏幕轮廓,然后绘制剪切路径 - 不使用beginPath-,然后关闭路径和剪辑 这样你描述的形状就是屏幕内的“洞” 路径功能必须描述封闭路径。

演示在这里:http://jsfiddle.net/gamealchemist/9DuJL/40/
我们可以看到它甚至可以用于多种形状, 只要他们不相交。

example of std clip

example of revert clip

代码如下:

// clips the canvas with the invert of provided path function
// if pathFunction is an array, remove clips defined by all functions
function clipRevert(pathFunction) {
    ctx.beginPath();
    ctx.rect(0, 0, canvas.width, ctx.canvas.height);
    if (Array.isArray(pathFunction)) pathFunction.forEach(execute);
    else pathFunction();
    ctx.clip();
}


function execute(fn) {
    return fn();
}

使用示例:(将使用圆形的反转剪辑绘制图像):

function circlePath(x, y, r) {
    ctx.arc(x, y, r, 0, Math.PI * 2, true);
}

window.clipRevertExample = function () {
    ctx.save();
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    clipRevert(circlePath.bind(null, 100, 60, 40));
    ctx.drawImage(img, 0, 0);
    ctx.restore();
}

最后评论:您实际上可以选择任意基本形状来减去。

答案 2 :(得分:2)

您可以使用context.globalCompositeOperation =“xor”根据任何路径或绘图从现有图像中删除。

此合成模式将使用您在应用合成后执行的任何绘图“取消”现有像素。

在这种情况下,现有图像将根据您的弧线“未拉伸”:

enter image description here

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

<!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; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

var img=new Image();
img.onload=function(){
    ctx.save();
    ctx.drawImage(img,0,0);
    ctx.globalCompositeOperation="xor";
    ctx.beginPath();
    ctx.arc(106, 77, 74, 0, Math.PI * 2, false);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
}
img.src="http://i.imgur.com/gwlPu.jpg";


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=200 height=158></canvas>
</body>
</html>