ข้ามไปยังเนื้อหา

เรนเดอร์ HTML เป็น PDF

ใช้ writeHtml() เรนเดอร์ส่วนย่อยของ Hypertext Markup Language (HTML) และ Cascading Style Sheets (CSS) ให้เป็นเนื้อหาหน้า Portable Document Format (PDF) เพียงส่งมาร์กอัปเข้าไป NextPDF จะเรนเดอร์หน้าที่จัดรูปแบบแล้วให้ โค้ดฉบับสมบูรณ์ที่รันได้อยู่ที่ examples/08-html-basic.php ทำตามขั้นตอนด้านล่าง หรือคัดลอกตัวอย่างไปใช้ได้โดยตรง

NextPDF อ่าน HTML ที่ระบุเพียงครั้งเดียว แล้วสตรีมผลลัพธ์เข้าสู่หน้าโดยตรง นี่คือไปป์ไลน์สตรีมมิงแบบรอบเดียว คุณไม่จำเป็นต้องเข้าใจโมเดลนี้เพื่อใช้สูตรนี้ อย่างไรก็ตาม ควรจดจำไว้ เพราะโมเดลนี้ช่วยอธิบายกฎบางข้อที่จะกล่าวถึงต่อไปในหน้านี้

Terminal window
composer require nextpdf/core:^3

คำสั่งนี้ติดตั้งแพ็กเกจ nextpdf/core ตัวอย่างบนหน้านี้รันบน PHP 8.4 และรันไทม์ >=8.4 <9.0 คือช่วงเวอร์ชันที่รองรับ

writeHtml() รับสตริง HTML แล้ววาดลงในหน้าปัจจุบัน โดยเริ่มจากตำแหน่งเคอร์เซอร์ปัจจุบัน ภายในเอนจิน NextPDF จะสแกน HTML ที่ระบุเพียงครั้งเดียวและแยกเป็นโทเค็น (HtmlTokenizer) จากนั้นไล่ผ่านรายการนั้นจากซ้ายไปขวา (HtmlParser) สำหรับแต่ละองค์ประกอบ เอนจินจะเขียนคำสั่งวาด PDF ที่ตรงกัน ซึ่งเรียกว่าตัวดำเนินการคอนเทนต์สตรีม ลงในบัฟเฟอร์ เอนจินไม่เคยสร้างหรือเก็บโครงสร้างต้นไม้ขององค์ประกอบไว้ในหน่วยความจำระหว่างการเรียก การออกแบบที่ตั้งใจไว้นี้คือโมเดลสตรีมมิงแบบรอบเดียวที่บันทึกไว้ใน ADR-001

องค์ประกอบระดับบล็อกที่รองรับแต่ละรายการจะกลายเป็นกล่องเค้าโครง และข้อความแต่ละช่วงจะกลายเป็นตัวดำเนินการแสดงข้อความ สไตล์จากแอตทริบิวต์ style แบบอินไลน์และบล็อก <style> จะถูกประมวลผลผ่าน CSS cascade ซึ่งเป็นกฎที่ตัดสินว่าสไตล์ใดมีผลเมื่อมีหลายสไตล์ที่ใช้ได้ การตัดบรรทัดข้อความ การจัดแนว และระยะห่างเป็นไปตามโมเดล CSS Text ซึ่งกำหนดว่าข้อความต้นฉบับจะกลายเป็นข้อความที่จัดรูปแบบและตัดบรรทัดแล้วอย่างไร (W3C CSS Text Level 3)

หากไม่ได้เลือกฟอนต์ ข้อความเนื้อหาจะใช้ฟอนต์ค่าเริ่มต้น ค่าเริ่มต้นนี้คือฟอนต์ Type 1 มาตรฐาน ซึ่งเป็นหนึ่งใน 14 ฟอนต์มาตรฐานที่ระบุไว้ใน ISO 32000-2 ค่าเริ่มต้นจะเปลี่ยนก็ต่อเมื่อลงทะเบียนและเลือกฟอนต์ของตนเอง หรือเมื่อโปรไฟล์การปฏิบัติตามข้อกำหนดบังคับให้ NextPDF ฝังฟอนต์ทดแทน

