Skip to main content

如何将画布转换为 PDF

你想将 Konva 阶段保存为 PDF 文件吗?

PDF 是一种复杂的格式。因此,我们需要使用一个外部库,如 jsPDF

将画布保存为PDF的思路很简单:

  1. 生成画布内容
  2. 将画布导出为图像
  3. 将图像添加到使用PDF库创建的PDF文档中
  4. 保存PDF文件

我还有两个小提示:

  1. 借助于 高质量导出,你可以在将节点转换为图像时使用 pixelRatio 属性来提高 PDF 的质量。

  2. 可以使文本在 PDF 中可选择。即使我们将画布作为图像添加到 PDF 中,我们也可以手动插入文本。那并不简单,如果你有复杂样式可能会很困难。此外,PDF 上的文本渲染与 Konva 的文本渲染不同。但是我们可以尽量使之接近。为了演示,我们将在 PDF 文件中绘制“隐藏”的文本。文本将放置在图像下方,因此不会可见。但它仍然是可选择的。作为“复杂样式”的演示,我将模糊文本。

说明:查看画布。然后尝试将其保存为 PDF。

import Konva from 'konva';

// 创建用于 PDF 导出的按钮
const saveButton = document.createElement('button');
saveButton.textContent = '保存为 PDF';
saveButton.style.position = 'absolute';
saveButton.style.top = '5px';
saveButton.style.left = '5px';
document.body.appendChild(saveButton);

// 创建舞台
const width = window.innerWidth;
const height = window.innerHeight;

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

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

// 添加背景
const back = new Konva.Rect({
  width: stage.width(),
  height: stage.height(),
  fill: 'rgba(200, 200, 200)',
});
layer.add(back);

// 添加带模糊效果的文本
const text = new Konva.Text({
  text: '这是达斯·维达',
  x: 15,
  y: 40,
  rotation: -10,
  filters: [Konva.Filters.Blur],
  blurRadius: 4,
  fontSize: 18,
});
text.cache();
layer.add(text);

// 添加箭头
const arrow = new Konva.Arrow({
  points: [70, 50, 100, 80, 150, 100, 190, 100],
  tension: 0.5,
  stroke: 'black',
  fill: 'black',
});
layer.add(arrow);

// 添加图像
const imageUrl = 'https://konvajs.org/assets/darth-vader.jpg';
Konva.Image.fromURL(
  imageUrl,
  function (darthNode) {
    darthNode.setAttrs({
      x: 200,
      y: 50,
      scaleX: 0.5,
      scaleY: 0.5,
    });
    layer.add(darthNode);
  },
  function () {
    console.error('加载图像失败');
  }
);

// 处理 PDF 导出
saveButton.addEventListener('click', function () {
  // 我们需要检查 jsPDF 是否已加载
  if (typeof jsPDF !== 'undefined') {
    const pdf = new jsPDF('l', 'px', [stage.width(), stage.height()]);
    pdf.setTextColor('#000000');
    
    // 首先添加文本
    stage.find('Text').forEach((text) => {
      const size = text.fontSize() / 0.75; // 将像素转换为点
      pdf.setFontSize(size);
      pdf.text(text.text(), text.x(), text.y(), {
        baseline: 'top',
        angle: -text.getAbsoluteRotation(),
      });
    });

    // 然后在文本上绘制图像(使文本不可见)
    pdf.addImage(
      stage.toDataURL({ pixelRatio: 2 }),
      0,
      0,
      stage.width(),
      stage.height()
    );

    pdf.save('canvas.pdf');
  } else {
    console.error('jsPDF 库未加载。请将其包含在你的项目中。');
    alert('jsPDF 库未加载。在真实项目中,你需要将其包含进来。');
  }
});

// 动态加载 jsPDF 库以供演示
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js';
script.integrity = 'sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/';
script.crossOrigin = 'anonymous';
document.head.appendChild(script);