تخطَّ إلى المحتوى
getnextpdf.com

الاستقرار: تجريبي

ترميز نص CJK مع مراعاة cmap

تسجّل هذه الوصفة وجه خط TrueType من نوع CJK. ثم ترمّز النص الصيني التقليدي عبر الواجهة التي تراعي cmap FontInfo::encodeText(). تُنتج هذه الواجهة دفق بايتات CID ثنائية البايت بترميز Identity-H. تتبع الوصفة examples/35-cjk-cmap-demo.php. اقرأ ملاحظة النطاق أدناه قبل الاعتماد عليها.

النطاق والحالة (اقرأ أولًا)

قسم بعنوان «النطاق والحالة (اقرأ أولًا)»

تُطرح بنية ترميز النص التي تراعي cmap على مراحل (ADR-013). اكتملت المرحلة 1: وُصِلت الواجهة FontInfo::encodeText() واستراتيجية الترميز التي تراعي cmap، وأصبحتا متاحتين من مساحة المستخدم. المرحلة 2 قيد التنفيذ: تمرّر أداة العرض والكاتب عبر الواجهة. المرحلتان 3 و4 معلّقتان: إصدار /ToUnicode و/CIDSystemInfo و/Encoding و/CIDToGIDMap لكل خط، ومُحلِّل الخط البديل، لم يُوصَّلا بعد إلى الكاتب.

ضع في حسبانك هذه التبعات:

  • توضّح هذه الوصفة واجهة الترميز — أي طبقة ترميز النص — لا وضع كتابة عمودية جاهزًا. يوجد الآن مؤلِّف وضع كتابة عمودية تجريبي يُفعَّل اختياريًا لمسار تخطيط ⁨HTML⁩/⁨CSS⁩ (راية layoutVerticalComposer، التي تشغّل ⁨CSS⁩ vertical-rl / vertical-lr)؛ راجع وضع الكتابة العمودية. أما سطح المستند فلا يزال لا يملك طريقة setWritingMode الأمرية ولا أداة ضبط vertical-rl — فالتأليف العمودي اختياري وتقوده ⁨CSS⁩.
  • المثال الداعم، وفق ترويسته نفسها، هو اختبار دخان تكاملي، لا تجهيزة مطابقة. سيتراجع التحقّق من ⁨PDF/UA-2⁩ و ⁨PDF⁩/A-4 للمخرجات المنتَجة بهذه الطريقة حتى تكتمل المرحلتان 3 و4. لا تذكر أن المخرجات من هذا المسار مطابقة. المدقّق هو من يقرّر المطابقة، وهذه المخرجات لن تجتازه بعد.
  • توجد بنية مقاييس الكتابة العمودية لكنها داخلية. هذه البنية هي كائن القيمة CjkVerticalMetrics ومُصدِرا /W2 و/DW2. لا يكشف عنها كاستدعاء “اكتب عموديًا” في مساحة المستخدم، ولا يُصدِر الكاتب قواميسها بعد.
Terminal window
composer require nextpdf/core:^3

يطابق القيد حزمة nextpdf/core. يعمل المثال على ⁨PHP 8.4⁩. تجعل تجهيزة اختبار Noto Sans TC المرفقة هذه الوصفة مكتفية بذاتها.

يصوغ ⁨ISO 32000-2⁩ إخراج النص في ثلاث طبقات: نقطة ترميز Unicode، ورمز الحرف، ومعرّف المحرف الرسومي. بالنسبة إلى وجه خط TrueType من نوع CJK، يستخدم المحرّك خطًا مركّبًا من نوع Type 0 بترميز Identity-H. مع هذا الترميز، تكون السلسلة المعروضة أزواج بايتات تُفهرس CIDFont (⁨ISO 32000-2⁩، reference_id=).

يحلّل FontRegistry::register() وجه الخط. ثم يحدّد FontInfo::encodeText($unicodeText) استراتيجية الترميز عبر FontEncodingStrategyResolver. بالنسبة إلى وجه خط TrueType مسجّل من نوع CJK، يوجّه الطلب إلى TrueTypeCmapStrategy. يحمل EncodedGlyphRun المُعاد دفق بايتات Identity-H، ومُعامل سلسلة ⁨PDF⁩، وعروض التقدّم لكل محرف رسومي، ونقاط الترميز المستخدَمة، وخريطة GID←Unicode. يستهلك تجزيء خطوط CJK نقاط الترميز المستخدَمة وفق ADR-008. سيستخدم دفق /ToUnicode مستقبلًا خريطة GID←Unicode. الوضع المحدَّد هو EncodingMode::TwoByteCid.

