How to deal with fabric JS image mask?

2020-03-08 07:52发布

I am trying to implement image mask as example below :

Example image here: https://s3-ap-northeast-1.amazonaws.com/utonly/demo/demo.jpg

I have tried so many ways and took a lot of time, but still can't find a good solution for it. The image must be able to resizing and rotating inside the mask, or edit from another view, and then apply the result back to the image.

I found similar example here http://jsfiddle.net/tbqrn/68/ , but I don't want images pass through each other. Is that possible? Or do I have any chance to try other ways to do this?

var img01URL = 'http://fabricjs.com/assets/printio.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';

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

var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.rect(10,10,150,150);
    ctx.rect(170,10,200,200);
    ctx.rect(10,170,150,150);
    ctx.closePath();
    ctx.stroke();
    ctx.clip();

fabric.Image.fromURL(img01URL, function(oImg) {
    oImg.scale(.25);
    oImg.left = 10;
    oImg.top = 10;
    canvas.add(oImg);
    canvas.renderAll();
});

fabric.Image.fromURL(img02URL, function(oImg) {
    oImg.scale(.40);
    oImg.left = 180;
    oImg.top = 0;
    canvas.add(oImg);
    canvas.renderAll();
});

fabric.Image.fromURL(img03URL, function(oImg) {
    oImg.left = 10;
    oImg.top = 170;
    canvas.add(oImg);
    canvas.renderAll();
});

Thanks for the help.

1条回答
我欲成王,谁敢阻挡
2楼-- · 2020-03-08 07:56

TO EXPLAIN BETTER THIS ANSWER: This code is not in fabricJS, clipPath is not a fabricJS property ( even if i want it to be soon ). This solution is a little bit better than using clipTo function ( that is deprecated in fabric 2.0 ) because it allows you to use standard fabric shapes for clipping. The idea is attach a standard shape to another defining it as clipPath. the clipPath then can be fixed (like if it was attached to canvas) or move with the image. This idea has to be better explored yet.

There are many way to accomplish this. Those are no one liner solutions and require custom coding. This is a solution using a clipPath attached to image. It requires to modify the main Image _render method.

var img01URL = 'http://fabricjs.com/assets/printio.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';
var img03URL = 'http://fabricjs.com/assets/ladybug.png';



    fabric.Image.prototype._render = function(ctx) {
      // custom clip code
      if (this.clipPath) {
        ctx.save();
        if (this.clipPath.fixed) {
          var retina = this.canvas.getRetinaScaling();
          ctx.setTransform(retina, 0, 0, retina, 0, 0);
          // to handle zoom
          ctx.transform.apply(ctx, this.canvas.viewportTransform);
          //
          this.clipPath.transform(ctx);
        }
        this.clipPath._render(ctx);
        ctx.restore();
        ctx.clip();
      }
      
      // end custom clip code
    
    
      var x = -this.width / 2, y = -this.height / 2, elementToDraw;

      if (this.isMoving === false && this.resizeFilter && this._needsResize()) {
        this._lastScaleX = this.scaleX;
        this._lastScaleY = this.scaleY;
        this.applyResizeFilters();
      }
      elementToDraw = this._element;
      elementToDraw && ctx.drawImage(elementToDraw,
                                     0, 0, this.width, this.height,
                                     x, y, this.width, this.height);
      this._stroke(ctx);
      this._renderStroke(ctx);
    };

var canvas = new fabric.Canvas('c');
canvas.setZoom(0.5)
fabric.Image.fromURL(img01URL, function(oImg) {
    oImg.scale(.25);
    oImg.left = 10;
    oImg.top = 10;
    oImg.clipPath = new fabric.Circle({radius: 40, top: 50, left: 50, fixed: true, fill: '', stroke: '' });
    canvas.add(oImg);
    canvas.renderAll();
});

fabric.Image.fromURL(img02URL, function(oImg) {
    oImg.scale(.40);
    oImg.left = 180;
    oImg.top = 0;
    oImg.clipPath = new fabric.Path('M85.6,606.2c-13.2,54.5-3.9,95.7,23.3,130.7c27.2,35-3.1,55.2-25.7,66.1C60.7,814,52.2,821,50.6,836.5c-1.6,15.6,19.5,76.3,29.6,86.4c10.1,10.1,32.7,31.9,47.5,54.5c14.8,22.6,34.2,7.8,34.2,7.8c14,10.9,28,0,28,0c24.9,11.7,39.7-4.7,39.7-4.7c12.4-14.8-14-30.3-14-30.3c-16.3-28.8-28.8-5.4-33.5-11.7s-8.6-7-33.5-35.8c-24.9-28.8,39.7-19.5,62.2-24.9c22.6-5.4,65.4-34.2,65.4-34.2c0,34.2,11.7,28.8,28.8,46.7c17.1,17.9,24.9,29.6,47.5,38.9c22.6,9.3,33.5,7.8,53.7,21c20.2,13.2,62.2,10.9,62.2,10.9c18.7,6.2,36.6,0,36.6,0c45.1,0,26.5-15.6,10.1-36.6c-16.3-21-49-3.1-63.8-13.2c-14.8-10.1-51.4-25.7-70-36.6c-18.7-10.9,0-30.3,0-48.2c0-17.9,14-31.9,14-31.9h72.4c0,0,56-3.9,70.8,26.5c14.8,30.3,37.3,36.6,38.1,52.9c0.8,16.3-13.2,17.9-13.2,17.9c-31.1-8.6-31.9,41.2-31.9,41.2c38.1,50.6,112-21,112-21c85.6-7.8,79.4-133.8,79.4-133.8c17.1-12.4,44.4-45.1,62.2-74.7c17.9-29.6,68.5-52.1,113.6-30.3c45.1,21.8,52.9-14.8,52.9-14.8c15.6,2.3,20.2-17.9,20.2-17.9c20.2-22.6-15.6-28-16.3-84c-0.8-56-47.5-66.1-45.1-82.5c2.3-16.3,49.8-68.5,38.1-63.8c-10.2,4.1-53,25.3-63.7,30.7c-0.4-1.4-1.1-3.4-2.5-6.6c-6.2-14-74.7,30.3-74.7,30.3s-108.5,64.2-129.6,68.9c-21,4.7-18.7-9.3-44.3-7c-25.7,2.3-38.5,4.7-154.1-44.4c-115.6-49-326,29.8-326,29.8s-168.1-267.9-28-383.4C265.8,13,78.4-83.3,32.9,168.8C-12.6,420.9,98.9,551.7,85.6,606.2z',{top: 0, left: 180, fixed: true, fill: '', stroke: '', scaleX: 0.2, scaleY: 0.2 });
    canvas.add(oImg);
    canvas.renderAll();
});
#c {
    border:1px solid #ccc;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.16/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>

查看更多
登录 后发表回答