Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node JS Fabric scaling objects issue #4812

Closed
radiolondra opened this issue Mar 13, 2018 · 14 comments
Closed

Node JS Fabric scaling objects issue #4812

radiolondra opened this issue Mar 13, 2018 · 14 comments

Comments

@radiolondra
Copy link

Node Fabric version: 2.2.0

I need to scale the objects in the canvas (Textbox and Image derived custom classes) to follow the new canvas width and height assigned in the node app. After this I create a PNG file with the scaled objects.
Note that the Textbox objects have OriginX=left and OriginY=top.

[NodeJS app Code]
ftest.post('/process', function(req, res) {
// fabric & canvas variables come from an included module with functions getFabric() and createNodeCanvas()
var fabric = getFabric(); // var fabric = require('/usr/local/lib/node_modules/fabric').fabric;
var canvas = createNodeCanvas(); // var canvas = new fabric.StaticCanvas();

var oriCanvasW = 900; // original canvas width
var oriCanvasH = 510; // original canvas height
var wantedW = 1920; // new width
var wantedH = 1080; // new height

canvas.setWidth(wantedW);
canvas.setHeight(wantedH);

var scaleMultiplierX = wantedW / oriCanvasW;
var scaleMultiplierY = wantedH / oriCanvasH;

var projectFile = __dirname + '/project23.viprj'; // read the objects from file

fs.readFile(projectFile, 'utf8', function(err, data) {
	if (err) throw err;
	console.log('OK: ' + projectFile);
	
	//console.log(data);
	
	// REMOVE THE BOM or loadFromJSON will fail
	data = data.replace(/^\uFEFF/, '');
	
	canvas.loadFromJSON(data, function() {
		console.log("loaded");
		canvas.renderAll();

// SCALING & REPOSITIONING OBJECTS
canvas.forEachObject(function (obj) {

			obj.set('scaleX', Math.round(obj.get('scaleX') * scaleMultiplierX));
			obj.set('scaleY', Math.round(obj.get('scaleY') * scaleMultiplierY));

			obj.set('left', Math.round(obj.get('left') * scaleMultiplierX));
			obj.set('top', Math.round(obj.get('top') * scaleMultiplierY));

			obj.setCoords();
			console.log('DIM Left:' + obj.left + ' Top:' + obj.top + ' ScaleX:' + obj.scaleX + ' ScaleY:' + obj.scaleY);
		});
	    
		canvas.renderAll();
			
		console.log("rendered");

// CREATING PNG FILE
var out = fs.createWriteStream(__dirname + '/mio2.png');
var stream = canvas.createPNGStream();
stream.on('data', function(chunk){
//res.write(chunk);
out.write(chunk);
});
stream.on('end', function() {
res.end();
console.log("Finished!");
});
});
});
});

The problem is that the PNG image (with scaled objects) seems to have all the objects well scaled and positioned BUT one Textbox (and I don't understand why). Its scaled TOP, as reported by the console.log, should be 15 (I suppose from its top but it seems to be from its bottom...?!?!? I'm confused.)

wrong

Removing the scaling, everything is well positioned (top/left) but, obviously, not scaled.

noscale

In the browser version of the same code, using fabric 1.7.20, the PNG image is created with all the objects correctly scaled and positioned.

Maybe I'm assuming/doing something wrong. Maybe node-canvas does something different. I don't know.

Any idea? Could you helpme?

Thanks
Rob

@asturur
Copy link
Member

asturur commented Mar 16, 2018

Why you do not do just canvas.setZoom(scale) and try in that way?

@radiolondra
Copy link
Author

@asturur Because setZoom() doesn't affect the object properties. setZoom() seems to be merely a visual function the user can play with. In fact using setZoom() the saved PNG has all the canvas' objects unchanged.
Other ideas?
setzoom

@asturur
Copy link
Member

asturur commented Mar 17, 2018

is unclear from the issue what is the start design, the desired effect, and the actual behaviour.

@asturur
Copy link
Member

asturur commented Mar 17, 2018

making a png bigger, starting from a design, can be done with toDataUrl using the multiplier option.

if the text is misplaced is often fault of nodecanvas text management.

@radiolondra
Copy link
Author

