콘텐츠로 이동

Content: 텍스트 + 구조화 콘텐츠 모델

Content 모듈은 텍스트 표시 연산자, 텍스트 상태 연산자, 텍스트 그림자, 문서 수준 JavaScript, 표시된 콘텐츠 속성 사전을 빌드합니다. 레이아웃과 콘텐츠 스트림 사이에 위치한 계층입니다.

Terminal window
composer require nextpdf/core:^3

Content는 해석된 텍스트를 PDF 연산자로 변환하는 프리미티브를 제공합니다. TextRenderer가 핵심 구성 요소입니다. 문자열에 대한 텍스트 표시 연산자와 그 앞에 오는 텍스트 상태 연산자를 빌드합니다. Tj 연산자는 현재 글꼴과 그 밖의 텍스트 관련 그래픽 매개변수로 문자열의 글리프를 그립니다 — ISO 32000-2 §9. TextRenderer는 활성 TypographyMode에 따라 단일 표시 연산자와 위치가 지정된 TJ 배열 중 하나를 선택합니다. 모드가 TJ 배열을 사용하는 경우 커닝 조정을 적용합니다.

텍스트 상태도 완전하게 모델링되어 있습니다. setTextRenderingMode()TextRenderingMode 열거형을 받습니다. 여덟 가지 케이스는 ISO 32000-2 텍스트 렌더링 모드(채우기, 스트로크, 채우기 후 스트로크, 보이지 않음, 그리고 네 가지 클립 변형)에 일대일로 매핑됩니다(Table 104). 렌더러는 스트로크 너비, 문자 및 단어 간격, 가로 늘이기, 텍스트 올림, 오른쪽에서 왼쪽 방향, 선택적 Hyphenator도 제어합니다. buildTextStateOperators()를 호출하면 누적된 상태가 단일 연산자 블록으로 출력됩니다.

TextShadow는 값 객체입니다 — 색상, 사용자 단위의 X 및 Y 오프셋, 불투명도를 담습니다. 렌더러는 이를 사용해 오프셋된 두 번째 그리기 패스를 출력합니다. 기본 오프셋은 0.5 불투명도를 가진 미세한 0.5/−0.5이며, CSS 스타일의 부드러운 그림자에 해당합니다.

JavaScriptManager는 문서 수준 스크립팅을 담당합니다. includeJs()는 문서 스크립트를 등록합니다. addJsObject()는 명명된 스크립트 객체를 등록합니다. writeJavaScript() / writeOpenAction()는 이를 카탈로그와 OpenAction에 직렬화합니다. 매니저는 출력 전에 모든 스크립트 본문을 방어 처리하고 PDF 문자열로 인코딩합니다.

PropertiesRegistry는 표시된 콘텐츠 속성 저장소입니다. register()는 속성 사전에 대해 안정적인 태그 인덱스를 반환합니다. registerOcg() / registerOcgs()는 선택적 콘텐츠 그룹을 객체 번호에 바인딩합니다. writeProperties()는 레지스트리를 페이지 리소스 사전에 직렬화합니다. ContentStream 모듈이 속성 목록과 함께 표시된 시퀀스를 열 때 참조하는 데이터입니다.

두 이미지 디코더가 여기에 포함된 이유는 이들이 PDF 네이티브 패스스루 형식이기 때문입니다. JBig2LoaderJpxLoader는 JBIG2 및 JPEG 2000 세그먼트 구조를 파싱하고, 픽셀을 래스터화하지 않은 채 ImageData를 반환합니다. 인코딩된 바이트는 변경 없이 뷰어로 전달됩니다. JBIG2 소스가 별도의 globals 세그먼트를 포함하는 경우, JBig2Loader는 이미지 XObject의 /JBIG2Globals 스트림 참조를 통해 이를 임베드합니다. in-stream/in-line 형식은 이전과 같이 계속 라운드트립됩니다. 이는 구조적 연결일 뿐입니다 — globals 바이트는 디코딩되지 않고 래스터화 없이 그대로 전달됩니다.

클래스주요 메서드역할
TextRendererbuildTextShowOperator(), buildTextStateOperators(), setTextRenderingMode(), setTextStrokeWidth(), setTextShadow(), setFontSpacing(), setWordSpacing(), setFontStretching(), setTextRise(), setRTL(), setHyphenation()텍스트 표시 + 텍스트 상태 연산자 빌더
TextRenderingMode (열거형)Fill, Stroke, FillStroke, Invisible, FillClip, StrokeClip, FillStrokeClip, ClipISO 32000-2 텍스트 렌더링 모드
TextShadow__construct(Color, offsetX, offsetY, opacity)오프셋 그리기 패스 값 객체
JavaScriptManagerincludeJs(), addJsObject(), hasJavaScript(), writeJavaScript(), writeOpenAction()문서 수준 JavaScript 카탈로그 연결
PropertiesRegistryregister(), getTagIndex(), registerOcg(), registerOcgs(), getAll(), writeProperties()표시된 콘텐츠 + OCG 속성 저장소
JBig2Loaderload(), loadFromString(), parseSegments()JBIG2 패스스루 디코더
JpxLoaderload(), loadFromString(), parseBoxes()JPEG 2000 패스스루 디코더

전체 PHPDoc 표를 확인하려면 composer docs:generate-api-php -- --module=Content를 실행하십시오.

