Canvas 如何在HTML5画布中剪裁形状?

Canvas 如何在HTML5画布中剪裁形状?,canvas,clipping,Canvas,Clipping,我发现了许多用于剪裁圆弧外部区域的示例(例如:)。我似乎不知道如何在圆弧形状内进行剪裁 下面是一个示例,说明我当前如何剪裁外部区域,这与我想要的基本相反: 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 =

我发现了许多用于剪裁圆弧外部区域的示例(例如:)。我似乎不知道如何在圆弧形状内进行剪裁

下面是一个示例,说明我当前如何剪裁外部区域,这与我想要的基本相反:

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

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

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

在这种情况下,现有图像将基于弧“未绘制”:

下面是代码和小提琴:


正文{背景色:象牙;}
#画布{边框:1px纯红;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var img=新图像();
img.onload=函数(){
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$(函数(){});
可用选项 对于不规则形状,可以使用两种方法:

  • 复合模式
  • 剪辑
  • 使用实际剪辑模式或复合模式
    目标输出
    的更好选择是什么

    正如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();
    

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

    结果:

    /// 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();
    
    我们在上面打了一个洞,背景显示:

    复合模式:目标输出 使用复合模式
    目标输出
    将像剪切一样清除像素:

    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';
    

    结果:

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

    与“剪切为<代码>目标输出时删除像素”相同

    复合模式:异或 在存在透明像素()的情况下,使用
    xor

    只有alpha值被反转。由于我们没有实心像素,alpha不会从255变为0(
    255-255
    ),而是
    255-实际值
    ,使用此模式会导致背景未清除


    (如果您使用相同的模式再次绘制,“删除的”像素将被恢复,以便以其他方式使用)。

    您当然可以使用样式的“反转”剪辑形状进行剪辑:只需绘制第一个 屏幕轮廓,然后在不使用beginPath的情况下绘制剪辑路径,然后关闭路径并剪辑。
    这样,您描述的形状就是屏幕中的一个“孔”。
    路径函数必须描述闭合路径

    这里有一个演示:
    我们可以看到,它甚至适用于多种形状, 只要它们不相交

    代码如下所示:

    // 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();
    }
    
    使用示例:(将使用圆形的反向剪辑绘制图像):


    最后一句话:事实上,你可以选择一个任意的基形状进行减法运算。

    你有没有关于你想要的代码应该得到什么结果的图片?是的,正如@Mike'Pomax'Kamermans所说,你能更好地解释一下“clip inside”对你意味着什么吗?它不能像绘制画布大小的图像,然后在该图像上绘制蓝色圆圈那样简单。在我发布的示例中,剪辑发生在弧外。换句话说,圆弧以外的区域将被剪裁(删除)。我想要的是相反的效果,圆弧内的区域被剪裁(删除),而圆弧外的区域仍然正常渲染。