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

تضمين الصور داخل مستند

ضع صورة نقطية في موضع مطلق وبعرض صريح. احذف الارتفاع، فيستنتجه ⁨NextPDF⁩ من نسبة العرض إلى الارتفاع في المصدر. يتّبع هذا المثال examples/07-images.php. يمكنك استخدام ملفات ⁨JPEG⁩ و⁨PNG⁩ و⁨GIF⁩ و⁨BMP⁩ و⁨WebP⁩ و⁨AVIF.⁩

يضمّن ⁨NextPDF⁩ الصورة بوصفها كائن ⁨XObject⁩ للصورة وفق ⁨ISO 32000-2.⁩ ويحدّد قاموس الصورة العرض والارتفاع وعدد البتات لكل مكوّن بصورة صريحة.

Terminal window
composer require nextpdf/core:^3

واجهة image() البرمجية جزء من ⁨Core.⁩ ولا تحتاج إلى أي شيء آخر لتضمين ملف موجود. يولّد المثال المرافق صورة اختبارية باستخدام ⁨GD⁩، لذا يتطلّب ext-gd. ظلّت الواجهة البرمجية مستقرة منذ 1.0.0 وتعمل على مصفوفة النقل الخلفي 8.1–8.4.

تُحمِّل image($file, x, y, width, height) الملف عبر سجلّ الصور، وتفكّ ترميزه، ثم تضعه. يتحقّق السجلّ من صحة المسار قبل فكّ الترميز، ويرفض أي مسار يحتوي على بايت ⁨NUL⁩ أو يبدو كمخطّط مُحدِّد موارد موحَّد ‏(⁨URL⁩)‏ ‏(scheme://…). تقرأ image() الملفات المحلية فقط، ولا تقرأ أبدًا عنوان ⁨URL⁩ بعيدًا. ويرفض السجلّ كذلك أي قيمة غير موجبة لـ width أو height.

يستخدم الوضع مصفوفة التحويل الحالية لتعيين مربّع الوحدة الخاص بالصورة داخل المستطيل الهدف. يحدّد ⁨ISO 32000-2⁩ §8.8 المُعامِل cm داخل زوج q/Q لهذا الوضع، بحيث يبقى التحويل معزولًا. تصبح الصورة النقطية بعد فكّ ترميزها كائن ⁨XObject⁩ صورة. قيمة BitsPerComponent مطلوبة ويجب أن تكون إحدى القيم 1 أو 2 أو 4 أو 8 أو 16 ‏(§8.9.5).

يُولَّد سطح الواجهة البرمجية من ⁨PHPDoc.⁩ ويستخدم هذا المثال طريقة واحدة:

  • image(string $file, ?float $x = null, ?float $y = null, ?float $width = null, ?float $height = null): static — تضمّن صورة نقطية محلية وتضعها. احذف height للحفاظ على نسبة العرض إلى الارتفاع في المصدر. وترفض مسارات مخطّطات ⁨URL⁩ ومسارات بايت ⁨NUL⁩ والأبعاد غير الموجبة مع إطلاق PageLayoutException.

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

قسم بعنوان «نموذج الشيفرة — البدء السريع»
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
// Absolute position; height inferred from the source aspect ratio.
$doc->image(__DIR__ . '/logo.png', x: 15, y: 30, width: 80);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/images.pdf');

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

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
if (!\extension_loaded('gd')) {
fwrite(STDERR, "ext-gd required for the self-contained test image\n");
exit(1);
}
// Build a deterministic test image (fixed pixels — no entropy).
$imgPath = \tempnam(\sys_get_temp_dir(), 'npf') . '.png';
$img = \imagecreatetruecolor(200, 100);
if ($img === false) {
fwrite(STDERR, "GD imagecreatetruecolor failed\n");
exit(1);
}
$bg = (int) \imagecolorallocate($img, 30, 58, 138);
$fg = (int) \imagecolorallocate($img, 255, 255, 255);
\imagefilledrectangle($img, 0, 0, 199, 99, $bg);
\imagestring($img, 5, 40, 40, 'NextPDF Image', $fg);
\imagepng($img, $imgPath);
\imagedestroy($img);
try {
$doc = Document::createStandalone();
$doc->setTitle('Image Embedding');
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Image Embedding', newLine: true);
$doc->ln(5);
// Absolute placement; width fixed, height from aspect ratio.
$doc->image($imgPath, x: 15, y: 50, width: 80);
// Same image, narrower — scaled down by the CTM, not re-decoded.
$doc->image($imgPath, x: 15, y: 105, width: 40);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/images.pdf';
$doc->save($out);
echo "Created images.pdf\n";
} finally {
@\unlink($imgPath);
}
  • لا توجد عناوين ⁨URL⁩ بعيدة. يُرفض أي مسار يطابق scheme://… مع إطلاق PageLayoutException. نزّل الأصل إلى ملف محلي أولًا، ثم مرّر ذلك المسار. لا يجلب المُحمِّل أي شيء عبر الشبكة نيابةً عنك. هذه حماية متعمَّدة ضد تزوير الطلب من جانب الخادم ‏(⁨SSRF⁩).
  • الأبعاد غير الموجبة تُطلِق استثناءً. تؤدّي قيمة width <= 0 أو height <= 0 إلى إطلاق PageLayoutException. لاستخدام الحجم الطبيعي، احذف الوسيطة بدلًا من تمرير 0.
  • رفض المسار الذي يحتوي على بايت ⁨NUL.⁩ يُرفض أي مسار يحتوي على \0. وهذا يقي من مسارات التسميم بالبايت الصفري. تحقّق من صحة أسماء الملفات المقدَّمة من المستخدم.
  • نسبة العرض إلى الارتفاع. مرّر width وحده، أو height وحده، للتحجيم المتناسب. قد يؤدّي تمرير كلتا القيمتين إلى تشويه الصورة.
  • الملف نفسه مُضمَّن مرّتين. أعد استخدام مسار واحد للتحجيم عبر مصفوفة التحويل. لا يعيد المحرّك فكّ ترميز البايتات المتطابقة. وفضّل إعادة استخدام المسار على تكرار الملفات.

تتناسب تكلفة فكّ الترميز مع عدد بكسلات المصدر، لذا تكفي ميزانية 96 ⁨MB⁩ للسماح بصورة فوتوغرافية متوسطة. وضع المسار نفسه مرّة أخرى تكلفته منخفضة: مُعامِل Do إضافي واحد مع cm، وليس فكّ ترميز ثانٍ. لا يقلّل التصغير بحسب العرض من البكسلات المخزَّنة. أعد ضبط حجم صور المصدر الكبيرة مسبقًا إذا كان حجم المستند مهمًّا.

يقي رفض مخطّط ⁨URL⁩ وبايت ⁨NUL⁩ من ⁨SSRF⁩ وحقن المسارات. لا يمكن خداع image() لجلب http://… أو التجاوز إلى ما بعد البايت الصفري. ومع ذلك، عامِل أسماء الملفات المقدَّمة من المستخدم باعتبارها غير موثوقة. حُلّها بالنسبة إلى دليل أساس مسموح به قبل استدعاء image(). عندما يكون الملف مرفوعًا من المستخدم، يجري فكّ ترميز الصورة من بايتات يتحكّم فيها المهاجم. ضع سقفًا لحجم المُدخَل وفكّر في فكّ الترميز ضمن عامل معزول.

البيانالمواصفةالبند⁨reference_id⁩
يحدّد قاموس الصورة العرض والارتفاع وعدد البتات لكل مكوّن بصورة صريحة.⁨ISO 32000-2⁩§8.9.5
BitsPerComponent مطلوبة وقيمتها 1 أو 2 أو 4 أو 8 أو 16.⁨ISO 32000-2⁩§8.9.5
تُوضَع الصورة بواسطة المُعامِل cm داخل q/Q.⁨ISO 32000-2⁩§8.8

ملف قابلية إعادة الإنتاج — بنيوي. بايتات الصورة حتمية لمصدر ثابت. يحمل كل مستند محفوظ /ID في المقطورة وذرّات تاريخ، لذا تجرّدها منظومة الاختبار وتقارن البنية المُسوّاة بـ ⁨qpdf.⁩ يصف هذا المثال كيفية إنتاج ⁨NextPDF⁩ للبنية، ولا يقدّم ادعاء مطابقة شاملًا لـ ⁨ISO 32000-2.⁩

لا ينطبق. تضمين الصور النقطية قدرة في ⁨Core⁩، دون بوابة ⁨Premium.⁩