Lewati ke konten

Menyusun teks CJK dengan pengodean sadar cmap

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.

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 setWritingMode dan tidak ada penyetel vertical-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 CjkVerticalMetrics serta emiter /W2 dan /DW2. NextPDF tidak memaparkannya sebagai panggilan “tulis secara vertikal” di ranah pengguna, dan penulis belum memancarkan kamus-kamus tersebut.
Terminal window
composer require nextpdf/core:^3

Batasan ini sesuai dengan paket nextpdf/core. Contoh ini berjalan pada PHP 8.4. Fikstur uji Noto Sans TC yang disertakan membuat resep ini mandiri.

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.

  • FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistry.
  • FontInfo::encodeText(string $unicodeText): EncodedGlyphRunNextPDF\Typography\FontInfo. Fasad Fase 1.
  • EncodedGlyphRunNextPDF\Typography\Encoding\EncodedGlyphRun (byteStream, pdfStringOperand, mode, advanceWidths, toUnicodeMap, usedCodepoints, glyphCount()).
  • EncodingModeNextPDF\Typography\Encoding\EncodingMode (SingleByte, TwoByteCid).
  • CjkVerticalMetricsNextPDF\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.

<?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 fired
echo $encoded->glyphCount() . " glyph run entries\n";

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)
  • 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-rl dan vertical-lr. Emiter /W2 dan /DW2 ada secara internal. Keduanya tidak dipaparkan dan belum ditulis ke dalam kamus fon.
  • Kepemilikan registri. Document::createStandalone() membangun registrinya sendiri. Gunakan DocumentFactory agar 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).

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.

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.

PernyataanSpesifikasiKlausareference_id
Untuk fon Type 0 Identity-H/Identity-V, untaian yang ditampilkan berupa pasangan bita yang mengindeks CIDFont.ISO 32000-2iso32000_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-2iso32000_2_sec9#x1.x44.p23
Larik DW2 memberikan metrik penulisan vertikal baku untuk sebuah CIDFont.ISO 32000-2iso32000_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.

Tidak berlaku.