Search code examples
javascriptjsoncanvasfabricjs

objects in canvas aren't loading with the same size - fabric.js loadFromJSON


https://jsfiddle.net/Wadsack/ovcx1rtj/38

var canvas = new fabric.Canvas('canvas_1');
var canvas2 = new fabric.Canvas('canvas_2');

var imgObj = new Image();
imgObj.src = "https://gtaprinting.ca/wp-content/uploads/2021/05/blank-t-shirt-front-grey.png";
imgObj.onload = () => {
  var image = new fabric.Image(imgObj);
  image.set({
    left: canvas.getWidth()/2,
    top: canvas.getHeight()/2,
    originX: 'center',
    originY: 'center',
    centeredScaling: true,
  }).scaleToWidth(canvas.getWidth()/2);
  canvas.add(image);
  canvas.renderAll();
  canvas2.loadFromJSON(JSON.stringify(canvas));
    canvas2.renderAll();
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.2.0/fabric.min.js"></script>
<canvas id="canvas_1"></canvas>
<canvas id="canvas_2"></canvas>

When creating 2 duplicate canvases and using toJSON to export the first canvas and loadFromJSON to populate the second canvas, results in the objects in the second canvas being smaller than the first.

I'm using fabricjs 4.2.0

Does anyone know why this is happening or a solution to the problem? I have tried everything but to make matters worse when combining png and jpeg files in the same canvas, they are both off in size by different amounts. ie the png is 10% smaller and the jpeg is 10% smaller

Internet you are my only hope


Solution

  • http://fabricjs.com/fabric-gotchas

    Wrong position after reloading a JSON object - NUM_FRACTION_DIGITS

    Fabric can serialize and deserialize objects in a plain object format. When dealing with serialization, floats can be a problem and give long strings with an unnecessary quantity of decimals. This blows up the string size. To reduce that, there is a constant defined on the Object called NUM_FRACTION_DIGITS, historically set to 2. That means that a top value of 3.454534413123 is saved as 3.45, same for scale, width, height. This is mostly fine unless you are dealing without situation where precision matter. To make an example, a very large image, can be scaled down to a small size using a scale of 0.0151. In this case a serialization would save it as 0.02 changing meaningully the scale. If you are facing such situations, in your project set the constant higher: fabric.Object.NUM_FRACTION_DIGITS = 8 to have 8 decimals on properties. This affects SVG export too.

    your image is more than 4000px large, you fall into this issue

    corrected fiddle with the "num fraction digits" set to 8 : https://jsfiddle.net/xrfa5dzc/