为图像创建复杂的剪切路径?

Creating complex clipping path for image?

我是 fabricjs 的新手(一般来说 Javascript 开发)。我是 "porting" 遗留 Flex/Actionscript 项目,需要允许用户为图像创建复杂的剪切路径。

我在 Actionscript 中的方法是使用 Actionscript Graphics class 使用 BlendMode.ERASE 到 "erase" 从黄色基本矩形(即给出外观擦除),然后使用该组 rects 创建一个位图,作为动态创建的最终图像(第 3 步)的 alpha 通道。

谁能建议我如何在 Fabric 中实现类似的功能?它似乎不支持 HTML5 Canvas Blend modes,虽然我看到它支持图像的剪切路径,但我没有看到如何让用户在不进行大量交叉检查的情况下以交互方式创建剪切路径来尝试导出点以动态创建新路径。

谢谢!


第 1 步: 用户绘制了一个基础矩形后,drag-option/alt-key 使他们能够绘制一个矩形(红线),该矩形将从基础中减去矩形。

第 2 步: 基本矩形显示减法。

第 3 步: 基本矩形用于裁剪或屏蔽基本图像的一部分


第 1 步


第 2 步


第 3 步

威尔塔,

没有简单的方法可以做到。以下是步骤:

  1. 绘制'Yellow'矩形
  2. 绘制'Red'矩形
  3. 使用像 PolyBool 这样的剪辑库进行交集和异或运算
  4. 将绘图结果转换为组合矩形的裁剪路径
  5. 剪辑你的图片

我创建了一些快速 fiddle。您必须单击每个按钮才能剪辑。如果您不在 canvas 上添加 2 个矩形,它就不会剪裁。这是一个非常简单的例子。为了正常工作,您必须用鼠标绘制矩形(使它们动态)。此外,此逻辑并未考虑这些变化(您也必须对它们进行处理): 对于这些用例,Clipping Library 将 return 给你 2 组结果,这意味着应该实现不同的逻辑。

没有 jQuery、FabriJs 和 PolyBool 库的实际代码:

var imgURL = 'http://fabricjs.com/lib/pug.jpg';
var clipYellowRect = null;
var clipRedRect = null;
var pug = null;
var canvas = new fabric.Canvas('c');

// insert image into canvas
var pugImg = new Image();
pugImg.onload = function (img) {    
    pug = new fabric.Image(pugImg, {
        angle: 0,
        width: 500,
        height: 500,
        left: 100,
        top: 50,
        scaleX: 0.5,
        scaleY: 0.5,
        clipName: 'pug',
    });
    canvas.add(pug);
};
pugImg.src = imgURL;

//draw yellow rectangle
$('#btnYellowRect').on('click', function(){
    clipYellowRect = new fabric.Rect({
      originX: 'left',
      originY: 'top',
      left: 120,
      top: 60,
      width: 200,
      height: 200,
      fill: 'rgba(255,255,0,0.5)',
      strokeWidth: 0,
      selectable: false
  });
canvas.add(clipYellowRect);
});

//draw red rectangle
$('#btnRedRect').on('click', function(){
    clipRedRect = new fabric.Rect({
      originX: 'left',
      originY: 'top',
      left: 90,
      top: 120,
      width: 100,
      height: 100,
      strokeWidth: 3,
      fill: 'transparent',
      stroke: 'rgba(255,0,0,1)', /* use transparent for no fill */
      strokeWidth: 0,
      selectable: false
  });

canvas.add(clipRedRect);
});

//clip
$('#btnClip').on('click', function(){
    var yellowRectRegion = getRegion(clipYellowRect);
  var redRectRegion = getRegion(clipRedRect);
  //determine inersection
  var intersectResult = PolyBool.intersect({
    regions: [yellowRectRegion],
    inverted: false
  }, {
    regions: [redRectRegion],
    inverted: false
  });

  //generate clipping path
  var xorResult = PolyBool.xor({
    regions: [yellowRectRegion],
    inverted: false
  }, {
    regions: intersectResult.regions,
    inverted: false
  });
  clipImage(xorResult.regions[0]);
});

//prepare data for clipping library
function getRegion(rect){
return [[rect.left, rect.top],
                [rect.left + rect.width, rect.top],
        [rect.left + rect.width, rect.top + rect.height],
        [rect.left, rect.top + rect.height]]
}


function clipImage(points){
     //actual clipping 
  pug.clipTo = function (ctx) {
      var scaleXTo1 = (1 / pug.scaleX);
      var scaleYTo1 = (1 / pug.scaleY);
      ctx.save();

      var ctxLeft = -( pug.width / 2 );
      var ctxTop = -( pug.height / 2 );

      ctx.translate( ctxLeft, ctxTop );
      ctx.scale(scaleXTo1, scaleYTo1);
      ctx.beginPath();
      console.log(points)
      ctx.moveTo(points[0][0] - pug.oCoords.tl.x, points[0][1] - pug.oCoords.tl.y);
      for (var i=1; i < points.length; i++){
      ctx.lineTo(points[i][0] - pug.oCoords.tl.x, points[i][1] - pug.oCoords.tl.y);
      }
      ctx.closePath();
      ctx.restore();
      };
      clipYellowRect.remove();
        clipRedRect.remove();
      canvas.renderAll();
}

希望对您有所帮助。