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

เค้าโครง: ส่วนหัว ส่วนท้าย คอลัมน์ บุ๊กเล็ต และการจัดการหน้า

โมดูล Layout ประกอบด้วยเอนจินจัดวางองค์ประกอบประจำหน้าที่อยู่เบื้องหลังฟาซาด Document ได้แก่ ส่วนหัว ส่วนท้าย เค้าโครงหลายคอลัมน์ การจัดเรียงบุ๊กเล็ตแบบเย็บกลางเล่ม และการดำเนินการเชิงโครงสร้างกับหน้า โมดูลนี้มีขนาดเล็กและเสถียร: หกคลาส ทั้งหมด @since 1.0.0

Terminal window
composer require nextpdf/core:^3

Layout (src/Layout/ หกคลาส @since 1.0.0) คือชั้นเอนจินที่อยู่ใต้คอนเซิร์น HasLayout แอปพลิเคชันของคุณเรียกเมท็อดฟาซาดบน Document จากนั้นเทรตจะส่งต่อการเรียกแต่ละครั้งไปยังเอนจินที่เกี่ยวข้อง ไฟล์ manifest กำหนดโมดูลนี้ให้มีระดับความเสี่ยง standard และเสถียรภาพ internal โดยมี Core เป็นโมดูลเดียวที่ขึ้นต่อโมดูลนี้ ควรใช้งานผ่านฟาซาด ไม่ใช่สร้างอินสแตนซ์ของคลาสเหล่านี้โดยตรง

HeaderFooter เรนเดอร์ส่วนหัวและส่วนท้ายที่แสดงซ้ำในทุกหน้า โดยเก็บสถานะของชื่อเรื่อง คำอธิบาย โลโก้ ฟอนต์ ระยะขอบ และสีของแต่ละแถบ แล้วปล่อยตัวดำเนินการ (operator) สำหรับ content stream ในรูปแบบ Portable Document Format (PDF) ตามการเรียก renderHeader() และ renderFooter() ส่วนท้ายค่าเริ่มต้นจะพิมพ์สตริง "page / total" โดยจัดชิดขวา setHeaderCallback() และ setFooterCallback() แทนที่เค้าโครงค่าเริ่มต้นด้วยโคลเชอร์ที่ผู้เรียกกำหนดเอง getHeaderContentHeight() รายงานพื้นที่แนวตั้งที่ส่วนหัวใช้ เพื่อให้เนื้อหาของหน้าเริ่มต้นถัดลงมาด้านล่างได้ เมื่อเอกสารอยู่ในโหมด tagged-PDF HasPages จะระงับส่วนหัวอัตโนมัติตั้งแต่ต้นทาง เพราะเนื้อหาส่วนหัวอยู่นอก structure tree

ColumnLayout จัดการการไหลของเนื้อหาแบบหลายคอลัมน์ setEqualColumns(int $count, float $totalWidth, float $gap = 5) แบ่งความกว้างที่มีอยู่ออกเป็นคอลัมน์เท่า ๆ กัน setColumnsArray() รับตำแหน่งและความกว้างของ ColumnDefinition ที่ระบุอย่างชัดเจน ใช้ selectColumn() เพื่อเลือกคอลัมน์ หรือ nextColumn() เพื่อเลื่อนไปยังคอลัมน์ถัดไป getCurrentColumnX() / getCurrentColumnWidth() คืนค่าเรขาคณิตของคอลัมน์ที่กำลังใช้งานอยู่ จำนวนคอลัมน์ที่ไม่ถูกต้อง ระยะห่างที่เป็นค่าลบ หรือความกว้างคอลัมน์ที่คำนวณแล้วไม่เป็นบวก จะทำให้เกิด PageLayoutException

BookletLayout จัดลำดับหน้าใหม่สำหรับการเข้าเล่มแบบเย็บกลางเล่ม (พับกลาง) reorderPages() เติมรายการหน้าให้มีจำนวนเป็นทวีคูณของสี่ เนื่องจากแผ่นบุ๊กเล็ตหนึ่งแผ่นมีช่องสำหรับสี่หน้า จากนั้นจัดเรียงหน้าจากด้านนอกเข้าด้านใน เพื่อให้แผ่นที่พับและเย็บแล้วอ่านได้ตามลำดับ getMarginAdjustments() คืนค่าระยะขอบด้านใน (สันเล่ม) และด้านนอก (ขอบ) ของแต่ละด้าน ณ ตำแหน่งที่กำหนด getSheetCount() รายงานว่าจำนวนหน้าที่กำหนดต้องใช้แผ่นพิมพ์สองหน้ากี่แผ่น การจัดลำดับใหม่เปลี่ยนเฉพาะการจัดวางเนื้อหาเท่านั้น ลำดับหน้า PDF ที่อยู่เบื้องล่างยังคงเป็นเชิงเส้น สอดคล้องกับ page tree ซึ่งกำหนดการเรียงลำดับของหน้าในเอกสาร (ISO 32000-2 §7.7)

