Cannot scale up and rasterize SVG

Hello,

I can usually produce high quality PNG export via the rasterize function in my notebooks. (see this one for example, I can create 11000 pixels wide images)

It works with import { serialize } from "@mbostock/saving-svg"

But in my latest notebook, I can only produce 4400 pixels wide images. I have tried different computer on Chrome and I dont see the problem.

With the help of ChatGPT, I found the error, here is a resume of the problem and its solution


Issue:

I was trying to rasterize an SVG chart in an Observable notebook using a function that converts it to a PNG. When setting PNGprecision = 5, the function stopped working. Debugging logs showed that the canvas size was unexpectedly doubling, leading to excessive memory usage (~81MB) and possible crashes.

Cause:

The issue was due to automatic canvas scaling on high-DPI screens. Browsers adjust context2d dimensions based on window.devicePixelRatio, resulting in a canvas size twice as large as expected.

Solution:

Explicitly set the canvas width and height after creating the context to prevent unwanted scaling:

context.canvas.width = width;  // Prevent automatic scaling
context.canvas.height = height;

Outcome:

This fixed the issue, ensuring the canvas size matched the expected resolution. Now, the rasterization function works smoothly, even at high precision! :rocket:


I still hit a limit when having PNG Precision: 7 and the file output is corrupted (very small)

observablehq-390:17 Generated Image Size: 6454 x 6454
observablehq-390:27 Max WebGL Texture Size: 16384
observablehq-390:31 Total JS Heap Size (MB): 10.87
observablehq-390:35 Used JS Heap Size (MB): 7.72
observablehq-390:39 JS Heap Limit (MB): 4095.75
observablehq-390:49 Estimated memory usage (MB): 158.89784240722656
observablehq-390:69 Canvas Size: 6454 x 6454

It seems that the limit is the 160 MB of memory usage in a browser…

I need 7016 pixels to be able to print A1 at 300 DPI. Is there any other solution

EDIT:

I saw that by toggling the dark mode, it actually worked for this resolution!!!

So the only line that made sens where the bug was was:

  .style("mix-blend-mode", darkMode ? "normal" : "multiply")

By removing the multiply and use normal. it works for white mode !


The next limit is now PNGresolution = 8 which gives


Estimated memory usage (MB): 295.41015625
observablehq-390:69 Canvas Size: 8800 x 8800

where it crashes, but because the level before 7 is


Estimated memory usage (MB): 226.17340087890625
observablehq-390:69 Canvas Size: 7700 x 7700

this is enough for A1 print, not for A0 thought… if any one has a solution, it is welcome!

Interestingly, this notebook can create image which are 13000 pixels wide with no problem!

DOM.context2d has a third argument that sets the scaling factor (both by scaling the canvas dimensions and setting a transform), which defaults to devicePixelRatio. For exports (or when calling drawImage) you’ll want to set that to 1.

Browsers also have varying constraints for canvas dimensions (in the range of 16K-32K side length).

Thank you @mootari , I have add the third agument, but stiil hit limits. I have seen on this different computer the following error in my consol when trying higher resolution:

WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost

and

POST https://o299802.ingest.sentry.io/api/5593183/envelope/?sentry_key=ca9eac14b9164458a334243bb3c08c45&sentry_version=7&sentry_client=sentry.javascript.nextjs%2F8.32.0 net::ERR_BLOCKED_BY_CLIENT

I actually realize now the the .style("mix-blend-mode", "multiply") create a lower limit on the size export as well. If I remove this line (but it does not look so good) I can scale to a higher degree, but not sufficiant enough.

I have tried to do the scaling via inkscape or image magic and I had some result, but the text on the curved path and the font are broken…

Then ChatGPT suggested using the print feature of the browser when seeing the SVG file with looks just perfect. Setting the A1 size in the print as file, it gives a perfect PDF!

I can then use Ghostscript to create a png image gs -sDEVICE=png16m -r600 -o output.png input.pdf at the resolution needed.

Also, it looks like you can custom the print output of chrome via Virtual Printer (CUPS-PDF) or export to postscript