FabricJS如何防止canvas.clipTo裁剪canvas.backgroundImage?

29
我希望在使用 Fabric 的 Canvas 中设置一个全局的 clipTo,它将影响所有用户添加的图层。我需要一个背景图像和一个叠加图像,这些图像不会受到此剪切蒙版的影响。
示例:

enter image description here

这张照片中发生了什么事情:
  1. 一个画布覆盖图像使T恤看起来自然皱纹。 这个覆盖图像大多是透明的
  2. 添加了一个与T恤形状完全相同的背景图像,这应该使T恤看起来是蓝色的
  3. 添加了canvas.clipTo函数,它将画布剪切成矩形形状
  4. 添加了用户添加的图像(著名的Fabric pug)
我希望用户添加的图像(pug)被限制在矩形区域内。
不希望剪辑区域影响背景图像(蓝色T恤形状)。
有没有简单的方法可以实现这一点? 我真的不想不整洁地为每个用户图层添加clipTo,而只想添加一个整洁的全局clipTo
您可以使用JS fiddle来解决这个问题here

你曾经让它工作过吗? - Rivka
@Rivka,不是我喜欢的方式。我通过为每个用户层添加一个(非常复杂的)clipTo,而不是一个简单的全局clipTo来使其工作。 - chadoh
4个回答

1
我来这里也是出于同样的需求,最终找到了解决方案。或许可以帮到你:
对于SVG路径,在clipTo函数中,您可以在调用render(ctx)之前直接修改ctx,这些更改将应用于剪切路径之外。像这样:
var clipPath = new fabric.Path("M 10 10 L 100 10 L 100 100 L 10 100", {
  fill: 'rgba(0,0,0,0)',
});

var backgroundColor = "rgba(0,0,0, 0.2)";

var opts = {
  controlsAboveOverlay: true,
  backgroundColor: 'rgb(255,255,255)',
  clipTo: function (ctx) {
    if (typeof backgroundColor !== 'undefined') {
      ctx.fillStyle = backgroundColor;
      ctx.fillRect(0, 0, 300, 150);
    }
    clipPath.render(ctx);
  }
}
var canvas = new fabric.Canvas('c', opts);

canvas.add(new fabric.Rect({
  width: 50,
  height: 50,
  left: 30,
  top: 30,
  fill: 'rgb(255,0,0)'
}));

当然,您可以添加图像而不是颜色,或者任何其他您想要的东西。 我发现的诀窍是将其直接放在ctx上的clipTo函数中。

这里有一个示例


据我所知,这是为了添加一个简单的矩形剪辑区域。我已经能够添加一个全局剪辑区域。它运行良好。问题在于它会剪裁背景形状。我想要一个不会剪裁背景形状的全局剪辑区域。 - chadoh
我很确定我们在谈论同一件事情。在从剪辑路径(顺便说一句-在这个例子中它是一个简单的矩形,但它可以是任何你想要的 SVG 形状)渲染之前,在 clipTo 函数内修改 ctx,你可以在全局剪辑区域之外绘制到画布上。因此,在 fiddle 示例中,你可以绘制一张图像而不是灰色背景,或者在你的情况下绘制 T 恤和 T 恤蓝色叠加层,它们不会受全局剪辑的影响。看这里 - Kyle Shike

0
一个(有点hacky的)解决方案:在你的canvas元素上设置CSS背景图像,如https://jsfiddle.net/qpnvo3cL/所示。
<canvas id="c" width="500" height="500"></canvas>
<style>
  background: url('http://fabricjs.com/assets/jail_cell_bars.png') no-repeat;
</style>
<script>
  var canvas = window._canvas = new fabric.Canvas('c');
  canvas.clipTo = function(ctx) {
      ctx.rect(100,100,100,100);
  }
</script>

这里至少有两个问题:1)如果将SVG用作背景图像并更改其颜色,则需要以某种方式在CSS中使用此动态生成的SVG作为背景图像——也许您可以将其导出为内联数据图像来解决这个问题。2)从Fabric导出最终图像时,您的CSS样式当然不会被包含在内,因此在生成的图像中您的衬衫颜色将是错误的。 - chadoh

0

你尝试过剪裁织物吗?你可以把整件衬衫当作一个画布。中央图形将成为一个组,你可以将其剪裁到想要的位置。白色T恤和蓝色覆盖层当然不会成为被剪裁组的一部分。

这里有一个剪裁组的例子:

var rect = new fabric.Rect({width:100, height: 100, fill: 'red' });
var circle = new fabric.Circle({ radius: 100, fill: 'green' });
var group1 = new fabric.Group([ circle, rect ], { left: 100, top: 100 });
canvas.add(group1);

group1.clipTo = function(ctx) {
    ctx.rect(50,50,200,200);
};

看看我做的这个 jsfiddle:https://jsfiddle.net/uvepfag5/4/


-1

我发现剪辑速度相对较慢,所以我倾向于使用globalCompositeOperation来进行遮罩。

如果你真的需要使用剪辑,请与save和restore一起使用。

// ctx is canvas context 2d
// pug is the image to be clipped

// draw your background
ctx.save(); // save state
ctx.rect(100,100,100,100); // set the clip area
ctx.clip(); // apply the clip 
ctx.drawImage(pug,x,y); // draw the clipped image
ctx.restore(); // remove the clipping
// draw the other layers.

或者你可以

// draw background
ctx.globalCompositeOperation = "xor";  // set up the mask
ctx.fillRect(100,100,100,100); // draw the mask, could be an image. 
                               // Alpha will effect the amount of masking,
                               // not available with clip 
ctx.globalCompositeOperation = "destination-over";
ctx.drawImage(pug,x,y); // draw the image that is masked                        
ctx.globalCompositeOperation = "source-over";
// draw the stuff that needs to be over everything.

复合操作的优点在于您可以在每个像素级别上控制剪辑,包括通过像素 alpha 值的剪辑量。

谢谢!看起来您的回答好像是我在手动绘制画布上进行绘图。但是我不是这样做的。我正在使用FabricJS进行大部分绘制。现在,我对所有这些画布方面都很陌生,也许我误解了!您看过我的JSfiddle了吗?您能否通过该部分的分支演示此方法?我不明白如何将您告诉我的内容应用于我描述的情况... - chadoh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接