콘텐츠로 이동

레이아웃: 머리글, 바닥글, 단, 소책자, 페이지 관리자

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는 반복되는 머리글과 바닥글을 렌더링합니다. 각 영역은 제목, 설명, 로고, 글꼴, 여백, 색상 상태를 보유합니다. renderHeader()renderFooter()를 통해 요청 시 PDF 콘텐츠 스트림 연산자를 생성합니다. 기본 바닥글은 오른쪽 정렬된 "page / total" 문자열을 출력합니다. setHeaderCallback()setFooterCallback()는 기본 레이아웃을 호출자가 제공한 클로저로 대체합니다. getHeaderContentHeight()는 머리글이 차지하는 세로 공간을 반환하여 페이지 본문이 그 아래에서 시작될 수 있게 합니다. 문서가 태그된 PDF 모드인 경우 머리글 콘텐츠가 구조 트리 밖에 위치하므로, 자동 머리글은 상위 단계인 HasPages에서 억제됩니다.

ColumnLayout는 다단 흐름을 관리합니다. setEqualColumns(int $count, float $totalWidth, float $gap = 5)는 사용 가능한 너비를 동일한 너비의 단으로 나눕니다. setColumnsArray()는 명시적인 ColumnDefinition 위치와 너비를 받습니다. 커서는 selectColumn()으로 단을 선택하거나 nextColumn()으로 다음 단으로 넘어갑니다. getCurrentColumnX() / getCurrentColumnWidth()는 활성 단의 X 좌표와 너비를 반환합니다. 단 개수가 잘못되었거나, 간격이 음수이거나, 계산된 단 너비가 양수가 아닌 경우 PageLayoutException이 발생합니다.

BookletLayout는 중철(가운데 접기) 제본을 위해 페이지를 재배열합니다. reorderPages()는 페이지 목록을 4의 배수로 채운 다음(소책자 한 장은 네 개의 페이지 슬롯을 담습니다), 접어서 스테이플로 고정했을 때 순서대로 읽히도록 페이지를 바깥쪽에서 안쪽으로 배치합니다. getMarginAdjustments()는 주어진 위치에 대해 구분된 안쪽(접지) 여백과 바깥쪽(가장자리) 여백을 반환합니다. getSheetCount()는 특정 페이지 수에 양면 용지가 몇 장 필요한지 알려 줍니다. 재배열은 콘텐츠 배치만 변경합니다. 기반 PDF 페이지 시퀀스는 선형으로 유지되며, 이는 문서 내 페이지의 순서를 정의하는 페이지 트리와 일치합니다(ISO 32000-2 §7.7).

PageManager는 콘텐츠 렌더링과 분리된 구조적 페이지 작업을 제공합니다. movePage(), copyPage(), deletePage()PageData 배열을 참조로 받아 작동합니다. 페이지 영역(addPageRegion(), isInRegion(), getRegionOffset())은 쓰기 금지 구역을 정의합니다. 페이지 그룹(startPageGroup(), getGroupPageNo())은 섹션별 페이지 번호 매기기를 지원합니다. PageRegionColumnDefinition은 엔진이 사용하는 두 개의 값 운반자입니다. 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() 호출 때마다 렌더링되고, 바닥글은 페이지가 플러시될 때 렌더링됩니다.

바닥글 콜백은 페이지 번호 텍스트를 담당하고, 단 엔진은 2단 본문 흐름을 처리합니다. 두 엔진 모두 파사드를 통해 접근합니다.

<?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()는 마지막 페이지의 치수에서 복제한 빈 페이지로 4의 배수까지 채웁니다. 페이지 목록이 비어 있으면 빈 배열을 반환합니다. 재배열은 배치에만 영향을 미치며, 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 렌더 경로로 한정되며, 이 레이아웃 엔진들을 직접 게이트하지 않습니다. 1500 ms / 64 MB의 performance_budget는 빠른 시작에 대한 캔버스 범위이며, 호출당 계약이 아닙니다.

이 엔진들은 호출자가 제공하는 문자열과 로고 경로를 사용합니다. 로고 경로는 이미지 엔진을 거치며, 이미지 엔진은 파일을 임베드하기 전에 이를 검증합니다. renderHeader()renderFooter()는 제목, 설명, 페이지 번호 텍스트가 콘텐츠 스트림에 도달하기 전에 중앙 집중식 PDF 문자열 이스케이퍼를 통해 이스케이프하므로, 호출자 텍스트가 리터럴 문자열 문법을 벗어날 수 없습니다. 머리글 또는 바닥글 콜백은 문서의 나머지 부분과 동일한 신뢰 수준으로 호출자 코드를 실행하므로, 콜백이 읽는 모든 외부 데이터도 그에 맞게 취급하십시오. PageManager 페이지 작업은 기존 PageData에 대한 참조를 이동하며, 신뢰할 수 없는 바이트를 파싱하지 않습니다.

주장표준조항근거
소책자 출력을 위한 페이지 재배열은 배치만 변경하며, 페이지 트리는 여전히 문서 내 페이지의 선형 순서를 정의합니다.ISO 32000-2§7.7
직렬화된 페이지 트리 노드의 Kids 항목은 해당 노드의 직접 자식에 대한 간접 참조 배열입니다.ISO 32000-2§7.7.3.2

조항은 의역되고 용어집에 고정되어 있으며, 규범적 텍스트는 재현되지 않습니다.