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

时间:2017-01-19 21:34:17

标签: javascript fabricjs

我是fabricjs的新手(以及一般的Javascript开发)。我正在“移植”传统的Flex / Actionscript项目,需要使用户能够为图像创建复杂的剪切路径。

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

有人可以建议我如何在Fabric中实现类似的功能吗?它似乎不支持HTML5 Canvas Blend modes,虽然我看到它支持图像的剪切路径,但我没有看到如何使用户能够交互式地创建剪切路径而无需进行大量的交叉检查以尝试派生点来动态创建新路径。

谢谢!

步骤1:在用户绘制基本矩形后,使用drag-option / alt-key可以绘制一个矩形(红线),该矩形将从基本矩形中减去。

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

第3步:基本矩形用于剪切或遮罩基本图像的一部分

第1步

enter image description here

第2步

enter image description here

第3步

enter image description here

1 个答案:

答案 0 :(得分:2)

Will Tower,

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

  1. 画'黄色'矩形
  2. 画'红色'矩形
  3. 使用像PolyBool这样的剪切库进行交叉和xor操作
  4. 将绘图结果转换为组合矩形的剪裁路径
  5. 剪辑图片
  6. 我创建了一些快速fiddle。您必须单击每个按钮才能剪辑。如果你不在画布上添加2个矩形,它将不会剪辑。这是一个非常简单的例子。为了正常工作,你必须用鼠标绘制矩形(使它们动态)。此外,这个逻辑不考虑这些变化(你也必须对它们进行处理): enter image description here 对于这些用例,Clipping Library将返回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();
    }
    

    希望它会对你有帮助。