إضافة علامات مائية نصية أو صورية وخلفيات إلى الصفحات
لمحة سريعة
قسم بعنوان «لمحة سريعة»يمكنك إضافة علامة “DRAFT” أو “CONFIDENTIAL” إلى كل صفحة، أو وضع شعار باهت خلف المحتوى. توضّح هذه الوصفة كيفية إضافة الخيارين إلى صفحات NextPDF الأساسية باستخدام واجهة المستند العامة: setAlpha() للشفافية، وstartTransform() / rotate() / stopTransform() للختم القطري، وtext() للعلامة، وimage() للخلفية النقطية.
يرجع الفرق بين العلامة المائية والخلفية إلى اختيار واحد: ترتيب الرسم.
- الخلفية: ارسمها أولًا، ثم اكتب محتوى صفحتك فوقها. تظهر العلامة خلف النص.
- العلامة المائية المتراكبة: اكتب محتوى صفحتك أولًا، ثم ارسم العلامة فوقه. تظهر العلامة في الأعلى.
يرسم NextPDF المحتوى بالترتيب الذي تستدعيه به، لذلك يحدد ترتيب الاستدعاءات ترتيب الطبقات. لا يوجد “وضع خلفية” منفصل؛ بل تحدد الطبقة باختيار وقت الرسم.
المتطلبات المسبقة: ثبّت النواة (composer require nextpdf/core:^3)، واستخدم، لإضافة خلفية صورية، ملفًا نقطيًا قابلًا للقراءة (PNG أو JPEG أو WebP) على القرص. يُنفَّذ المسار كله داخل العملية، من دون متصفح بلا واجهة أو استدعاء عبر الشبكة.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/core:^3نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»أي علامة تضيفها هي محتوى صفحة عادي يُرسم عبر الحالة الرسومية. تعمل ثلاثة أجزاء من الواجهة العامة معًا لإنتاج علامة مائية:
-
الشفافية. يضبط
setAlpha(float $alpha, BlendMode $mode = BlendMode::Normal)عتامة التعبئة لكل ما ترسمه بعد ذلك، من0.0(غير مرئي) إلى1.0(معتم). تكون العلامة المائية عادةً أفضل عند0.1إلى0.3، بحيث يبقى المحتوى الذي تحتها مقروءًا. يأتي وضع المزج من تعدادNextPDF\Graphics\BlendMode. على سبيل المثال، يُعتِّمBlendMode::Multiplyالمناطق التي تتداخل فيها العلامة مع المحتوى. -
التدوير. الختم القطري نص مُدوَّر حول نقطة ارتكاز. يحفظ
startTransform()الحالة الرسومية، ويُدوِّرrotate(float $angle, float $x, float $y)نظام الإحداثيات عكس اتجاه عقارب الساعة حول($x, $y)، ثم يستعيدstopTransform()الحالة المحفوظة. تمنع إحاطة العلامة بكتلة تحويل تسرّب التدوير وقيمة alpha إلى بقية الصفحة. -
العلامة نفسها. يكتب
text(float $x, float $y, string $text)سلسلة نصية في موضع مطلق بالخط واللون وقيمة alpha الحالية. يضعimage(string $file, ?float $x, ?float $y, ?float $width, ?float $height)صورة نقطية، وهو الأساس لعلامة مائية صورية أو خلفية تملأ الصفحة.
تُستعاد الحالة الرسومية على نحو نظيف لأن startTransform() وstopTransform() يحيطان بالتغيير. تبقى قيمة setAlpha() سارية حتى تضبطها من جديد. إذا كان يجب أن يكون المحتوى اللاحق معتمًا تمامًا، فأعد ضبط العتامة إلى 1.0 بعد العلامة. يرسم النمط الأكثر أمانًا، الموضح أدناه، العلامة داخل كتلة تحويل خاصة بها ويضبط قيمة alpha لمحتوى الصفحة صراحةً.
تتضمن الحزمة أيضًا كائنَي القيمة NextPDF\Graphics\Watermark وNextPDF\Graphics\WatermarkPosition. Watermark حاوية إعدادات غير قابلة للتغيير للنص وحجم الخط والزاوية واللون وعلم التراكب والمواضع مسبقة الضبط، مثل WatermarkPosition::Diagonal. تمثّل هذه الكائنات معاملات العلامة المائية. ترسم هذه الوصفة العلامة باستخدام طرق تعديل الصفحة المذكورة أعلاه، فينتقل الإخراج مباشرةً إلى دفق محتوى الصفحة.
واجهة API
قسم بعنوان «واجهة API»كل الطرق أدناه عامة في NextPDF\Core\Document وتُرجع static، بحيث يمكنك تسلسلها.
setAlpha(float $alpha, BlendMode $mode = BlendMode::Normal): static: يضبط عتامة التعبئة (0.0-1.0) ووضع المزج للمحتوى اللاحق.startTransform(): static: يحفظ الحالة الرسومية (يُصدرq).rotate(float $angle, float $x = 0, float $y = 0): static: يُدوِّر نظام الإحداثيات بمقدار$angleدرجة عكس اتجاه عقارب الساعة حول نقطة الارتكاز($x, $y).stopTransform(): static: يستعيد الحالة المحفوظة عبرstartTransform()(يُصدرQ)، فيلغي التدوير وتغيير alpha معًا.setFont(string $family, string $style = '', float $size = 12.0): static: يحدد الخط للعلامة. عائلة Base-14helveticaمتاحة دائمًا ولا تحتاج إلى ملف خط.setTextColor(int $r, int $g = -1, int $b = -1): static: يضبط لون العلامة بالأحمر والأخضر والأزرق (أو قيمة تدرج رمادي واحدة).text(float $x, float $y, string $text): static: يكتب العلامة في موضع مطلق.image(string $file, ?float $x = null, ?float $y = null, ?float $width = null, ?float $height = null): static: يضع صورة نقطية، وهي الأساس لعلامة مائية صورية أو خلفية بملء الصفحة.getPageWidth(): float/getPageHeight(): float: يقرأ حجم الصفحة الحالي بالنقاط حتى يمكنك توسيط العلامة.
توجد الأنواع الداعمة ضمن NextPDF\Graphics: تعداد BlendMode، وكائن القيمة Color، وزوج الإعدادات Watermark / WatermarkPosition.
عينة شفرة — بداية سريعة
قسم بعنوان «عينة شفرة — بداية سريعة»تكتب هذه العينة صفحة واحدة، وترسم ختمًا قطريًا باهتًا بنص “DRAFT” فوق المحتوى، ثم تحفظ الملف. تحذف العينة معالجة الأخطاء لإظهار شكل الاستدعاء فقط. تضيف عينة الإنتاج أدناه إجراءات الحماية كاملةً.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->addPage();
// Page content first, so the watermark lands on top of it.$doc->setFont('helvetica', '', 12);$doc->text(20.0, 40.0, 'Quarterly report: internal review copy.');
// Watermark second: a translucent, rotated stamp through the page center.$pivotX = $doc->getPageWidth() / 2.0;$pivotY = $doc->getPageHeight() / 2.0;
$doc->startTransform();$doc->setAlpha(0.15);$doc->setTextColor(150, 150, 150);$doc->setFont('helvetica', 'B', 72);$doc->rotate(45.0, $pivotX, $pivotY);$doc->text($pivotX - 110.0, $pivotY, 'DRAFT');$doc->stopTransform();
file_put_contents(__DIR__ . '/watermarked.pdf', $doc->getPdfData());عينة شفرة — الإنتاج
قسم بعنوان «عينة شفرة — الإنتاج»يرسم هذا البرنامج القائم بذاته علامة مائية نصية قطرية فوق محتوى مُولَّد. عندما توفر مسار صورة عبر متغير البيئة NEXTPDF_WATERMARK_IMAGE، فإنه يضع تلك الصورة خلفيةً باهتة وموسَّطة على صفحة ثانية. يتحقق البرنامج من مسار الصورة قبل الاستخدام، ويلتقط أكثر استثناءات NextPDF تحديدًا، ويكتب النتيجة إلى مسار يتحكم فيه الخادم. استبدل المحتوى المخزَّن في الذاكرة بمحتواك الخاص، ثم اربط الإخراج باستجابتك أو بطبقة التخزين لديك.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;use NextPDF\Exception\ImageProcessingException;use NextPDF\Exception\NextPdfException;use NextPDF\Exception\PageLayoutException;
/** * Paint a translucent, rotated text stamp across the current page. * * The mark is bracketed in a transform block so the rotation and the alpha * change are undone together and never leak into later content. * * @param non-empty-string $mark The watermark text (for example "CONFIDENTIAL") */function paintTextWatermark(Document $doc, string $mark): void{ $pivotX = $doc->getPageWidth() / 2.0; $pivotY = $doc->getPageHeight() / 2.0;
// Estimate the mark width so the rotated text sits centered on the pivot. // Helvetica averages ~0.5 em per glyph; half the width offsets the origin. $fontSize = 64.0; $halfWidth = (\strlen($mark) * $fontSize * 0.5) / 2.0;
$doc->startTransform(); $doc->setAlpha(0.12); $doc->setTextColor(120, 120, 120); $doc->setFont('helvetica', 'B', $fontSize); $doc->rotate(45.0, $pivotX, $pivotY); $doc->text($pivotX - $halfWidth, $pivotY, $mark); $doc->stopTransform();}
/** * Place a raster image as a faint, full-page background behind later content. * * The image is drawn first and at low opacity; page content written after this * call sits over it. The path is validated by the caller before it arrives. * * @param non-empty-string $imagePath A readable raster image (PNG, JPEG, WebP) * * @throws ImageProcessingException If the file is missing, unreadable, or corrupt. * @throws PageLayoutException If the placement coordinates are rejected. */function paintImageBackground(Document $doc, string $imagePath): void{ $doc->startTransform(); $doc->setAlpha(0.08); // Cover the full page: origin at the top-left, sized to the page box. $doc->image( file: $imagePath, x: 0.0, y: 0.0, width: $doc->getPageWidth(), height: $doc->getPageHeight(), ); $doc->stopTransform();}
$doc = Document::createStandalone();$doc->setTitle('Watermark and background sample');
// Page 1: content first, then an overlay text watermark on top.$doc->addPage();$doc->setAlpha(1.0);$doc->setTextColor(0, 0, 0);$doc->setFont('helvetica', '', 12);$doc->text(20.0, 40.0, 'Quarterly report: internal review copy.');
try { paintTextWatermark($doc, 'CONFIDENTIAL');} catch (PageLayoutException $e) { // Raised if a coordinate or page state is rejected while placing the mark. throw new RuntimeException( sprintf('Watermark placement failed: %s', $e->getConstraint()), previous: $e, );}
// Page 2: an optional image background, then content over it.$imagePath = getenv('NEXTPDF_WATERMARK_IMAGE');
if ($imagePath !== false && $imagePath !== '') { // Validate the path before touching the image loader: reject NUL bytes, // require a real readable file, and resolve it to defeat path traversal. if (str_contains($imagePath, "\0")) { throw new RuntimeException('Image path must not contain NUL bytes.'); }
$resolved = realpath($imagePath);
if ($resolved === false || !is_file($resolved) || !is_readable($resolved)) { throw new RuntimeException( sprintf('Background image "%s" is not a readable file.', $imagePath), ); }
$doc->addPage();
try { paintImageBackground($doc, $resolved); } catch (ImageProcessingException $e) { // Raised when the file cannot be decoded as a supported raster format. throw new RuntimeException( sprintf( 'Background image rejected (%s, op "%s").', $e->getFormat(), $e->getOperation(), ), previous: $e, ); } catch (PageLayoutException $e) { throw new RuntimeException( sprintf('Background placement failed: %s', $e->getConstraint()), previous: $e, ); }
$doc->setAlpha(1.0); $doc->setTextColor(0, 0, 0); $doc->setFont('helvetica', '', 12); $doc->text(20.0, 40.0, 'Page two over a faint background.');}
try { $pdf = $doc->getPdfData();} catch (NextPdfException $e) { // Base of the NextPDF exception hierarchy: any output-stage failure. throw new RuntimeException( sprintf('Document output failed: %s', $e->getMessage()), previous: $e, );}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$path = $out !== false && $out !== '' ? $out : __DIR__ . '/watermarked.pdf';
if (file_put_contents($path, $pdf) === false) { throw new RuntimeException(sprintf('Could not write PDF to "%s".', $path));}
printf("Wrote %d-byte PDF to %s\n", strlen($pdf), $path);الإخراج القياسي المتوقع (STDOUT) (يعتمد حجم البايتات على البناء وعلى ما إذا كنت قد وفّرت صورة):
Wrote <n>-byte PDF to <path>الحالات الحدية والمزالق
قسم بعنوان «الحالات الحدية والمزالق»- ترتيب الطبقات هو ترتيب الاستدعاء. الخلفية محتوى يُرسم قبل محتوى صفحتك، والعلامة المائية المتراكبة محتوى يُرسم بعده. لا يوجد علم يعيد ترتيب الطبقات؛ انقل الاستدعاء بدلًا من ذلك.
- تبقى قيمة alpha سارية حتى إعادة الضبط. يغيّر
setAlpha()الحالة لكل ما يُرسم بعد ذلك. إما أن تحيط العلامة بـstartTransform()/stopTransform()، الذي يستعيد قيمة alpha السابقة، أو أن تستدعيsetAlpha(1.0)قبل المحتوى المعتم. تستخدم عينة الإنتاج الأسلوبين. - وازِن كل كتلة تحويل. يحتاج كل
startTransform()إلىstopTransform()مطابق. تترك الكتلة غير المتوازنة التدوير أو قيمة alpha مطبَّقة على المحتوى اللاحق، ويُنشئ غيابstopTransform()اختلالًا في الحالة الرسومية يرفضه الكاتب عند الإخراج. - يرتكز
rotate()بإحداثيات المستخدم. نقطة الارتكاز($x, $y)بوحدات المستخدم مقاسة من أعلى يسار الصفحة، في الإطار نفسه الذي يستخدمهtext(). للحصول على قطر يمر عبر المركز، استخدم مركز الصفحة (getPageWidth() / 2،getPageHeight() / 2). - يحتاج النص المُدوَّر إلى إزاحة عرض يدوية. يضع
text()أصل السلسلة النصية؛ وهو لا يوسِّطها نيابةً عنك. اطرح ما يقارب نصف عرض النص المقدَّر من نقطة الارتكاز X حتى تتمركز العلامة المُدوَّرة حول المركز، كما تفعل الدالة المساعدة. - تتحجَّم الصور وفق الصندوق الذي تمرره. يمدد
image()الصورة النقطية إلىwidthوheightاللذين تمررهما. للحصول على خلفية تملأ الصفحة، مرر عرض الصفحة وارتفاعها؛ وللحصول على شعار في الزاوية، مرر حجمه الطبيعي. يثير البُعد الصفري أو السالبPageLayoutException. - يرفض
image()عناوين URL وبايتات NUL. يثير مسارscheme://أو بايت NUL في$fileاستثناءPageLayoutExceptionقبل أي فك ترميز. مرر مسارًا محليًا متحققًا منه فقط. - العلامة محتوى مرئي. العلامة المائية المرسومة بهذه الطريقة هي محتوى صفحة حقيقي، وليست تعليقًا توضيحيًا مخفيًا. يمكن لأي شخص يمتلك الملف قراءتها. إنها إشارة بصرية، وليست تحكمًا في الوصول.
الأداء
قسم بعنوان «الأداء»تستخدم العلامة المائية النصية عددًا قليلًا من معاملات دفق المحتوى لكل صفحة، ولا تضيف وقتًا أو ذاكرة يُذكران. تتطلب العلامة المائية الصورية أو الخلفية عملية فك ترميز نقطي واحدة، بالإضافة إلى بايتات الصورة المضمَّنة في الإخراج. تؤدي إعادة استخدام الصورة نفسها عبر الصفحات إلى إعادة استخدام XObject المفكوك ترميزه عبر ذاكرة التخزين المؤقت للصور، فتتحمل تكلفة فك الترميز مرة واحدة. حدّد حجم صور الخلفية وفق صندوق عرضها قبل التضمين. تخزِّن صورة بحجم 4000 px مُحجَّمة داخل صفحة بحجم letter بايتات لا يراها القارئ أبدًا. تبقى العلامة المائية النصية النموذجية ذات الصفحة الواحدة ضمن حدٍّ زمني قدره 500 ms وميزانية ذروة قدرها 32 MB بهامش جيد. تتبع خلفية الصورة الحجم المفكوك ترميزه للصورة النقطية المصدر.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»يعمل المسار داخل العملية. لا تغادر أي بايتات المستند المضيف، ولا يُجرى أي استدعاء عبر الشبكة. عامِل أي مسار صورة يأتي من خارج شفرتك بوصفه إدخالًا غير موثوق.
- تحقق من مسار الصورة قبل الاستخدام. ارفض بايتات NUL، وحُل المسار باستخدام
realpath()، وأكِّدis_file()وis_readable()قبل أن تستدعيimage()، تمامًا كما تفعل عينة الإنتاج. يمنع هذا اجتياز المسارات ويرفض الأدلة والروابط المعلَّقة مبكرًا. - لا تُدرج حقل طلب داخل مسار أبدًا. اشتق مسار الصورة ومسار المخرج من قيم يتحكم فيها الخادم، لا من معامل طلب. يمنعك هذا من قراءة أو كتابة ملفات خارج الدليل المقصود.
- عامِل الصور غير الموثوقة بوصفها إدخالًا عدائيًا. تثير الصورة النقطية المشوَّهة
ImageProcessingExceptionبدلًا من إفساد المستند، ويحدد المُحمِّل سقفًا لأبعاد الصورة لمقاومة مدخلات قنابل فك الضغط. التقط الاستثناء وارفض الملف المرفوع. لا تُعد المحاولة دون فحص. - العلامة المائية ليست مخزنًا للأسرار. العلامة محتوى مرئي. لا تُرمِّز بيانات الاعتماد أو الرموز المميزة أو المعرِّفات الداخلية في علامة مائية أو خلفية تُرجعها إلى عميل.
المطابقة
قسم بعنوان «المطابقة»لا تقدم هذه الوصفة أي ادعاء معياري خاص بها بشأن المعايير. إنها تركِّب أوليات alpha والتحويل والنص والصورة العامة. تُصدر كل أولية معاملات دفق محتوى PDF القياسية. تُعزَل الحالة الرسومية بمعاملَي q / Q اللذين يُصدرهما startTransform() وstopTransform()، وتُنقل الشفافية عبر معامل الحالة الرسومية ExtGState. الإخراج جديد بنيويًا وليس ثابت البايتات، لذلك تعلن هذه الصفحة عن ملف تعريف قابلية إعادة الإنتاج structural. للحصول على تفاصيل على مستوى المعاملات حول واجهة التحويل والحالة الرسومية، راجع مرجع وحدة Graphics.
انظر أيضًا
قسم بعنوان «انظر أيضًا»- مرجع وحدة Graphics: واجهة المسار والتحويل واللون والحالة الرسومية الكاملة التي تعتمد عليها هذه الطرق.
- تضمين الصور: تحميل الصور النقطية وتحديد حجمها ووضعها، وهي الأساس لعلامة مائية صورية أو خلفية.
- التدرجات والشفافية: واجهة alpha ووضع المزج بتعمق، بما في ذلك التعبئات شبه الشفافة.
- تحويل فضاء الإحداثيات: تدوير المحتوى وتحجيمه وإزاحته بكتل تحويل متوازنة.
- معالجة الأخطاء المدركة للاستثناءات: تسلسل استثناءات NextPDF الذي تعتمد عليه
ImageProcessingExceptionوPageLayoutExceptionوNextPdfException.