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

  sonic0002        2025-03-06 01:34:53       216        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 

範例計算

讓我們用數字來分解它(這裡的單位可以是 mm 或其他):

  • 假設原始網頁高度為 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

Java to Go