Pular para o conteúdo

Layout: cabeçalhos, rodapés, colunas, livreto e gerenciador de páginas

O módulo Layout reúne os motores de elementos fixos de página por trás da fachada Document: cabeçalhos, rodapés, layout de múltiplas colunas, imposição de livreto em lombada canoa e operações estruturais de página. Ele é pequeno e estável: seis classes, todas @since 1.0.0.

Terminal window
composer require nextpdf/core:^3

Layout (src/Layout/, seis classes, @since 1.0.0) é a camada de motores sob o concern HasLayout. A aplicação chama métodos de fachada em Document; o trait encaminha cada chamada para um destes motores. O manifesto marca o módulo com risco standard e estabilidade internal, tendo Core como seu único dependente. Use-o por meio da fachada, sem instanciar as classes diretamente.

HeaderFooter renderiza cabeçalhos e rodapés repetidos. Ele mantém o estado de título, descrição, logotipo, fonte, margem e cor de cada faixa. Sob demanda, emite operadores de fluxo de conteúdo do Portable Document Format (PDF) por meio de renderHeader() e renderFooter(). O rodapé padrão imprime uma string "page / total" alinhada à direita. setHeaderCallback() e setFooterCallback() substituem o layout padrão por uma closure fornecida pelo chamador. getHeaderContentHeight() informa o espaço vertical consumido pelo cabeçalho, para que o corpo da página possa começar abaixo dele. Quando o documento está em modo de PDF marcado, HasPages suprime o cabeçalho automático a montante, porque o conteúdo do cabeçalho fica fora da árvore de estrutura.

ColumnLayout gerencia o fluxo em múltiplas colunas. setEqualColumns(int $count, float $totalWidth, float $gap = 5) divide a largura disponível em colunas iguais. setColumnsArray() aceita posições e larguras explícitas de ColumnDefinition. Use selectColumn() para escolher uma coluna ou nextColumn() para avançar. getCurrentColumnX() / getCurrentColumnWidth() retornam a geometria da coluna ativa. Uma contagem de colunas inválida, um espaçamento negativo ou uma largura de coluna calculada não positiva lança PageLayoutException.

BookletLayout reordena as páginas para encadernação em lombada canoa (dobra central). reorderPages() completa a lista de páginas até um múltiplo de quatro, porque uma folha de livreto comporta quatro posições de página, e então impõe as páginas de fora para dentro para que as folhas dobradas e grampeadas sejam lidas na ordem correta. getMarginAdjustments() retorna as margens interna (lombada) e externa (borda) de cada lado em uma determinada posição. getSheetCount() informa quantas folhas frente e verso uma contagem de páginas exige. A reordenação altera apenas o posicionamento do conteúdo. A sequência subjacente de páginas do PDF permanece linear, consistente com a árvore de páginas, que define a ordenação das páginas no documento (ISO 32000-2 §7.7).

PageManager fornece operações estruturais de página separadas da renderização de conteúdo. movePage(), copyPage() e deletePage() operam sobre um array de PageData por referência. Regiões de página (addPageRegion(), isInRegion(), getRegionOffset()) definem zonas em que não se deve escrever. Grupos de página (startPageGroup(), getGroupPageNo()) dão suporte à numeração de páginas por seção. PageRegion e ColumnDefinition são os dois tipos de valor usados por estes motores. O módulo Writer serializa as páginas resultantes em uma árvore de páginas cuja entrada Kids é um array de referências indiretas aos filhos imediatos de um nó da árvore de páginas (ISO 32000-2 §7.7.3.2).

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

Fonte: examples/13-header-footer.php. O cabeçalho é renderizado a cada chamada de addPage(); o rodapé é renderizado quando a página é liberada.

Um callback de rodapé controla o texto do número da página, e o motor de colunas conduz um corpo em duas colunas. Você acessa os dois motores por meio da fachada.

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