ควรกำหนดความคาดหวังนี้ตั้งแต่ต้น NextPDF รองรับ HTML และ CSS เพียงบางส่วน ไม่ได้รองรับทั้งหมดของทั้งสองอย่าง สูตรนี้ครอบคลุมเฉพาะส่วนที่รองรับ และไม่ได้อ้างว่ารองรับ HTML เต็มรูปแบบหรือ CSS เต็มรูปแบบ สำหรับสถานะของแต่ละโมดูลที่แม่นยำและผ่านการตรวจสอบแล้ว โปรดดู เมทริกซ์การรองรับ CSS ประกอบ

ลายเซ็นเมท็อดคือ writeHtml(string $html): static เมท็อดนี้ประกาศไว้บนอินเทอร์เฟซ NextPDF\Contracts\PdfDocumentInterface และนำไปใช้งานใน NextPDF\Core\Concerns\HasTextOutput เมท็อดนี้จะเรนเดอร์ลงในหน้าปัจจุบัน และจะสร้างหน้าให้หากยังไม่มีหน้าอยู่ ตาราง PHPDoc ฉบับเต็มสำหรับเมท็อดนี้สร้างขึ้นจากซอร์สโค้ด

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$doc->writeHtml('<h1>HTML Rendering in NextPDF</h1><p>Rendered with <strong>writeHtml()</strong>.</p>');
$doc->save(__DIR__ . '/out.pdf');

ตัวอย่างฉบับเต็มที่ทำงานได้ในตัวเองนี้คือรายการที่ test harness รัน ตัวอย่างนี้สะท้อน examples/08-html-basic.php และแทนที่จะฮาร์ดโค้ดพาธเอาต์พุต จะเขียนไปยังพาธที่ harness ระบุให้ วิธีนี้ทำให้ reproducibility harness รันสคริปต์สองครั้งและเปรียบเทียบผลลัพธ์ได้

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML content</strong> directly into PDF pages.
This is the recommended approach for <em>mixed formatting</em>.</p>
<h2>Supported elements</h2>
<ul>
<li>Headings (h1-h6)</li>
<li>Paragraphs with <strong>bold</strong> and <em>italic</em></li>
<li>Ordered and unordered lists</li>
<li>Tables with borders and alignment</li>
<li>Inline styles (color, font-size, margin)</li>
</ul>
<h2>Ordered list</h2>
<ol>
<li>Create a Document instance</li>
<li>Add pages and content</li>
<li>Call save() or output()</li>
</ol>
HTML;
$doc->writeHtml($html);
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script twice.
// Honour it: do not hard-code a path, do not echo the PDF to STDOUT.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-html-to-pdf.pdf');
echo "Wrote render-html-to-pdf.pdf\n";

STDOUT ที่คาดไว้:

Wrote render-html-to-pdf.pdf
  • การส่งต่อเคอร์เซอร์ writeHtml() จะย้ายเคอร์เซอร์ไปยังจุดสิ้นสุดของเนื้อหาที่เรนเดอร์แล้ว การเรียก cell() ในภายหลังหรือ writeHtml() ครั้งที่สองจะดำเนินต่อจากจุดนั้น ไม่ใช่จากด้านบนของหน้า
  • ยังไม่มีหน้า หากยังไม่มีหน้า writeHtml() จะเพิ่มหนึ่งหน้าก่อนการเรนเดอร์ เรียก addPage() ก่อนเมื่อจำเป็นต้องกำหนดขนาดหน้าเฉพาะ
  • ขีดจำกัดองค์ประกอบและการซ้อน เอนจินสตรีมมิงบังคับใช้ขีดจำกัดองค์ประกอบที่ 50,000 รายการ และขีดจำกัดการซ้อนที่ 100 ระดับ (ADR-001) เอกสารที่เกินขีดจำกัดข้อใดข้อหนึ่งจะถูกปฏิเสธ แทนที่จะถูกตัดทอนโดยไม่แจ้งเตือน
  • มาร์กอัปที่ไม่รองรับ องค์ประกอบและคุณสมบัติที่อยู่นอกขอบเขตที่รองรับจะถูกละเว้นหรือใช้ค่าสำรอง โดยจะไม่เกิดข้อผิดพลาดขึ้น ตรวจสอบความครอบคลุมกับเมทริกซ์การรองรับ CSS ก่อนพึ่งพาคุณสมบัติใดๆ
  • ทรัพยากรภายนอก รูปภาพและสไตล์ชีตระยะไกลเป็นไปตามนโยบายทรัพยากรภายนอก นโยบายค่าเริ่มต้นจะไม่ดึง URL ระยะไกลใดๆ โดยพลการ

