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

تضمين خط TrueType وإنشاء مجموعة فرعية منه

سجّل خط ⁨TrueType⁩، واعرض النص به، واترك أداة الكتابة تضمّن المجموعة الفرعية المطلوبة فقط. تتبع هذه الوصفة مسار المحتوى نفسه الذي يتبعه examples/04-text-and-fonts.php، مع إضافة خط ⁨TrueType⁩ ‏(.⁨ttf⁩) مُسجَّل.

Terminal window
composer require nextpdf/core:^3

يثبّت هذا القيد حزمة nextpdf/core. يعمل المثال على ⁨PHP 8.4⁩، ويجعل تجهيز الاختبار المُضمَّن LiberationSans-Regular.ttf الوصفة مكتفية ذاتيًا.

سجّل وجه خط باستخدام FontRegistry::register($path, $alias). يحلّل السجل الملف ويُرجع FontInfo، مستخدمًا TrueTypeParser لملفات .ttf و.otf. لتفعيل الوجه، حدّد اسمه المستعار باستخدام setFont($alias, ...). يسجّل هذا الاستدعاء أيضًا النقاط الرمزية المستخدمة.

تُنشَأ المجموعة الفرعية تلقائيًا عند save(). يجمع كاتب خط ⁨PDF⁩ النقاط الرمزية المستخدمة ويستدعي FontSubsetter::subset()، أو CffSubsetter لوجوه خطوط ⁨Compact Font Format⁩ ‏(⁨CFF⁩) أو ⁨OpenType.⁩ عندما تكون المجموعة الفرعية أصغر من البرنامج الكامل، تضمّن أداة الكتابة المجموعة الفرعية. وتعيد أيضًا كتابة BaseFont وFontName بوسم مجموعة فرعية مكوَّن من ستة أحرف كبيرة موصولة بعلامة زائد. هذه هي صيغة ABCDEF+FontName التي يشترطها ⁨ISO 32000-2⁩ للمجموعة الفرعية من الخط. تخزّن أداة الكتابة برنامج ⁨TrueType⁩ المُضمَّن بوصفه FontFile2 في واصف الخط (⁨ISO 32000-2⁩).

تُولَّد بادئة المجموعة الفرعية على نحو حتمي من اسم ⁨PostScript⁩، لذا يُنتج البناء الحتمي وسمًا ثابتًا. لهذا السبب يكون ملف قابلية إعادة الإنتاج لهذه الوصفة structural. يطبّع الملف الهيكلي بادئة المجموعة الفرعية ومذيّل /ID بدلًا من التحقق منهما بايتًا ببايت.

  • FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistry.
  • setFont(string $family, string $style = '', float $size = 12.0): staticNextPDF\Core\Concerns\HasTypography؛ مرّر الاسم المستعار المُسجَّل بوصفه $family.
  • إنشاء المجموعة الفرعية عملية داخلية في أداة الكتابة (NextPDF\Writer\PdfFontWriter -> NextPDF\Typography\FontSubsetter). لا يوجد مفتاح عام للتشغيل أو الإيقاف: تُنشئ أداة الكتابة المجموعة الفرعية دائمًا عندما تكون النقاط الرمزية معروفة وتكون المجموعة الفرعية أصغر.

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

نموذج التعليمات البرمجية — البدء السريع

قسم بعنوان «نموذج التعليمات البرمجية — البدء السريع»
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();
$registry->register(__DIR__ . '/MyFont-Regular.ttf', alias: 'MyFont');
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFont('MyFont', '', 14);
$doc->cell(0, 10, 'Rendered with an embedded, subset TrueType face.', newLine: true);
$doc->save(__DIR__ . '/out.pdf');

ينشئ Document::createStandalone() سجله الخاص. لاستخدام سجل عبّأته بنفسك، أنشئ المستند عبر DocumentFactory، كما هو موضّح في نموذج بيئة الإنتاج. يجعل المصنع أداة الكتابة تقرأ وجه الخط الذي سجّلته.

نموذج التعليمات البرمجية — بيئة الإنتاج

قسم بعنوان «نموذج التعليمات البرمجية — بيئة الإنتاج»

هذا النموذج مكتفٍ ذاتيًا وقابل للتشغيل ضمن منظومة الاختبار. يسجّل ملف LiberationSans-Regular.ttf المُضمَّن ويعرض النص عبر DocumentFactory، لذلك يكون السجل المُعبَّأ هو المُستخدَم. يعتمد النموذج على الإنشاء التلقائي للمجموعة الفرعية عند الحفظ.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// A bundled TrueType test fixture keeps this recipe self-contained.
// Replace with a font you have the right to embed.
$fontPath = __DIR__ . '/../../fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';
if (!is_file($fontPath)) {
// Fall back to the repository-relative fixture location.
$fontPath = dirname(__DIR__, 2) . '/fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';
}
$fontRegistry = new FontRegistry();
$fontRegistry->register($fontPath, alias: 'LiberationSans');
$imageRegistry = new ImageRegistry(maxCacheBytes: 0);
$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$doc = $documentFactory->create();
$doc->setTitle('Embedded Subset Font');
$doc->addPage();
$doc->setFont('LiberationSans', '', 20);
$doc->cell(0, 14, 'Embedded TrueType face', newLine: true);
$doc->setFont('LiberationSans', '', 12);
$doc->multiCell(0, 7, 'Only the glyphs used by this document are embedded. '
. 'The writer subsets the font program and rewrites the BaseFont with a '
. 'deterministic six-letter subset prefix, for example ABCDEF+LiberationSans.');
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/embed-and-subset-fonts.pdf');
echo "Wrote embed-and-subset-fonts.pdf\n";