يحدّد بناءان من بنى CIDFont الكتابة العمودية في ⁨PDF⁩. الأول هو مصفوفة المقاييس العمودية لكل محرف رسومي /W2 (⁨ISO 32000-2⁩، reference_id=). والثاني هو المقاييس العمودية الافتراضية /DW2 (⁨ISO 32000-2⁩، reference_id=). يملك ⁨NextPDF⁩ كائن القيمة والمُصدِرات لكليهما، عبر CjkVerticalMetrics::toW2Array() وtoW2RangeArray() وtoDw2Array(). وهي داخلية، ولا يُصدِرها الكاتب بعد. راجع ملاحظة النطاق.

  • FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistry.
  • FontInfo::encodeText(string $unicodeText): EncodedGlyphRunNextPDF\Typography\FontInfo. واجهة المرحلة 1.
  • EncodedGlyphRunNextPDF\Typography\Encoding\EncodedGlyphRun (byteStream, pdfStringOperand, mode, advanceWidths, toUnicodeMap, usedCodepoints, glyphCount()).
  • EncodingModeNextPDF\Typography\Encoding\EncodingMode (SingleByte, TwoByteCid).
  • CjkVerticalMetricsNextPDF\Typography\CjkVerticalMetrics. كائن قيمة داخلي للمقاييس العمودية. يُوثَّق للشفافية، لا كمسار كتابة في مساحة المستخدم.

يُولَّد جدول ⁨PHP⁩Doc الكامل من المصدر.

<?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";

هذه العيّنة قائمة بذاتها وقابلة للتشغيل ضمن إطار الاختبار. وهي تعكس examples/35-cjk-cmap-demo.php. أولًا، سجّل تجهيزة Noto Sans TC المرفقة. بعد ذلك، تأكّد من أن الواجهة التي تراعي cmap قابلة للوصول. ثم اعرض عبر DocumentFactory حتى يستخدم المستند السجل الذي ملأته.

<?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)
  • ليست تجهيزة مطابقة. وفق ترويسة المثال الداعم نفسها، هذه المخرجات اختبار دخان تكاملي. تتراجع فحوص ⁨PDF/UA-2⁩ و ⁨PDF⁩/A-4 لها حتى تكتمل المرحلتان 3 و4. لا تسجّلها كمرجع مطابقة ذهبي.
  • لا توجد واجهة برمجة أمرية لوضع الكتابة على مستوى المستند. لا يوجد استدعاء عام في Document مثل setWritingMode() ولا أداة ضبط vertical-rl / vertical-lr. أما مؤلِّف الكتابة العمودية التجريبي عبر ⁨HTML⁩/⁨CSS⁩ فهو منفصل، ويُفعَّل اختياريًا، وتقوده ⁨CSS⁩ عبر راية layoutVerticalComposer (راجع ملاحظة النطاق). يوجد مُصدِرا /W2 و/DW2 داخليًا. وهما غير مكشوفين ولم يُكتبا بعد في قاموس الخط.
  • ملكية السجل. يبني Document::createStandalone() سجله الخاص. استخدم DocumentFactory حتى يقرأ المستند السجل الذي ملأته بوجه خط CJK.
  • مسار دفق البايتات النهائي. حتى تُغلق المرحلة 2، لا يزال دفق المحتوى المرئي يمرّ عبر مسار النص القديم. الجزء المثبَت والمتاح اليوم هو خطوة الترميز الأولية، وهي البحث الأمامي في cmap إضافة إلى دفق بايتات Identity-H.
  • تكلفة تجزيء خطوط CJK. تُجزَّأ أوجه خطوط CJK الكبيرة عبر عملية فرعية معزولة. لدى تلك العملية الفرعية بديل أصلي بلغة ⁨PHP⁩ ومهلة من ثانيتين (ADR-008).

يُجري encodeText() تمريرة بحث أمامي واحدة في cmap على المُدخل. وهو خطّي في عدد نقاط الترميز، O(n). الميزانية هي wall_ms: 2000, peak_mb: 128. هذه الميزانية هي الأعلى في هذه المجموعة لأن أوجه خطوط CJK كبيرة، وتجزيئها هو التكلفة الغالبة. يعزل ADR-008 ذلك العمل بحيث لا يستطيع حجب المستدعي.

ملف خط CJK مُدخل ثنائي غير موثوق. يرفض المحلّل مسارات أغلفة الدفق وبايتات null. يعمل تجزيء خطوط CJK في عملية فرعية معزولة دون حالة موروثة (ADR-008). تحقّق من مصدر أوجه الخطوط التي يوفّرها المستخدم النهائي. يُعرَض محتوى نص CJK ولا يُفسَّر.

العبارةالمواصفةالبندreference_id
بالنسبة إلى خط Type 0 بترميز Identity-H/Identity-V، تكون السلسلة المعروضة أزواج بايتات تُفهرس CIDFont.ISO 32000-2iso32000_2_sec9#x1.x49.p90
تعطي مصفوفة W2 مقاييس الكتابة العمودية لكل محرف رسومي وتنطبق فقط على CIDFonts المستخدَمة للكتابة العمودية.ISO 32000-2iso32000_2_sec9#x1.x44.p23
تعطي مصفوفة DW2 مقاييس الكتابة العمودية الافتراضية لـ CIDFont.ISO 32000-2iso32000_2_sec9#x1.x44.p22

تُظهر هذه الوصفة أن واجهة ترميز CJK التي تراعي cmap قابلة للوصول من مساحة المستخدم (المرحلة 1). وهي لا تدّعي إخراج كتابة عمودية ولا مطابقة ⁨PDF/UA-2⁩ / ⁨PDF⁩/A-4 للملف المنتَج. إصدار /ToUnicode والمقاييس العمودية من جانب الكاتب (المرحلتان 3 و4) لا يزال معلّقًا، ولن تجتاز هذه المخرجات المدقّق اليوم.

لا ينطبق.