เข้ารหัสข้อความ CJK ด้วยการเข้ารหัสที่รับรู้ cmap
ภาพรวมโดยสังเขป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสังเขป”สูตรนี้ลงทะเบียนฟอนต์ TrueType สำหรับภาษาจีน ญี่ปุ่น และเกาหลี (CJK) แล้วเข้ารหัสข้อความภาษาจีนตัวเต็มผ่าน facade FontInfo::encodeText() ที่รับรู้ cmap โดย facade จะคืนค่าเป็นไบต์สตรีม CID แบบสองไบต์ Identity-H สูตรนี้อ้างอิงจาก examples/35-cjk-cmap-demo.php โปรดอ่านหมายเหตุเรื่องขอบเขตก่อนนำไปใช้งานจริง
ขอบเขตและสถานะ (อ่านก่อน)
หัวข้อที่มีชื่อว่า “ขอบเขตและสถานะ (อ่านก่อน)”สถาปัตยกรรมการเข้ารหัสข้อความที่รับรู้ cmap ถูกส่งมอบเป็นเฟส (ADR-013) เฟส 1 พร้อมใช้งานแล้ว: facade FontInfo::encodeText() และกลยุทธ์การเข้ารหัสที่รับรู้ cmap ได้รับการเชื่อมต่อและเข้าถึงได้จากฝั่งผู้ใช้แล้ว เฟส 2 อยู่ระหว่างดำเนินการ: เป็นการกำหนดเส้นทาง renderer และ writer ผ่าน facade เฟส 3 และ 4 ยังรอดำเนินการ: การปล่อย /ToUnicode, /CIDSystemInfo, /Encoding และ /CIDToGIDMap แบบต่อฟอนต์ รวมถึงตัวแก้ฟอนต์ทดแทน ยังไม่ได้เชื่อมต่อเข้ากับ writer
โปรดวางแผนโดยคำนึงถึงผลต่อไปนี้:
- สูตรนี้สาธิต facade การเข้ารหัส ไม่ใช่โหมดการเขียนแนวตั้งที่สมบูรณ์ พื้นผิว API ของเอกสารในปัจจุบันไม่มี API โหมดการเขียนแบบสาธารณะ จึงไม่มีการเรียก
setWritingModeและไม่มี settervertical-rlให้เรียกใช้ - ตามที่ระบุไว้ในส่วนหัวของตัวอย่างที่รองรับ ตัวอย่างนี้เป็น integration smoke test ไม่ใช่ conformance fixture การตรวจสอบความถูกต้อง PDF/UA-2 และ PDF/A-4 จะ ถดถอย สำหรับเอาต์พุตที่สร้างด้วยวิธีนี้ จนกว่าเฟส 3 และ 4 จะพร้อมใช้งาน อย่าระบุว่าเอาต์พุตจากเส้นทางนี้สอดคล้องตามมาตรฐาน ตัวตรวจสอบเป็นผู้ตัดสินความสอดคล้องตามมาตรฐาน และเอาต์พุตนี้ยังไม่ผ่าน
- โครงสร้างพื้นฐานของเมตริกการเขียนแนวตั้งมีอยู่แล้ว แต่เป็น การทำงานภายใน ประกอบด้วย value object
CjkVerticalMetricsและตัวปล่อยข้อมูล/W2และ/DW2NextPDF ไม่ได้เปิดเผยฟังก์ชันนี้เป็นการเรียก “write vertically” ในฝั่งผู้ใช้ และ writer ยังไม่ปล่อย dictionary สำหรับฟังก์ชันนี้
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”composer require nextpdf/core:^3ข้อกำหนดเวอร์ชันนี้ตรงกับแพ็กเกจ nextpdf/core ตัวอย่างนี้ทำงานบน PHP 8.4 โดยมี test fixture ของ Noto Sans TC ที่มาพร้อมกันช่วยให้สูตรนี้ทำงานได้ด้วยตัวเอง
ภาพรวมเชิงแนวคิด
หัวข้อที่มีชื่อว่า “ภาพรวมเชิงแนวคิด”ISO 32000-2 กำหนดโมเดลการปล่อยข้อความเป็นสามชั้น ได้แก่ Unicode codepoint, character code และ glyph ID สำหรับฟอนต์ TrueType แบบ CJK เอนจินจะใช้ฟอนต์ composite Type 0 พร้อมการเข้ารหัส Identity-H ด้วยการเข้ารหัสนี้ สตริงที่แสดงจะใช้คู่ไบต์ที่ทำดัชนีไปยัง CIDFont (ISO 32000-2)
FontRegistry::register() ทำการแจงข้อมูลฟอนต์ จากนั้น FontInfo::encodeText($unicodeText) จะเลือกกลยุทธ์การเข้ารหัสผ่าน FontEncodingStrategyResolver สำหรับฟอนต์ TrueType แบบ CJK ที่ลงทะเบียนไว้ จะส่งต่อไปยัง TrueTypeCmapStrategy EncodedGlyphRun ที่คืนค่ามาจะมีไบต์สตรีม Identity-H, PDF string operand, ความกว้างการเลื่อนต่อ glyph, codepoint ที่ใช้งาน และแมป GID→Unicode การทำ subset ของ CJK ใช้ codepoint ตาม ADR-008 สตรีม /ToUnicode ในอนาคตจะใช้แมป GID→Unicode โหมดที่เลือกคือ EncodingMode::TwoByteCid
โครงสร้าง CIDFont สองชุดกำหนดการเขียนแนวตั้งใน PDF ชุดแรกคืออาร์เรย์เมตริกแนวตั้งต่อ glyph /W2 (ISO 32000-2) ชุดที่สองคือเมตริกแนวตั้งค่าเริ่มต้น /DW2 (ISO 32000-2) NextPDF จัดเตรียม value object และตัวปล่อยข้อมูลสำหรับทั้งสองชุดผ่าน CjkVerticalMetrics::toW2Array(), toW2RangeArray() และ toDw2Array() ทั้งสองส่วนเป็นการทำงานภายใน และ writer ยังไม่ปล่อยข้อมูลเหล่านี้ โปรดดูหมายเหตุเรื่องขอบเขต
พื้นผิว API
หัวข้อที่มีชื่อว่า “พื้นผิว API”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry(คลาส)FontInfo::encodeText(string $unicodeText): EncodedGlyphRun—NextPDF\Typography\FontInfofacade ของเฟส 1EncodedGlyphRun—NextPDF\Typography\Encoding\EncodedGlyphRun(byteStream,pdfStringOperand,mode,advanceWidths,toUnicodeMap,usedCodepoints,glyphCount())EncodingMode—NextPDF\Typography\Encoding\EncodingMode(SingleByte,TwoByteCid)CjkVerticalMetrics—NextPDF\Typography\CjkVerticalMetricsvalue object ของเมตริกแนวตั้งสำหรับใช้งานภายใน บันทึกไว้เพื่อความโปร่งใสเท่านั้น ไม่ใช่เส้นทางการเขียนสำหรับฝั่งผู้ใช้
ตาราง 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";ตัวอย่างโค้ด — สำหรับใช้งานจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — สำหรับใช้งานจริง”ตัวอย่างนี้ทำงานได้ด้วยตัวเองและรันผ่าน harness ได้ โดยสะท้อน examples/35-cjk-cmap-demo.php ขั้นแรก ลงทะเบียน fixture ของ Noto Sans TC ที่มาพร้อมกัน ถัดไป ยืนยันว่า facade ที่รับรู้ cmap เข้าถึงได้ จากนั้นเรนเดอร์ผ่าน DocumentFactory เพื่อให้เอกสารใช้ registry ที่คุณเพิ่มข้อมูลไว้
<?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)กรณีขอบและข้อควรระวัง
หัวข้อที่มีชื่อว่า “กรณีขอบและข้อควรระวัง”- ไม่ใช่ conformance fixture ตามที่ระบุไว้ในส่วนหัวของตัวอย่างที่รองรับ เอาต์พุตนี้เป็น integration smoke test การตรวจสอบ PDF/UA-2 และ PDF/A-4 จะถดถอยสำหรับเอาต์พุตนี้ จนกว่าเฟส 3 และ 4 จะพร้อมใช้งาน อย่าลงทะเบียนเอาต์พุตนี้เป็น conformance golden
- ไม่มี API โหมดการเขียน ไม่มีการเรียกสาธารณะสำหรับสลับไปใช้การเขียนแนวตั้ง ซึ่งจะครอบคลุม
vertical-rlและvertical-lrตัวปล่อยข้อมูล/W2และ/DW2มีอยู่ภายใน ตัวปล่อยข้อมูลเหล่านี้ไม่ได้เปิดเผยและยังไม่ได้เขียนลงใน font dictionary - ความเป็นเจ้าของ registry
Document::createStandalone()สร้าง registry ของตนเอง ใช้DocumentFactoryเพื่อให้เอกสารอ่าน registry ที่คุณเพิ่มฟอนต์ CJK ไว้ - เส้นทางไบต์สตรีมสุดท้าย จนกว่าเฟส 2 จะเสร็จสมบูรณ์ content stream ที่มองเห็นได้ยังคงผ่านเส้นทางข้อความแบบเดิม ส่วนที่พิสูจน์แล้วและเข้าถึงได้ในปัจจุบันคือขั้นตอนการเข้ารหัสต้นทาง ได้แก่ การค้นหาแบบไปข้างหน้าของ cmap พร้อมไบต์สตรีม Identity-H
- ต้นทุนการทำ subset ของ CJK ฟอนต์ CJK ขนาดใหญ่จะทำ subset ผ่าน subprocess ที่แยกต่างหาก โดย subprocess ดังกล่าวมี fallback แบบ PHP-native และ timeout สองวินาที (ADR-008)
ประสิทธิภาพ
หัวข้อที่มีชื่อว่า “ประสิทธิภาพ”encodeText() ทำการค้นหาแบบไปข้างหน้าของ cmap เพียงรอบเดียวบนอินพุต มีความซับซ้อนเชิงเส้นตามจำนวน codepoint คือ O(n) งบประมาณคือ wall_ms: 2000, peak_mb: 128 งบประมาณนี้สูงที่สุดในชุดนี้เนื่องจากฟอนต์ CJK มีขนาดใหญ่ และการทำ subset เป็นส่วนที่มีต้นทุนหลัก ADR-008 แยกงานดังกล่าวออกไปเพื่อไม่ให้บล็อกผู้เรียกใช้
หมายเหตุด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “หมายเหตุด้านความปลอดภัย”ไฟล์ฟอนต์ CJK เป็นอินพุตไบนารีที่ไม่น่าเชื่อถือ ตัวแจงปฏิเสธพาธแบบ stream-wrapper และ null byte การทำ subset ของ CJK ทำงานใน subprocess ที่แยกต่างหากโดยไม่มีการสืบทอดสถานะ (ADR-008) ตรวจสอบที่มาของฟอนต์ที่ผู้ใช้ปลายทางจัดหามา เนื้อหาข้อความ CJK ถูกเรนเดอร์ ไม่ใช่ถูกตีความ
ความสอดคล้องตามมาตรฐาน
หัวข้อที่มีชื่อว่า “ความสอดคล้องตามมาตรฐาน”| ข้อความยืนยัน | มาตรฐาน | ข้อ | รหัสอ้างอิง (reference_id) |
|---|---|---|---|
| สำหรับฟอนต์ Type 0 แบบ Identity-H/Identity-V สตริงที่แสดงเป็นคู่ไบต์ที่ทำดัชนีไปยัง CIDFont | ISO 32000-2 | iso32000_2_sec9#x1.x49.p90 | |
| อาร์เรย์ W2 ให้เมตริกการเขียนแนวตั้งต่อ glyph และใช้เฉพาะกับ CIDFont ที่ใช้สำหรับการเขียนแนวตั้งเท่านั้น | ISO 32000-2 | iso32000_2_sec9#x1.x44.p23 | |
| อาร์เรย์ DW2 ให้เมตริกการเขียนแนวตั้งค่าเริ่มต้นสำหรับ CIDFont | ISO 32000-2 | iso32000_2_sec9#x1.x44.p22 |
สูตรนี้แสดงให้เห็นว่า facade การเข้ารหัส CJK ที่รับรู้ cmap เข้าถึงได้จากฝั่งผู้ใช้ (เฟส 1) สูตรนี้ไม่ได้อ้างว่าสร้างเอาต์พุตการเขียนแนวตั้งหรือให้ความสอดคล้องตามมาตรฐาน PDF/UA-2 / PDF/A-4 สำหรับไฟล์ที่สร้างขึ้น การปล่อย /ToUnicode และเมตริกแนวตั้งในฝั่ง writer (เฟส 3 และ 4) ยังรอดำเนินการ และตัวตรวจสอบจะยังไม่ให้เอาต์พุตนี้ผ่านในปัจจุบัน
บริบทเชิงพาณิชย์
หัวข้อที่มีชื่อว่า “บริบทเชิงพาณิชย์”ไม่มี