How to convert canvas to pdf

Do you want to save Konva stage into a PDF file?

PDF is a complicated format. So we have to use an external library such as jsPDF.

The idea of saving canvas to pdf is simple:

  1. Generate canvas content
  2. Export canvas into the image
  3. Add image into PDF document created with the PDF library
  4. Save PDF file

Also I have two tips for you:

  1. Thanks to High quality Exports, you can increase the quality of a PDF using pixelRatio attribute when you are converting a node into the image.

  2. It is possible to make a text selectable in the PDF. Even if we are adding the canvas into the PDF as an image, we can insert texts manually. That is not trivial and it can be difficult if you have complex styles. Also text rendering on PDF is different from the text rendering with Konva. But we can try to make it as close as possible. For the demo, we will draw “hidden” text inside PDF file. The text will be places under the image, so it is no visible. But it is still selectable. As a demo of “complex styles” I will blur the text.

Instructions: take a look into the canvas. Then try to save it as PDF.

Konva PDF demoview raw
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/[email protected]/konva.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js"
integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/"
crossorigin="anonymous"
></script>
<meta charset="utf-8" />
<title>Konva PDF Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
#save {
position: absolute;
top: 5px;
left: 5px;
}
</style>
</head>

<body>
<div id="container"></div>
<button id="save">Save as PDF</button>
<script>
var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});

var layer = new Konva.Layer();
stage.add(layer);

var back = new Konva.Rect({
width: stage.width(),
height: stage.height(),
fill: 'rgba(200, 200, 200)',
});
layer.add(back);

var text = new Konva.Text({
text: 'This is the Darth Vader',
x: 15,
y: 40,
rotation: -10,
filters: [Konva.Filters.Blur],
blurRadius: 4,
fontSize: 18,
});
text.cache();
layer.add(text);

var arrow = new Konva.Arrow({
points: [70, 50, 100, 80, 150, 100, 190, 100],
tension: 0.5,
stroke: 'black',
fill: 'black',
});
layer.add(arrow);
layer.draw();

// alternative API:
Konva.Image.fromURL(
'https://konvajs.org//assets/darth-vader.jpg',
function (darthNode) {
darthNode.setAttrs({
x: 200,
y: 50,
scaleX: 0.5,
scaleY: 0.5,
});
layer.add(darthNode);
layer.batchDraw();
}
);

document.getElementById('save').addEventListener('click', function () {
var pdf = new jsPDF('l', 'px', [stage.width(), stage.height()]);
pdf.setTextColor('#000000');
// first add texts
stage.find('Text').forEach((text) => {
const size = text.fontSize() / 0.75; // convert pixels to points
pdf.setFontSize(size);
pdf.text(text.text(), text.x(), text.y(), {
baseline: 'top',
angle: -text.getAbsoluteRotation(),
});
});

// then put image on top of texts (so texts are not visible)
pdf.addImage(
stage.toDataURL({ pixelRatio: 2 }),
0,
0,
stage.width(),
stage.height()
);

pdf.save('canvas.pdf');
});
</script>
</body>
</html>
Enjoying Konva? Please consider to support the project.