如何动态地将文本块分割成jsPDF的页面?

问题描述 投票:0回答:2

我有一个 React 应用程序,页面显示一些包含标题、文本、一些图像等的帖子。我正在尝试从中生成 PDF 文件。

实际页面非常曲折、动态且复杂,因此我没有尝试将 HTML 转换为 PDF,而是使用 jsPDF 包,并从 Redux 存储中插入状态变量作为内容。这将是理想的情况 - 我有生成布局的工具,我有一些内容,但是......我遇到了一个问题。我的帖子的文本长度可以从很小到几页不等,因此在这种情况下,应该将其传递到下一页。我已经弄清楚如何获取“pageHeight”和“textHeight”,因此当“textHeight”大于“pageHeight”时,我可以通过 doc.addPage() 添加另一页,但是文本仅保留在一页上并被切断在页面末尾(请参阅随附的屏幕截图)。这是我到目前为止的代码:

const pdfGenerator = () => {
    // Default export is a4 paper, portrait, using millimeters for units
    const doc = new jsPDF();
    const pageHeight = doc.internal.pageSize.height;

    const wrappedText = doc.splitTextToSize(post.text, 200);
    doc.setFontSize(14);
    const dim = doc.getTextDimensions(wrappedText);
    const textHeight = dim.h;
    doc.text(15, 10, wrappedText);
    if (textHeight >= pageHeight) {
      doc.addPage();
    }
    // const textPages = Math.ceil(dim.h / pageHeight);
    // Don't know what to do with it....

    doc.save(`${post.title}.pdf`);
  };

一种可能的解决方案是将整个文本分割成适合页面的块数组,然后进行循环或通过每次添加 doc.addPage() 来映射它。最大的问题是——它会在随机的地方分割文本,比如在单词的中间。

我尽力寻找解决方案,浪费了很多时间却没有结果......

请帮忙!

Generated PDF page break

javascript reactjs pdf react-redux jspdf
2个回答
3
投票
splitTextToSize 函数将返回一个数组,其中文本被分割成行,我们只需要用它来控制交互即可。下面的代码应该可以解决您的问题。

const pdfGenerator = () => { // Default export is a4 paper, portrait, using millimeters for units const doc = new jsPDF(); const pageHeight = doc.internal.pageSize.height; const wrappedText = doc.splitTextToSize(post.text, 180); doc.setFontSize(14); let iterations = 1; // we need control the iterations of line const margin = 15; //top and botton margin in mm const defaultYJump = 5; // default space btw lines wrappedText.forEach((line) => { let posY = margin + defaultYJump * iterations++; if (posY > pageHeight - margin) { doc.addPage(); iterations = 1; posY = margin + defaultYJump * iterations++; } doc.text(15, posY, line); }); doc.save(`${post.title}.pdf`); };
    

0
投票
这是对@Thiago Moura 答案的改进。唯一的神奇数字,即完全主观的数字,取决于您的喜好,是利润。其他一切都是派生的。也无需计算行数。 我包含了创建页眉和页脚的方法(即使没有要求),以提供如何计算边距的上下文。您可以省略页眉/页脚逻辑并减小或调整 yMargin 值,而不影响整体逻辑。

if (format === "PDF") { const doc = new jsPDF("portrait", "px", "a4"); doc.setFontSize(12); const pageWidth = doc.internal.pageSize.getWidth(); const pageHeight = doc.internal.pageSize.getHeight(); const xMargin = 25; // left and right margin const yMargin = 75; // top and botton margin including the header/footer. In px since that's what hte jsPDF is set to use const lineHeight = doc.getLineHeight(); // default space between lines const needNewPageAfterThisYPos = pageHeight - yMargin // the `description` variable here is the pdf content const wrappedText = doc.splitTextToSize(description, pageWidth - (2 * xMargin)); // account for both the left and right marigns let yPos; wrappedText.forEach((line) => { if (yPos > needNewPageAfterThisYPos) { doc.addPage(); yPos = undefined; } if (yPos === undefined) { yPos = yMargin; } else { yPos = yPos + lineHeight; } doc.text(line, xMargin, yPos); }); this.#addPDFHeaderAndFooter(doc, pageWidth, pageHeight, (yMargin / 2), data.label); doc.save(file); // file is the file path to save to } else { ... }
以及页眉/页脚逻辑

/** * Private method to add the header and footer to each page of a generated pdf. */ #addPDFHeaderAndFooter = (doc, pageWidth, pageHeight, margin, message) => { const pageCount = doc.internal.getNumberOfPages(); doc.setFont('Times'); doc.setFontSize(10); for (var i = 1; i <= pageCount; i++) { doc.setPage(i); // add the header to the page doc.text(message, pageWidth / 2, margin, { align: 'center' }); // add the footer to the page doc.text(message, pageWidth / 2, pageHeight - margin, { align: 'center' }) } }
    
© www.soinside.com 2019 - 2024. All rights reserved.