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

عرض HTML داخل صفحة PDF

استخدم writeHtml() لعرض مقطع من لغة ترميز النص التشعبي (⁨HTML⁩) وأوراق الأنماط المتتالية (⁨CSS⁩) كمحتوى صفحة بتنسيق المستند المحمول (⁨PDF⁩). مرّر الترميز، وسيعرض ⁨NextPDF⁩ صفحة منسّقة. النسخة الكاملة القابلة للتشغيل من هذا الكود موجودة في examples/08-html-basic.php. اتّبع الخطوات أدناه، أو انسخ المثال مباشرةً.

يقرأ ⁨NextPDF⁩ ملف ⁨HTML⁩ الخاص بك مرّة واحدة ويدفق النتيجة مباشرةً إلى الصفحة. ويُعرف ذلك بمسار تدفق أحادي المرور. لا تحتاج إلى فهم هذا النموذج لاستخدام هذه الوصفة. ومع ذلك، من المفيد أن تضعه في الحسبان، لأنه يفسّر بعض القواعد التي سترد لاحقًا في هذه الصفحة.

Terminal window
composer require nextpdf/core:^3

يثبّت هذا الأمر حزمة nextpdf/core. تعمل الأمثلة في هذه الصفحة على ⁨PHP⁩ 8.4، وبيئة التشغيل المدعومة هي >=8.4 <9.0.

تستقبل writeHtml() سلسلة ⁨HTML⁩ وترسمها في الصفحة الحالية، بدءًا من موضع المؤشر الحالي. داخل المحرّك، يفحص ⁨NextPDF⁩ ملف ⁨HTML⁩ مرّة واحدة ويقسّمه إلى رموز (HtmlTokenizer). ثم يمرّ على تلك القائمة من اليسار إلى اليمين (HtmlParser). ولكل عنصر، يكتب في مخزن مؤقت تعليمات الرسم المقابلة في ⁨PDF⁩، وهي ما يُسمّى معاملات دفق المحتوى. لا يبني المحرّك شجرة عناصر ولا يحتفظ بها في الذاكرة بين الاستدعاءات أبدًا. هذا التصميم المتعمّد هو نموذج التدفق أحادي المرور المسجّل في ⁨ADR-001.⁩

يتحوّل كل عنصر كتلة مدعوم إلى صندوق تخطيط، ويتحوّل كل تسلسل نصي إلى معامل عرض نص. تُحسم الأنماط الواردة من سمات style المضمّنة ومن كتلة <style> عبر تتالي ⁨CSS⁩، أي القواعد التي تحدّد النمط الذي تكون له الأولوية عندما ينطبق أكثر من نمط. يتبع التفاف النص ومحاذاته وتباعده نموذج ⁨CSS Text⁩، الذي يحدّد كيف يصبح النص المصدري نصًّا منسّقًا وملتفًّا على الأسطر (⁨W3C CSS Text Level 3⁩).

إذا لم تختر خطًّا، يستخدم نص المتن خطًّا افتراضيًّا. هذا الخط الافتراضي هو خط ⁨Type 1⁩ قياسي، وهو أحد الخطوط القياسية الأربعة عشر المسمّاة في ⁨ISO 32000-2.⁩ لا يتغيّر الخط الافتراضي إلا عندما تسجّل خطًّا خاصًّا بك وتحدّده، أو عندما يقتضي ملف توافق أن يُضمّن ⁨NextPDF⁩ خطًّا بديلًا.

اضبط هذا التوقّع مبكرًا: يدعم ⁨NextPDF⁩ مجموعة فرعية من ⁨HTML⁩ و⁨CSS⁩، وليس كامل أيٍّ منهما. تغطّي هذه الوصفة المجموعة الفرعية المدعومة، ولا تدّعي دعمًا كاملًا لـ ⁨HTML⁩ أو دعمًا كاملًا لـ ⁨CSS.⁩ لمعرفة الحالة الدقيقة والمتحقَّق منها لكل وحدة، راجع مصفوفة دعم ⁨CSS⁩.

توقيع الدالة هو writeHtml(string $html): static. وهي معلَنة في الواجهة NextPDF\Contracts\PdfDocumentInterface ومنفَّذة في NextPDF\Core\Concerns\HasTextOutput. تعرض الدالة المحتوى في الصفحة الحالية، وتنشئ لك صفحة إن لم تكن هناك صفحة بعد. يُنشأ جدول ⁨PHPDoc⁩ الكامل للدالة من الكود المصدري.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$doc->writeHtml('<h1>HTML Rendering in NextPDF</h1><p>Rendered with <strong>writeHtml()</strong>.</p>');
$doc->save(__DIR__ . '/out.pdf');