การแบ่งเป็นโทเค็นและการเรนเดอร์เกิดขึ้นในรอบเดียวบนอินพุตที่ระบุ ต้นทุนจึงเพิ่มขึ้นเชิงเส้นตามจำนวนโทเค็น O(n) งบประมาณค่าเริ่มต้นสำหรับสูตรนี้คือ wall_ms: 1500, peak_mb: 96 เนื่องจากเอนจินสตรีมเอาต์พุตและไม่เก็บ Document Object Model (DOM) ไว้ในหน่วยความจำ หน่วยความจำสูงสุดจึงเป็นไปตามบัฟเฟอร์คอนเทนต์สตรีมและสแตกสไตล์ที่ใช้งานอยู่ ไม่ใช่ตามขนาดของเอกสารทั้งฉบับ

ส่วนที่คัดมาจากเมทริกซ์การรองรับ CSS (เฉพาะแถวที่ผ่านการตรวจสอบแล้ว)

หัวข้อที่มีชื่อว่า “ส่วนที่คัดมาจากเมทริกซ์การรองรับ CSS (เฉพาะแถวที่ผ่านการตรวจสอบแล้ว)”

ส่วนที่คัดมานี้รวมเฉพาะแถวที่จัดระดับเป็น Verified ใน เมทริกซ์การรองรับ CSS เท่านั้น “Verified” หมายถึงการนำไปใช้งานใน src/Html/ และชุดฟิกซ์เจอร์เฉพาะที่มีสาระสำคัญ ซึ่งผ่านอย่างกำหนดได้ภายใต้โปรไฟล์เชิงโครงสร้าง

โมดูล W3Cระดับสถานะหลักฐาน
CSS Flexible Box Layout — เค้าโครงกล่องแบบยืดหยุ่น (css_flexbox_1)1Verifiedsrc/Html/Flex/, tests/Unit/Html/Flex/
CSS Grid Layout (css_grid_1)1Verifiedsrc/Html/Grid/, คอร์ปัส WPT
CSS Cascading and Inheritance (css_cascade_3)3Verifiedsrc/Html/Cascade/, tests/Unit/Html/Cascade/
CSS Table (css_tables_3)3Verifiedsrc/Html/Table/, ฟิกซ์เจอร์ตาราง + golden PDF
CSS Fonts (css_fonts_4)4Verifiedsrc/Html/FontFace/, tests/Unit/Html/FontFace/

คุณสมบัติอย่าง text-align, text-indent และ color จัดระดับเป็น “Claimed” ในเมทริกซ์ (มีการนำไปใช้งานแล้ว แต่ไม่มีฟิกซ์เจอร์เฉพาะของโมดูล) จึงไม่ได้แสดงเป็น Verified ที่นี่

