CJK-tekst verwerken met cmap-bewuste codering
In een oogopslag
Sectie met titel “In een oogopslag”Dit recipe registreert een Chinees, Japans en Koreaans (CJK) TrueType-lettertype en codeert daarna traditioneel-Chinese tekst via de cmap-bewuste FontInfo::encodeText()-facade. De facade retourneert een Identity-H tweebyte-CID-bytestream. Het recipe volgt examples/35-cjk-cmap-demo.php. Lees de scope-notitie voordat je erop vertrouwt.
Scope en status (lees dit eerst)
Sectie met titel “Scope en status (lees dit eerst)”De cmap-bewuste tekstcodeerarchitectuur wordt in fasen uitgeleverd (ADR-013). Fase 1 is opgeleverd: de FontInfo::encodeText()-facade en de cmap-bewuste coderingsstrategie zijn aangesloten en bereikbaar vanuit userland. Fase 2 is in uitvoering: deze routeert de renderer en de writer via de facade. Fase 3 en 4 zijn nog in behandeling: de emissie per lettertype van /ToUnicode, /CIDSystemInfo, /Encoding en /CIDToGIDMap, plus de resolver voor vervangende lettertypen, zijn nog niet aangesloten op de writer.
Houd in je planning rekening met deze gevolgen:
- Dit recipe demonstreert de codeerfacade, niet een volledige modus voor verticaal schrijven. Het documentoppervlak heeft momenteel geen publieke API voor de schrijfmodus, dus er is geen
setWritingMode-aanroep en geenvertical-rl-setter. - Het onderliggende voorbeeld is, volgens de eigen kop, een integratie-smoketest, geen conformiteitsfixture. De validatie van PDF/UA-2 en PDF/A-4 zal regresseren voor uitvoer die op deze manier wordt geproduceerd, totdat fase 3 en 4 landen. Ga er niet van uit dat uitvoer via dit pad conform is. Een checker bepaalt conformiteit, en die laat deze uitvoer nog niet door.
- De infrastructuur voor metingen bij verticaal schrijven bestaat, maar is intern. Deze omvat het waardeobject
CjkVerticalMetricsen de emitters voor/W2en/DW2. NextPDF stelt deze niet beschikbaar als userland-aanroep voor “verticaal schrijven”, en de writer emitteert de bijbehorende dictionaries nog niet.
Installeren
Sectie met titel “Installeren”composer require nextpdf/core:^3De constraint komt overeen met het pakket nextpdf/core. Het voorbeeld draait op PHP 8.4. Dankzij de meegeleverde Noto Sans TC-testfixture blijft dit recipe op zichzelf staand.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”ISO 32000-2 modelleert tekstuitvoer in drie lagen: Unicode-codepunt, tekencode en glief-ID. Voor een CJK TrueType-lettertype gebruikt de engine een samengesteld Type 0-lettertype met Identity-H-codering. Met deze codering gebruikt de getoonde tekenreeks bytepaarindexen in de CIDFont (ISO 32000-2).
FontRegistry::register() parseert het lettertype. FontInfo::encodeText($unicodeText) bepaalt vervolgens een coderingsstrategie via FontEncodingStrategyResolver. Voor een geregistreerd TrueType CJK-lettertype dispatcht deze naar TrueTypeCmapStrategy. De geretourneerde EncodedGlyphRun bevat de Identity-H-bytestream, de PDF-tekenreeksoperand, de advance widths per glief, de gebruikte codepunten en de GID→Unicode-toewijzing. CJK-subsetting gebruikt de codepunten conform ADR-008. Een toekomstige /ToUnicode-stream zal de GID→Unicode-toewijzing gebruiken. De geselecteerde modus is EncodingMode::TwoByteCid.
Twee CIDFont-structuren definiëren verticaal schrijven in PDF. De eerste is de /W2-array met verticale metingen per glief (ISO 32000-2). De tweede is /DW2, de standaard verticale meting (ISO 32000-2). NextPDF levert het waardeobject en de emitters voor beide via CjkVerticalMetrics::toW2Array(), toW2RangeArray() en toDw2Array(). Ze zijn intern, en de writer emitteert ze nog niet. Zie de scope-notitie.
API-oppervlak
Sectie met titel “API-oppervlak”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry.FontInfo::encodeText(string $unicodeText): EncodedGlyphRun—NextPDF\Typography\FontInfo. De facade van fase 1.EncodedGlyphRun—NextPDF\Typography\Encoding\EncodedGlyphRun(byteStream,pdfStringOperand,mode,advanceWidths,toUnicodeMap,usedCodepoints,glyphCount()).EncodingMode—NextPDF\Typography\Encoding\EncodingMode(SingleByte,TwoByteCid).CjkVerticalMetrics—NextPDF\Typography\CjkVerticalMetrics. Intern waardeobject voor verticale metingen. Het is gedocumenteerd voor transparantie, niet als userland-schrijfpad.
De volledige PHPDoc-tabel wordt uit de broncode gegenereerd.
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”<?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";Codevoorbeeld — Productie
Sectie met titel “Codevoorbeeld — Productie”Dit voorbeeld is op zichzelf staand en uitvoerbaar via de harness. Het weerspiegelt examples/35-cjk-cmap-demo.php. Registreer eerst de meegeleverde Noto Sans TC-fixture. Controleer vervolgens dat de cmap-bewuste facade bereikbaar is. Render daarna via DocumentFactory, zodat het document de registry gebruikt die je hebt gevuld.
<?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";Verwachte STDOUT:
Wrote cjk-vertical-writing.pdf (Phase 1+2 dry-run; not a conformance fixture)Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- Geen conformiteitsfixture. Volgens de eigen kop van het onderliggende voorbeeld is deze uitvoer een integratie-smoketest. De controles voor PDF/UA-2 en PDF/A-4 regresseren ervoor totdat fase 3 en 4 landen. Gebruik deze uitvoer niet als conformiteits-golden.
- Geen API voor de schrijfmodus. Geen publieke aanroep schakelt over op verticaal schrijven, wat
vertical-rlenvertical-lrzou dekken. De emitters voor/W2en/DW2bestaan intern. Ze zijn niet beschikbaar gesteld en worden nog niet naar de lettertype-dictionary geschreven. - Eigenaarschap van de registry.
Document::createStandalone()bouwt een eigen registry. GebruikDocumentFactory, zodat het document de registry leest die je met het CJK-lettertype hebt gevuld. - Route van de uiteindelijke bytestream. Totdat fase 2 is afgerond, routeert de zichtbare contentstream nog steeds via het verouderde tekstpad. Het bewezen, bereikbare deel van vandaag is de upstream-coderingsstap: de voorwaartse cmap-lookup plus de Identity-H-bytestream.
- Kosten van CJK-subsetting. Grote CJK-lettertypen worden gesubset via een geïsoleerd subproces. Dat subproces heeft een PHP-native fallback en een time-out van twee seconden (ADR-008).
Prestaties
Sectie met titel “Prestaties”encodeText() maakt één voorwaartse cmap-lookup-pass over de invoer. Het is lineair in het aantal codepunten, O(n). Het budget is wall_ms: 2000, peak_mb: 128. Dit budget is het hoogste in deze reeks omdat CJK-lettertypen groot zijn en subsetting de dominante kostenpost is. ADR-008 isoleert dat werk, zodat het de aanroeper niet kan blokkeren.
Beveiligingsnotities
Sectie met titel “Beveiligingsnotities”Een CJK-lettertypebestand is niet-vertrouwde binaire invoer. De parser weigert stream-wrapper-paden en null-bytes. CJK-subsetting draait in een geïsoleerd subproces zonder overgenomen state (ADR-008). Valideer de herkomst van lettertypen die eindgebruikers aanleveren. CJK-tekstinhoud wordt weergegeven, niet geïnterpreteerd.
Conformiteit
Sectie met titel “Conformiteit”| Bewering | Spec | Clausule | reference_id |
|---|---|---|---|
| Voor een Identity-H/Identity-V Type 0-lettertype gebruikt de getoonde tekenreeks bytepaarindexen in de CIDFont. | ISO 32000-2 | iso32000_2_sec9#x1.x49.p90 | |
| De W2-array geeft verticale metingen per glief en is alleen van toepassing op CIDFonts die voor verticaal schrijven worden gebruikt. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p23 | |
| De DW2-array geeft de standaard verticale metingen voor een CIDFont. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p22 |
Dit recipe toont aan dat de cmap-bewuste CJK-codeerfacade bereikbaar is vanuit userland (fase 1). Het claimt geen uitvoer voor verticaal schrijven of PDF/UA-2- / PDF/A-4-conformiteit voor het geproduceerde bestand. De emissie aan writer-zijde van /ToUnicode en verticale metingen (fase 3 en 4) is nog in behandeling, en een checker zou deze uitvoer momenteel niet doorlaten.
Commerciële context
Sectie met titel “Commerciële context”Niet van toepassing.