Aller au contenu

Mise en page : en-têtes, pieds de page, colonnes, livret, gestionnaire de pages

Le module Layout regroupe les moteurs d’éléments répétitifs auxquels la façade Document délègue : rendu des en-têtes et pieds de page, mise en page multicolonne, imposition de livret à piqûre à cheval et opérations structurelles sur les pages. C’est un petit module stable : six classes, toutes en @since 1.0.0.

Fenêtre de terminal
composer require nextpdf/core:^3

Layout (src/Layout/, six classes, @since 1.0.0) est la couche moteur sous-jacente au concern HasLayout. Le code d’application appelle les méthodes de façade sur Document ; le trait achemine chaque appel vers l’un de ces moteurs. Dans le manifeste, le module est marqué avec le risque standard et la stabilité internal, avec Core comme unique dépendant. Tu y accèdes par la façade, sans construire les classes directement.

HeaderFooter rend l’en-tête et le pied de page répétitifs. Il porte l’état du titre, de la description, du logo, de la police, de la marge et de la couleur pour chaque bande. À la demande, il produit des opérateurs de flux de contenu PDF via renderHeader() et renderFooter(). Le pied de page par défaut imprime une chaîne "page / total" alignée à droite. setHeaderCallback() et setFooterCallback() remplacent la mise en page par défaut par une closure fournie par l’appelant. getHeaderContentHeight() indique l’espace vertical consommé par l’en-tête, afin que le corps de la page puisse commencer en dessous. Quand le document est en mode PDF balisé, l’en-tête automatique est supprimé en amont dans HasPages, car son contenu se situe en dehors de l’arbre de structure.

ColumnLayout gère le flux multicolonne. setEqualColumns(int $count, float $totalWidth, float $gap = 5) répartit une largeur disponible en colonnes égales. setColumnsArray() accepte des positions et des largeurs ColumnDefinition explicites. Le curseur sélectionne une colonne avec selectColumn() ou avance avec nextColumn(). getCurrentColumnX() / getCurrentColumnWidth() renvoient la géométrie de la colonne active. Un nombre de colonnes invalide, une gouttière négative ou une largeur de colonne calculée non positive lève PageLayoutException.

BookletLayout réordonne les pages pour une reliure à piqûre à cheval (pli central). reorderPages() complète la liste des pages jusqu’à un multiple de quatre (une feuille de livret comporte quatre emplacements de page), puis impose les pages de l’extérieur vers l’intérieur afin que les feuilles pliées et agrafées se lisent dans l’ordre. getMarginAdjustments() renvoie, pour une position donnée, les marges intérieures (côté reliure) et extérieures (côté bord) par côté. getSheetCount() indique combien de feuilles recto-verso nécessite un nombre de pages donné. Le réordonnancement ne modifie que le placement du contenu. La séquence de pages PDF sous-jacente reste linéaire et cohérente avec l’arbre de pages, qui définit l’ordre des pages dans le document (ISO 32000-2 §7.7).

PageManager fournit des opérations structurelles sur les pages, distinctes du rendu du contenu. movePage(), copyPage() et deletePage() opèrent sur un tableau PageData par référence. Les régions de page (addPageRegion(), isInRegion(), getRegionOffset()) définissent des zones non inscriptibles. Les groupes de pages (startPageGroup(), getGroupPageNo()) prennent en charge la pagination par section. PageRegion et ColumnDefinition sont les deux porteurs de valeurs utilisés par les moteurs. Le module Writer sérialise les pages obtenues dans un arbre de pages dont l’entrée Kids est un tableau de références indirectes vers les enfants directs d’un nœud de l’arbre de pages (ISO 32000-2 §7.7.3.2).

SymboleTypeStabilitéDepuis
HeaderFooter::setHeaderData(string, string, string, float): selfméthodestable1.0.0
HeaderFooter::setHeaderFont(string, float): self / setHeaderMargin(float): selfméthodestable1.0.0
HeaderFooter::setFooterFont(string, float): self / setFooterMargin(float): selfméthodestable1.0.0
HeaderFooter::setHeaderCallback(Closure): self / setFooterCallback(Closure): selfméthodestable1.0.0
HeaderFooter::getHeaderContentHeight(): floatméthodestable1.0.0
HeaderFooter::renderHeader(float, float, float, float, int, int): stringméthodestable1.0.0
HeaderFooter::renderFooter(float, float, float, float, int, int, string): stringméthodestable1.0.0
ColumnLayout::setEqualColumns(int, float, float): selfméthodestable1.0.0
ColumnLayout::setColumnsArray(array): self / resetColumns(): selfméthodestable1.0.0
ColumnLayout::selectColumn(int): self / nextColumn(): boolméthodestable1.0.0
ColumnLayout::getCurrentColumnX(float): float / getCurrentColumnWidth(float): floatméthodestable1.0.0
BookletLayout::setBooklet(bool, float, float): voidméthodestable1.0.0
BookletLayout::reorderPages(array): arrayméthodestable1.0.0
BookletLayout::getMarginAdjustments(int): array{left: float, right: float}méthodestable1.0.0
BookletLayout::getSheetCount(int): intméthodestable1.0.0
PageManager::movePage(int, int, array): void / copyPage(int, array): void / deletePage(int, array): voidméthodestable1.0.0
PageManager::addPageRegion(float, float, float, float): void / isInRegion(float, float): boolméthodestable1.0.0
PageManager::getRegionOffset(float, float, float, float): floatméthodestable1.0.0
PageManager::startPageGroup(): void / getGroupPageNo(int): intméthodestable1.0.0
PageRegion / ColumnDefinitionporteur de valeursstable1.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');