PageManager ให้บริการการดำเนินการเชิงโครงสร้างกับหน้า โดยแยกออกจากการเรนเดอร์เนื้อหา movePage() copyPage() และ deletePage() ดำเนินการกับอาร์เรย์ PageData โดยอ้างอิง (by reference) พื้นที่ของหน้า (addPageRegion() isInRegion() getRegionOffset()) กำหนดโซนห้ามเขียน กลุ่มหน้า (startPageGroup() getGroupPageNo()) รองรับการกำหนดหมายเลขหน้าแยกตามส่วน PageRegion และ ColumnDefinition คือตัวพาค่า (value carrier) สองตัวที่เอนจินเหล่านี้ใช้ โมดูล Writer จะซีเรียลไลซ์หน้าที่ได้ลงใน page tree โดยรายการ Kids เป็นอาร์เรย์ของการอ้างอิงทางอ้อมไปยังโหนดลูกโดยตรงของโหนด page tree (ISO 32000-2 §7.7.3.2)

สัญลักษณ์ชนิดเสถียรภาพตั้งแต่
HeaderFooter::setHeaderData(string, string, string, float): selfเมท็อดเสถียร1.0.0
HeaderFooter::setHeaderFont(string, float): self / setHeaderMargin(float): selfเมท็อดเสถียร1.0.0
HeaderFooter::setFooterFont(string, float): self / setFooterMargin(float): selfเมท็อดเสถียร1.0.0
HeaderFooter::setHeaderCallback(Closure): self / setFooterCallback(Closure): selfเมท็อดเสถียร1.0.0
HeaderFooter::getHeaderContentHeight(): floatเมท็อดเสถียร1.0.0
HeaderFooter::renderHeader(float, float, float, float, int, int): stringเมท็อดเสถียร1.0.0
HeaderFooter::renderFooter(float, float, float, float, int, int, string): stringเมท็อดเสถียร1.0.0
ColumnLayout::setEqualColumns(int, float, float): selfเมท็อดเสถียร1.0.0
ColumnLayout::setColumnsArray(array): self / resetColumns(): selfเมท็อดเสถียร1.0.0
ColumnLayout::selectColumn(int): self / nextColumn(): boolเมท็อดเสถียร1.0.0
ColumnLayout::getCurrentColumnX(float): float / getCurrentColumnWidth(float): floatเมท็อดเสถียร1.0.0
BookletLayout::setBooklet(bool, float, float): voidเมท็อดเสถียร1.0.0
BookletLayout::reorderPages(array): arrayเมท็อดเสถียร1.0.0
BookletLayout::getMarginAdjustments(int): array{left: float, right: float}เมท็อดเสถียร1.0.0
BookletLayout::getSheetCount(int): intเมท็อดเสถียร1.0.0
PageManager::movePage(int, int, array): void / copyPage(int, array): void / deletePage(int, array): voidเมท็อดเสถียร1.0.0
PageManager::addPageRegion(float, float, float, float): void / isInRegion(float, float): boolเมท็อดเสถียร1.0.0
PageManager::getRegionOffset(float, float, float, float): floatเมท็อดเสถียร1.0.0
PageManager::startPageGroup(): void / getGroupPageNo(int): intเมท็อดเสถียร1.0.0
PageRegion / ColumnDefinitionตัวพาค่าเสถียร1.0.0
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Header and Footer');
$doc->setHeaderData(
title: 'NextPDF Example',
description: 'Header and Footer Demonstration',
);
$doc->setHeaderFont('helvetica', 10);
$doc->setHeaderMargin(5);
$doc->setFooterFont('helvetica', 8);
$doc->setFooterMargin(10);
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, 'Document with Header and Footer', newLine: true);
$doc->save(__DIR__ . '/output/13-header-footer.pdf');

