Pular para o conteúdo

Pagine conteúdo HTML extenso em várias páginas

Use quebras automáticas de página para distribuir conteúdo extenso em várias páginas. Adicione um esquema para que os leitores acessem diretamente as seções. Esta receita segue examples/12-bookmarks-and-toc.php.

Terminal window
composer require nextpdf/core:^3

Use esta restrição para o pacote nextpdf/core. Este exemplo é executado em PHP 8.4.

setAutoPageBreak(true, $margin) orienta o mecanismo a iniciar uma nova página antes que o conteúdo ultrapasse o limite da margem inferior. Nesse limite, o mecanismo fragmenta o texto extenso escrito por meio de multiCell() ou writeHtml(). O módulo de Fragmentação das Cascading Style Sheets (CSS) (css_break_3) está classificado como Verificado na matriz de suporte. Ele oferece suporte ao comportamento de quebra no pipeline de Hypertext Markup Language (HTML).

bookmark($title, $level) adiciona um item de esquema na posição atual. Um item de esquema do Portable Document Format (PDF) associa um destino para que os leitores possam ir diretamente a uma página (ISO 32000-2). O mecanismo grava esse destino como a entrada Dest do item (ISO 32000-2). Use o argumento level para aninhar itens em um sumário hierárquico na barra lateral do leitor.

O pipeline continua sendo de passagem única (ADR-001). O mecanismo decide a paginação enquanto emite o stream, sem reter uma árvore de layout.

  • setAutoPageBreak(bool $enabled, float $margin = 20): staticNextPDF\Core\Concerns\HasPages.
  • bookmark(string $title, int $level = 0, float $y = -1): staticNextPDF\Core\Concerns\HasNavigation.
  • multiCell(...) / writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutput.

A tabela completa de PHPDoc é gerada a partir do código-fonte.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setAutoPageBreak(true, margin: 25);
$doc->addPage();
$doc->bookmark('Section 1', level: 0);
$doc->setFont('helvetica', '', 11);
for ($i = 1; $i <= 80; $i++) {
$doc->multiCell(0, 7, "Paragraph {$i} of a long flowing document.");
}
$doc->save(__DIR__ . '/out.pdf');

Este exemplo autocontido é executado no harness. Ele constrói um documento com vários capítulos, um esquema aninhado e quebras automáticas de página, espelhando examples/12-bookmarks-and-toc.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Bookmarks and Navigation');
$doc->setPrintHeader(false);
$doc->setPrintFooter(false);
$doc->setAutoPageBreak(true, margin: 25);
$chapters = [
'Chapter 1: Introduction' => ['What is NextPDF?', 'Key Features'],
'Chapter 2: Getting Started' => ['Installation', 'Your First PDF'],
'Chapter 3: Advanced Topics' => ['Worker-safe Architecture', 'Streaming Output'],
];
$body = 'NextPDF is a modern PDF 2.0 library for PHP. This paragraph is '
. 'repeated so the content overflows the page and the engine inserts '
. 'an automatic page break at the bottom-margin threshold.';
foreach ($chapters as $chapter => $sections) {
$doc->addPage();
$doc->bookmark($chapter, level: 0);
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, $chapter, newLine: true);
$doc->ln(3);
foreach ($sections as $section) {
$doc->bookmark($section, level: 1);
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, $section, newLine: true);
$doc->setFont('helvetica', '', 11);
for ($i = 0; $i < 12; $i++) {
$doc->multiCell(0, 7, $body);
}
$doc->ln(4);
}
}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/paginate-long-html.pdf');
echo "Wrote paginate-long-html.pdf\n";

Saída padrão esperada (STDOUT):

Wrote paginate-long-html.pdf
  • Desativar e esquecer. Quando a quebra automática de página está desativada, o mecanismo recorta o conteúdo que ultrapassa a margem inferior em vez de distribuí-lo. Reative-a antes de processar conteúdo extenso.
  • Conteúdo indivisível. Um único bloco mais alto que a altura útil da página pode lançar UnsplittableContentException. Uma linha de tabela muito alta ou uma imagem grande podem causar isso. Divida o conteúdo na origem.
  • Marque antes do conteúdo. Chame bookmark() na posição para a qual você quer que o destino aponte. Coloque a chamada imediatamente antes do próximo título, na página desejada.
  • Cabeçalho e rodapé reservam espaço. Um cabeçalho ou rodapé de impressão reduz a altura útil do conteúdo, e o limite de quebra leva isso em conta. Desativar ambos, como este exemplo faz, dá a você a altura total do corpo.
  • Aninhamento do esquema. level é a profundidade do aninhamento. Um filho em level: 1 deve vir depois de um pai em level: 0. Caso contrário, o leitor achata a árvore do esquema.

O mecanismo decide a paginação durante a única passagem de emissão. O custo é linear em relação ao tamanho do conteúdo, O(n). O orçamento é wall_ms: 2000, peak_mb: 96. O tempo decorrido é um pouco maior do que nas receitas de página única porque a referência cruzada (xref) de várias páginas e a montagem do esquema acrescentam processamento. O modelo de streaming mantém a memória limitada, e o esquema continua sendo uma pequena lista plana.

Trecho da matriz de suporte de CSS (apenas linhas Verificadas)

Seção intitulada “Trecho da matriz de suporte de CSS (apenas linhas Verificadas)”

Esta tabela reproduz apenas as linhas Verificadas da matriz de suporte de CSS, cuja veracidade foi auditada.

Módulo do W3CNívelStatusEvidência
Fragmentação de CSS (css_break_3)3Verificadosrc/Html/Fragmentation/, tests/Unit/Html/PagedMedia/
Tabela de CSS (css_tables_3)3Verificadosrc/Html/Table/ + PDFs de referência (golden)
CSS Cascading and Inheritance — cascata e herança (css_cascade_3)3Verificadosrc/Html/Cascade/

@page define os seletores de página nomeada que pertencem ao CSS Paged Media. Antes de depender deles, consulte a matriz para verificar a classificação atual desse módulo.

Restrições de streaming de passagem única (ADR-001)

Seção intitulada “Restrições de streaming de passagem única (ADR-001)”

O mecanismo emite quebras de página à medida que o stream flui. Como não há uma árvore retida para redistribuição, cada decisão de quebra é final. Alguns conteúdos, como uma referência cruzada, precisam do número final da página após o layout. Esse tipo de conteúdo é restrito; portanto, escreva-o com esse limite em mente.

A paginação é responsabilidade do controlador de quebra de página, não do parser. O parser não emite operadores brutos de transição de página; ele solicita uma quebra por meio do contrato do controlador.

O modelo de streaming mantém o buffer da página atual e a lista plana do esquema, não todas as páginas ao mesmo tempo. Um documento muito longo permanece dentro do teto do ADR-020 porque o mecanismo descarrega as páginas concluídas. Tabelas e contêineres flex ainda obedecem ao limite de 5,000 nós por contexto.

Um documento hostil não pode forçar uso ilimitado de memória. Os limites de elementos e de aninhamento (ADR-001), somados ao orçamento de nós por contexto (ADR-020), limitam o processamento. Valide o tamanho e a estrutura do conteúdo longo recebido de usuários. O mecanismo renderiza como texto um título de esquema controlado pelo invasor e nunca o interpreta.

DeclaraçãoEspecificaçãoCláusulareference_id
Cada item de esquema pode ser associado a um destino para permitir acesso direto a ele.ISO 32000-2iso32000_2_sec12#x1.x5.p4
A entrada Dest de um item de esquema nomeia o destino exibido quando o item é ativado.ISO 32000-2iso32000_2_sec12#x1.x11.p30

Esta receita mostra como o NextPDF distribui conteúdo extenso e constrói um esquema. A matriz de suporte classifica a Fragmentação de CSS como Verificado.

Não aplicável.