FabricJS 防止 canvas.clipTo 剪切 canvas.backgroundImage

Posted

技术标签:

【中文标题】FabricJS 防止 canvas.clipTo 剪切 canvas.backgroundImage【英文标题】:FabricJS prevent canvas.clipTo from clipping canvas.backgroundImage 【发布时间】:2016-01-04 23:06:52 【问题描述】:

我想在我的 Fabric-powered Canvas 中设置一个全局 clipTo,它将影响所有用户添加的图层。我想要一个不受此剪辑蒙版影响的背景图像和叠加图像。

例子:

这是这张照片中发生的事情:

    帆布叠加图像使 T 恤看起来自然起皱。此叠加图像大部分是透明的 添加了与 T 恤形状完全相同的背景图像,应该使 T 恤看起来是蓝色的 添加了canvas.clipTo 函数,将画布裁剪为矩形 添加了用户添加的图像(著名的 Fabric 哈巴狗)

我希望将用户添加的图像(哈巴狗)限制在矩形区域内。

我确实希望背景图像(蓝色 T 恤形状)受到剪辑区域的影响。

有没有一种简单的方法可以做到这一点?我真的不想在每个用户层上添加一个clipTo,而不是一个整洁的全局clipTo

您可以使用 JS fiddle 来显示问题 here。

【问题讨论】:

你做过这个工作吗? @Rivka 不是我喜欢的方式。我通过向每个用户层添加一个(非常复杂的)clipTo 而不是一个简单的全局 clipTo 来让它工作。 【参考方案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 函数中。

here's a fiddle

【讨论】:

据我所知,这是用于添加一个简单的矩形剪辑区域。我已经能够添加一个全局剪辑区域。它工作得很好。不过,麻烦的是它会裁剪背景形状。我想要一个不剪裁背景形状的全局剪裁区域。 我很确定我们说的是同一件事。通过在从剪辑路径渲染之前修改 clipTo 函数中的 ctx(顺便说一句,它是一个简单的矩形,但它可以是您想要的任何 svg 形状),您可以绘制到全局剪辑区域之外的画布.因此,在小提琴示例中,您可以绘制图像而不是灰色背景,或者在您的情况下绘制 T 恤和 T 恤蓝色叠加层,它们不会受到全局剪辑的影响。 See here【参考方案2】:

一个(有点老套的)解决方案:在你的画布元素上设置一个 CSS 背景图像,如 https://jsfiddle.net/qpnvo3cL/ 所示

<canvas id="c"  ></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 作为背景图像并更改其颜色,您将需要以某种方式使用此动态生成的 svg 作为 CSS 中的背景图像——也许您可以通过将其导出为内联数据图像来克服这一点。 2) 从 Fabric 导出最终图像时,您的 CSS 样式当然不会被包含在内,因此生成的图像中您的衬衫颜色将是错误的。【参考方案3】:

您是否尝试过剪裁布料Group?你可以把整件衬衫做成一块帆布。中心图形将是一个组,您可以将其剪辑到您想要的位置。白色 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/

【讨论】:

【参考方案4】:

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

如果你真的需要使用剪辑,那么将它与保存和恢复结合使用。

// 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 吗?你能用它的一个分支来演示这种方法吗?我不明白如何将您告诉我的内容应用于我所描述的情况......

以上是关于FabricJS 防止 canvas.clipTo 剪切 canvas.backgroundImage的主要内容,如果未能解决你的问题,请参考以下文章

防止 Fabric js 对象超出画布边界

将对象的边缘相互对齐并防止重叠

vuetify中如何防止canvas溢出卡并使其响应?

vuetify中如何防止canvas溢出卡并使其响应?

Fabricjs做组态和流程图-认识Fabricjs

使用 FabricJS 裁剪图像