使用 FabricJs 的裁剪功能

Posted

技术标签:

【中文标题】使用 FabricJs 的裁剪功能【英文标题】:Crop Functionality using FabricJs 【发布时间】:2013-09-14 23:41:15 【问题描述】:

如何在使用 fabric.js 加载到画布上的图像上实现裁剪工具? 我在画布上加载了一个图像。现在我想实现裁剪工具,允许用户裁剪图像并在完成后将其重新加载到画布上。

【问题讨论】:

您想以相同的角度裁剪图像,还是同时支持旋转? @kangax:就像绘画应用中的裁剪工具一样。我的意思是以相同的角度裁剪图像。简单裁剪图像的选定区域 @kangax: 我们可以使用 toDataURL 裁剪功能来裁剪画布上加载的图像并重新加载吗? 是的,你可以使用img.toDataURL(...) @John 你成功获得像疼痛这样的裁剪功能了吗? 【参考方案1】:

(这个答案是Tom's 答案中小提琴的迭代。谢谢你,汤姆,让我继续前进。)

您可以使用 fabric.Object.clipTo() 或 fabric.Object.toDataURL() 在 Fabric.js 中进行裁剪。 clipTo() 方法保留原始图像并通过蒙版显示裁剪。 toDataURL() 方法创建一个新图像。

我的完整示例使用clipTo() 方法。我在末尾添加了一小段代码,显示了toDataURL() 方法。

解决方案 1

总结

    准备一个不可见的矩形。当用户在画布上单击并拖动鼠标时让它绘制。 当用户释放鼠标点击时,裁剪底层图像

与汤姆的回答不同

在汤姆的回答中,我想改变几件小事。所以在我的例子中,差异是

    裁剪框从左到右和从右到左工作(汤姆的作品只从右到左)

    您有不止一次机会绘制裁剪框(尝试在 Tom's 导致框跳转中重新绘制裁剪框)

    适用于 Fabric.js v1.5.0

    代码更少。

守则

 // set to the event when the user pressed the mouse button down
var mouseDown;
// only allow one crop. turn it off after that
var disabled = false;
var rectangle = new fabric.Rect(
    fill: 'transparent',
    stroke: '#ccc',
    strokeDashArray: [2, 2],
    visible: false
);
var container = document.getElementById('canvas').getBoundingClientRect();
var canvas = new fabric.Canvas('canvas');
canvas.add(rectangle);
var image;
fabric.util.loadImage("http://fabricjs.com/lib/pug.jpg", function(img) 
    image = new fabric.Image(img);
    image.selectable = false;
    canvas.setWidth(image.getWidth());
    canvas.setHeight(image.getHeight());
    canvas.add(image);
    canvas.centerObject(image);
    canvas.renderAll();
);
// capture the event when the user clicks the mouse button down
canvas.on("mouse:down", function(event) 
    if(!disabled) 
        rectangle.width = 2;
        rectangle.height = 2;
        rectangle.left = event.e.pageX - container.left;
        rectangle.top = event.e.pageY - container.top;
        rectangle.visible = true;
        mouseDown = event.e;
        canvas.bringToFront(rectangle);
    
);
// draw the rectangle as the mouse is moved after a down click
canvas.on("mouse:move", function(event) 
    if(mouseDown && !disabled) 
        rectangle.width = event.e.pageX - mouseDown.pageX;
        rectangle.height = event.e.pageY - mouseDown.pageY;
        canvas.renderAll();
    
);
// when mouse click is released, end cropping mode
canvas.on("mouse:up", function() 
    mouseDown = null;
);
$('#cropB').on('click', function() 
    image.clipTo = function(ctx) 
        // origin is the center of the image
        var x = rectangle.left - image.getWidth() / 2;
        var y = rectangle.top - image.getHeight() / 2;
        ctx.rect(x, y, rectangle.width, rectangle.height);
    ;
    image.selectable = true;
    disabled = true;
    rectangle.visible = false;
    canvas.renderAll();
);
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js" type="text/javascript"></script>
</head>
<body>
<canvas style="border: 1px solid black" id="canvas"></canvas>
<button id=cropB>crop</button>
</body>

解决方案 2

或者,我们可以使用toDataURL() 生成新图像,而不是像上面那样使用clipTo()。像这样的

$('#cropB').on('click', function() 
    image.selectable = true;
    disabled = true;
    rectangle.visible = false;
    var cropped = new Image();
    cropped.src = canvas.toDataURL(
        left: rectangle.left,
        top: rectangle.top,
        width: rectangle.width,
        height: rectangle.height
    );
    cropped.onload = function() 
        canvas.clear();
        image = new fabric.Image(cropped);
        image.left = rectangle.left;
        image.top = rectangle.top;
        image.setCoords();
        canvas.add(image);
        canvas.renderAll();
    ;
);

【讨论】:

为什么当我评论 onload 时仍然有效?,当 toDataURL 之后的 put 警报时,这个警报永远不会触发? canvas.toDataURL 在对画布应用缩放时返回不同的图像。有没有办法通过放大和缩小视图来裁剪图像 在您的解决方案 2 中,由于 toDataUrl(),图像质量非常差。是否有任何替代解决方案可以保持质量(与原始图像相同)并且与解决方案 2 一样工作。 如果它是大图像,那么它不起作用我添加了 scaleToWidth 和 scaleToHeight 以适应织物画布上的大图像,但它不起作用【参考方案2】:

总结

    设置el.selectable = false 使用鼠标事件在其上绘制一个矩形 获取矩形左/上和宽度/高度 然后使用下面的函数

对不起,让我解释一下。 ctx.rect 将从对象的中心点裁剪图像。还应考虑scaleX 因素。

x = select_el.left - object.left;
y = select_el.top - object.top;

x *= 1 / scale;
y *= 1 / scale;

width = select_el.width * 1 / scale;
heigh = select_el.height * 1 / scale;

object.clipTo = function (ctx) 
    ctx.rect (x, y, width, height);

完整示例:http://jsfiddle.net/hellomaya/kNEaX/1/

查看http://jsfiddle.net/hellomaya/hzqrM/ 以生成选择框。 以及 Fabric 事件的参考:https://github.com/kangax/fabric.js/wiki/Working-with-events

【讨论】:

如何在图像对象上绘制选择框?我所要做的就是将图像设置为背景然后裁剪???否则如何在图像对象上绘制矩形?其他对象上的事件? 更新了小提琴你能检查一下我哪里出错了吗?jsfiddle.net/hzqrM/5 也只有剪辑工作图像不显示 ::我们可以使用 toDataURL 裁剪功能来裁剪画布上加载的图像并重新加载吗? 请注意,如果先旋转原件,此答案将不起作用。 如果图像根据画布很大,则它不起作用我已将 scaleToWidth 和 scaleToHeight 添加到画布图像。我正在尝试添加您的代码,但它没有正确剪辑我的代码 fabric.util.loadImage(src, function (img) object = new fabric.Image(img); object.set( left: 100, top: 100, selectable: false ); object.hasRotatingPoint = true; object.scaleX = object.scaleY = 0.25; object.scaleToWidth("400"); object.scaleToHeight("400"); canvas.add(object); canvas.renderAll(); );【参考方案3】:

我使用最新的 fabric js 版本开发了简单快速的图像裁剪 https://github.com/kpomservices/Fabric-JS-Image-CROP

演示:http://kpomservices.com/imagecropdemo/index.html

我使用cropx,cropy来保持作物。

【讨论】:

请不要只发布一些工具或库作为答案。至少在答案本身中展示how it solves the problem。 这个效果很好,但是当你保存面料并返回裁剪后的图像时,单击时图像会消失。

以上是关于使用 FabricJs 的裁剪功能的主要内容,如果未能解决你的问题,请参考以下文章

使用 FabricJS 裁剪图像

使用 FabricJs 在同一画布上裁剪多个图像

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

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

Fabricjs:显示横幅的预览

Fabric JS 2.4.1 如何使用 clipPath 裁剪已缩放为小于或大于 1:1 比例的图像