我目前正致力于使用FabricJS进行照片编辑的网络应用程序,我需要实现的功能之一就是从Photoshop剪切蒙版。
例如我有this assets:框架,蒙版和图像。我需要在框架内插入图像并用面具剪辑它。最棘手的部分是要求:
我目前的解决方案是:
globalCompositeOperation
设置为source-out
clipTo
功能。 在此解决方案clipTo
函数中保留图像的矩形区域内的图像,并借助globalCompositeOperation
我将剪切图像剪切为实际蒙版。乍一看它工作正常,但如果我在这个新添加的组上面添加新图层,它将因globalCompositeOperation="source-out"
规则而被切断。我已创建JSFiddle来显示此内容。
那么,我可以试试吗?我在StackOverflow上看到了一些帖子,建议使用SVG进行剪贴蒙版,但如果我理解正确,SVG必须只包含一个路径。这可能是一个问题,因为我的应用程序的第三个要求。
任何正确方向的建议都会有所帮助,因为现在我完全坚持这个问题。
答案 0 :(得分:2)
您可以通过使用要屏蔽的Img Object的ClipPath属性来执行此操作。这样,您可以屏蔽任何类型的对象。并且还需要在Img Object的ClipTo函数中添加一些Ctx配置。 检查此链接https://jsfiddle.net/naimsajjad/8w7hye2v/8/
(function() {
var img01URL = 'http://fabricjs.com/assets/printio.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var canvas = new fabric.Canvas('c');
canvas.backgroundColor = "red";
canvas.setHeight(500);
canvas.setWidth(500);
canvas.setZoom(1)
var circle = new fabric.Circle({radius: 40, top: 50, left: 50, fixed: true, fill: '', stroke: '1' });
canvas.add(circle);
canvas.renderAll();
fabric.Image.fromURL(img01URL, function(oImg) {
oImg.scale(.25);
oImg.left = 10;
oImg.top = 10;
oImg.clipPath = circle;
oImg.clipTo = function(ctx) {
clipObject(this,ctx)
}
canvas.add(oImg);
canvas.renderAll();
});
var bili = new fabric.Path('M85.6,606.2c-13.2,54.5-3.9,95.7,23.3,130.7c27.2,35-3.1,55.2-25.7,66.1C60.7,814,52.2,821,50.6,836.5c-1.6,15.6,19.5,76.3,29.6,86.4c10.1,10.1,32.7,31.9,47.5,54.5c14.8,22.6,34.2,7.8,34.2,7.8c14,10.9,28,0,28,0c24.9,11.7,39.7-4.7,39.7-4.7c12.4-14.8-14-30.3-14-30.3c-16.3-28.8-28.8-5.4-33.5-11.7s-8.6-7-33.5-35.8c-24.9-28.8,39.7-19.5,62.2-24.9c22.6-5.4,65.4-34.2,65.4-34.2c0,34.2,11.7,28.8,28.8,46.7c17.1,17.9,24.9,29.6,47.5,38.9c22.6,9.3,33.5,7.8,53.7,21c20.2,13.2,62.2,10.9,62.2,10.9c18.7,6.2,36.6,0,36.6,0c45.1,0,26.5-15.6,10.1-36.6c-16.3-21-49-3.1-63.8-13.2c-14.8-10.1-51.4-25.7-70-36.6c-18.7-10.9,0-30.3,0-48.2c0-17.9,14-31.9,14-31.9h72.4c0,0,56-3.9,70.8,26.5c14.8,30.3,37.3,36.6,38.1,52.9c0.8,16.3-13.2,17.9-13.2,17.9c-31.1-8.6-31.9,41.2-31.9,41.2c38.1,50.6,112-21,112-21c85.6-7.8,79.4-133.8,79.4-133.8c17.1-12.4,44.4-45.1,62.2-74.7c17.9-29.6,68.5-52.1,113.6-30.3c45.1,21.8,52.9-14.8,52.9-14.8c15.6,2.3,20.2-17.9,20.2-17.9c20.2-22.6-15.6-28-16.3-84c-0.8-56-47.5-66.1-45.1-82.5c2.3-16.3,49.8-68.5,38.1-63.8c-10.2,4.1-53,25.3-63.7,30.7c-0.4-1.4-1.1-3.4-2.5-6.6c-6.2-14-74.7,30.3-74.7,30.3s-108.5,64.2-129.6,68.9c-21,4.7-18.7-9.3-44.3-7c-25.7,2.3-38.5,4.7-154.1-44.4c-115.6-49-326,29.8-326,29.8s-168.1-267.9-28-383.4C265.8,13,78.4-83.3,32.9,168.8C-12.6,420.9,98.9,551.7,85.6,606.2z',{top: 0, left: 180, fixed: true, fill: 'white', stroke: '', scaleX: 0.2, scaleY: 0.2 });
canvas.add(bili);
canvas.renderAll();
fabric.Image.fromURL(img02URL, function(oImg) {
oImg.scale(0.5);
oImg.left = 180;
oImg.top = 0;
oImg.clipPath = bili;
oImg.clipTo = function(ctx) {
clipObject(this,ctx)
}
canvas.add(oImg);
canvas.renderAll();
});
function clipObject(thisObj,ctx)
{
if (thisObj.clipPath) {
ctx.save();
if (thisObj.clipPath.fixed) {
var retina = thisObj.canvas.getRetinaScaling();
ctx.setTransform(retina, 0, 0, retina, 0, 0);
// to handle zoom
ctx.transform.apply(ctx, thisObj.canvas.viewportTransform);
thisObj.clipPath.transform(ctx);
}
thisObj.clipPath._render(ctx);
ctx.restore();
ctx.clip();
var x = -thisObj.width / 2, y = -thisObj.height / 2, elementToDraw;
if (thisObj.isMoving === false && thisObj.resizeFilter && thisObj._needsResize()) {
thisObj._lastScaleX = thisObj.scaleX;
thisObj._lastScaleY = thisObj.scaleY;
thisObj.applyResizeFilters();
}
elementToDraw = thisObj._element;
elementToDraw && ctx.drawImage(elementToDraw,
0, 0, thisObj.width, thisObj.height,
x, y, thisObj.width, thisObj.height);
thisObj._stroke(ctx);
thisObj._renderStroke(ctx);
}
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>
答案 1 :(得分:0)
不确定你想要什么。
如果您希望加载最后一个图像(名为img2
),则发送到后面的图像不会影响上面的图层,请执行以下操作。
您有mask
,frame
,img
和img2
;
按以下顺序放置它们并使用以下补偿设置。
如果你想要别的东西,你将不得不更详细地解释它。
就个人而言,当我向客户提供屏蔽时,我给予他们对所有复合方法的完全访问权限,并允许他们计算出他们需要做什么才能达到预期的效果。提供允许您更改comp设置的UI和图层顺序使得更容易理清有时令人困惑的画布复合规则。
答案 2 :(得分:0)
我建议看看这个解决方案。
Multiple clipping areas on Fabric.js canvas
您最终会得到一个用于定义蒙版形状的形状图层。然后,该形状将作为剪辑应用于您的图像。
我可以想到的一个限制是你可能遇到的是当你开始旋转各种形状时。我知道我有一个矩形和圆形工作很好,但是我记得多边形的问题...这是所有设置在FabricJS的旧版本和旧版本,所以可能有一些改进我我没经验过。
我遇到的另一个问题是当传递给运行FabricJS的NodeJS服务器时,投影无法正确呈现。