Fabric.js: Canvas acquired via createCanvasForNode is broken

Created on 25 Apr 2017  Â·  53Comments  Â·  Source: fabricjs/fabric.js

Hello,

When working with the v2.0.0-beta.1 version of fabric on the server side, the node canvas acquired via createCanvasForNode does not seem to behave like a node canvas acquired via "new Canvas", although createCanvasForNode seemingly creates a valid node canvas via "new Canvas" as well. Below is the sample SERVER SIDE code required to re-create the issue

Notes:
Using our own built version of node-canvas, since the pre-built one conflicts with sharp image processing library.
OS: Windows 7
Node version: 7.9

Here is the file used for the test case:
honey_im_subtle

let Canvas = require('canvas');
let fabric = require('fabric').fabric;
fabric.canvasModule = 'canvas';

var fs = require('fs');

fs.readFile("honey_im_subtle.png", function (err, data) {
    if (err) {
        return console.log(err);
    }

    let fabric_canvas = fabric.createCanvasForNode(179, 132);

    let node_canvas = fabric_canvas.nodeCanvas;

    // using a newly created canvas works
    //let node_canvas = new Canvas(179, 132);

    let background_img = new Canvas.Image;
    background_img.src = data;

    let ctx = node_canvas.getContext('2d');
    ctx.drawImage(background_img, 0, 0, 179, 132); // fails

    // ensure the image was drawn to canvas
    let out = fs.createWriteStream(__dirname + '/canvas.png');
    let stream = node_canvas.pngStream();

    stream.on('data', function (chunk) {
        out.write(chunk);
    });

    stream.on('end', function () {
        console.log('saved canvas');
    });
});

The error message reads "Image or Canvas expected". I am attempting now to access the node canvas directly only because the following two attempts fail with the exact same error:

  • Setting a background image on the fabric canvas via SetBackgroundImage
  • Adding an image to the fabric canvas via "add"

Any help would be greatly appreciated!

Thomas

Most helpful comment

Just starting to with Fabric + Node and ended up here, after banging my head against the wall trying to follow the intro (part4). Good to see that TypeError: fabric.createCanvasForNode is not a function is actually a valid error - I couldn't work out why I couldn't even find that function in the project source code.

It would be great to get some updated docs. Cheers.

All 53 comments

we removed canvasForNode completely, please ask if you have any question. Use this issue even if is closed now

So how do we create a canvas for node now? http://fabricjs.com/fabric-intro-part-4#node still references the old way to do it...
Thanks for your help

new fabric.StaticCanvas() should do the trick.
I'll update tutorials

Thank you, and what would be the equivalent of fabric_canvas.nodeCanvas.toBuffer(); ?

is not really available anymore, i m exposing some node-canvas methods with

    fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {
      var impl = fabric.jsdomImplForWrapper(this.lowerCanvasEl);
      return impl && impl.createJPEGStream(opts);
    };

i think you should do fabric.jsdomImplForWrapper(canvas.lowerCanvasEl).methodOfYourChoice

otherwise i should replicate every old and new node-canvas methods here and it does not really make sense to me.

now i feel sorry that i exposed those 2 and created an exception. i should have waited more.

When I use
fabric.jsdomImplForWrapper(canvas.lowerCanvasEl).toBuffer()
I just get TypeError: fabric.jsdomImplForWrapper(...).toBuffer is not a function.
Do you know, what I am doing wrong?

what do you get when you do:
fabric.jsdomImplForWrapper(canvas.lowerCanvasEl)

isn't it a NodeCanvas instance?

Hm, this seems to be the error, it's an HTMLCanvasElementImpl instance.

(How) do I need to explicitly tell fabric to use node canvas?

so that can be my fault then, let me look at it better.
Jsdom uses node-canvas automatically, and i m trying to leverage differences to it.

ok i found it, applying a fix. i'll do the same for Image.

Great, looking forward to your fixes!

try to do fabric.jsdomImplForWrapper(canvas.lowerCanvasEl)._canvas this should give you an instance of nodeCanvas where you can use .toBuffer.

