Skip to content

Instantly share code, notes, and snippets.

@mattdesl
Last active February 22, 2024 06:39
Show Gist options
  • Save mattdesl/0386cdf9e87d3da6ba5f7e912dd7a20e to your computer and use it in GitHub Desktop.
Save mattdesl/0386cdf9e87d3da6ba5f7e912dd7a20e to your computer and use it in GitHub Desktop.
Parse & render SVG with penplot

parse & render SVG file with penplot

This might be handy if you have an SVG file that you want to use as, say, a mask for a generative algorithm.

Place the SVG file in the same directory that you are running penplot from.

test

import { Orientation } from 'penplot';
import { polylinesToSVG } from 'penplot/util/svg';
import { parse } from 'extract-svg-path';
import parseSvgPath from 'parse-svg-path';
import svgPathContours from 'svg-path-contours';
import normalizePathScale from 'normalize-path-scale';
import boundPoints from 'bound-points';
export const orientation = Orientation.LANDSCAPE;
export const dimensions = [ 22.0, 22.0 ];
export default function createPlot (context, dimensions) {
const [ width, height ] = dimensions;
let lines = [];
return window.fetch('svg-test.svg')
.then(resp => resp.text())
.then(text => {
// Update list of lines
lines = toPolylines(text);
// Return penplot options to start rendering
return {
draw,
print,
background: 'white',
animate: false,
clear: true
};
});
// render SVG into line segments for penplotter
function toPolylines (svgContents) {
// Extract <path> data from SVG contents
const svgPath = parse(svgContents);
// Turn into MoveTo, LineTo, etc SVG commands
const svgCommands = parseSvgPath(svgPath);
// Normalize all the commands and discretize curves/etc into 2D polylines
const curveDetail = 1;
const contours = svgPathContours(svgCommands, curveDetail);
// Now, to work with general SVGs you may want to normalize the path scale
// so that your print doesn't need to match the same size as your SVG
// Do this by getting all 2D points of the polylines
const points = contours.reduce((a, b) => a.concat(b), []);
// Then get the bounding box of all 2D points
const bounds = boundPoints(points);
// And normalize each polyline to that bounding box
const lines = contours.map(line => normalizePathScale(line, bounds));
// Now you are in 0..1 range, you can apply translation/scale here to center it
const x = width / 2;
const y = height / 2;
const margin = 2; // margin from edge in centimeters
const scale = Math.min(width, height) / 2 - margin;
return lines.map(line => {
return line.map(point => {
return [ x + point[0] * scale, y + point[1] * scale ];
});
});
}
function draw () {
lines.forEach(points => {
context.beginPath();
points.forEach(p => context.lineTo(p[0], p[1]));
context.stroke();
});
}
function print () {
return polylinesToSVG(lines, {
dimensions
});
}
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment