الصور والجداول والقوائم
نادرًا ما يصنع النص وحده مستندًا مكتملًا. في هذا الدرس التعليمي تضيف ثلاث لبنات يومية: صورة وجدولًا وقائمة نقطية. تكتب سكربتين صغيرين، وكلٌّ منهما يُنتج ملف PDF (صيغة المستند المحمول) حقيقيًّا يمكنك فتحه على الفور.
ما الذي ستبنيه
قسم بعنوان «ما الذي ستبنيه»01-image.php— ملف PDF من صفحة واحدة يحتوي على عنوان وصورة مربّعة كهرمانية، موضوعة في مكان محدّد بدقّة على الصفحة.02-table-and-lists.php— ملف PDF من صفحة واحدة يحتوي على جدول صغير بالكتب وقائمة نقطية أسفله.
كلا السكربتين برنامجان كاملان. واصل استخدام مجلّد المشروع من
الدرس التعليمي الأول
واحفظ كل سكربت بجوار composer.json.
الخطوة 1: ضع صورة على الصفحة
قسم بعنوان «الخطوة 1: ضع صورة على الصفحة»يحمل هذا السكربت صورته الخاصة. تنتقل صورة PNG (رسوميات الشبكة المحمولة) صغيرة جدًّا بأبعاد 8 x 8 بكسل داخل السكربت على هيئة سلسلة Base64. وBase64 طريقة لكتابة البيانات الثنائية كنص عادي، ما يتيح لها أن تستقرّ داخل الكود المصدري. في مشروع حقيقي ستتخطّى هذا الجزء، لأن ملف صورتك موجود بالفعل على القرص.
احفظ هذا باسم 01-image.php ونفّذه بالأمر php 01-image.php:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// A tiny 8 x 8 pixel amber PNG, stored as text inside this script.// In a real project the image file already exists on disk, so you// would skip this block and point image() at your own file.$pngBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAEUlEQVR42mP4Oo8bK2IYWhIAq6BngWh/dt4AAAAASUVORK5CYII=';
@mkdir(__DIR__ . '/out');
$pngPath = __DIR__ . '/out/amber-square.png';$pngBytes = base64_decode($pngBase64, true);if ($pngBytes === false) { fwrite(STDERR, "The embedded image data is damaged.\n"); exit(1);}file_put_contents($pngPath, $pngBytes);
$document = Document::createStandalone();$document->setTitle('Tutorial: images');$document->addPage();
$document->setFont('helvetica', 'B', 20);$document->cell(0, 26, 'A picture inside a PDF', newLine: true);
$document->setFont('helvetica', '', 12);$document->cell(0, 18, 'The amber square below comes from a tiny PNG file.', newLine: true);
// Place the image 72 points (one inch) from the left edge and// 160 points down from the top, printed as a 96 x 96 point square.$document->image($pngPath, x: 72, y: 160, width: 96, height: 96);
$document->save(__DIR__ . '/out/image.pdf');
echo "Wrote out/image.pdf\n";من المفترض أن ترى Wrote out/image.pdf على الشاشة. افتح out/image.pdf
وستجد العنوان وسطرًا واحدًا من النص ومربّعًا كهرمانيًّا.
ما الذي حدث للتوّ
قسم بعنوان «ما الذي حدث للتوّ»- يفكّ السكربت أولًا ترميز سلسلة Base64 ليعيدها إلى بايتات الصورة، ثم
يكتبها في
out/amber-square.png. وهذه ليست سوى الحيلة التي تجعل الدرس التعليمي مكتفيًا بذاته. يبدأ الدرس عند استدعاءimage()الذي يقرأ بالطريقة نفسها أيَّ ملف PNG أو JPEG (مجموعة خبراء التصوير الفوتوغرافي المشترَكة) موجود. - ينشئ
@mkdir(__DIR__ . '/out')مجلّد المُخرَجات. تُخفي علامة@التحذير غير الضارّ الذي ستحصل عليه عندما يكون المجلّد موجودًا بالفعل، بحيث يمكن تشغيل السكربت مرّتين متتاليتين. - يأخذ
image()مسار ملف بالإضافة إلى موضع وحجم مطبوع. تُقاس المواضع والأحجام بالنقاط، و72 نقطة تساوي بوصة واحدة. أصل الصفحة هو الزاوية العلوية اليسرى، لذا فإنy: 160يعني 160 نقطة إلى الأسفل من الأعلى. - البكسلات والنقاط شيئان مختلفان. الصورة لا تتجاوز 8 x 8 بكسل، لكن
width: 96, height: 96يطبعها مربّعًا عرضه بوصة وثلث. أنت من يختار الحجم المطبوع، وليس عدد البكسلات. - يضع
image()الصورة في المكان المحدّد الذي تسمّيه. وهو لا يحرّك موضع الكتابة الذي تستخدمهcell(). إن كتابة النص أولًا ثم وضع الصور يمنع تصادم الاثنين. - يقرأ NextPDF الصورة من ملف محلّي فقط، ولا يقرؤها أبدًا من عنوان ويب. ويتحقّق من أن الملف صورة حقيقية ومدعومة قبل تضمينها. تقيك هذه الحماية عندما تأتي أسماء الملفات من المستخدمين.
الخطوة 2: أضف جدولًا وقائمة نقطية
قسم بعنوان «الخطوة 2: أضف جدولًا وقائمة نقطية»الجداول والقوائم محتوى مُهيكل. وأسرع طريقة لوصف البنية هي HTML (لغة ترميز النص الفائق)، وهو الترميز نفسه الذي تستخدمه صفحات الويب. يعرض NextPDF مجموعة مدعومة من HTML مباشرةً على صفحة PDF. ولا يتدخّل أي متصفّح.
احفظ هذا باسم 02-table-and-lists.php ونفّذه بالأمر
php 02-table-and-lists.php:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();$document->setTitle('Tutorial: tables and lists');$document->addPage();
$document->setFont('helvetica', 'B', 20);$document->cell(0, 26, 'A reading list, two ways', newLine: true);$document->ln(8);
$html = <<<'HTML'<h2>The books as a table</h2><table border="1" cellpadding="6" style="width: 100%;"> <thead> <tr style="background-color: #1E3A8A; color: #FFFFFF;"> <th style="width: 50%;">Title</th> <th style="width: 20%; text-align: center;">Year</th> <th style="width: 30%; text-align: right;">Pages</th> </tr> </thead> <tbody> <tr> <td>The Paper Office</td> <td style="text-align: center;">2019</td> <td style="text-align: right;">312</td> </tr> <tr style="background-color: #F8FAFC;"> <td>Ink and Pixels</td> <td style="text-align: center;">2023</td> <td style="text-align: right;">208</td> </tr> </tbody></table>
<h2>Why these two books</h2><ul> <li>Short chapters that fit into a lunch break</li> <li>Worked examples on every page</li> <li>No jargon without an explanation</li></ul>HTML;
$document->writeHtml($html);
$document->save(__DIR__ . '/out/table-and-lists.pdf');
echo "Wrote out/table-and-lists.pdf\n";من المفترض أن ترى Wrote out/table-and-lists.pdf. يحتوي ملف PDF على
عنوان وجدول من ثلاثة أعمدة بصفّ ترويسة داكن وقائمة نقطية.
ما الذي حدث للتوّ
قسم بعنوان «ما الذي حدث للتوّ»- يمزج السكربت بين أسلوبَي الكتابة في صفحة واحدة. تطبع
cell()العنوان الكبير عند موضع الكتابة الحالي. ثم تدفعwriteHtml()الجدول والقائمة إلى أسفل الصفحة تحته. - تضيف
ln(8)فجوة عمودية صغيرة، بارتفاع ثماني نقاط، بين العنوان ومحتوى HTML. وبدونها سيلتصق الاثنان معًا بإحكام. - يستخدم الجدول ترميز جداول عاديًّا:
<thead>لصفّ الترويسة، و<tbody>لصفوف البيانات، و<th>لخلايا الترويسة، و<td>لخلايا البيانات. يرسمborder="1"خطوط الشبكة، ويضيفcellpadding="6"متّسعًا داخل كل خلية. - عروض الأعمدة نِسب مئوية، مثل
width: 50%. فهي تقتسم العرض الكامل للجدول، بحيث يصمد التخطيط أمام تغيّر حجم الصفحة. تغطّي وصفة تخطيط جدول HTML الترويسات والتذييلات وتحديد أحجام الأعمدة بعمق. - تستخدم سمات
styleتصريحات CSS (أوراق الأنماط المتتالية)، لغة التنسيق الخاصة بالويب. تعمل الألوان والمحاذاة والعروض كما هو موضّح هنا. قبل أن تعتمد على خصائص أخرى، راجع مصفوفة دعم CSS. - القائمة النقطية ليست سوى
<ul>مع<li>واحد لكل عنصر. يرسم NextPDF علامات التنقيط والإزاحة نيابةً عنك.
إذا حدث خطأ ما
قسم بعنوان «إذا حدث خطأ ما»- الخطأ الذي يذكر
ImageProcessingExceptionيعني تعذُّر قراءة ملف الصورة أو فكّ ترميزه. تحقّق من المسار، وتحقّق من أن الملف بصيغة مدعومة مثل PNG أو JPEG. - الخطأ الذي يذكر
PageLayoutExceptionيعني رفض موضع أو حجم. يجب أن يكون العرض والارتفاع أكبر من صفر، ويجب أن يشير المسار إلى ملف محلّي، لا إلى عنوان ويب. - كلا الخطأين موصوف في مرجع أخطاء المحرّك.
- إذا ظهر الجدول بشكل غريب، فتحقّق من الترميز أولًا. يحتاج كل صفّ
<tr>وكل خلية<td>إلى وسم الإغلاق الخاص به. - لأي شيء آخر، ابدأ من دليل استكشاف الأخطاء وإصلاحها.
الخطوة التالية
قسم بعنوان «الخطوة التالية»يمكن لصفحاتك الآن أن تحمل صورًا وجداول وقوائم. في الدرس التعليمي التالي تدع المستند ينمو ليتجاوز صفحة واحدة وتُبقيه مرتّبًا بترويسات وتذييلات وأرقام صفحات. وللتعمّق أكثر في مواضيع اليوم، تغطّي وصفة تضمين الصور في مستند صيغ الصور وقواعد تحديد الحجم.