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

الصور والجداول والقوائم

نادرًا ما يصنع النص وحده مستندًا مكتملًا. في هذا الدرس التعليمي تضيف ثلاث لبنات يومية: صورة وجدولًا وقائمة نقطية. تكتب سكربتين صغيرين، وكلٌّ منهما يُنتج ملف ⁨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> إلى وسم الإغلاق الخاص به.
  • لأي شيء آخر، ابدأ من دليل استكشاف الأخطاء وإصلاحها.

يمكن لصفحاتك الآن أن تحمل صورًا وجداول وقوائم. في الدرس التعليمي التالي تدع المستند ينمو ليتجاوز صفحة واحدة وتُبقيه مرتّبًا بترويسات وتذييلات وأرقام صفحات. وللتعمّق أكثر في مواضيع اليوم، تغطّي وصفة تضمين الصور في مستند صيغ الصور وقواعد تحديد الحجم.