I have created the following image as fabricjs-json:
The json looks like the following:
{
"version": "5.2.1",
"objects": [
{
"type": "circle",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": "100",
"top": "100",
"width": "60",
"height": "60",
"fill": "#e53e3e",
"name": "a",
"radius": "30",
"stroke": null,
"padding": "0"
},
{
"type": "triangle",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": "80",
"top": "229.13",
"fill": "#e0da2e",
"name": "b",
"height": "100",
"width": "100",
"stroke": null,
"padding": "0"
},
{
"type": "rect",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": "303.02",
"top": "69.96",
"width": "50",
"height": "50",
"fill": "#4976d0",
"name": "c",
"rx": "0",
"ry": "0",
"stroke": null,
"padding": "0"
},
{
"type": "image",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": "272.23",
"top": "287.63",
"width": "400",
"height": "400",
"scaleX": "0.58",
"scaleY": "0.58",
"name": "d",
"rx": "0",
"ry": "0",
"stroke": null,
"padding": "0",
"src": "https:\/\/picsum.photos\/id\/1014\/400",
"crossOrigin": null
},
{
"type": "textbox",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": "210.97",
"top": "100",
"width": "265.14180221557615",
"height": "25.99",
"fill": "#000000",
"angle": "33.4",
"name": "e",
"text": "This awesome image",
"textAlign": "left",
"fontSize": "23",
"charSpacing": "7",
"lineHeight": "1.16",
"fontWeight": "400",
"fontFamily": "Inter",
"fontStyle": "normal",
"textBackgroundColor": null,
"maxHeight": "487",
"stroke": null,
"padding": "20"
}
],
"background": "#24bd0f"
}
I created the following script to convert the json to an image:
var fs = require('fs'),
fabric = require('fabric').fabric,
out = fs.createWriteStream(__dirname + '/output.png');
let jsonstr = fs.readFileSync(__dirname + '/json/test_json.json', 'utf-8');
let json = JSON.parse(jsonstr);
var canvas = new fabric.StaticCanvas(null, { width: 500, height: 500 });
canvas.loadFromJSON(json, function() {
canvas.renderAll.bind(canvas);
var dataUrlOutput = canvas.toDataURL(); // png is default format
console.log(dataUrlOutput)
fs.writeFile(__dirname + '/output/output.png', dataUrlOutput, function(err) {
if (err) throw err;
});
});
This is my package.json
:
{
"name": "jsonToImage",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"canvas": "^2.9.3",
"fabric": "^5.2.4"
}
}
However, when opening the image I get:
I created the following sandbox to parse the json:
Codesandbox Example - JSONtoIMAGE
Any suggestions what I am doing wrong?
UPDATE
I checked the dataUrlOutput
from the script and I get the following:
As you can see half of the elements are there.
There seem to be a few things going on, namely the formatting of your JSON, rendering the canvas, and saving the file in Node.
The numbers in your json file are enclosed in quotes (e.g. "left": "100"
), while for those numerical values, fabric.js expects them not to be in quotes (e.g. "left": 100
). When there are quotes around the numbers, fabric.js seems to quasi-load some objects, but not others.
When you're saving your canvas as JSON, you can use JSON.stringify
to ensure that the formatting is preserved. For example, JSON.stringify(canvas.toJSON())
;
You're calling canvas.renderAll.bind(canvas)
, which creates a new function but doesn't call it. It should just be canvas.renderAll()
.
Saving a data url directly as a text file does not create an image in an encoded binary file. While you could use the data url to create a binary file (like from this answer), fabric.js adds some convenience functions to save a file, namely canvas.createPNGStream()
.
It looks something like this (thanks to this answer):
var out = fs.createWriteStream(__dirname + '/output.png');
var stream = canvas.createPNGStream();
stream.pipe(out);
With the modified JSON and code, the results look something like this:
Your data file, 'json/test_json.json'
{
"version": "5.2.1",
"objects": [
{
"type": "circle",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": 100,
"top": 100,
"width": 60,
"height": 60,
"fill": "#e53e3e",
"name": "a",
"radius": 30,
"stroke": null,
"padding": 0
},
{
"type": "triangle",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": 80,
"top": 229.13,
"fill": "#e0da2e",
"name": "b",
"height": 100,
"width": 100,
"stroke": null,
"padding": 0
},
{
"type": "rect",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": 303.02,
"top": 69.96,
"width": 50,
"height": 50,
"fill": "#4976d0",
"name": "c",
"rx": 0,
"ry": 0,
"stroke": null,
"padding": 0
},
{
"type": "image",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": 272.23,
"top": 287.63,
"width": 400,
"height": 400,
"scaleX": 0.58,
"scaleY": 0.58,
"name": "d",
"rx": 0,
"ry": 0,
"stroke": null,
"padding": 0,
"src": "https:\/\/picsum.photos\/id\/1014\/400",
"crossOrigin": null
},
{
"type": "textbox",
"version": "5.2.1",
"originX": "center",
"originY": "center",
"left": 210.97,
"top": 100,
"width": 265.14180221557615,
"height": 25.99,
"fill": "#000000",
"angle": 33.4,
"name": "e",
"text": "This awesome image",
"textAlign": "left",
"fontSize": 23,
"charSpacing": 7,
"lineHeight": 1.16,
"fontWeight": 400,
"fontFamily": "Inter",
"fontStyle": "normal",
"textBackgroundColor": null,
"maxHeight": 487,
"stroke": null,
"padding": 20
}
],
"background": "#24bd0f"
}
And your node.js program:
var fs = require('fs'),
fabric = require('fabric').fabric,
out = fs.createWriteStream(__dirname + '/output.png');
let jsonstr = fs.readFileSync(__dirname + '/json/test_json.json', 'utf-8');
let json = JSON.parse(jsonstr);
var canvas = new fabric.StaticCanvas(null, { width: 500, height: 500 });
canvas.loadFromJSON(json, function() {
canvas.renderAll();
var stream = canvas.createPNGStream();
stream.pipe(out);
out.on('finish', function () {
// do something here
});
});
http://fabricjs.com/fabric-intro-part-4 (the 'Fabric on Node.js' section)