Create Multiple Page PDF with Top and Bottom Margins using jsPDF addImage

  sonic0002        2025-03-06 01:34:53       217        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

我一直在开发一个浏览器扩展,它使用 jsPDF + html2canvas 以阅读器模式将网页保存为 PDF,从而提供了一种干净且无干扰的离线查看方式。一切进展顺利,直到我注意到一个 UI 问题——页面中断区域没有顶部和底部边距。

original.jpg

当使用 html2canvasjsPDF 将 HTML 页面转换为 PDF 时,该过程首先将整个网页渲染为画布。html2canvas 捕获浏览器中可见的所有内容,并将其转换为图像。然后使用 jsPDF.addImage() 将此图像添加到 PDF 中。

但是,如果网页的长度超过 PDF 中的单个页面,则 jsPDF 不会自动智能地处理分页符。相反,它只是将完整图像放置在第一页上,如果图像太高,则会被截断。为了支持多页 PDF,我们必须手动切片图像,并将每个片段正确地放置在单独的页面上。

默认情况下,jsPDF 不会在分页符处留下任何边距——每个新页面只是从前一个页面结束的地方开始。这可能会产生视觉上不舒服的体验,尤其是在文本在页面之间突然分割时。为了解决这个问题,我们需要手动计算并添加边距。这涉及调整每页图像的位置,并使用 doc.rect() 遮盖我们想要填充的区域。

没有边距的原始代码如下所示:

const imgHeight = fullHeight * scale; // height of the HTML content image
const pageHeight = 297; // A4 height in mm

let heightLeft = imgHeight;
let position = 0;
let currentPage = 1;

// if we have more than one page, we need to add padding to the top and bottom
if(imgHeight > pageHeight){
    // Additional pages
    while (heightLeft > 0) {
        doc.addImage(
            jpegDataUrl,
            'JPEG',
            0,                  // x position
            position,           // y position
            pdfWidth,           // width
            imgHeight,          // height: ensure last page fits correctly
            "",
            "FAST"
        );

        currentPage++;
        position -= pageHeight;  // Move the starting position down
        heightLeft -= pageHeight;
    
        if(heightLeft > 0){
            doc.addPage();
        }
    }
} else {
    // Single page
    ...
}

支持添加顶部和底部边距的新代码

const imgHeight = fullHeight * scale; // height of the HTML content image
const pageHeight = 297; // A4 height in mm
const topPadding = 10;  
const bottomPadding = 10;
const contentHeight = pageHeight - topPadding - bottomPadding;

let heightLeft = imgHeight;
let position = topPadding;
let currentPage = 1;

// if we have more than one page, we need to add padding to the top and bottom
if(imgHeight > contentHeight){
    // Additional pages
    while (heightLeft > 0) {
        doc.addImage(
            jpegDataUrl,
            'JPEG',
            0,                  // x position
            position,           // y position
            pdfWidth,           // width
            imgHeight,          // height: ensure last page fits correctly
            "",
            "FAST"
        );

        doc.setFillColor(255, 255, 255);
        doc.rect(0, 0, pdfWidth, topPadding, 'F'); // padding top
        doc.rect(0, pageHeight - bottomPadding, pdfWidth, bottomPadding, 'F'); // padding bottom 

        currentPage++;
        position -= contentHeight;  // Move the starting position down
        heightLeft -= contentHeight;
    
        if(heightLeft > 0){
            doc.addPage();
        }
    }
} else {
    // Single page
    ...
}

这里的关键代码是两行代码,它们遮盖了由于引入顶部和底部填充而导致的溢出内容。

doc.setFillColor(255, 255, 255);
doc.rect(0, 0, pdfWidth, topPadding, 'F'); // padding top
doc.rect(0, pageHeight - bottomPadding, pdfWidth, bottomPadding, 'F'); // padding bottom 

示例计算

让我们用数字来分解它(这里的单位可以是毫米或其他):

  • 假设原始网页高度为 180。
  • 页面高度设置为 100,顶部和底部边距各为 10。
  • 这意味着每页的实际内容高度 (contentHeight) 为 100 - 10 - 10 = 80。

第一页:

  • 位置从 10 开始。
  • 原始网页内容的前 0-90 放置在第一页上(因为调用了 addImage())。
  • 然后 doc.rect() 遮盖顶部 10 和底部 10,留下原始网页的 0-80 区域可见。

第二页:

  • 新位置是(先前位置 - contentHeight)= (10 - 80) = -70。
  • 这意味着原始网页的 70 到 170 的内容呈现在第二页上。
  • 同样,doc.rect() 遮盖 70-80(原始网页内容)和 160-170 区域,留下原始内容的 80-160 可见。

由于填充在每页的开头和结尾创建了一个空白区域,因此它可以确保干净且可读的格式,而不会在分页符处出现突然的截断。

new.jpg

希望这可以帮助遇到同样问题的任何人!

JSPDF  MULTIPLE PAGE  MARGIN  BOTTOM MARGIN  ADDIMAGE 

           

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Welcome to hell