مخرجات ⁨STDOUT⁩ المتوقعة:

Wrote embed-and-subset-fonts.pdf

للتأكد من المجموعة الفرعية، افتح الناتج وافحص قاموس الخط. يقرأ BaseFont القيمة <TAG>+LiberationSans، ويحمل الواصف FontFile2. لا يبلّغ تشغيل qpdf --check عن أي أخطاء هيكلية.

  • ملكية السجل. ينشئ Document::createStandalone() سجله الخاص. الخط الذي سجّلته على FontRegistry منفصل ولا يكون مرئيًا له. استخدم DocumentFactory لتمرير سجلك، كما يفعل نموذج بيئة الإنتاج.
  • حقوق التضمين. لا يغيّر إنشاء المجموعة الفرعية الترخيص. لا تضمّن سوى الخطوط المرخَّص لك تضمينها. تضبط بعض الخطوط بتات تقييد التضمين؛ ويقرأ المحلّل تلك البتات، لكن مسؤولية الامتثال تبقى على عاتقك.
  • مسار ⁨CFF/OpenType.⁩ تُنشَأ المجموعة الفرعية لوجوه .otf و⁨CFF⁩ بواسطة CffSubsetter، وليس FontSubsetter. السلوك وإعادة كتابة وسم المجموعة الفرعية متكافئان. مسار التعليمات البرمجية وحده هو الذي يختلف.
  • لا اختصار في الحجم. أحيانًا لا تكون المجموعة الفرعية أصغر من الأصل. قد يحدث هذا مع الخطوط الصغيرة جدًا أو عند استخدام جميع الرسوم الحرفية. في تلك الحالة، تضمّن أداة الكتابة البرنامج الأصلي دون وسم مجموعة فرعية. هذا سلوك صحيح، وليس إخفاقًا.
  • خطوط ⁨CJK.⁩ تستخدم وجوه الخطوط الصينية واليابانية والكورية (⁨CJK⁩) الكبيرة استراتيجية متدرجة لإنشاء المجموعة الفرعية وفق ⁨ADR-008⁩، مع عملية فرعية معزولة وحل احتياطي أصيل بلغة ⁨PHP.⁩ راجع ضبط نص ⁨CJK⁩ بترميز مدرك لـ ⁨cmap⁩ لمعرفة تفاصيل ⁨CJK⁩ وحالة خط الأنابيب الحالية.

يستغرق التحليل مرورًا واحدًا على جداول الخط، وتزداد تكلفة إنشاء المجموعة الفرعية بازدياد عدد الرسوم الحرفية. تُنشَأ المجموعة الفرعية لوجوه الخطوط اللاتينية غير ⁨CJK⁩ داخل العملية ضمن ميزانية wall_ms: 1500, peak_mb: 96. تُوجَّه وجوه خطوط ⁨CJK⁩ الكبيرة إلى عملية فرعية معزولة بمهلة زمنية فعلية مدتها ثانيتان وحل احتياطي أصيل بلغة ⁨PHP⁩ ‏(⁨ADR-008⁩). يعني هذا التوجيه أن إنشاء مجموعة فرعية بطيء أو منهار لا يمكن أن يحجب المُستدعي.

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

البيانالمواصفةالبند⁨reference_id⁩
يحمل ⁨BaseFont/FontName⁩ للمجموعة الفرعية من الخط بادئة مجموعة فرعية مكوَّنة من ستة أحرف كبيرة موصولة بعلامة زائد.⁨ISO 32000-2⁩⁨iso32000_2_sec9⁩#⁨x1.x66.p2⁩
يُخزَّن برنامج خط ⁨TrueType⁩ المُضمَّن بوصفه ⁨FontFile2⁩ في واصف الخط.⁨ISO 32000-2⁩⁨iso32000_2_sec9⁩#⁨x1.x65.p15⁩

توضّح هذه الوصفة كيف يضمّن ⁨NextPDF⁩ وجه خط ⁨TrueType⁩ وينشئ مجموعة فرعية منه ويُصدر بادئة مجموعة فرعية مطابِقة. وهي لا تؤكد الامتثال لترخيص الخط. حقوق التضمين مسؤولية الجهة المُدمِجة.

لا ينطبق.