ข้ามไปยังเนื้อหา

เข้ารหัสข้อความ 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 และไม่มี setter vertical-rl ให้เรียกใช้
  • ตามที่ระบุไว้ในส่วนหัวของตัวอย่างที่รองรับ ตัวอย่างนี้เป็น integration smoke test ไม่ใช่ conformance fixture การตรวจสอบความถูกต้อง PDF/UA-2 และ PDF/A-4 จะ ถดถอย สำหรับเอาต์พุตที่สร้างด้วยวิธีนี้ จนกว่าเฟส 3 และ 4 จะพร้อมใช้งาน อย่าระบุว่าเอาต์พุตจากเส้นทางนี้สอดคล้องตามมาตรฐาน ตัวตรวจสอบเป็นผู้ตัดสินความสอดคล้องตามมาตรฐาน และเอาต์พุตนี้ยังไม่ผ่าน
  • โครงสร้างพื้นฐานของเมตริกการเขียนแนวตั้งมีอยู่แล้ว แต่เป็น การทำงานภายใน ประกอบด้วย value object CjkVerticalMetrics และตัวปล่อยข้อมูล /W2 และ /DW2 NextPDF ไม่ได้เปิดเผยฟังก์ชันนี้เป็นการเรียก “write vertically” ในฝั่งผู้ใช้ และ writer ยังไม่ปล่อย dictionary สำหรับฟังก์ชันนี้
Terminal window
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 ยังไม่ปล่อยข้อมูลเหล่านี้ โปรดดูหมายเหตุเรื่องขอบเขต

  • FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistry (คลาส)
  • FontInfo::encodeText(string $unicodeText): EncodedGlyphRunNextPDF\Typography\FontInfo facade ของเฟส 1
  • EncodedGlyphRunNextPDF\Typography\Encoding\EncodedGlyphRun (byteStream, pdfStringOperand, mode, advanceWidths, toUnicodeMap, usedCodepoints, glyphCount())
  • EncodingModeNextPDF\Typography\Encoding\EncodingMode (SingleByte, TwoByteCid)
  • CjkVerticalMetricsNextPDF\Typography\CjkVerticalMetrics value 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 fired
echo $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 สตริงที่แสดงเป็นคู่ไบต์ที่ทำดัชนีไปยัง CIDFontISO 32000-2iso32000_2_sec9#x1.x49.p90
อาร์เรย์ W2 ให้เมตริกการเขียนแนวตั้งต่อ glyph และใช้เฉพาะกับ CIDFont ที่ใช้สำหรับการเขียนแนวตั้งเท่านั้นISO 32000-2iso32000_2_sec9#x1.x44.p23
อาร์เรย์ DW2 ให้เมตริกการเขียนแนวตั้งค่าเริ่มต้นสำหรับ CIDFontISO 32000-2iso32000_2_sec9#x1.x44.p22

สูตรนี้แสดงให้เห็นว่า facade การเข้ารหัส CJK ที่รับรู้ cmap เข้าถึงได้จากฝั่งผู้ใช้ (เฟส 1) สูตรนี้ไม่ได้อ้างว่าสร้างเอาต์พุตการเขียนแนวตั้งหรือให้ความสอดคล้องตามมาตรฐาน PDF/UA-2 / PDF/A-4 สำหรับไฟล์ที่สร้างขึ้น การปล่อย /ToUnicode และเมตริกแนวตั้งในฝั่ง writer (เฟส 3 และ 4) ยังรอดำเนินการ และตัวตรวจสอบจะยังไม่ให้เอาต์พุตนี้ผ่านในปัจจุบัน

ไม่มี