Automattic / node-canvas

Node canvas is a Cairo backed Canvas implementation for NodeJS.
10.15k stars 1.17k forks source link

chartjs-node-canvas producing strange visual artifacts when deployed to Windows #2178

Open chxpel opened 1 year ago

chxpel commented 1 year ago

spent 5 hours yesterday debugging the "canvas.node is not a valid win 32 application" bug. This was occurring because I was deploying to a Windows server, but using a pipeline running on Ubuntu.

Then, I had to deal with "Error: The module ...canvas.node'was compiled against a different Node.js version usingNODE_MODULE_VERSION 93. This version of Node.js requiresNODE_MODULE_VERSION 83. Please try re-compiling..."

I managed to fix this by forcing my pipeline to run Node 14 instead of 16.

I've got an Azure DevOps pipeline that deploys a NestJS (Node) app to a Windows server. Part of this app is an API which has an endpoint that renders a chart into a PDF. This works fine locally.

Once I finished fixing this bug and getting my app to deploy, this is what the PDF looks like: image

This is what the exact same code looks like running locally: image

On my machine, I run Node 12.22.1 For the pipeline, I am using Node 12.22.1 My package.json has chart.js version 3.9.1 and chartjs-node-canvas version 4.1.6

My actual server is running Node 12.21.0

I've tried messing around with versions of node, chartjs, and chartjs-node-canvas, but it is very, very easy to trigger the error "The module was compiled against a different node version...". My best idea so far was to make sure my local machine, pipeline, and deployment server were all running Node 12. I then downgraded both dependencies, but continued receiving the different node version error mentioned above.

Does anyone familiar with this package have any idea why this is happening? It's so weird. This is delaying a very important release.

Also can I post this anywhere else? Not sure if the other canvas related communities can help. I truly am desperate here.

LinusU commented 1 year ago

Seems to be something with fonts. Are you shipping fonts with your application and registrering them with registerFont? Otherwise, are you sure that the font you are using is present at your target machine?

zbjornson commented 1 year ago

I'm betting this is #857 and those grey blocks are small parts of massive text. Unfortunately everyone ran out of troubleshooting ideas. Quite a few people have run into issues with canvas on Azure and have ended up running on Linux instead of Windows to avoid the issues.

chxpel commented 1 year ago

Seems to be something with fonts. Are you shipping fonts with your application and registrering them with registerFont? Otherwise, are you sure that the font you are using is present at your target machine?

So I went and implemented this like so: At the top of my service file I have this:

const chartJSNodeCanvas = new ChartJSNodeCanvas({width, height, backgroundColor, chartCallback: (ChartJS) => {
        ChartJS.defaults.font.family = 'Arial';
        ChartJS.defaults.font.size = '14';
    } });

@Injectable()
export class MetricsService {
    private readonly logger: Logger = new Logger(MetricsService.name);
....

Then below in the function that is running to generate the PDF I have:

async exportPDF(body) {
        chartJSNodeCanvas.registerFont(process.env.ASSETS_PATH + 'font/arial.ttf', { family: 'Arial' });
        ....

Finally, I loaded arial.ttf in the assets folder of my project.

Now the result looks like this: image

It's essentially the same but the labels show up now. This is definitely a font problem. Considering the shape of the grey blob up top, you can tell it is 'Access Nutrition Tool' in giant characters all stacked on top of each other. Registering the font like this did work on my local machine. I can play around with the size attribute and verify new output. But deployed there are still issues.

Unfortunately, switching to Linux is not an option. I would have to spend weeks redesigning a lot of core infrastructure. (This is a large app in production)

chxpel commented 1 year ago

The other strange thing is I am showing these exact same charts on my Angular front end, which is also deployed to Windows. And that's been working fine forever.

UPDATE: I just tried setting the font to an absurd custom downloaded cursive script font. When deployed, the result is exactly the same (giant block text). So it looks like the new font is not getting registered properly. Did I misunderstand how to implement registerFont()?