ที่มา: examples/13-header-footer.php ส่วนหัวจะเรนเดอร์ทุกครั้งที่เรียก addPage() ส่วนท้ายจะเรนเดอร์เมื่อหน้านั้นถูกล้างออก (flush)

คอลแบ็กของส่วนท้ายควบคุมข้อความหมายเลขหน้า และเอนจินคอลัมน์ขับเคลื่อนเนื้อหาแบบสองคอลัมน์ คุณเข้าถึงเอนจินทั้งสองตัวผ่านฟาซาด

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Two-Column Report');
$doc->setFooterCallback(static function (Document $d): void {
$d->setFont('helvetica', '', 8);
$d->text(180.0, 285.0, 'Page ' . ($d->getPage() + 1));
});
$doc->addPage();
$doc->setEqualColumns(2, gap: 8);
$doc->selectColumn(0);
$doc->setFont('helvetica', '', 10);
$doc->multiCell(0, 6, 'Left column flows here.');
$doc->selectColumn(1);
$doc->multiCell(0, 6, 'Right column flows here.');
$doc->save(__DIR__ . '/output/two-column-report.pdf');

ที่มา: รูปแบบจาก examples/13-header-footer.php

  • setEqualColumns() ปฏิเสธจำนวนคอลัมน์ที่ต่ำกว่า 1 ระยะห่างที่เป็นค่าลบ หรือเค้าโครงใดก็ตามที่ความกว้างคอลัมน์ซึ่งคำนวณแล้วไม่เป็นบวก โดยจะทำให้เกิด PageLayoutException แทนที่จะคืนค่าเค้าโครงที่ลดคุณภาพลง
  • selectColumn() จะเพิกเฉยต่อดัชนีที่อยู่นอกช่วงและคงคอลัมน์ปัจจุบันไว้ โดยจะไม่โยนข้อยกเว้นสำหรับดัชนีที่ไม่ถูกต้อง nextColumn() คืนค่า false เมื่ออยู่ที่คอลัมน์สุดท้ายแล้ว
  • BookletLayout::reorderPages() เติมหน้าให้มีจำนวนเป็นทวีคูณของสี่ด้วยหน้าว่างที่โคลนมาจากขนาดของหน้าสุดท้าย รายการหน้าที่ว่างเปล่าจะคืนค่าอาร์เรย์ว่าง การจัดลำดับใหม่มีผลเฉพาะการจัดวางเท่านั้น ดัชนีของ movePage() ยังคงอ้างอิงตามลำดับเชิงตรรกะ
  • PageManager::movePage() copyPage() และ deletePage() จะไม่ทำสิ่งใดอย่างเงียบ ๆ สำหรับดัชนีที่อยู่นอกช่วง โดยตรวจสอบด้วย isset() แล้วคืนค่าออกไปโดยไม่แก้ไขอาร์เรย์ ควรตรวจสอบดัชนีด้วยตนเองเมื่อหน้าที่ขาดหายไปถือเป็นข้อผิดพลาดของผู้เรียก
  • getHeaderContentHeight() คืนค่า 0.0 เมื่อส่วนหัวถูกปิดใช้งานหรือไม่มีทั้งชื่อเรื่องและคำอธิบาย เนื้อหาของหน้าจะเริ่มต้นที่ระยะขอบบน
  • ในโหมด tagged-PDF ส่วนหัวอัตโนมัติจะถูกระงับที่ต้นทาง ควรสร้างเค้าโครงที่คำนึงถึงโครงสร้างสำหรับเอกสารที่เข้าถึงได้

