Mr Pablo
Mr Pablo

Reputation: 4188

Weird behaviour with fabric.util.loadImage() when looping through objects loaded via loadFromJSON()

In order to try and get around the odd issue in having with CORS (here) I am attempting to reload any images loaded via canvas.loadFromJSON()

But, I am experiencing weird issues. Sometimes only one image is replaced, other times I get duplicates of one image.

Here is my code:

canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
  var objArray = canvas.getObjects();

  for (var i = 0; i < objArray.length; i++) {
      canvas.setActiveObject(objArray[i]);

      var activeObject = canvas.getActiveObject();

      if(activeObject.type === 'image') {

          fabric.util.loadImage(activeObject.src, function(img) {
              var object = new fabric.Image(img);

              object.hasControls = true;
              object.lockUniScaling = true;
              object.scaleX = activeObject.scaleX;       
              object.scaleY = activeObject.scaleY;
              object.originX = activeObject.originX;
              object.originY = activeObject.originY;                
              object.centeredRotation = true;
              object.centeredScaling = true;

              canvas.add(object);
          }, null, {crossOrigin: 'Anonymous'});

          canvas.remove(activeObject);
      }
      activeObject.setCoords();
  }

  canvas.deactivateAll();
  canvas.renderAll();
  canvas.calcOffset();
});

Any ideas why I'm getting these weird issues?

Upvotes: 2

Views: 2047

Answers (2)

I had the same problem and overcome it downloading again the image then reassign it to object._element once each fabric object was created using loadFromJSON.

export const getImage = url => {
  return new Promise((resolve, reject) => {
      let img = new Image();
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.setAttribute('crossOrigin', 'anonymous');
      img.src = url;
  });
}
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), async (o, object) => {
  if (object.type === "image") {
    let imagecore = await getImage(object.src);
    object._element = imagecore;
  }
});

Upvotes: 1

PromInc
PromInc

Reputation: 1233

First glance at your code I don't see anything wrong... But I'm also thinking the code might be a bit inefficient? Is there a need to create a new image instance?

I believe you should be able to just set the crossOrigin property on the image object.

This code is untested, but I'd try something like this:

canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
  var objArray = canvas.getObjects();
  for (var i = 0; i < objArray.length; i++) {
    canvas.setActiveObject(objArray[i]);
    var activeObject = canvas.getActiveObject();
    if(activeObject.type === 'image') {
      activeObject.crossOrigin = 'Anonymous';
    }
  }
  canvas.deactivateAll();
  canvas.renderAll();
  canvas.calcOffset();
});

Upvotes: 1

Related Questions