jsonimagefabricjstaint

canvas is throw error of tainted after LoadFromJson


I am using fabric js version 1.7.22

when image set in a repetitive manner in a rectangle of fabric js, at the first time it will be loaded and saved into JSON using toJSON() and save an image using todataUrl() method, but when cal canvas a loadFromJson method at that time, this canvas not savable, because it throws tainted canvas error.

Please help me,

I already set crossOrigin in a pattern but it not working. and not added in canvas JSON.

I have made one Fiddle For Generate Issue :

[http://jsfiddle.net/Mark_1998/kt387vLc/1/][1]

Steps to generate issue :

click on 'set pattern'

then click on 'save canvas'

then click on 'reload canvas' // load canvas from JSON

then click on 'save canvas' // cause issue of tainted canvas


Solution

  • This issue is fixed in new version of fabricjs already. If you are still using 1.7.20 the override fabric.Pattern.prototype.toObject and fabric.Pattern.prototype.initialize, find code in snippet.

    var canvas = new fabric.Canvas('canvas', {
      height: 500,
      width: 500,
    });
    canvas.backgroundColor = '#ff0000';
    canvas.renderAll();
    var canvasJSON = {};
    
    document.getElementById('setPat').addEventListener('click', function() {
      fabric.util.loadImage('https://cdn.dribbble.com/assets/icon-backtotop-1b04df73090f6b0f3192a3b71874ca3b3cc19dff16adc6cf365cd0c75897f6c0.png', function(image) {
        var pattern = new fabric.Pattern({
          source: image,
          repeat: 'repeat',
          crossOrigin: 'Anonymous'
        });
        var patternObject = new fabric.Rect({
          left: 0,
          top: 0,
          height: canvas.height,
          width: canvas.width,
          angle: 0,
          fill: pattern,
          objectCaching: false
        })
        canvas.add(patternObject);
      }, null, {
        crossOrigin: 'Anonymous'
      });
    })
    document.getElementById('saveCanvas').addEventListener('click', function() {
      console.log('save canvas');
      canvasJSON = canvas.toJSON();
      var image = canvas.toDataURL("image/png", {
        crossOrigin: 'Anonymous'
      }); // don't remove this, i need it as thumbnail.
      //console.log('canvas.Json', canvasJSON);
      //console.log('image', image);
      canvas.clear();
      canvas.backgroundColor = '#ff0000';
      canvas.renderAll();
    });
    document.getElementById('reloadCanvas').addEventListener('click', function() {
      console.log('save canvas');
      canvas.loadFromJSON(canvasJSON, function() {
        canvas.set({
          crossOrigin: 'Anonymous'
        })
      });
      console.log('canvas.Json', canvasJSON);
    });
    
    //cross origin was not added in toObject JSON
    fabric.Pattern.prototype.toObject = (function(toObject) {
      return function() {
        return fabric.util.object.extend(toObject.call(this), {
          crossOrigin: this.crossOrigin,
          patternTransform: this.patternTransform ? this.patternTransform.concat() : null
        });
      };
    })(fabric.Pattern.prototype.toObject);
    //cross origin was not added while creating image
    fabric.Pattern.prototype.initialize = function(options, callback) {
      options || (options = {});
    
      this.id = fabric.Object.__uid++;
      this.setOptions(options);
      if (!options.source || (options.source && typeof options.source !== 'string')) {
        callback && callback(this);
        return;
      }
      // function string
      if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') {
        this.source = new Function(fabric.util.getFunctionBody(options.source));
        callback && callback(this);
      } else {
        // img src string
        var _this = this;
        this.source = fabric.util.createImage();
        fabric.util.loadImage(options.source, function(img) {
          _this.source = img;
          callback && callback(_this);
        }, null, this.crossOrigin);
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.js"></script>
    <button id="setPat">
      Set pattern
    </button>
    <button id="saveCanvas">
      Save canvas
    </button>
    <button id="reloadCanvas">
      Reload CAnvas
    </button>
    <canvas id="canvas"></canvas>