تخطَّ إلى المحتوى

التخطيط: الترويسات والتذييلات والأعمدة والكتيّب وإدارة الصفحات

تضم وحدة ⁨Layout⁩ محرّكات تجهيزات الصفحة خلف واجهة Document: الترويسات والتذييلات والتخطيط متعدد الأعمدة وفرض ترتيب الكتيّب بخياطة السرج والعمليات الهيكلية للصفحات. وهي وحدة صغيرة ومستقرة: ست فئات، جميعها @since 1.0.0.

Terminal window
composer require nextpdf/core:^3

Layout (src/Layout/، ست فئات، @since 1.0.0) هي طبقة المحرّك أسفل الجانب البرمجي HasLayout. يستدعي تطبيقك أساليب الواجهة على Document؛ وتوجّه السمة كل استدعاء إلى أحد هذه المحرّكات. يصنّف البيان الوحدة بمخاطر من نوع standard واستقرار من نوع internal، وتبقى Core الوحدة الوحيدة المعتمِدة عليها. استخدمها عبر الواجهة، لا عبر إنشاء الفئات مباشرةً.

يعرض HeaderFooter الترويسة والتذييل المتكررين. ويخزّن حالة العنوان والوصف والشعار والخط والهامش واللون لكل شريط. ويُصدِر معاملات تدفق المحتوى لتنسيق المستندات المحمول (⁨PDF⁩) عند الطلب عبر renderHeader() وrenderFooter(). يطبع التذييل الافتراضي سلسلة "page / total" بمحاذاة إلى اليمين. يستبدل setHeaderCallback() وsetFooterCallback() التخطيط الافتراضي بإغلاق يوفّره المستدعي. يُبلِغ getHeaderContentHeight() عن المساحة الرأسية التي تشغلها الترويسة، حتى يبدأ متن الصفحة أسفلها. عندما يكون المستند في وضع ⁨PDF⁩ الموسوم، يكبت HasPages الترويسة التلقائية أعلى السلسلة لأن محتوى الترويسة يقع خارج شجرة البنية.

يدير ColumnLayout التدفق متعدد الأعمدة. يقسّم setEqualColumns(int $count, float $totalWidth, float $gap = 5) العرض المتاح إلى أعمدة متساوية. يقبل setColumnsArray() مواضع وعروضًا صريحة من نوع ColumnDefinition. استخدم selectColumn() لاختيار عمود، أو nextColumn() للتقدّم إلى العمود التالي. يُرجِع getCurrentColumnX() / getCurrentColumnWidth() هندسة العمود النشط. يؤدي عدد أعمدة غير صالح أو فجوة سالبة أو عرض عمود محسوب غير موجب إلى رفع PageLayoutException.

يعيد BookletLayout ترتيب الصفحات للتجليد بخياطة السرج (الطي من المنتصف). يحشو reorderPages() قائمة الصفحات لتصبح من مضاعفات الأربعة لأن ورقة الكتيّب تستوعب أربع خانات للصفحات، ثم يفرض ترتيب الصفحات من الخارج إلى الداخل بحيث تُقرأ الأوراق المطوية والمدبّسة بالترتيب. يُرجِع getMarginAdjustments() الهامشين الداخلي (عند الكعب) والخارجي (عند الحافة) لكل جانب عند موضع معيّن. يُبلِغ getSheetCount() عن عدد الأوراق ذات الوجهين التي يتطلبها عدد صفحات معيّن. تغيّر إعادة الترتيب موضع المحتوى فقط. ويبقى تسلسل صفحات ⁨PDF⁩ الأساسي خطيًا، بما يتسق مع شجرة الصفحات التي تحدد ترتيب الصفحات في المستند (⁨ISO 32000-2⁩ §7.7).

