【问题标题】:Creating complex clipping path for image?为图像创建复杂的剪切路径?
【发布时间】:2017-06-04 18:16:09
【问题描述】:

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

我在 Actionscript 中的方法是使用 Actionscript Graphics 类,使用 BlendMode.ERASE 从黄色基础矩形“擦除”(即呈现擦除的外观),然后使用该组矩形创建位图用作动态创建的最终图像(第 3 步)的 Alpha 通道。

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

谢谢!


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

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

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


第一步


第 2 步


第 3 步

【问题讨论】:

    标签: javascript fabricjs


    【解决方案1】:

    威尔塔,

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

    1. 绘制“黄色”矩形
    2. 绘制“红色”矩形
    3. 使用 PolyBool 之类的裁剪库进行交集和异或运算
    4. 将绘制结果转换为组合矩形的剪切路径
    5. 剪辑您的图像

    我创建了一些快速的fiddle。您必须单击每个按钮才能进行剪辑。如果您不在画布上添加 2 个矩形,它将不会剪辑。这是一个非常简单的例子。为了正常工作,您必须用鼠标绘制矩形(使它们动态)。此外,这个逻辑没有考虑到这些变化(你也必须处理它们): 对于这些用例 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();
    }
    

    希望对你有所帮助。

    【讨论】:

    • 太棒了——感谢您的帮助!看起来我将不得不重新考虑一些事情,因为看起来剪切路径在转换剪切的图像时不会缩放或移动。我还是 JS(和 Fabric)的新手,所以我对将其他库与它结合起来有点胆怯。我想我会研究一个 Node 图像库(如 pngjs-image)以动态创建一个带有 alpha 的图像——这是用于 Electron 中的桌面应用程序,因此速度和安全性都可以。
    猜你喜欢
    • 2011-10-15
    • 2016-08-01
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2015-08-11
    相关资源
    最近更新 更多