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

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

ฉันได้พัฒนา ส่วนขยายเบราว์เซอร์ ที่บันทึกหน้าเว็บเป็นไฟล์ PDF ในโหมดอ่านโดยใช้ jsPDF + html2canvas ซึ่งเป็นวิธีที่สะอาดและปราศจากสิ่งรบกวนในการดูแบบออฟไลน์ ทุกอย่างเป็นไปอย่างราบรื่นจนกระทั่งฉันสังเกตเห็นปัญหา UI อย่างหนึ่ง นั่นคือไม่มีระยะขอบด้านบนและด้านล่างในบริเวณที่แบ่งหน้า

original.jpg

เมื่อแปลงหน้า HTML เป็น PDF โดยใช้ html2canvas และ jsPDF กระบวนการจะทำงานโดยการเรนเดอร์หน้าเว็บทั้งหมดเป็นผืนผ้าใบก่อน html2canvas จะจับภาพทุกสิ่งที่มองเห็นได้ในเบราว์เซอร์และแปลงเป็นรูปภาพ จากนั้นรูปภาพนี้จะถูกเพิ่มลงใน PDF โดยใช้ jsPDF.addImage().

อย่างไรก็ตาม หากหน้าเว็บยาวกว่าหนึ่งหน้าใน 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

Crazy Atom Plugin