소스: examples/28-text-rendering.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;
use NextPDF\Content\TextRenderingMode;
$renderer = new TextRenderer();
$renderer
->setTextRenderingMode(TextRenderingMode::FillStroke)
->setTextStrokeWidth(0.3)
->setWordSpacing(0.5);
$stateOps = $renderer->buildTextStateOperators();

다음 예시는 부드러운 그림자와 하이프네이터를 추가한 뒤, 호출자가 제공한 이스케이프 함수(ADR-015의 정식 PdfStringEscaper 연결 지점)로 표시 연산자를 빌드합니다.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;
use NextPDF\Content\TextShadow;
use NextPDF\Graphics\Color;
use NextPDF\Support\PdfStringEscaper;
$renderer = new TextRenderer();
$renderer
->setTextShadow(new TextShadow(Color::rgb(0, 0, 0), 0.4, -0.4, 0.45))
->setRTL(false);
$showOp = $renderer->buildTextShowOperator(
text: 'Quarterly report',
fontKey: 'F1',
metrics: $fontMetrics,
escapeSegment: static fn (string $s): string => PdfStringEscaper::escapeLiteral($s),
);
$pageContent = $renderer->buildTextStateOperators() . $showOp;
  • buildTextShowOperator()는 빈 입력이면 빈 문자열을 반환합니다. 빈 Tj는 출력하지 않아야 합니다 — 레이아웃이 빈 런을 생성할 수 있다면 상위 레이어에서 방어해야 합니다.
  • 이스케이프 콜백은 필수이며 문자열 안전성을 담당합니다. 정식 PdfStringEscaper::escapeLiteral()를 전달해야 합니다 (ADR-015). 불완전한 이스케이퍼는 구문상 손상된 리터럴 문자열을 생성합니다.
  • TextShadow::offsetY는 왼쪽 위 원점을 기준으로 아래쪽이 음수입니다. 양수 Y는 그림자를 위로 밀어 올리며, 이는 의도된 경우가 드뭅니다.
  • JavaScriptManager는 스크립트 입력을 방어합니다. 유효하지 않은 스크립트 본문은 쓰기 시점에 조용히 폐기되지 않으며, 등록 시점에 거부됩니다.
  • JBig2LoaderJpxLoader는 절대 래스터화하지 않습니다. 이들은 인코딩된 바이트를 검증한 뒤 그대로 전달합니다. 손상된 세그먼트는 빈 이미지가 아니라 파싱 오류로 표면화됩니다.
  • PropertiesRegistry::register()는 사전별로 멱등적입니다 — 동일한 속성 사전은 하나의 태그 인덱스를 재사용합니다.

연산자 구성은 문자열 길이에 대해 O(n)이며, 타이포그래피 모드가 TJ 배열을 사용할 때 O(n) 커닝 패스가 추가됩니다. 여기에는 레이아웃이나 셰이핑 비용이 포함되지 않습니다 — 해당 비용은 Typography 및 Layout 모듈에 남습니다. JavaScript 및 속성 직렬화는 O(entries)입니다. 패스스루 이미지 로더는 디코딩 비용이 0인 O(bytes) 파싱입니다. 이는 스캔된 문서 워크로드에서 패스스루 이미지 로더의 주요 장점입니다. 참조 워크로드의 performance_budget는 벽시계 시간 1500 ms 및 피크 64 MB입니다.

JavaScriptManager는 신뢰할 수 없는 템플릿에서 비롯될 수 있는 스크립트 본문을 받습니다. 모든 본문을 방어 처리하고 PDF 문자열로 인코딩하지만, 문서 JavaScript는 여전히 활성 콘텐츠 표면입니다. 신뢰할 수 없는 출력에서는 이를 비활성화하거나, /modules/core/security/에 설명된 새니타이징 경로로 제거해야 합니다. JBig2LoaderJpxLoader는 신뢰할 수 없는 세그먼트 구조를 파싱합니다. 입력 크기와 파싱 시간을 제한하고, 소스가 사용자 제공인 경우 제한된 워커에서 추출을 실행해야 합니다. 텍스트 이스케이프 경계는 호출자가 제공한 콜백입니다. 제어 바이트가 리터럴 문자열을 벗어날 수 없도록 항상 정식 이스케이퍼를 전달해야 합니다.

이 모듈은 ISO 32000-2 §9 텍스트 모델과 일치하는 텍스트 표시 및 텍스트 상태 연산자를 출력합니다. 여기에는 Tj 연산자 의미론과 TextRenderingMode 열거형이 미러링하는 Table 104 렌더링 모드가 포함됩니다. 이는 구현 사실입니다. 연산자 형태는 src/Content/TextRenderer.phpTextRenderingMode 열거형에 의해 생성되며, tests/Unit/Content/TextRenderer*, JavaScriptManagerIsoTest, 그리고 PropertiesRegistryTest에서 검증됩니다. 이들은 종단 간 PDF 2.0 적합성을 단언하지 않습니다. 문자열 이스케이프 계약은 ADR-015 및 ISO 32000-2 §7.3.4.2를 따릅니다. JBIG2 및 JPEG 2000 패스스루 경로는 인코딩된 스트림을 변경하지 않고 보존합니다. 별도의 JBIG2 globals 세그먼트는 이미지 XObject의 /JBIG2Globals 스트림 참조로 임베드됩니다 — 디코딩 충실도 주장이 아니라 구조적 연결로서 검증됩니다. 문서 수준 적합성은 /modules/core/conformance/의 오라클 및 골든 스위트로 검증됩니다.