Fabric JS clipPath:裁剪后如何使图像适合画布?

Posted

技术标签:

【中文标题】Fabric JS clipPath:裁剪后如何使图像适合画布?【英文标题】:Fabric JS clipPath: how to fit the image to the canvas after cropping? 【发布时间】:2020-07-04 02:23:35 【问题描述】:

我使用 FabricJS 和 clipPath 属性实现了图像裁剪。

问题是如何使图像在裁剪后适合画布?我希望裁剪后的图像填充画布区域,但不知道是否可以使用fabric js。

所以我希望用户单击裁剪按钮后图像的选定部分适合画布大小:

关于代码:我在画布上画了一个矩形,用户可以调整大小和移动它。之后,用户可以单击裁剪按钮并获得裁剪后的图像。但是裁剪后的部分保持与原始图像相同的大小,而我希望它可以缩放并适合画布。

注意:我尝试使用 scaleToWidth 等方法。此外,我将选择矩形的 absolutePositioned 设置为 true。我尝试将此属性设置为 false 来缩放到图像,但没有帮助。

请不要建议使用cropX 和cropY 属性代替clipPath 进行裁剪,因为它们不适用于旋转图像。

html

<button>Crop</button>
<canvas id="canvas"  ></canvas>

JS:

// crop button
var button = $("button");

// handle click
button.on("click", function()

  let rect = new fabric.Rect(
    left: selectionRect.left,
    top: selectionRect.top,
    width: selectionRect.getScaledWidth(),
    height: selectionRect.getScaledHeight(),
    absolutePositioned: true
  );

  currentImage.clipPath = rect;

  canvas.remove(selectionRect);

  canvas.renderAll();
);

var canvas = new fabric.Canvas('canvas');

canvas.preserveObjectStacking = true;

var selectionRect;
var currentImage;

fabric.Image.fromURL('https://www.sheffield.ac.uk/polopoly_fs/1.512509!/image/DiamondBasement.jpg', img => 
  img.scaleToHeight(500);

  img.selectable = true;

  canvas.add(img);

  canvas.centerObject(img);

  currentImage = img;

  canvas.backgroundColor = "#333";

  addSelectionRect();

  canvas.setActiveObject(selectionRect);

  canvas.renderAll();
);

function addSelectionRect() 
  selectionRect = new fabric.Rect(
    fill: 'rgba(0,0,0,0.3)',
    originX: 'left',
    originY: 'top',
    stroke: 'black',
    opacity: 1,
    width: currentImage.width,
    height: currentImage.height,
    hasRotatingPoint: false,
    transparentCorners: false,
    cornerColor: 'white',
    cornerStrokeColor: 'black',
    borderColor: 'black',
  );

  selectionRect.scaleToWidth(300);
  canvas.centerObject(selectionRect);
  selectionRect.visible = true;
  canvas.add(selectionRect);

这是我的 jsfiddle:https://jsfiddle.net/04nvdeb1/23/

【问题讨论】:

剪裁区域必须是绝对的吗?或者那是你尝试过的东西?与剪切区域相比,您希望图像可移动吗? @AndreaBogazzi,感谢您对此进行调查!剪裁区域不一定是绝对的,我想我把它设为绝对是为了简化计算。理想情况下,当图像移动时,剪切区域应该“固定”到图像上。另外,我需要有一个旋转图像的功能,所以剪辑也应该适用于旋转的图像。 剪辑也适用于旋转的图像,只是你反向旋转剪辑区域。 【参考方案1】:

其实你不必使用 clipPath 方法。你想要的实际上是将你需要的区域移动到角落,并改变画布的大小。

所以sodo代码如下:

fabricCanvas.setDimensions(
    width: cropRectObject.getScaledWidth(),
    height: cropRectObject.getScaledHeight()
)
imageObject.set(
    left: -cropRectObject.left,
    top: -cropRectObject.top
)
fabricCanvas.remove(cropRectObject);

稍微调整了你的小提琴来展示这个想法: https://jsfiddle.net/tgy320w4/4/

希望这会有所帮助。

【讨论】:

【参考方案2】:

这几天我也遇到了同样的问题。但是即使我也找到了您的 SO 问题和 github 问题,我也找不到任何解决方案。我认为 clipPath 是使用漂亮的可调节麝香来剪辑图像的最佳选择。

Demo Link

Github Repo Link

在按钮回调函数中,必须这样实现

第 1 步:首先您必须创建一个 Image 实例来保存裁剪后的图像

let cropped = new Image();

第 2 步:您必须使用 Canvas.toDataURL() 将 canvas 元素导出到 dataurl 图像。这里wan想只导出选择矩形或者遮罩矩形,所以我们传入mast rect left,top,width,height

cropped.src = canvas.toDataURL(
                    left: rect.left,
                    top: rect.top,
                    width: rect.width,
                    height: rect.height,
                );

第 3 步:图像加载后的最后一步,我们清除画布。使用我们裁剪的图像创建新对象,并设置一些选项并重新渲染画布

cropped.onload = function () 
                    canvas.clear();
                    image = new fabric.Image(cropped);
                    image.left = rect.left;
                    image.top = rect.top;
                    image.setCoords();
                    canvas.add(image);
                    canvas.renderAll();
                ;

我实际上已将Crop Functionality using FabricJs #soution2 与您的问题联系起来。

【讨论】:

以上是关于Fabric JS clipPath:裁剪后如何使图像适合画布?的主要内容,如果未能解决你的问题,请参考以下文章

Fabric JS 2.4.1 ClipPath Crop 不适用于动态创建的矩形蒙版

Fabric.js:裁剪图像后的选择框

SVG.js Mask覆盖和ClipPath裁剪

裁剪 Sprite 与单个图像的 Fabric.js 效率

Fabric.js 动态裁剪区域对图像和 SVG/形状的影响不同

如何使用fabric js仅通过覆盖矩形打孔?