هذا المثال الكامل والمكتفي ذاتيًّا هو ما تشغّله أداة الاختبار، وهو يطابق examples/08-html-basic.php. وبدلًا من ترميز مسار إخراج ثابت في الكود، يكتب إلى المسار الذي توفّره الأداة. وهذا يتيح لأداة قابلية إعادة الإنتاج تشغيل السكربت مرّتين ومقارنة النتائج.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML content</strong> directly into PDF pages.
This is the recommended approach for <em>mixed formatting</em>.</p>
<h2>Supported elements</h2>
<ul>
<li>Headings (h1-h6)</li>
<li>Paragraphs with <strong>bold</strong> and <em>italic</em></li>
<li>Ordered and unordered lists</li>
<li>Tables with borders and alignment</li>
<li>Inline styles (color, font-size, margin)</li>
</ul>
<h2>Ordered list</h2>
<ol>
<li>Create a Document instance</li>
<li>Add pages and content</li>
<li>Call save() or output()</li>
</ol>
HTML;
$doc->writeHtml($html);
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script twice.
// Honour it: do not hard-code a path, do not echo the PDF to STDOUT.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-html-to-pdf.pdf');
echo "Wrote render-html-to-pdf.pdf\n";

المخرج القياسي ⁨STDOUT⁩ المتوقّع:

Wrote render-html-to-pdf.pdf
  • تسليم المؤشر. تنقل writeHtml() المؤشر إلى نهاية المحتوى المعروض. ويبدأ أي استدعاء لاحق لـ cell() أو استدعاء ثانٍ لـ writeHtml() من هناك، لا من أعلى الصفحة.
  • لا توجد صفحة بعد. إذا لم تكن هناك صفحة، تضيف writeHtml() صفحةً قبل العرض. استدعِ addPage() أولًا عندما تحتاج إلى تعيين حجم صفحة محدّد.
  • حدّا العناصر والتداخل. يفرض محرّك التدفق حدًّا أقصاه 50,000 عنصر وحدًّا أقصاه 100 مستوى تداخل (⁨ADR-001⁩). ويُرفض المستند الذي يتجاوز أيًّا من الحدّين بدلًا من اقتطاعه بصمت.
  • الترميز غير المدعوم. تُتجاهَل العناصر والخصائص الواقعة خارج المجموعة الفرعية المدعومة أو يُستخدم لها بديل احتياطي؛ ولا تثير أخطاء. تحقّق من التغطية في مصفوفة دعم ⁨CSS⁩ قبل الاعتماد على خاصية.
  • الموارد الخارجية. تتبع الصور وأوراق الأنماط البعيدة سياسة الموارد الخارجية؛ والسياسة الافتراضية لا تجلب عناوين ⁨URL⁩ بعيدة عشوائية.

يجري التقطيع إلى رموز والعرض في مرور واحد على مدخلاتك، لذلك تنمو الكلفة خطّيًّا مع عدد الرموز، ⁨O⁩(⁨n⁩). الميزانية الافتراضية لهذه الوصفة هي wall_ms: 1500, peak_mb: 96. ولأن المحرّك يدفق المخرجات ولا يحتفظ بنموذج كائن المستند (⁨DOM⁩) في الذاكرة، فإن ذروة الذاكرة تتبع مخزن دفق المحتوى وكدسة الأنماط النشطة، لا حجم المستند بأكمله.

مقتطف من مصفوفة دعم ⁨CSS⁩ (الصفوف المتحقَّق منها فقط)

قسم بعنوان «مقتطف من مصفوفة دعم ⁨CSS⁩ (الصفوف المتحقَّق منها فقط)»

يتضمّن هذا المقتطف الصفوف المصنّفة متحقَّق منها فقط في مصفوفة دعم ⁨CSS⁩ المدقّقة على أساس الحقيقة. وتعني “متحقَّق منها” وجود تنفيذ في src/Html/ ومجموعة تجهيزات اختبار جوهرية ومخصّصة تنجح حتميًّا ضمن إطار الملف البنيوي.

وحدة ⁨W3C⁩المستوىالحالةالدليل
تخطيط الصندوق المرن في ⁨CSS⁩ ‏(css_flexbox_1)1متحقَّق منهاsrc/Html/Flex/، tests/Unit/Html/Flex/
تخطيط الشبكة في ⁨CSS⁩ ‏(css_grid_1)1متحقَّق منهاsrc/Html/Grid/، مجموعة ⁨WPT⁩
التتالي والوراثة في ⁨CSS⁩ ‏(css_cascade_3)3متحقَّق منهاsrc/Html/Cascade/، tests/Unit/Html/Cascade/
الجدول في ⁨CSS⁩ ‏(css_tables_3)3متحقَّق منهاsrc/Html/Table/، تجهيزات اختبار الجداول + ملفات ⁨PDF⁩ مرجعية
الخطوط في ⁨CSS⁩ ‏(css_fonts_4)4متحقَّق منهاsrc/Html/FontFace/، tests/Unit/Html/FontFace/