يوفّر PageManager عمليات هيكلية على الصفحات منفصلة عن عرض المحتوى. تعمل movePage() وcopyPage() وdeletePage() على مصفوفة PageData بالمرجع. تحدد مناطق الصفحات (addPageRegion() وisInRegion() وgetRegionOffset()) مناطق المنع من الكتابة. تدعم مجموعات الصفحات (startPageGroup() وgetGroupPageNo()) ترقيم الصفحات لكل قسم. PageRegion وColumnDefinition هما حاملا القيم اللذان تستخدمهما هذه المحرّكات. تسلسل وحدة ⁨Writer⁩ الصفحات الناتجة في شجرة صفحات يكون مدخل Kids فيها مصفوفة من المراجع غير المباشرة إلى الأبناء المباشرين لعقدة شجرة الصفحات (⁨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()؛ ويُعرض التذييل عند تفريغ الصفحة.

يتحكم رد نداء التذييل في نص رقم الصفحة، ويقود محرّك الأعمدة متنًا بعمودين. تصل إلى كلا المحرّكين عبر الواجهة.

<?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 عندما تكون الترويسة معطّلة أو لا تحمل عنوانًا ولا وصفًا. عندئذٍ يبدأ متن الصفحة عند الهامش العلوي.
  • في وضع ⁨PDF⁩ الموسوم، تُكبت الترويسة التلقائية أعلى السلسلة. أنشئ تخطيطًا واعيًا بالبنية للمستندات القابلة للوصول.

يلحق عرض الترويسة والتذييل المعاملات بمخزّن الصفحة النشطة بتعقيد ⁨O⁩(محتوى التجهيزات)؛ إذ تتناسب التكلفة مع العنوان والوصف والفاصل المكتوب، لا مع حجم المستند. ويكون حساب الأعمدة بتعقيد ⁨O⁩(1) لكل استدعاء. يعمل BookletLayout::reorderPages() بتعقيد ⁨O⁩(⁨n⁩) في عدد الصفحات، مع تمريرة حشو لمرة واحدة؛ وتلمس حلقة الفرض كل خانة محشوة مرة واحدة. تعمل اختبارات المناطق في PageManager بتعقيد ⁨O⁩(المناطق) لكل نقطة، وتعمل عمليات الصفحات بتعقيد ⁨O⁩(⁨n⁩) بسبب عمليات وصل المصفوفة. لا تحتفظ هذه المحرّكات بأي حالة لكل صفحة عبر المستند، لذلك لا تضيف نموًا في الذاكرة على المستندات الطويلة. التكلفة الأكبر في الذاكرة هي تدفق المحتوى المتراكم، ويغطيها مفهوم التدفق والذاكرة. بوابة زمن الاستجابة وميزانية الذاكرة لأنبوب لغة ترميز النص التشعبي (⁨HTML⁩) موثّقة في ⁨PERFORMANCE-BUDGETS⁩؛ وهي محصورة في مسار عرض ⁨HTML⁩ ولا تضبط محرّكات التخطيط هذه مباشرةً. performance_budget البالغ 1500 ⁨ms⁩ / 64 ⁨MB⁩ هو مغلّف اللوحة للبدء السريع، وليس عقدًا لكل استدعاء.

تستهلك هذه المحرّكات سلاسل يوفّرها المستدعي ومسار شعار يوفّره المستدعي. يمر مسار الشعار عبر محرّك الصور، الذي يتحقق من الملف قبل تضمينه. يهرّب renderHeader() وrenderFooter() نص العنوان والوصف ورقم الصفحة عبر مُهرّب سلاسل ⁨PDF⁩ المركزي قبل أن تصل إلى تدفق المحتوى، بحيث لا يمكن لنص المستدعي أن يخرج عن قواعد السلسلة الحرفية. يشغّل رد نداء الترويسة أو التذييل شيفرة المستدعي بدرجة الثقة نفسها الممنوحة لبقية المستند؛ فتعامل مع أي بيانات خارجية يقرأها وفقًا لذلك. تنقل عمليات الصفحات في PageManager مراجع إلى PageData قائمة؛ ولا تحلّل بايتات غير موثوقة.

الادّعاءالمعيارالبندالدليل
تغيّر إعادة ترتيب الصفحات لإخراج الكتيّب الموضع فقط؛ ولا تزال شجرة الصفحات تحدد الترتيب الخطي للصفحات في المستند.⁨ISO 32000-2⁩§7.7
مدخل Kids لعقدة شجرة الصفحات المُسلسلة هو مصفوفة من المراجع غير المباشرة إلى الأبناء المباشرين لتلك العقدة.⁨ISO 32000-2⁩§7.7.3.2

يعيد الجدول صياغة كل بند ويُبقي مصطلحات المسرد ثابتة؛ ولا يعيد إنتاج النص المعياري.