เอนจิน HTML ไม่เก็บ DOM ไว้ สถานะของเอนจินคือเคอร์เซอร์แบบสเกลาร์รวมกับสแตกสไตล์แบบ push/pop โหนดข้อความที่มีเฉพาะช่องว่างจะถูกทิ้งในขั้นตอนการแบ่งโทเค็น ผลที่ตามมาอย่างหนึ่งคือองค์ประกอบที่มาภายหลังไม่สามารถจัดสไตล์ให้องค์ประกอบก่อนหน้าใหม่ได้ และตัวเลือกที่ต้องใช้บริบทของต้นไม้ทั้งหมด (ตัวอย่างเช่น กรณี :has() ที่ซับซ้อน) จะถูกจำกัดตาม ADR-006 ให้วางแผนเค้าโครงโดยพึ่งพาเฉพาะลำดับของเอกสารเท่านั้น

การแยกวิเคราะห์ การจัดวางเค้าโครง และการวาดเป็นเลเยอร์ที่แยกจากกัน ตัวแยกวิเคราะห์ไม่ปล่อยตัวดำเนินการวาดแบบดิบ และตัวจัดส่งเค้าโครงไม่แยกวิเคราะห์ CSS การข้ามขอบเขตเหล่านี้ถือเป็นหนี้การพึ่งพาที่ ADR-010 ห้ามไว้ สำหรับผู้เขียนสูตร นี่หมายความว่าจุดเข้าใช้งานสาธารณะคือ writeHtml() อย่าเข้าถึงส่วนภายในของตัวแยกวิเคราะห์

ตาม ADR-020 บริบทการจัดรูปแบบที่มีคอนเทนเนอร์เป็นขอบเขต (flex, table) อาจสร้างต้นไม้ย่อยชั่วคราว โดยจำกัดไว้ที่ 5,000 โหนดต่อบริบท ลึก 20 ระดับ พร้อมเพดานหน่วยความจำที่ใช้งานอยู่ 50 MB รวมทุกบริบทที่ทำงานอยู่ และขีดจำกัดการซ้อน 10 ระดับ นอกบริบทเหล่านี้ โมเดลสตรีมมิงจะไม่เก็บต้นไม้ใดๆ ไว้ รักษาตารางและคอนเทนเนอร์ flex แต่ละรายการให้อยู่ภายในขีดจำกัดโหนดเพื่อให้หน่วยความจำคาดการณ์ได้

ปฏิบัติต่ออินพุต HTML เสมือนเป็นข้อมูลที่ไม่น่าเชื่อถือเสมอ NextPDF ไม่ประมวลผลสคริปต์ และนโยบายทรัพยากรภายนอกค่าเริ่มต้นจะไม่ดึง URL ระยะไกลใดๆ โดยพลการ เอนจินจึงระมัดระวังในตัวเอง ถึงอย่างนั้น ควรตรวจสอบความถูกต้องหรือทำความสะอาด HTML ที่ประกอบขึ้นจากอินพุตของผู้ใช้ก่อนเรนเดอร์ ขีดจำกัดองค์ประกอบและการซ้อนยังช่วยป้องกันได้ด้วยการจำกัดปริมาณงานที่เอกสารที่มุ่งร้ายหรือมีรูปแบบผิดพลาดสามารถเรียกร้องได้

ข้อความระบุข้อกำหนดข้อreference_id (รหัสอ้างอิง)
CSS Text ควบคุมการแปลงข้อความต้นฉบับให้เป็นข้อความที่จัดรูปแบบและตัดบรรทัดแล้วW3C CSS Text Level 3css_text_3#x1.x2.p4
ฟอนต์เนื้อหาค่าเริ่มต้นจะถูกกำหนดเป็นฟอนต์ Type 1 มาตรฐานISO 32000-2iso32000_2_sec9#x1.x29

สูตรนี้แสดงวิธีที่ NextPDF เรนเดอร์ส่วนของ HTML และ CSS ที่รองรับ สูตรนี้ไม่ได้ยืนยันว่ารองรับ HTML หรือ CSS อย่างเต็มรูปแบบ สถานะที่ผ่านการตรวจสอบแล้วของแต่ละโมดูลอยู่ในเมทริกซ์การรองรับ CSS

ไม่มี