hmmmmm... so do you think the problem comes from node-canvas?
Has this, in your opinion, something to do with Pango or other libs used by node-canvas?
Is there a way to understand where node-canvas is faulting?
I searched in node-canvas to see if someone else have had similar scaling issues, without result.
Is it possible that noone is trying to scale text in node-canvas?
Maybe I'm doing something wrong...
Very strange.

@radiolondra
Copy link
Author

OK, I'll try to circumvent the issue. Client side I'll create a new temporary project with all the objects already resized in a new hidden canvas (with the right dimensions) and send this temp project to the server app.

It should work (no more rescaling objects server side, just generate the PNG) but before to say "Hurray" I have to check.
Anyway, the server side scaling issue in NodeJS still remain the same, so if someone has a solution please let me know.
Thanks

@radiolondra
Copy link
Author

radiolondra commented Mar 17, 2018

Unfortunately the attempt to circumvent the issue was not successful. :(
The server side created PNG is still wrong. And it seems the problem is not the scaling...

To try to circumvent the issue, I sent with the browser to the server a project file with all the objects already scaled and positioned for the new canvas dimensions.
The server loads the project (loadFromJson) and render the canvas.
It seems that the canvas is rendered fine because I exported the canvas content into a new file to check if all the objects had the right properties set. And they have.

Next, on the server, I save the canvas using canvas.toDataURL and write the PNG file.
But the result is still the same. The red text at the top is still missed even if its properties are correct (it falls outside the image).

mio2

Here is an excerpt of the (Ubuntu 16.04) server side NodeJS code:
....
// data comes from client side with an already resized project
canvas.loadFromJSON(data, function() {
console.log("loaded");
canvas.renderAll();
// after rendering save the objects into a new project to check objects' properties
// the check reports ALL THE OBJECTS PROPERTIES ARE FINE!
var saveJson = JSON.stringify(canvas);
fs.writeFile("saveJSON.prj", saveJson, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file has been saved!");
}
});

	console.log("rendered");
	// Now save the canvas to PNG
	var dataUrl = canvas.toDataURL({format:'png'});
	dataUrl = dataUrl.split(',')[1]; 
	
	var buffer = new Buffer(dataUrl, 'base64');
	
	// writes the buffer to PNG file
	fs.writeFile(__dirname + '/mio2.png', 
		buffer.toString('binary'), 
		'binary', 
	(err) => {
  		if (err) throw err;
		console.log('--------- mio2.png file has been saved!');
	});	
});

Now I have no idea where the issue can be. :(

@radiolondra
Copy link
Author

If someone is interested I created this repo on Github to better explain the problem and to share a couple of nodejs test applications to demonstrate the issues.

FYI. I also sent a post in node-canvas github w/o any answer.

If this is the real situation, both NodeJs Fabric & Node-Canvas are totally unreliable and unusable for my very simple scopes.

Thanks anyway.

@asturur
Copy link
Member

asturur commented Mar 25, 2018

node-canvas is not a canvas, and the part that does not work well is text and patterns.

nodecanvas 2.0 works a little bit better text related, but is in alpha.

If you want to have a reliable canvas outside the browser, use a real canvas in an headless environment ( chrome or firefox )

@radiolondra
Copy link
Author

radiolondra commented Apr 2, 2018

@asturur Thanks Andrea, I created a Nodejs test app using Puppeteer (headless browser) and Fabric 1.7.20 (no Node version, this is the same version I used client side) and now the PNG is generated PERFECTLY!
frame00097

If someone is interested, I could create a new repo on Github to show the "How-to".
Grazie infinite
Roberto

@asturur
Copy link
Member

asturur commented Apr 2, 2018

Hi roberto, if you want to setup an howto from start to end on how to render something using puppeteer that would be a nice addition on fabricjs.com

@asturur
Copy link
Member

asturur commented Apr 2, 2018

i keep the issue closed since is not something i need to fix.

@asturur asturur closed this as completed Apr 2, 2018
@radiolondra
Copy link
Author

Ciao Andrea, lo farò sicuramente al più presto. Lasciami solo organizzare l'esempio per bene in modo che sia chiaro e semplice.
Grazie
Rob

@radiolondra
Copy link
Author

Ciao Andrea,
this is the repo for Puppeteer usage with FabricJs:

https://github.com/radiolondra/Server-side-FabricJs-using-Puppeteer

Waiting for your comments/suggestions.
Thanks
Rob

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants