Inspecione as caixas de layout antes de posicionar o conteúdo
Visão geral
Seção intitulada “Visão geral”Leia a geometria de layout ativa de um documento antes de posicionar o conteúdo. Esta receita lê a caixa da página, as margens, as regiões de não escrita e o cursor atual. Assim, a lógica de posicionamento pode usar valores reais em vez de coordenadas adivinhadas. A receita é apoiada por examples/34-inspect-layout-boxes.php e pela estrutura de testes correspondente, tests/Cookbook/Php/InspectLayoutBoxesRecipeTest.php.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Você não precisa de nenhum pacote Pro ou Enterprise. A interface de consulta de layout faz parte do Core e funciona no PHP 8.1 até 8.4.
Visão conceitual
Seção intitulada “Visão conceitual”Uma página em Portable Document Format (PDF) possui caixas de limite. Entre elas, a mínima é a MediaBox, o retângulo que define a extensão da página (ISO 32000-2 §7.7.3.3). O conteúdo é posicionado no espaço do usuário. Por padrão, o espaço do usuário começa no canto inferior esquerdo, e uma unidade equivale a 1/72 de polegada (§8.3.2). O NextPDF oferece a você uma visão a partir do canto superior esquerdo, mais amigável para autoria, e expõe a geometria por meio de métodos de consulta somente leitura:
getPageWidth()/getPageHeight()— dimensões da caixa da página.getMargins()— o objeto de valorMarginativo (top/right/bottom/left).getPageRegions()— as regiões de não escrita declaradas (PageRegion[]). Cada uma é um retângulo imutável onde o posicionamento de conteúdo é proibido.getX()/getY()— a posição do cursor ativo no espaço do autor.
Essas leituras são idempotentes. Elas não emitem conteúdo, não avançam o cursor nem alteram o estado. Use-as para calcular o espaço vertical restante e, em seguida, decidir se deve continuar escrevendo ou chamar addPage(). Você também pode dispor um bloco em relação a uma região de não escrita em vez de usar um deslocamento fixo codificado.
Interface da API
Seção intitulada “Interface da API”A application programming interface (API) é gerada a partir do PHPDoc. Os principais pontos de entrada estão nos traits \NextPDF\Core\Concerns\HasPages e HasLayout:
Document::getPageWidth(): float/Document::getPageHeight(): floatDocument::getMargins(): \NextPDF\ValueObjects\MarginDocument::getPageRegions(): array(list<\NextPDF\Layout\PageRegion>)Document::addPageRegion(float $x, float $y, float $w, float $h): staticDocument::getX(): float/Document::getY(): float
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->addPage();
$pageHeight = $doc->getPageHeight();$margins = $doc->getMargins();$cursorY = $doc->getY();
// Vertical space left before the bottom margin.$remaining = $pageHeight - $margins->bottom - $cursorY;
// Geometry is in user-space units (PDF points; 1 pt = 1/72 in).echo sprintf("Page height: %.2f pt\n", $pageHeight);echo sprintf("Bottom margin: %.2f pt\n", $margins->bottom);echo sprintf("Cursor Y: %.2f pt\n", $cursorY);echo sprintf("Remaining: %.2f pt\n", $remaining);Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”Este programa autocontido é executado pela estrutura de testes. Ele espelha examples/34-inspect-layout-boxes.php. Ele lê a geometria da página, declara uma região de não escrita para o rodapé e toma uma decisão orientada por dados para cada bloco. Se o próximo bloco colidir com uma região ou ultrapassar a margem inferior, ele adiciona uma página em vez de sobrepor conteúdo.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Layout Box Inspection Demo');$doc->setLanguage('en');$doc->addPage();
// Read the geometry (idempotent, no side effects). Values are in// user-space units (PDF points; 1 pt = 1/72 in).$pageWidth = $doc->getPageWidth();$pageHeight = $doc->getPageHeight();$margins = $doc->getMargins();
echo sprintf("Page box: %.2f x %.2f pt\n", $pageWidth, $pageHeight);echo sprintf("Cursor start: (%.2f, %.2f)\n", $doc->getX(), $doc->getY());
// A 15 pt tall footer no-write zone across the text column.$footerHeight = 15.0;$footerTop = $pageHeight - $margins->bottom - $footerHeight;$doc->addPageRegion( $margins->left, $footerTop, $pageWidth - $margins->left - $margins->right, $footerHeight,);
$blocks = [ 'Section 1. Each block measures the live cursor against the page box ' . 'and any no-write region before it is placed.', 'Section 2. The lowest Y at which any region starts is the hard floor ' . 'for new content; crossing it forces a page break.', 'Section 3. Reading geometry is idempotent — the query methods never ' . 'advance the cursor, so they are safe in the placement loop.', 'Section 4. This final block forces a second page when the column is ' . 'already near the footer keep-out zone.',];
$blockHeight = 42.0;$pagesUsed = 1;
foreach ($blocks as $index => $text) { $cursorY = $doc->getY();
// Lowest Y a region starts at — the hard floor for new content. $regionFloor = $pageHeight - $margins->bottom; foreach ($doc->getPageRegions() as $region) { $regionFloor = min($regionFloor, $region->y); }
if ($cursorY + $blockHeight > $regionFloor) { $doc->addPage(); ++$pagesUsed; // A fresh page resets the region set; re-declare the footer zone. $footerTop = $doc->getPageHeight() - $doc->getMargins()->bottom - $footerHeight; $doc->addPageRegion( $doc->getMargins()->left, $footerTop, $doc->getPageWidth() - $doc->getMargins()->left - $doc->getMargins()->right, $footerHeight, ); }
$doc->setFont('helvetica', 'B', 12); $doc->cell(0, 8, 'Block ' . ($index + 1), newLine: true); $doc->setFont('helvetica', '', 11); $doc->multiCell(0, 7, $text); $doc->ln(6);}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the// semantic profile (validated by structural AST + metadata, not a byte hash).$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false && $out !== '' ? $out : __DIR__ . '/inspect-layout-boxes.pdf');
echo sprintf("Pages used: %d (page breaks decided from layout geometry)\n", $pagesUsed);A saída padrão esperada (STDOUT) é esta. Os números da caixa da página refletem o tamanho de página A4 padrão, e o cursor começa na origem do conteúdo no canto superior esquerdo:
Page box: 595.28 x 841.89 ptCursor start: (<x>, <y>)Pages used: 2 (page breaks decided from layout geometry)Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Leia antes de a página existir.
getPageWidth()egetPageHeight()refletem a página atual, então chame-os apósaddPage(). Antes da primeira página, eles retornam a geometria do tamanho de página padrão, não a de uma página que você ainda não adicionou. - As regiões são retângulos no espaço do autor. Um
PageRegionyé medido como distância no espaço do autor a partir do canto superior esquerdo, de forma consistente comgetY(). Não misture essa medida com coordenadas PDF brutas a partir do canto inferior esquerdo. - As leituras são livres de efeitos colaterais. Nenhum dos métodos de consulta avança o cursor nem emite conteúdo. Chamá-los em um laço de alta frequência é seguro e custa pouco.
- As margens podem mudar por página. Se uma página posterior definir margens diferentes, releia
getMargins()em vez de armazenar em cache o primeiro valor. - As regiões não reformatam o texto automaticamente. Uma região de não escrita é uma restrição que você deve respeitar, não um limite automático para quebra de texto. A receita mostra a verificação explícita de colisão. Em escritas com posicionamento livre, o engine nunca move o conteúdo para fora de uma região por conta própria.
Desempenho
Seção intitulada “Desempenho”Cada método descrito aqui faz apenas uma leitura de propriedade. Ele é executado em tempo constante, sem alocação e sem entrada ou saída. O exemplo cria um pequeno documento de várias páginas bem dentro do orçamento de 1500 ms / 96 MB. O perfil de reprodutibilidade é semântico, porque o PDF gerado carrega o /ID do trailer e os metadados de criação. As decisões de geometria observáveis do exemplo são o aspecto relevante; por isso, a estrutura de testes valida essas decisões por meio de uma comparação estrutural de abstract syntax tree (AST) combinada com os metadados, em vez de um hash de bytes.
Notas de segurança
Seção intitulada “Notas de segurança”- Residência de dados e mitigações de PII. Não aplicável. A receita lê a geometria e posiciona o texto fornecido pelo chamador, portanto não introduz nenhum novo caminho de dados. Aplique ao texto que você posiciona o mesmo princípio de minimização que aplicaria em qualquer outro lugar.
- Telemetria segura e limpeza de logs. O exemplo imprime números de geometria e uma linha de progresso fixa. Ele não registra em log o texto do documento.
- Modelo de ameaças. Não aplicável. A interface de consulta é somente leitura e não analisa nenhuma entrada externa. Ela não é um limite de confiança.
- Comportamento no modo FIPS. Não aplicável. Nenhuma operação criptográfica é executada.
Conformidade
Seção intitulada “Conformidade”| Declaração | Especificação | Cláusula | reference_id |
|---|---|---|---|
| Um objeto de página define sua extensão por meio de caixas de limite (MediaBox). | ISO 32000-2 | §7.7.3.3 | |
| O retângulo da página é o limite do conteúdo. | ISO 32000-2 | §7.7.3.3 | |
| As posições são medidas no espaço do usuário; uma unidade é 1/72 de polegada. | ISO 32000-2 | §8.3.2 |
Esta receita lê a geometria definida pelas cláusulas citadas da ISO 32000-2 sobre caixa de página e espaço do usuário. Ela não declara conformidade integral com a ISO 32000-2. A interface de consulta de layout depende dessas cláusulas.