Saturday, 3 March 2018

Creating SVG Vector Drawings with p5js

The way p5js is mostly used results in a canvas in a web page, with your artwork rendered as a bitmap - made of pixels. This is fine and works well for many scenarios.

But sometimes it would be really useful to have your artwork, not approximated as a set of pixels, but as a vector drawing, made of actual shapes like lines and circles.

The benefits of vector drawings is that they can be scaled up without loss of accuracy, and when they're rendered at high resolution, they are rendered at the maximum possible resolution. In other words, we avoid seeing the pixels that make up a bitmap image.

Here's a visual explanation of the difference between pixel (raster) images and vector drawings [source].


A good open standard for vector drawings is SVG.

Right now, the official p5js doesn't render SVG.


p5.js-svg

There was a Google Summer of Code project which aimed to allow p5js code to render as SVG.



Sadly, the project appears to be unmaintained, and the last release was linked to p5js v0.5.2 from January 2016.

To use it, we have to download the p5.svg.js library, and a patched p5.js which needs to be used instead of the current latest p5js.

Despite the age - it seems to work .. mostly.


Simplest Example

Here's a very simple example which I tried first to see if I could get p5js rendering to SVG working.

The HTML file is:

<!DOCTYPE html>
<html>
  <head>
     <meta charset="UTF-8"> 
    <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
    <style> body {padding: 0; margin: 0;} </style>
    <script src="../svg/p5.js"></script>
    <script src="../svg/p5.svg.js"></script>
    <script src="sketch.js"></script>
  </head>
  <body>
  </body>

You can see the direct references to the patched p5.js and the supporting p5.svg.js.

The p5js sketch is:

function setup() {
    createCanvas(800, 600, SVG);
    background(255);
    noLoop();
}

function draw() {
    ellipse(400, 300, 200, 200);
}

This is a really simple sketch, all it does is draw a circle. An important difference to normal p5js is the SVG parameter in the createCanvas() command, which tells this p5js to target SVG and not a pixel canvas.

The other difference is the ellipse command. I normally leave out the final parameter because modern p5js assumes you want a circle with the same horizontal and vertical diameter. With this older version of p5js we need to explicitly set both.

Here's the result:


The rendering didn't always work. Editing the sketch sometimes results in no change to the rendered image, or results in no image at all. Closing and opening a new tab to the sketch seems to be a workaround.


More Complex Example

In the book we develop some moderately sophisticated code and images. The last chapter on L-systems is a good example of this.


That's an interesting, fairly detailed image, made of quite a few lines and circles. The code for the image is online at https://www.openprocessing.org/sketch/514823.

Normally, if we wanted higher fidelity renders of that image, we'd have to increase the size of the canvas and adjust the size of the circles and length of the lines to scale up in proportion.

We can now modify the source code, like the simple example above, and see if we can successfully create an SVG vector drawing, made of actual circles and lines .. not pixels that approximate those lines.

... and it seems to work! The resulting SVG can be saved from the web page. I haven't found a simple way of doing that, like you can save an image. I had to copy the SVG element from the page source (using the web developer debugging console) and paste it into a plain text file, and saved with an .svg extension.

Here's the resulting SVG file: l-systems.svg. You can open it with most web browsers, file previewers and vector drawing editors like Adobe Illustrator, Affinity Designer and the open source Inkscape.

Comparision

Here's a zoomed a zoomed in section of the normal pixel image saved from the original p5js code.


You can see the poor fidelity as the pixels start to become apparent, resulting in "jaggies" instead of smooth edges.

Here's a zoomed in section of the vector drawing.


The circles are still smooth circles, and the lines are still smooth lines.

Here's an even deeper zoom, just to prove the point that vector drawings maintain render quality.


That's pretty amazing!


Conclusion

We've found a way to create SVG vector drawing from our p5js code - although the supporting library is a little outdated, and appears unmaintained.

The resulting vector drawings can be used to create very high fidelity renders - such as printing the cover image of a book!

3 comments:

  1. Thank you for the info.
    Are you sure you need a patched p5.js 0.5.2, instead of the last version? It looks to work also for the latest 0.5.16.

    ReplyDelete
    Replies
    1. Thanks for the update Alessandro - if thel atest p5js unpatched works that's good news!

      Delete