i created fabric.util.getNodeCanvas(element) so that you can use on what you want, either images or canvases

Just tried it. It works!

Unfortunately I ran into https://github.com/Automattic/node-canvas/issues/855 when debugging from within VS Code. Updating node canvas to 2.x alpha gave me another error:
Cannot read property 'imageSmoothingEnabled' of null
Shall I open another issue for this?

tp update to node canvas 2 you have to patch nodejs. node canvas 2 is in alpha stage i ll wait before using it.

sorry, you have to patch JSDOM

Ok, I see, thanks for all your help!

Just starting to with Fabric + Node and ended up here, after banging my head against the wall trying to follow the intro (part4). Good to see that TypeError: fabric.createCanvasForNode is not a function is actually a valid error - I couldn't work out why I couldn't even find that function in the project source code.

It would be great to get some updated docs. Cheers.

Hello, as _asturur_ said new fabric.StaticCanvas(); is solving the issue, nevertheless, it seems that canvas.loadFromJSON isn't working anymore too . Any idea ?
Cheers

What do you mean but loadFromJSON is not working?

I mean TypeError: canvas.loadFromJSON is not a function
http://prntscr.com/holer7
Am I missing something ?

Looks super weird to me. i recently test loadFromJSON with node and was
completely ok.

2017-12-17 11:14 GMT+01:00 Yohan Bouché notifications@github.com:

I mean TypeError: canvas.loadFromJSON is not a function
http://prntscr.com/holer7
Am I missing something ?

—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/kangax/fabric.js/issues/3885#issuecomment-352244992,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABI4QHRBtGmSQSw85EZEQfuU97Ei3ve-ks5tBOmGgaJpZM4NHYWr
.

Ok, I previously made a git clone of the repo then built the Fabric using node build.js modules=node then used the files in the dist folder as libs for my project. Damn, I just saw I missed the serialization module.
My bad ! Anyway thanks for replying so quickly

Please update the documentation

where is the doc still pointing at createCanvasForNode?

const canvas = new fabric.StaticCanvas(null, { width: size, height: size });

@asturur

Any hope of updating the node,js example?

This:

var fs = require('fs'),
    fabric = require('fabric').fabric,
    out = fs.createWriteStream(__dirname + '/helloworld.png');

var canvas = fabric.StaticCanvas(200, 200);
var text = new fabric.Text('Hello world', {
  left: 100,
  top: 100,
  fill: '#f55',
  angle: 15
});
canvas.add(text);

var stream = canvas.createPNGStream();
stream.on('data', function(chunk) {
  out.write(chunk);
});

gives this error:

      this.initialize.apply(this, arguments);
                      ^

TypeError: Cannot read property 'apply' of undefined

yes i ll update it now. is the new function but with the old arguments.

@asturur

If I may ask... Could you also please clearly list dependencies in one spot, along with the required versions of jsdom, node-canvas, node.js?

That'd be phenomenal.

Yes.
I ll add in that old page.
I m trying to migrate to node-canvas 2 and latest jsdom anyway.
Anyway npm install, and following node-canvas prerequisites should give you all you need.

Great!

I also wanted to say that instead of pointing users to various external links that contain installation instructions, it would be lot easier for us to just have a single npm install that'll do the job :-)

Sure, but npm-install can't take care of system level deps that will make the node-canvas able to compile correctly.
That is where most of the burden come from

Hi @asturur
I've been trying to get fabric on node working with no luck. I'm getting the same error as temuri416.
I appreciate you are very busy, but would you be able to post the current working version numbers of fabric, node-canvas, node etc, the required dependencies and any change to the node.js example code on this thread please?
I'm working to a really tight deadline on a project so this would be really appreciated!
Thank you,
Leo

on what system, architecure, are you running node?

linux? macos? windows? In case of linux which distro? is it an x86 or x64 machine?

Apologies, Windows x64.

that would be your production environment too?

Yes, production is planned to be on our Azure Windows Server 2016 VM. We could also create an Ubuntu VM if needed, but we'd prefer to use our existing Windows VM.

do you know if there is an integration script from github to azure so that
i can add an automatic test setup on windows?

