Menyusun teks CJK dengan pengodean sadar cmap
Sekilas pandang
Bagian berjudul “Sekilas pandang”Resep ini mendaftarkan wajah fon TrueType Tionghoa, Jepang, dan Korea (CJK), lalu mengenkode teks Tionghoa Tradisional melalui fasad FontInfo::encodeText() yang sadar cmap. Fasad ini mengembalikan aliran bita CID dua-bita Identity-H. Resep ini mengikuti examples/35-cjk-cmap-demo.php. Baca catatan cakupan sebelum Anda mengandalkannya.
Cakupan dan status (baca dahulu)
Bagian berjudul “Cakupan dan status (baca dahulu)”Arsitektur enkode teks yang sadar cmap dirilis secara bertahap (ADR-013). Fase 1 sudah tersedia: fasad FontInfo::encodeText() dan strategi enkode yang sadar cmap telah terpasang dan dapat dijangkau dari ranah pengguna. Fase 2 sedang berjalan: fase ini mengarahkan renderer dan penulis melalui fasad tersebut. Fase 3 dan 4 masih tertunda: emisi /ToUnicode, /CIDSystemInfo, /Encoding, dan /CIDToGIDMap per fon, serta resolver fon pengganti, belum terpasang di penulis.
Rencanakan dengan mempertimbangkan konsekuensi berikut:
- Resep ini mendemonstrasikan fasad enkode, bukan mode penulisan vertikal yang lengkap. Saat ini, permukaan dokumen tidak memiliki API mode penulisan publik, sehingga tidak ada panggilan
setWritingModedan tidak ada penyetelvertical-rl. - Berdasarkan tajuknya sendiri, contoh pendukungnya adalah uji asap integrasi, bukan fikstur kesesuaian. Validasi PDF/UA-2 dan PDF/A-4 akan gagal untuk keluaran yang diproduksi dengan cara ini hingga Fase 3 dan 4 tersedia. Jangan menyatakan bahwa keluaran dari jalur ini telah sesuai. Pemeriksalah yang menentukan kesesuaian, dan saat ini pemeriksa belum akan meloloskan keluaran ini.
- Infrastruktur metrik penulisan vertikal ada, tetapi bersifat internal. Infrastruktur itu mencakup objek nilai
CjkVerticalMetricsserta emiter/W2dan/DW2. NextPDF tidak memaparkannya sebagai panggilan “tulis secara vertikal” di ranah pengguna, dan penulis belum memancarkan kamus-kamus tersebut.
Instalasi
Bagian berjudul “Instalasi”composer require nextpdf/core:^3Batasan ini sesuai dengan paket nextpdf/core. Contoh ini berjalan pada PHP 8.4. Fikstur uji Noto Sans TC yang disertakan membuat resep ini mandiri.
Tinjauan konseptual
Bagian berjudul “Tinjauan konseptual”ISO 32000-2 memodelkan emisi teks dalam tiga lapisan: titik kode Unicode, kode karakter, dan ID glif. Untuk wajah fon TrueType CJK, mesin menggunakan fon Type 0 komposit dengan enkode Identity-H. Dengan enkode ini, untaian yang ditampilkan menggunakan pasangan bita yang mengindeks CIDFont (ISO 32000-2).
FontRegistry::register() mengurai wajah fon. FontInfo::encodeText($unicodeText) kemudian menentukan strategi enkode melalui FontEncodingStrategyResolver. Untuk wajah CJK TrueType yang terdaftar, fungsi ini mendelegasikan ke TrueTypeCmapStrategy. EncodedGlyphRun yang dikembalikan membawa aliran bita Identity-H, operand untaian PDF, lebar majuan per glif, titik kode yang digunakan, dan peta GID→Unicode. Pembuatan subset CJK menggunakan titik kode tersebut sesuai ADR-008. Aliran /ToUnicode di masa mendatang akan menggunakan peta GID→Unicode. Mode yang dipilih adalah EncodingMode::TwoByteCid.
Dua struktur CIDFont mendefinisikan penulisan vertikal di PDF. Yang pertama adalah larik metrik vertikal per glif /W2 (ISO 32000-2). Yang kedua adalah metrik vertikal baku /DW2 (ISO 32000-2). NextPDF menyediakan objek nilai dan emiter untuk keduanya melalui CjkVerticalMetrics::toW2Array(), toW2RangeArray(), dan toDw2Array(). Keduanya masih bersifat internal, dan penulis belum memancarkannya. Lihat catatan cakupan.
Permukaan API
Bagian berjudul “Permukaan API”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry.FontInfo::encodeText(string $unicodeText): EncodedGlyphRun—NextPDF\Typography\FontInfo. Fasad 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. Objek nilai metrik vertikal internal. Objek ini didokumentasikan demi transparansi, bukan sebagai jalur penulisan di ranah pengguna.
Tabel PHPDoc lengkap dihasilkan dari sumber.
Contoh kode — Mulai cepat
Bagian berjudul “Contoh kode — Mulai cepat”<?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";Contoh kode — Produksi
Bagian berjudul “Contoh kode — Produksi”Contoh ini bersifat mandiri dan dapat dijalankan melalui harnes. Contoh ini mencerminkan examples/35-cjk-cmap-demo.php. Pertama, daftarkan fikstur Noto Sans TC yang disertakan. Selanjutnya, pastikan fasad yang sadar cmap dapat dijangkau. Kemudian, render melalui DocumentFactory agar dokumen menggunakan registri yang telah Anda isi.
<?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 yang diharapkan:
Wrote cjk-vertical-writing.pdf (Phase 1+2 dry-run; not a conformance fixture)Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”- Bukan fikstur kesesuaian. Menurut tajuk contoh pendukungnya sendiri, keluaran ini adalah uji asap integrasi. Pemeriksaan PDF/UA-2 dan PDF/A-4 akan gagal untuk keluaran ini hingga Fase 3 dan 4 tersedia. Jangan mendaftarkannya sebagai fikstur golden untuk kesesuaian.
- Tidak ada API mode penulisan. Tidak ada panggilan publik yang mengaktifkan penulisan vertikal, yang akan mencakup
vertical-rldanvertical-lr. Emiter/W2dan/DW2ada secara internal. Keduanya tidak dipaparkan dan belum ditulis ke dalam kamus fon. - Kepemilikan registri.
Document::createStandalone()membangun registrinya sendiri. GunakanDocumentFactoryagar dokumen membaca registri yang telah Anda isi dengan wajah CJK. - Jalur aliran bita akhir. Hingga Fase 2 selesai, aliran konten yang terlihat masih melewati jalur teks lama. Bagian yang terbukti dan dapat dijangkau saat ini adalah langkah enkode hulu: pencarian maju cmap ditambah aliran bita Identity-H.
- Biaya pembuatan subset CJK. Wajah CJK berukuran besar dibuat menjadi subset melalui subproses terisolasi. Subproses itu memiliki fallback PHP-native dan batas waktu dua detik (ADR-008).
Kinerja
Bagian berjudul “Kinerja”encodeText() melakukan satu kali lintasan pencarian maju cmap pada masukan. Operasinya linear terhadap jumlah titik kode, O(n). Anggarannya adalah wall_ms: 2000, peak_mb: 128. Anggaran ini merupakan yang tertinggi di jalur ini karena wajah CJK berukuran besar, dan pembuatan subset adalah biaya yang dominan. ADR-008 mengisolasi pekerjaan itu agar tidak dapat memblokir pemanggil.
Catatan keamanan
Bagian berjudul “Catatan keamanan”Berkas fon CJK adalah masukan biner yang tidak tepercaya. Pengurai menolak jalur pembungkus stream dan bita null. Pembuatan subset CJK berjalan dalam subproses terisolasi tanpa status warisan (ADR-008). Validasi asal-usul wajah fon yang dipasok pengguna akhir. Konten teks CJK dirender, bukan ditafsirkan.
Kesesuaian
Bagian berjudul “Kesesuaian”| Pernyataan | Spesifikasi | Klausa | reference_id |
|---|---|---|---|
| Untuk fon Type 0 Identity-H/Identity-V, untaian yang ditampilkan berupa pasangan bita yang mengindeks CIDFont. | ISO 32000-2 | iso32000_2_sec9#x1.x49.p90 | |
| Larik W2 memberikan metrik penulisan vertikal per glif dan hanya berlaku untuk CIDFont yang digunakan untuk penulisan vertikal. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p23 | |
| Larik DW2 memberikan metrik penulisan vertikal baku untuk sebuah CIDFont. | ISO 32000-2 | iso32000_2_sec9#x1.x44.p22 |
Resep ini menunjukkan bahwa fasad enkode CJK yang sadar cmap dapat dijangkau dari ranah pengguna (Fase 1). Resep ini tidak mengeklaim keluaran penulisan vertikal atau kesesuaian PDF/UA-2 / PDF/A-4 untuk berkas yang dihasilkan. Emisi /ToUnicode dan metrik vertikal di sisi penulis (Fase 3 dan 4) masih tertunda, dan saat ini pemeriksa belum akan meloloskan keluaran ini.
Konteks komersial
Bagian berjudul “Konteks komersial”Tidak berlaku.