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

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

Tôi đã làm việc trên một tiện ích mở rộng trình duyệt giúp lưu các trang web dưới dạng file PDF ở chế độ đọc bằng cách sử dụng jsPDF + html2canvas, cung cấp một cách xem ngoại tuyến sạch sẽ và không bị phân tâm. Mọi thứ diễn ra suôn sẻ cho đến khi tôi nhận thấy một vấn đề về giao diện người dùng—không có lề trên và lề dưới ở khu vực ngắt trang.

original.jpg

Khi chuyển đổi một trang HTML sang PDF bằng cách sử dụng html2canvasjsPDF, quy trình hoạt động bằng cách trước tiên hiển thị toàn bộ trang web dưới dạng một canvas. html2canvas chụp mọi thứ hiển thị trong trình duyệt và chuyển đổi nó thành một hình ảnh. Hình ảnh này sau đó được thêm vào PDF bằng cách sử dụng jsPDF.addImage().

Tuy nhiên, nếu trang web dài hơn một trang trong PDF, jsPDF sẽ không tự động xử lý ngắt trang một cách thông minh. Thay vào đó, nó chỉ đơn giản đặt toàn bộ hình ảnh lên trang đầu tiên và nếu hình ảnh quá cao, nó sẽ bị cắt. Để hỗ trợ các file PDF nhiều trang, chúng ta phải tự cắt hình ảnh và định vị từng phân đoạn một cách chính xác trên các trang riêng biệt.

Theo mặc định, jsPDF không để lại bất kỳ lề nào ở các điểm ngắt trang—mỗi trang mới chỉ đơn giản tiếp tục chính xác nơi trang trước đó đã dừng lại. Điều này có thể tạo ra một trải nghiệm trực quan khó chịu, đặc biệt nếu văn bản bị chia cắt đột ngột giữa các trang. Để khắc phục điều này, chúng ta cần tính toán và thêm lề theo cách thủ công. Điều này bao gồm việc điều chỉnh vị trí của hình ảnh cho mỗi trang và sử dụng doc.rect() để che các khu vực mà chúng ta muốn thêm khoảng trắng.

Đoạn mã gốc không có lề sẽ như sau:

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
    ...
}

Đoạn mã mới hỗ trợ thêm lề trên và lề dưới

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
    ...
}

Đoạn mã quan trọng ở đây là hai dòng mã che nội dung bị tràn do việc giới thiệu phần đệm trên và dưới.

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

Ví dụ tính toán

Hãy chia nhỏ nó với các con số (đơn vị ở đây có thể là mm hoặc các đơn vị khác):

  • Giả sử chiều cao trang web ban đầu là 180.
  • Chiều cao trang được đặt thành 100, với lề trên và lề dưới là 10 mỗi bên.
  • Điều này có nghĩa là chiều cao nội dung thực tế (contentHeight) trên mỗi trang là 100 - 10 - 10 = 80.

Trang đầu tiên:

  • Vị trí bắt đầu ở 10.
  • 90 đầu tiên của nội dung trang web ban đầu được đặt trên trang đầu tiên (vì addImage() được gọi).
  • doc.rect() sau đó che 10 trên cùng và 10 dưới cùng, để lại vùng 0-80 của trang web ban đầu hiển thị.

Trang thứ hai:

  • Vị trí mới là (vị trí trước - contentHeight) = (10 - 80) = -70.
  • Điều này có nghĩa là nội dung từ 70 đến 170 của trang web ban đầu được hiển thị trên trang thứ hai.
  • Một lần nữa, doc.rect() che vùng 70-80 (nội dung trang web ban đầu) và vùng 160-170, để lại 80-160 của nội dung ban đầu hiển thị.

Vì phần đệm tạo ra một vùng trống ở đầu và cuối mỗi trang, nên nó đảm bảo một định dạng sạch sẽ và dễ đọc mà không bị cắt đột ngột ở các điểm ngắt trang.

new.jpg

Hy vọng điều này giúp ích cho bất kỳ ai gặp phải vấn đề tương tự! 

JSPDF  MULTIPLE PAGE  MARGIN  BOTTOM MARGIN  ADDIMAGE 

           

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Code blue