Fabric JS Add ClipPath to scaled Image with custom shape (Rect or Polygon) not working

22 Views Asked by At

I'm building an image annotation application using Fabric JS and Angular. I would like to be able to apply a mask to the target image from an object that I drew on it (a Rect or a Polygon). I can't get it to work. I appreciate any collaboration.

More specifically, I would like to crop the image as the object I draw on top of it, and then create a new image with that mask. I would not like to change the original image. And if there was more than one object drawn on the image, I would like to obtain a new image for each object, cut into its respective format.

I know my code is not doing this, but I was facing problems at the initial stage, which is simply cropping the image by the mask.

// create canvas
this._canvas = new fabric.Canvas('canvas', {
  selectionBorderColor: 'blue'
});
this._canvas.setWidth(this._width, {cssOnly:false});
this._canvas.setHeight(this._height, {cssOnly:false});
this._canvas.calcOffset();
// load image
fabric.Image.fromURL(path, (image) => {
  image.set({
    left: 0,
    top: 0,
    dirty: true
  });
  image.scale(0.1).setCoords();
  this._canvas.add(image);
});
//create polygon
var poly = new fabric.Polygon(this._current_polygon_points, {
  fill: 'rgba(0,0,0,0)',
  stroke: this.color,
  strokeWidth: 2,
  selectable: true,
  left: left,
  top: top,
  objectCaching: false,
  absolutePositioned: true,
  strokeUniform: true,
  strokeLineCap: "round",
  strokeLineJoin: "round",
  dirty: true
});
this._canvas.add(poly);
this._canvas.renderAll();
// try to create mask --NOT WORKING
// items is a list of active objects, for the case I want to apply a mask with multiple shapes
// image is the target image
var clippath = new fabric.Group(items);
clippath.setCoords();
clippath.scaleX = 1;
clippath.scaleY = 1;
clippath.scaleX /= image.scaleX;
clippath.scaleY /= image.scaleY;
clippath.originX = image.originX;
clippath.originY = image.originY;
image.clipPath = clippath;
image.setCoords();
image.dirty = true;
this._canvas.add(image);
this._canvas.renderAll();


/*
EXAMPLE OF ITEMS

var items = [{
    "type": "polygon",
    "version": "5.3.0",
    "originX": "left",
    "originY": "top",
    "left": -65.98,
    "top": 10.49,
    "width": 207.94,
    "height": 113.94,
    "fill": "rgba(220,211,82,0.8)",
    "stroke": "rgba(220,211,82,1)",
    "strokeWidth": 2,
    "strokeDashArray": null,
    "strokeLineCap": "round",
    "strokeDashOffset": 0,
    "strokeLineJoin": "round",
    "strokeUniform": true,
    "strokeMiterLimit": 4,
    "scaleX": 1,
    "scaleY": 1,
    "angle": 0,
    "flipX": false,
    "flipY": false,
    "opacity": 1,
    "shadow": null,
    "visible": true,
    "backgroundColor": "",
    "fillRule": "nonzero",
    "paintFirst": "fill",
    "globalCompositeOperation": "source-over",
    "skewX": 0,
    "skewY": 0,
    "points": [
        {
            "x": 252.45334489205715,
            "y": 194.89111062942803
        },
        {
            "x": 171.47721757110224,
            "y": 245.86263187097072
        },
        {
            "x": 269.448334576702,
            "y": 298.8330362984563
        },
        {
            "x": 379.4159148891099,
            "y": 215.87938408182796
        },
        {
            "x": 300.4391981192897,
            "y": 184.89669469971378
        },
        {
            "x": 300.4391981192897,
            "y": 184.89669469971378
        },
        {
            "x": 252.45334489205715,
            "y": 194.89111062942803
        }
    ]
    },
    {
    "type": "rect",
    "version": "5.3.0",
    "originX": "left",
    "originY": "top",
    "left": -143.96,
    "top": -126.43,
    "width": 219.94,
    "height": 79.96,
    "fill": "rgba(220,211,82,0.4)",
    "stroke": "rgba(220,211,82,1)",
    "strokeWidth": 3,
    "strokeDashArray": null,
    "strokeLineCap": "round",
    "strokeDashOffset": 0,
    "strokeLineJoin": "miter",
    "strokeUniform": true,
    "strokeMiterLimit": 4,
    "scaleX": 1,
    "scaleY": 1,
    "angle": 0,
    "flipX": false,
    "flipY": false,
    "opacity": 1,
    "shadow": null,
    "visible": true,
    "backgroundColor": "",
    "fillRule": "nonzero",
    "paintFirst": "fill",
    "globalCompositeOperation": "source-over",
    "skewX": 0,
    "skewY": 0,
    "rx": 0,
    "ry": 0
    }]
*/

Screenshot Screenshot2 Problems I am facing:

  1. A kind of mask is created, but it always appears in the wrong place in the image (it appears displaced to the right and down)
  2. The image is even cropped, but when I move the resulting image (with the mask applied), it leaves traces like in the image shown.

I tried changing the dirty and scale attributes, and I also tried adding setCoords(), but the truth is that I didn't quite understand how I should do it.

My goal in the end is to be able to extract each intersection between an object and the image as a new image, and not a single image with several masks applied to it.

0

There are 0 best solutions below