خصائص مثل text-align وtext-indent وcolor مصنّفة بأنها “مُدَّعاة” في المصفوفة (منفَّذة، لكن بلا تجهيزة اختبار مخصّصة للوحدة)، لذلك لا تُدرج هنا بوصفها متحقَّقًا منها.

قيود التدفق أحادي المرور (⁨ADR-001⁩)

قسم بعنوان «قيود التدفق أحادي المرور (⁨ADR-001⁩)»

لا يحتفظ محرّك ⁨HTML⁩ بأي ⁨DOM.⁩ تقتصر حالته على مؤشر قياسي مع كدسة أنماط من نوع ⁨push/pop⁩؛ وتُتجاهَل عقد النص التي تحوي مسافات بيضاء فقط عند التقطيع إلى رموز. ومن نتائج ذلك أن عنصرًا لاحقًا لا يمكنه إعادة تنسيق عنصر سابق، وأن المحدّدات التي تحتاج إلى سياق الشجرة الكاملة (على سبيل المثال، حالات :has() المعقّدة) مقيَّدة وفق ⁨ADR-006.⁩ خطّط تخطيطًا يعتمد على ترتيب المستند فقط.

التحليل والتخطيط والطلاء طبقات منفصلة. لا يُصدر المحلّل معاملات طلاء خام، ولا يحلّل توجيه التخطيط ⁨CSS.⁩ وتجاوز تلك الحدود هو دَيْن الاقتران الذي يحظره ⁨ADR-010.⁩ بالنسبة إلى مؤلّفي الوصفات، يعني هذا أن نقطة الدخول العامة هي writeHtml(). لا تتعامل مع التفاصيل الداخلية للمحلّل.

ميزانية الذاكرة للمستندات الكبيرة

قسم بعنوان «ميزانية الذاكرة للمستندات الكبيرة»

وفق ⁨ADR-020⁩، قد تبني سياقات التنسيق المحصورة بالحاوية (المرنة، الجدول) شجرة فرعية عابرة، محدودة بـ 5,000 عقدة لكل سياق، وبعمق 20 مستوى، مع سقف ذاكرة نشطة قدره 50 ⁨MB⁩ عبر السياقات الحيّة و10 مستويات تداخل. وخارج تلك السياقات، لا يحتفظ نموذج التدفق بأي شجرة. أبقِ الجداول والحاويات المرنة الفردية ضمن حدّ العقد لتحصل على استهلاك ذاكرة يمكن توقّعه.

تعامل مع مدخلات ⁨HTML⁩ على أنها غير موثوقة. لا ينفّذ ⁨NextPDF⁩ النصوص البرمجية، وسياسة الموارد الخارجية الافتراضية لا تجلب عناوين ⁨URL⁩ بعيدة عشوائية، لذلك فالمحرّك نفسه متحفّظ. ومع ذلك، تحقّق من صحة أي ⁨HTML⁩ تجمعه من مدخلات المستخدم أو نقّه قبل عرضه. ويحميك أيضًا حدّا العناصر والتداخل: فهما يقيّدان مقدار العمل الذي يمكن أن يطلبه مستند معادٍ أو مشوّه.

العبارةالمواصفةالبند⁨reference_id⁩
يتحكّم ⁨CSS Text⁩ في تحويل النص المصدري إلى نص منسّق وملتفّ على الأسطر.⁨W3C CSS Text Level 3⁩⁨css_text_3⁩#⁨x1.x2.p4⁩
يُحسم خط المتن الافتراضي إلى خط ⁨Type 1⁩ قياسي.⁨ISO 32000-2⁩⁨iso32000_2_sec9⁩#⁨x1.x29⁩

توضّح هذه الوصفة كيف يعرض ⁨NextPDF⁩ مجموعة فرعية مدعومة من ⁨HTML⁩ و⁨CSS.⁩ وهي لا تؤكّد دعمًا كاملًا لـ ⁨HTML⁩ أو دعمًا كاملًا لـ ⁨CSS.⁩ وتجد الحالة المتحقَّق منها لكل وحدة في مصفوفة دعم ⁨CSS.⁩

لا ينطبق.