Source : examples/13-header-footer.php. L’en-tête est rendu à chaque addPage() ; le pied de page est rendu quand la page est vidée.

Un callback de pied de page prend en charge le texte du numéro de page, tandis que le moteur de colonnes pilote un corps à deux colonnes. On atteint les deux moteurs via la façade.

<?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');

Source : motif tiré de examples/13-header-footer.php.

  • setEqualColumns() rejette un nombre de colonnes inférieur à 1, une gouttière négative ou une mise en page dont la largeur de colonne calculée n’est pas positive. Chacun de ces cas lève PageLayoutException au lieu de renvoyer une mise en page dégradée.
  • selectColumn() ignore un indice hors plage et conserve la colonne courante ; elle ne lève jamais d’exception pour un mauvais indice. nextColumn() renvoie false quand elle se trouve déjà sur la dernière colonne.
  • BookletLayout::reorderPages() complète jusqu’à un multiple de quatre avec des pages blanches clonées à partir des dimensions de la dernière page. Une liste de pages vide renvoie un tableau vide. Le réordonnancement n’affecte que le placement ; les indices de movePage() font toujours référence à l’ordre logique.
  • PageManager::movePage(), copyPage() et deletePage() sont silencieusement sans effet pour un indice hors plage : elles valident avec isset() et retournent sans modifier le tableau. Vérifie l’indice toi-même quand une page manquante est une erreur de l’appelant.
  • getHeaderContentHeight() renvoie 0.0 quand l’en-tête est désactivé ou n’a ni titre ni description. Le corps de la page commence alors à la marge supérieure.
  • En mode PDF balisé, l’en-tête automatique est supprimé en amont. Construis une mise en page respectueuse de la structure pour les documents accessibles.

Le rendu de l’en-tête et du pied de page ajoute des opérateurs au tampon de la page active en O(contenu des éléments répétitifs) : le coût est proportionnel au titre, à la description et au séparateur écrits, pas à la taille du document. Le calcul des colonnes est en O(1) par appel. BookletLayout::reorderPages() est en O(n) selon le nombre de pages, avec une seule passe de remplissage ; la boucle d’imposition touche chaque emplacement complété une seule fois. Les tests de région de PageManager sont en O(régions) par point ; les opérations sur les pages sont des découpages de tableau en O(n). Aucun de ces moteurs ne conserve d’état par page sur l’ensemble du document. Ils ne contribuent donc pas à la croissance mémoire sur les documents longs. Le coût mémoire dominant est le flux de contenu accumulé, que couvre le concept Streaming et mémoire. Le gate de latence et de budget mémoire du pipeline HTML est documenté dans PERFORMANCE-BUDGETS ; il est limité au chemin de rendu HTML et ne contrôle pas directement ces moteurs de mise en page. Le performance_budget de 1500 ms / 64 Mo est l’enveloppe du canevas pour le démarrage rapide, pas un contrat par appel.

Ces moteurs consomment des chaînes et un chemin de logo fournis par l’appelant. Le chemin du logo passe par le moteur d’images, qui valide le fichier avant son intégration. renderHeader() et renderFooter() échappent le titre, la description et le texte du numéro de page via l’échappeur de chaînes PDF centralisé avant qu’ils n’atteignent le flux de contenu, de sorte que le texte de l’appelant ne peut pas sortir de la grammaire des chaînes littérales. Un callback d’en-tête ou de pied de page exécute le code de l’appelant avec le même niveau de confiance que le reste du document : traite en conséquence toute donnée externe qu’il lit. Les opérations sur les pages de PageManager déplacent des références vers des PageData existants ; elles n’analysent pas d’octets non fiables.

AffirmationNormeArticlePreuve
Le réordonnancement des pages pour la sortie en livret ne modifie que le placement ; l’arbre de pages définit toujours l’ordre linéaire des pages dans le document.ISO 32000-2§7.7
L’entrée Kids du nœud d’arbre de pages sérialisé est un tableau de références indirectes vers les enfants directs de ce nœud.ISO 32000-2§7.7.3.2

Les articles sont paraphrasés et ancrés dans le glossaire ; aucun texte normatif n’est reproduit.