cmap 인식 인코딩으로 CJK 텍스트 처리
한눈에 보기
섹션 제목: “한눈에 보기”이 레시피는 CJK TrueType 페이스를 등록한 뒤, cmap 인식 FontInfo::encodeText() 파사드로 번체 중국어 텍스트를 인코딩합니다. 이 파사드는 Identity-H 2 바이트 CID 바이트 스트림을 생성합니다. 이 레시피는 examples/35-cjk-cmap-demo.php를 따릅니다. 이 동작에 의존하기 전에 아래 범위 안내를 읽어 보십시오.
범위 및 상태(먼저 읽기)
섹션 제목: “범위 및 상태(먼저 읽기)”cmap 인식 텍스트 인코딩 아키텍처는 단계적으로 도입됩니다(ADR-013). 1 단계가 도입되었습니다: FontInfo::encodeText() 파사드와 cmap 인식 인코딩 전략이 연결되어 사용자 영역에서 접근할 수 있습니다. 2 단계가 진행 중입니다: 렌더러와 라이터가 파사드를 통해 라우팅되도록 합니다. 3 단계와 4 단계는 보류 중입니다: 글꼴별 /ToUnicode, /CIDSystemInfo, /Encoding, /CIDToGIDMap 방출과 대체 글꼴 리졸버가 아직 라이터에 연결되지 않았습니다.
다음 사항을 고려해 계획하십시오:
- 이 레시피는 바로 사용할 수 있는 세로쓰기 모드가 아니라 인코딩 파사드를 보여줍니다. 현재 문서 표면에는 공개 쓰기 모드 API가 없으며, 이는
setWritingMode도 없고vertical-rl세터도 없음을 의미합니다. - 기반 예제의 자체 헤더에 따르면 이 예제는 적합성 픽스처가 아니라 통합 스모크 테스트입니다. 3 단계와 4 단계가 도입되기 전까지, 이 방식으로 생성된 출력에 대한 PDF/UA-2 및 PDF/A-4 검증 결과는 퇴행합니다. 이 경로에서 생성된 출력이 적합하다고 명시하지 마십시오. 적합성은 검사기가 결정하며, 검사기는 아직 이 출력을 통과시키지 않습니다.
- 세로쓰기 메트릭 인프라는 존재하지만 내부 기능입니다. 이는
CjkVerticalMetrics값 객체와/W2및/DW2방출기로 구성됩니다. NextPDF는 이를 사용자 영역의 “세로쓰기” 호출로 노출하지 않으며, 라이터는 아직 해당 딕셔너리를 방출하지 않습니다.
composer require nextpdf/core:^3이 제약 조건은 nextpdf/core 패키지와 일치합니다. 예제는 PHP 8.4에서 실행됩니다. 번들로 제공되는 Noto Sans TC 테스트 픽스처가 레시피를 자체 완결형으로 유지합니다.
개념 개요
섹션 제목: “개념 개요”ISO 32000-2는 텍스트 방출을 세 가지 계층으로 모델링합니다: 유니코드 코드포인트, 문자 코드, 글리프 ID. CJK TrueType 페이스의 경우, 엔진은 Identity-H 인코딩을 사용하는 복합 Type 0 글꼴을 사용합니다. 이 인코딩에서 표시되는 문자열은 CIDFont를 인덱싱하는 바이트 쌍입니다(ISO 32000-2).
FontRegistry::register()는 페이스를 파싱합니다. 그런 다음 FontInfo::encodeText($unicodeText)가 FontEncodingStrategyResolver를 통해 인코딩 전략을 결정합니다. 등록된 TrueType CJK 페이스의 경우, TrueTypeCmapStrategy로 디스패치합니다. 반환된 EncodedGlyphRun은 Identity-H 바이트 스트림, PDF 문자열 피연산자, 글리프별 전진 폭, 사용된 코드포인트, GID→유니코드 맵을 포함합니다. CJK 서브셋팅은 ADR-008에 따라 사용된 코드포인트를 소비합니다. 향후 /ToUnicode 스트림은 GID→유니코드 맵을 사용할 것입니다. 선택된 모드는 EncodingMode::TwoByteCid입니다.
PDF에서 세로쓰기를 정의하는 CIDFont 구조는 두 가지입니다. 첫 번째는 /W2 글리프별 세로 메트릭 배열입니다(ISO 32000-2). 두 번째는 /DW2 기본 세로 메트릭입니다(ISO 32000-2). NextPDF는 CjkVerticalMetrics::toW2Array(), toW2RangeArray(), toDw2Array()를 통해 두 구조 모두를 위한 값 객체와 방출기를 제공합니다. 이들은 내부 기능이며, 라이터는 아직 이를 방출하지 않습니다. 범위 안내를 참조하십시오.
API 표면
섹션 제목: “API 표면”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry.FontInfo::encodeText(string $unicodeText): EncodedGlyphRun—NextPDF\Typography\FontInfo. 1 단계 파사드입니다.EncodedGlyphRun—NextPDF\Typography\Encoding\EncodedGlyphRun(byteStream,pdfStringOperand,mode,advanceWidths,toUnicodeMap,usedCodepoints,glyphCount()).EncodingMode—NextPDF\Typography\Encoding\EncodingMode(SingleByte,TwoByteCid).CjkVerticalMetrics—NextPDF\Typography\CjkVerticalMetrics. 내부 세로 메트릭 값 객체입니다. 이는 사용자 영역의 쓰기 경로가 아니라 투명성을 위해 문서화되었습니다.
전체 PHPDoc 표는 소스에서 생성됩니다.
코드 샘플 — 빠른 시작
섹션 제목: “코드 샘플 — 빠른 시작”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Typography\Encoding\EncodingMode;use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();$font = $registry->register('/path/to/NotoSansTC-Regular.ttf', alias: 'NotoSansTC');
$encoded = $font->encodeText('PDF 2.0 引擎');
assert($encoded->mode === EncodingMode::TwoByteCid); // cmap-aware branch firedecho $encoded->glyphCount() . " glyph run entries\n";코드 샘플 — 프로덕션
섹션 제목: “코드 샘플 — 프로덕션”이 샘플은 자체 완결형이며 하니스에서 실행할 수 있습니다. examples/35-cjk-cmap-demo.php를 그대로 반영합니다. 먼저 번들로 제공되는 Noto Sans TC 픽스처를 등록합니다. 다음으로 cmap 인식 파사드에 접근할 수 있는지 확인합니다. 그런 다음 DocumentFactory를 통해 렌더링하여, 채워 둔 레지스트리가 사용되도록 합니다.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\Encoding\EncodingMode;use NextPDF\Typography\FontRegistry;
$cjkFontPath = dirname(__DIR__, 2) . '/fonts/test-fixtures/Noto Sans TC/NotoSansTC-Regular.ttf';if (!is_file($cjkFontPath)) { fwrite(STDERR, "Missing CJK font fixture: {$cjkFontPath}\n"); exit(1);}
$fontRegistry = new FontRegistry();$cjkFont = $fontRegistry->register($cjkFontPath, alias: 'NotoSansTC');
// Phase 1 facade: prove the cmap-aware path is reachable from userland.$cjkSample = 'PDF 2.0 引擎 — 使用 CMap 編碼';$encoded = $cjkFont->encodeText($cjkSample);
if ($encoded->mode !== EncodingMode::TwoByteCid) { fwrite(STDERR, "Expected TwoByteCid (TrueTypeCmapStrategy branch)\n"); exit(2);}
$imageRegistry = new ImageRegistry(maxCacheBytes: 0);$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$doc = $documentFactory->create();$doc->setTitle('NextPDF CJK CMap-Aware Encoding Demo');$doc->setLanguage('zh-Hant');$doc->addPage();
$doc->setFont('helvetica', 'B', 16);$doc->cell(0, 12, 'CJK cmap-aware encoding (Phase 1 facade)', newLine: true);$doc->setFont('helvetica', '', 10);$doc->cell(0, 6, 'Mode: ' . $encoded->mode->name . ' (Identity-H, 2-byte CIDs)', newLine: true);$doc->cell(0, 6, 'Glyphs: ' . $encoded->glyphCount() . ' run entries', newLine: true);$doc->cell(0, 6, 'Bytes: ' . strlen($encoded->byteStream) . ' encoded bytes', newLine: true);$doc->ln(4);
$doc->setFont('NotoSansTC', '', 18);$doc->cell(0, 12, $cjkSample, newLine: true);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/cjk-vertical-writing.pdf');
echo "Wrote cjk-vertical-writing.pdf (Phase 1+2 dry-run; not a conformance fixture)\n";예상 STDOUT:
Wrote cjk-vertical-writing.pdf (Phase 1+2 dry-run; not a conformance fixture)엣지 케이스 및 주의 사항
섹션 제목: “엣지 케이스 및 주의 사항”- 적합성 픽스처가 아닙니다. 기반 예제의 자체 헤더에 따르면, 이 출력은 통합 스모크 테스트입니다. 3 단계와 4 단계가 도입되기 전까지, 이 출력에 대한 PDF/UA-2 및 PDF/A-4 검사는 퇴행합니다. 이를 적합성 골든으로 등록하지 마십시오.
- 쓰기 모드 API가 없습니다.
vertical-rl및vertical-lr을 포괄해 세로쓰기로 전환하는 공개 호출이 없습니다./W2및/DW2방출기는 내부적으로 존재합니다. 이들은 노출되지 않으며 아직 글꼴 딕셔너리에 기록되지 않습니다. - 레지스트리 소유권.
Document::createStandalone()는 자체 레지스트리를 빌드합니다.DocumentFactory를 사용하여 문서가 CJK 페이스로 채워 둔 레지스트리를 읽도록 하십시오. - 최종 바이트 스트림 경로. 2 단계가 완료되기 전까지, 보이는 콘텐츠 스트림은 여전히 레거시 텍스트 경로를 통해 라우팅됩니다. 현재 검증되고 도달 가능한 부분은 업스트림 인코딩 단계로, 이는 cmap 정방향 조회와 Identity-H 바이트 스트림입니다.
- CJK 서브셋팅 비용. 대용량 CJK 페이스는 격리된 하위 프로세스를 통해 서브셋됩니다. 해당 하위 프로세스에는 PHP 네이티브 폴백과 2 초 타임아웃이 있습니다(ADR-008).
encodeText()는 입력을 단일 패스로 처리하며 cmap 정방향 조회를 수행합니다. 코드포인트 수에 대해 선형인 O(n)입니다. 예산은 wall_ms: 2000, peak_mb: 128입니다. CJK 페이스는 크고 서브셋팅 비용이 가장 크기 때문에, 이 예산은 이 세트에서 가장 높게 잡혀 있습니다. ADR-008은 해당 작업을 격리하여 호출자를 차단하지 못하도록 합니다.
보안 참고 사항
섹션 제목: “보안 참고 사항”CJK 글꼴 파일은 신뢰할 수 없는 바이너리 입력입니다. 파서는 스트림 래퍼 경로와 널 바이트를 거부합니다. CJK 서브셋팅은 상속된 상태가 없는 격리된 하위 프로세스에서 실행됩니다(ADR-008). 최종 사용자가 제공한 페이스라면 글꼴 출처를 검증하십시오. CJK 텍스트 콘텐츠는 해석되지 않고 렌더링됩니다.
적합성
섹션 제목: “적합성”| 진술 | 사양 | 조항 | reference_id |
|---|---|---|---|
| Identity-H/Identity-V Type 0 글꼴의 경우, 표시되는 문자열은 CIDFont를 인덱싱하는 바이트 쌍입니다. | ISO 32000-2 | iso32000_2_sec9#x1.x49.p90 | |
| W2 배열은 글리프별 세로쓰기 메트릭을 제공하며 세로쓰기에 사용되는 CIDFont에만 적용됩니다. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p23 | |
| DW2 배열은 CIDFont의 기본 세로쓰기 메트릭을 제공합니다. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p22 |
이 레시피는 cmap 인식 CJK 인코딩 파사드가 사용자 영역에서 접근 가능함을 보여줍니다(1 단계). 이는 생성된 파일에 대해 세로쓰기 출력이나 PDF/UA-2 / PDF/A-4 적합성을 주장하지 않습니다. 라이터 측의 /ToUnicode 및 세로 메트릭 방출(3 단계와 4 단계)은 보류 중이며, 검사기는 현재 이 출력을 통과시키지 않습니다.
상업적 컨텍스트
섹션 제목: “상업적 컨텍스트”해당 없음.