การเรนเดอร์ส่วนหัวและส่วนท้ายจะผนวกตัวดำเนินการเข้ากับบัฟเฟอร์ของหน้าที่กำลังใช้งานอยู่ในระดับ O(furniture content) ต้นทุนแปรผันตามชื่อเรื่อง คำอธิบาย และเส้นคั่นที่เขียน ไม่ใช่ตามขนาดของเอกสาร การคำนวณคอลัมน์เป็น O(1) ต่อการเรียกหนึ่งครั้ง BookletLayout::reorderPages() เป็น O(n) ตามจำนวนหน้า โดยมีการเติมหน้าเพียงครั้งเดียว ลูปการจัดเรียงจะแตะช่องที่เติมแล้วแต่ละช่องเพียงครั้งเดียว การทดสอบพื้นที่ของ PageManager เป็น O(regions) ต่อจุดหนึ่งจุด และการดำเนินการกับหน้าเป็นการตัดต่ออาร์เรย์แบบ O(n) เอนจินเหล่านี้ไม่เก็บสถานะรายหน้าตลอดทั้งเอกสาร จึงไม่ทำให้หน่วยความจำเติบโตขึ้นในเอกสารที่ยาว ต้นทุนหน่วยความจำหลักคือ content stream ที่สะสมไว้ ซึ่งครอบคลุมอยู่ใน แนวคิดสตรีมและหน่วยความจำ เกตด้านความหน่วง (latency) และงบประมาณหน่วยความจำของไปป์ไลน์ HyperText Markup Language (HTML) มีการบันทึกไว้ใน PERFORMANCE-BUDGETS โดยจำกัดขอบเขตอยู่ที่เส้นทางการเรนเดอร์ HTML และไม่ได้เป็นเกตควบคุมเอนจินเค้าโครงเหล่านี้โดยตรง performance_budget ที่ 1500 ms / 64 MB คือกรอบขอบเขตของแคนวาสสำหรับตัวอย่างเริ่มต้น ไม่ใช่สัญญาระดับการเรียกแต่ละครั้ง

เอนจินเหล่านี้รับสตริงและพาธโลโก้ที่ผู้เรียกจัดหาให้ พาธโลโก้จะไหลผ่านเอนจินรูปภาพ ซึ่งตรวจสอบความถูกต้องของไฟล์ก่อนฝังลงไป renderHeader() และ renderFooter() จะเอสเคปข้อความของชื่อเรื่อง คำอธิบาย และหมายเลขหน้าผ่านตัวเอสเคปสตริง PDF แบบรวมศูนย์ ก่อนที่ข้อความเหล่านั้นจะไปถึง content stream เพื่อให้ข้อความของผู้เรียกไม่สามารถหลุดออกจากไวยากรณ์ literal-string ได้ คอลแบ็กของส่วนหัวหรือส่วนท้ายจะรันโค้ดของผู้เรียกด้วยระดับความเชื่อถือเดียวกันกับส่วนอื่นของเอกสาร ดังนั้นควรจัดการกับข้อมูลภายนอกใด ๆ ที่คอลแบ็กอ่านอย่างเหมาะสม การดำเนินการกับหน้าของ PageManager จะย้ายการอ้างอิงไปยัง PageData ที่มีอยู่แล้ว โดยไม่แยกวิเคราะห์ไบต์ที่ไม่น่าเชื่อถือ

ข้ออ้างมาตรฐานข้อกำหนดหลักฐาน
การจัดลำดับหน้าใหม่สำหรับเอาต์พุตบุ๊กเล็ตเปลี่ยนเฉพาะการจัดวางเท่านั้น page tree ยังคงกำหนดการเรียงลำดับเชิงเส้นของหน้าในเอกสารISO 32000-2§7.7
รายการ Kids ของโหนด page tree ที่ซีเรียลไลซ์แล้วเป็นอาร์เรย์ของการอ้างอิงทางอ้อมไปยังโหนดลูกโดยตรงของโหนดนั้นISO 32000-2§7.7.3.2

ตารางนี้สรุปข้อกำหนดแต่ละข้อและคงคำศัพท์เฉพาะไว้ โดยไม่ได้ทำซ้ำข้อความเชิงบรรทัดฐาน

  • เทรต Core/HasLayout — คอนเซิร์นฟาซาดที่ประกอบเอนจินเค้าโครงเข้าด้วยกัน
  • เทรต Core/HasPages — ขนาดหน้าและระยะขอบที่การคำนวณคอลัมน์ใช้
  • Writer — ตัวปล่อยอ็อบเจกต์ PDF และ page tree ที่ทำการซีเรียลไลซ์หน้าที่จัดวางแล้ว
  • สตรีมและหน่วยความจำ — เหตุใดเอนจินจัดวางองค์ประกอบประจำหน้าจึงไม่เก็บสถานะรายหน้า และเส้นทางการเรนเดอร์ที่ผูกกับหน่วยความจำทำงานอย่างไร
  • ข้อจำกัด HTML / สตรีมมิง (ADR-001) — เหตุผลรองรับขอบเขตการสตรีมแบบรอบเดียว