Render to HTML canvas and to PNG
In the precedent chapters we have built vector drawing from the ground up. We have shown that it is possible to construct graphic primitives as lines and curves and to fill and stroke them with pure mathematical methods using vanilla Javascript and operating on a simple array of bytes. We got quite far with a codebase that is only 70 kB of size and does not have any dependencies.
You can run it on any website
http:///www.belle-nuit.com/site/files/minimal3.html
But we can go a step further. Vector drawing is present in other image formats. It is natively supported in the HTML canvas, it is present in SVG and also in PDF. We might also render the vector drawing to bitmap images like PNG. We will now further add these formats to render our PostScript code. As interface, we will use the setpagedevice operator and implement it as devices.
In the rpnContext device dictionary will have a number of booleans that tell rpn to render to the devices:
- raw (our canvas, this one is only true by default)
- rawurl (our canvas as downloadable PNG file)
- canvas (native canvas)
- canvasurl (the native canvas as downloadable PNG file)
- svg
- svgurl
- pdfurl
Furthermore, we will add modifiers for the rendering
- oversampling (1 default), already implemented
- width
- height
- color (0 = gray default, 1 = rob)
- transparent (0 = false default, 1 = true)
And we add the console output optional
- console
You will not have to provide an entire dictonary for setpagedevice. It will only change the values for the parameters you set explicitly. The code is quite straightforward and we do not check values like we did for oversampling as all values are just either false or true. setpagevice has to be used at start, as it resets the page device.
We will add two classes rpnRawDevice and rpnCanvasDevice. Each class implements initgraphics(), fill(), stroke() and showpage(). Both devices can render to a canvas and also produce a data URL for the downloadable PNG. The data is moved from rpnCanvas to rpnRawDevice. postScriptEditor adds devices to the nodes array to the rpnContext before running rpn().
The operators fill, stroke and showpage are simplified. They simply loop through the nodes and delegate the execution.
This is the raw rendering as we had it.
This is the raw rendering to a downloadable PNG.
Now, directly render to canvas is more involving. Canvas supports drawing paths with the following context methods of interest for us:
- beginPath()
- moveTo(x, y)
- lineTo(x, y)
- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
- closePath()
- fill()
- stroke()
The handling of y is reversed. Top is 0. The handling of the color is more complicated. It has separate fillStyle and strokeStyle properties using CSS strings.
This is the native rendering of canvas including a downloadable link.
We can also resize the page and disable the console
And our justified text
This took us only 150 lines more. We have now 2267 lines ps20240905.js
and a working minimal website
http:///www.belle-nuit.com/site/files/minimal4.html