Fonte: padrão de examples/13-header-footer.php.

  • setEqualColumns() rejeita uma contagem de colunas abaixo de 1, um espaçamento negativo ou qualquer layout cuja largura de coluna calculada não seja positiva. Ele lança PageLayoutException em vez de retornar um layout degradado.
  • selectColumn() ignora um índice fora do intervalo e mantém a coluna atual; ele nunca lança exceção para um índice inválido. nextColumn() retorna false quando já está na última coluna.
  • BookletLayout::reorderPages() completa até um múltiplo de quatro com páginas em branco clonadas a partir das dimensões da última página. Uma lista de páginas vazia retorna um array vazio. A reordenação afeta apenas o posicionamento; os índices de movePage() ainda se referem à ordem lógica.
  • PageManager::movePage(), copyPage() e deletePage() não fazem nada, silenciosamente, para um índice fora do intervalo; eles validam com isset() e retornam sem modificar o array. Verifique o índice você mesmo quando uma página ausente for um erro do chamador.
  • getHeaderContentHeight() retorna 0.0 quando o cabeçalho está desativado ou não tem título nem descrição. O corpo da página então começa na margem superior.
  • No modo de PDF marcado, o cabeçalho automático é suprimido a montante. Para documentos acessíveis, construa um layout ciente da estrutura.

A renderização de cabeçalho e rodapé acrescenta operadores ao buffer da página ativa em O(conteúdo dos elementos fixos); o custo escala com o título, a descrição e o separador escritos, não com o tamanho do documento. A matemática de colunas é O(1) por chamada. BookletLayout::reorderPages() é O(n) na contagem de páginas, com um único passe de preenchimento; o laço de imposição percorre cada posição preenchida uma vez. Os testes de região de PageManager são O(regiões) por ponto, e as operações de página são divisões de array O(n). Estes motores não retêm estado por página ao longo do documento, portanto não acrescentam crescimento de memória em documentos longos. O custo dominante de memória é o fluxo de conteúdo acumulado, abordado pelo conceito de streaming e memória. O gate de latência e orçamento de memória do pipeline de HyperText Markup Language (HTML) está documentado em PERFORMANCE-BUDGETS; ele é restrito ao caminho de renderização HTML e não controla diretamente estes motores de layout. O performance_budget de 1500 ms / 64 MB é o envelope de canvas para o início rápido, não um contrato por chamada.

Estes motores consomem strings e um caminho de logotipo fornecidos pelo chamador. O caminho do logotipo passa pelo motor de imagens, que valida o arquivo antes de incorporá-lo. renderHeader() e renderFooter() escapam o título, a descrição e o texto do número da página por meio do escapador centralizado de strings PDF antes que cheguem ao fluxo de conteúdo, de modo que o texto do chamador não possa escapar da gramática de string literal. Um callback de cabeçalho ou rodapé executa código do chamador com a mesma confiança que o restante do documento; trate qualquer dado externo que ele leia de acordo. As operações de página de PageManager movem referências a PageData existentes; elas não analisam bytes não confiáveis.

AfirmaçãoNormaCláusulaEvidência
A reordenação de páginas para saída em livreto altera apenas o posicionamento; a árvore de páginas ainda define a ordenação linear das páginas no documento.ISO 32000-2§7.7
A entrada Kids do nó serializado da árvore de páginas é um array de referências indiretas aos filhos imediatos desse nó.ISO 32000-2§7.7.3.2

A tabela parafraseia cada cláusula e mantém os termos do glossário fixos; ela não reproduz o texto normativo.

  • Trait Core/HasLayout — o concern de fachada que compõe os motores de layout.
  • Trait Core/HasPages — tamanho de página e margens usados pela matemática de colunas.
  • Writer — o emissor de objetos PDF e de árvore de páginas que serializa as páginas dispostas.
  • Streaming e memória — por que os motores de elementos fixos não mantêm estado por página e como funciona o caminho de renderização limitado por memória.
  • Restrições de HTML / Streaming (ADR-001) — a justificativa para o escopo de streaming de passe único.