On Thu, 13 Dec 2018, 12:39 retainleo <[email protected] wrote:

Yes, production is planned to be on our Azure Windows Server 2016 VM. We
could also create an Ubuntu VM if needed, but we'd prefer to use our
existing Windows VM.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/fabricjs/fabric.js/issues/3885#issuecomment-446938645,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABI4QCijwHC20JIfmnySqb8FRDwjSdIWks5u4jyBgaJpZM4NHYWr
.

I know you can deploy from github to azure via the azure CLI, would that help?
https://docs.microsoft.com/en-us/azure/app-service/scripts/app-service-cli-deploy-github

if azure would have a sort of free resources for open source projects, i
would happily integrate trough travis till it works, so that we would have
a living example of window configuration.

On Thu, 13 Dec 2018, 13:22 retainleo <[email protected] wrote:

I know you can deploy from github to azure via the azure CLI, would that
help?

https://docs.microsoft.com/en-us/azure/app-service/scripts/app-service-cli-deploy-github

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/fabricjs/fabric.js/issues/3885#issuecomment-446949851,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABI4QKqaTMMBuxLYxCB_Fu22XpYgfvEdks5u4kZ4gaJpZM4NHYWr
.

Azure do have Azure Pipelines which is free for open source projects: https://github.com/marketplace/azure-pipelines could this be the solution?

@asturur

Could you please tell us, at this moment, which versions of jsdom, node-canvas and node.js are supported/required by fabric.js v2?

It would be nice to have that information in one place :)

Cheers!

@asturur

Any hope of updating the node,js example?

This:

var fs = require('fs'),
    fabric = require('fabric').fabric,
    out = fs.createWriteStream(__dirname + '/helloworld.png');

var canvas = fabric.StaticCanvas(200, 200);
var text = new fabric.Text('Hello world', {
  left: 100,
  top: 100,
  fill: '#f55',
  angle: 15
});
canvas.add(text);

var stream = canvas.createPNGStream();
stream.on('data', function(chunk) {
  out.write(chunk);
});

gives this error:

      this.initialize.apply(this, arguments);
                      ^

TypeError: Cannot read property 'apply' of undefined

@temuri416 Did you ever figure out how to get rid of that apply of undefined error? I can't seem to get rid of it.

i updated it, i did not push up the website yet.
The new example is for fabric 3.0 and node-canvas 2.

Just starting to with Fabric + Node and ended up here, after banging my head against the wall trying to follow the intro (part4). Good to see that TypeError: fabric.createCanvasForNode is not a function is actually a valid error - I couldn't work out why I couldn't even find that function in the project source code.

It would be great to get some updated docs. Cheers.

https://github.com/fabricjs/fabric.js/issues/4586#issuecomment-354417724

@asturur hi i tried to run the server rendering demo introduced in tutorial
image

and the file was excuted perfectly shows no error , but the out put png has nothing on it.
image
would you please help me out? thank you so much~~~ @asturur

my node version is -> 13.11.0
node-canvas -> 2.6.1
jsdom -> 16.2.1
fabric -> 3.6.3
@asturur

because canvas.add will render before the next screen refresh ( i now is weird under node ). So you have to add a renderAll imperatively by yourself.
The demo should be fixed probably.

canvas.createPNGStream is the internal node-canvas functionality and does not know anything about what objects are on the canvas.

Hi friends,
Just wanted to comment that there still needs to be a canvas.renderAll() added in the hello world test otherwise it doesn't render anything:
http://fabricjs.com/fabric-intro-part-4

var fs = require('fs'),
    fabric = require('fabric').fabric,
    out = fs.createWriteStream(__dirname + '/helloworld.png');

var canvas = new fabric.StaticCanvas(null, { width: 200, height: 200 });
var text = new fabric.Text('Hello world', {
  left: 100,
  top: 100,
  fill: '#f55',
  angle: 15
});
canvas.add(text);
canvas.renderAll(); //added render all

var stream = canvas.createPNGStream();
stream.on('data', function(chunk) {
  out.write(chunk);
});

good point

Was this page helpful?
0 / 5 - 0 ratings