1

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.

david0116
  • 103
  • 2
  • 11
  • First read the docs and installation process from https://github.com/kangax/fabric.js and if there is any errors then back to here and post a question regarding the same. – Rohan Kumar Jul 07 '17 at 06:18
  • Sorry, I don't really understand what you mean. I guess you are talking about the example images' link. I have modified the link. Thank you. – david0116 Jul 07 '17 at 07:13
  • Please check this: https://stackoverflow.com/a/44574678/7132835 It has fiddle example as well – Observer Jul 07 '17 at 14:47
  • @Observer That post helps a lot, thank you. – david0116 Jul 10 '17 at 05:18

1 Answers1

6

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>
AndreaBogazzi
  • 14,323
  • 3
  • 38
  • 63
  • This is amazing!! You're giving many people hope who are doing this. Could you please explain for "custom clip code"? I don't get it. – david0116 Jul 10 '17 at 10:09
  • Is the same code you find around in the clipByName examples ( that i think they are not good ) and packaged in a better way that gives you the ability to attach a clipShape to a picture. Maybe it will be a fabricJS feature one day. Not this month or the next for sure. – AndreaBogazzi Jul 10 '17 at 10:13
  • Alright, thanks a lot. I just found this doesn't work with setZoom. Is that possible to be solved? This is a very important feature for the svg editor project. demo here: https://jsfiddle.net/cxhe03v8/ – david0116 Jul 10 '17 at 10:32
  • Your code works great. However when I use canvas.toSVG() the clipping data is lost. Is there a solution for this? – peerbolte Aug 30 '17 at 09:15
  • maybe yes, i should code it from scratch. would require a proper question with maybe this snippet copied in – AndreaBogazzi Aug 30 '17 at 12:52
  • How can i move clipPath? I need to allow moving clipPath with object and allow moving image by double click for example – user2455079 Jan 11 '18 at 20:53