<img src="https://assets.codepen.io/2209160/Hetzie-170x257_3.png" id="hetzie" style="display: none" crossOrigin="anonymous" />
<div id="workspace">
  <canvas id="canvas" class="a4-portrait" resize></canvas>
  <div class="toolbar"><button id="download-svg">Download SVG</button></div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

  <script>
    paper.install(window);
    paper.setup("canvas");
    // Sets the unit in JS to mm in conjunction with width/height
    // paper.view.scale(96 / 25.4, [0, 0]);
    // Export / Download SVG button
    document.addEventListener("DOMContentLoaded", function(event) {
      document.getElementById("download-svg").onclick = function() {
        const fileName = "a4.svg"
        const url = "data:image/svg+xml;utf8," + encodeURIComponent(paper.project.exportSVG({
          asString: true
        }));
        const link = document.createElement("a");
        link.download = fileName;
        link.href = url;
        link.click();
      }
    });
  </script>
body {
  width: 100%;
  height: 100vh;
  margin: 0;
  background: #bcbcbc;
  display: flex;
  justify-content: center;
  align-items: center;
}

#workspace {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.toolbar {
  margin-top: 5mm;
}

#canvas {
  display: block;
  background: #efefef;
}

#canvas.a4-portrait {
  width: 210mm;
  height: 297mm;
  /*   width: calc(210mm / 96 * 72);
  height: calc(297mm / 96 * 72); */
}
// All units in mm
const bleed = 20;
const width = 210 - bleed * 2;
const height = 297 - bleed * 2;

const scale = 96 / 25.4;
const yDivisions = 2;
const xDivisions = 2;

//------- - DRAW
const hetzie = new Raster("hetzie");
hetzie.visible = false;

// Layers can group items (for penplotter drawing)
const redGroup = new Group();
const greenGroup = new Group();
const blueGroup = new Group();

//------- - UPDATE
hetzie.onLoad = function () {
  hetzie.size = new Size(170, 257);
  const data = hetzie.getImageData(
    new Rectangle(0, 0, hetzie.width, hetzie.height)
  ).data;

  for (let y = 0; y < hetzie.height; y += 1) {
    let red = new Path({
      strokeColor: "red",
      strokeWidth: 1.2,
      blendMode: "multiply"
    });
    let green = new Path({
      strokeColor: "green",
      strokeWidth: 1.2,
      blendMode: "multiply"
    });
    let blue = new Path({
      strokeColor: "blue",
      strokeWidth: 1.2,
      blendMode: "multiply"
    });

    for (let x = 0; x < hetzie.width; x += 1) {
      const r = Number(data[(y * hetzie.width + x) * 4 + 0] / 255);
      const g = data[(y * hetzie.width + x) * 4 + 1] / 255;
      const b = data[(y * hetzie.width + x) * 4 + 2] / 255;

      if (r === 1) {
        redGroup.addChild(red);
        red = null;
      }

      if (g > 0.2) {
        greenGroup.addChild(green);
        green = null;
      }

      if (b > 0.4) {
        blueGroup.addChild(blue);
        blue = null;
      }

      if (r === 1 && g === 1 && b === 1) {
        continue;
      }

      if (r !== 1 && red == null) {
        red = new Path({
          strokeColor: "red",
          strokeWidth: 1.2,
          blendMode: "multiply"
        });
      }
      if (g <= 0.2 && green == null) {
        green = new Path({
          strokeColor: "green",
          strokeWidth: 1.2,
          blendMode: "multiply"
        });
      }
      if (b <= 0.4 && blue == null) {
        blue = new Path({
          strokeColor: "blue",
          strokeWidth: 1.2,
          blendMode: "multiply"
        });
      }

      if (r !== 1) {
        red.add(new Point(x, y - r * 2));
      }
      if (g <= 0.2) {
        green.add(new Point(x, y - g));
      }
      if (b <= 0.4) {
        blue.add(new Point(x, y - 0.5 - b));
      }
    }
  }

  hetzie.remove();

  project.layers.forEach((layer) => {
    layer.translate(new Point(bleed, bleed));
    layer.scale(96 / 25.4, new Point(0, 0));
  });
};

// Update event - called per frame
view.onFrame = function (event) {};

//------- - CLEAN UP

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.