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

تحويل فضاء الإحداثيات: تدوير وتحجيم وإمالة وانعكاس

حوِّل فضاء إحداثيات الرسم حول محور ارتكاز تختاره. تغطي هذه الوصفة التدوير والتحجيم والإمالة والانعكاس. يظل كل تحويل معزولًا داخل كتلة حالة رسومية محفوظة، لذلك لا يؤثر في المحتوى اللاحق. وتتبع الوصفة examples/21-transforms.php.

Terminal window
composer require nextpdf/core:^3

لا تحتاج إلى حزمة ⁨Pro⁩ أو ⁨Enterprise.⁩ تأتي واجهة برمجة التطبيقات (⁨API⁩) الخاصة بالتحويل مع ⁨Core⁩، وتعمل على ⁨PHP⁩ من الإصدار 8.1 حتى 8.4.

يُرسم محتوى تنسيق المستندات المحمول (⁨PDF⁩) في فضاء المستخدم. يقع أصل فضاء المستخدم افتراضيًا في الزاوية السفلية اليسرى من الصفحة، وتساوي الوحدة الواحدة 1/72 بوصة (⁨ISO 32000-2⁩ §8.3.2). يضرب التحويل مصفوفة التحويل الحالية (⁨CTM⁩) في مصفوفة جديدة عبر المُعامِل cm (§8.3.4). وتتركب التحويلات عبر تسلسل المصفوفات، لذلك يهم الترتيب.

يتيح لك ⁨NextPDF⁩ العمل في نظام إحداثيات المؤلف الذي يبدأ من الزاوية العلوية اليسرى. وداخليًا، يحوّل ذلك النظام إلى فضاء المستخدم الأصلي الذي يبدأ من الزاوية السفلية اليسرى عبر إسقاط toY() في توابع التحويل. تستخدم المواضع وحدات فضاء المستخدم: نقاط ⁨PDF⁩، حيث تساوي النقطة الواحدة 1/72 بوصة. لإبقاء التحويل محليًا، غلِّفه بين startTransform() وstopTransform(). تصدر هذه التوابع مُعاملَي حالة الرسوميات q ‏(الحفظ) وQ ‏(الاستعادة) ‏(§8.4.2). ويرث كل ما يُرسم بينهما هذا التحويل. أما كل ما يأتي بعد stopTransform() فيعود إلى مصفوفة التحويل الحالية (⁨CTM⁩) السابقة. يأخذ كل استدعاء من rotate()/scale()/skewX()/mirrorH() محور ارتكاز صريحًا، فيرتكز التحويل حيث تتوقعه بدلًا من أصل الصفحة.

سطح واجهة برمجة التطبيقات (⁨API⁩)

قسم بعنوان «سطح واجهة برمجة التطبيقات (⁨API⁩)»

يُولَّد سطح واجهة برمجة التطبيقات (⁨API⁩) من ⁨PHPDoc.⁩ وتأتي نقاط الدخول الرئيسية من السمة (⁨trait⁩) ‏\NextPDF\Core\Concerns\HasTransforms:

  • Document::startTransform(): static — يصدر q ويفتح كتلة حالة
  • Document::stopTransform(): static — يصدر Q ويغلق الكتلة
  • Document::rotate(float $angle, float $x = 0, float $y = 0): static
  • Document::scale(float $sx, float $sy, float $x = 0, float $y = 0): static
  • Document::skewX(float $angle, float $x = 0, float $y = 0): static / skewY(...)
  • Document::mirrorH(float $x = 0): static / mirrorV(float $y = 0): static
  • Document::translateCtm(float $dx, float $dy): static
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Coordinate Transforms');
$doc->addPage();
$cx = 60.0;
$cy = 60.0;
// Rotate 30° around (cx, cy). The transform is scoped to this block.
$doc->startTransform();
$doc->rotate(30, $cx, $cy);
$doc->setFont('helvetica', '', 14);
$doc->text($cx, $cy, 'Rotated 30 degrees');
$doc->stopTransform();
// Back to the untransformed CTM — this text is upright.
$doc->setFont('helvetica', '', 10);
$doc->text($cx, $cy + 20, 'Not rotated');
$doc->save(__DIR__ . '/transforms.pdf');
echo "Created: transforms.pdf\n";

يعمل هذا البرنامج المكتفي ذاتيًا ضمن منظومة اختبار دليل الوصفات. ويحاكي قسم التحجيم من examples/21-transforms.php. يبقى كل تحويل داخل كتلة حالة رسومية محفوظة مع محور ارتكاز صريح. وتُعاد حالة اللون والخط إلى الوضع الأصلي في النهاية، فلا يتسرب شيء إلى صفحة لاحقة.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Coordinate Transforms');
$doc->addPage();
$doc->setFont('helvetica', 'B', 13);
$doc->cell(0, 8, 'Scaling a reference square at 0.5x, 1.0x, 1.5x, 2.0x', newLine: true);
$doc->ln(6);
$scaleBaseY = $doc->getY();
$scaleFactors = [0.5, 1.0, 1.5, 2.0];
$doc->setDrawColor(30, 58, 138);
$doc->setLineWidth(0.4);
foreach ($scaleFactors as $idx => $factor) {
$cx = 25.0 + $idx * 45;
$cy = $scaleBaseY + 5;
$doc->startTransform();
$doc->scale($factor, $factor, $cx, $cy); // scale about (cx, cy)
$doc->setFillColor(220, 230, 241);
$doc->rect($cx, $cy, 15, 15, 'DF');
$doc->line($cx, $cy, $cx + 15, $cy + 15);
$doc->stopTransform(); // CTM restored here
// Drawn AFTER the block — at the original scale, untransformed.
$doc->setFont('helvetica', '', 8);
$doc->setTextColor(0);
$doc->text($cx, $scaleBaseY + 38, sprintf('%.1fx', $factor));
}
// Explicit state reset so nothing carries into the next section.
$doc->setTextColor(0);
$doc->setFillColor(255);
$doc->setDrawColor(0);
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script twice under
// the structural profile (the transform stream itself is deterministic).
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false && $out !== '' ? $out : __DIR__ . '/transforms.pdf');
echo "Wrote transforms.pdf\n";

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

Wrote transforms.pdf

يغطي المثال الكامل عائلات التحويل الأربع كلها: التدوير والتحجيم والإمالة والانعكاس. شغِّله عبر php examples/21-transforms.php؛ فيكتب examples/output/21-transforms.pdf.

  • اقرن الكتلة دائمًا. يجب أن يكون لكل startTransform() ما يطابقه من stopTransform(). يؤدي اختلال توازن عدد q/Q إلى إفساد حالة الرسوميات في بقية الصفحة ‏(⁨ISO 32000-2⁩ §8.4.2). يتتبع ⁨NextPDF⁩ العمق، لكن العقد على مستوى الوصفة يبقى واحدًا لواحد.
  • الترتيب غير تبادلي. تتركب التحويلات عبر تسلسل المصفوفات، لذلك فإن rotate() ثم scale() ليس مثل scale() ثم rotate(). طبِّقها داخل كتلة واحدة بالترتيب الذي تقصده.
  • محور الارتكاز يكون افتراضيًا عند الأصل. إذا أغفلت محور الارتكاز، فإن التحويل يرتكز حول أصل الصفحة، لا حول الشكل. وهذا عادةً ليس ما تريده، لذلك مرِّر محور الارتكاز صراحةً.
  • محور ⁨Y⁩ في فضاء المؤلف. قيمة y لمحور الارتكاز هي المسافة من الزاوية العلوية اليسرى في فضاء المؤلف، ويسقطها ⁨NextPDF⁩ إلى فضاء المستخدم الأصلي. يؤدي خلط إحداثيات ⁨PDF⁩ الخام مع واجهة برمجة تطبيقات المؤلف إلى نتيجة معكوسة.
  • تسرب الحالة. يستمر اللون والخط وعرض الخط المحددة داخل كتلة التحويل بعد stopTransform()، لأن Q في سطح واجهة برمجة التطبيقات هذا يستعيد مصفوفة التحويل الحالية (⁨CTM⁩) فقط. أعد ضبط هذه القيم صراحةً إذا كان ينبغي ألا يرثها قسم لاحق، كما يفعل مثال الإنتاج.

يصدر التحويل مُعامِل cm واحدًا إضافةً إلى زوج q/Q. يبلغ حجم كل جزء بضعة بايتات فقط، ولا يضيف أي تكلفة قابلة للقياس في زمن التشغيل، لذلك تبقى الوصفة ضمن ميزانية 1500 ⁨ms⁩ / 96 ⁨MB.⁩ ملف إمكانية التكرار هو بنيوي. يحتوي الإخراج على مصفوفة /ID في الذيل وبيانات وصفية للإنشاء لا تثبت عبر عمليات التشغيل، لذلك يجب تطبيعها قبل المقارنة. أما دفق التحويل نفسه فهو حتمي.

  • إقامة البيانات وإجراءات التخفيف الخاصة بالمعلومات الشخصية التعريفية (⁨PII⁩). لا ينطبق. ترسم هذه الوصفة عناصر هندسية أولية وتسميات قصيرة، ولا تعالج أي بيانات خارجية أو شخصية.
  • القياس عن بُعد الآمن وتنقية السجلات. تكتب الوصفة سطر تقدُّم ثابتًا واحدًا، ولا تسجل أي محتوى للمستند.
  • نموذج التهديد. لا ينطبق. لا يوجد تحليل للمدخلات، ولا تشفير، ولا حدود ثقة. فالتحويل مجرد إصدار خالص لدفق المحتوى.
  • السلوك في وضع المعايير الفيدرالية لمعالجة المعلومات (⁨FIPS⁩). لا ينطبق. لا توجد أي عملية تشفير.
العبارةالمواصفةالبند⁨reference_id⁩
يسلسل التحويل مصفوفةً مع مصفوفة التحويل الحالية (⁨CTM⁩) عبر مُعامِل cm.⁨ISO 32000-2⁩§8.3.4
تتركب التحويلات عبر تسلسل المصفوفات، والترتيب مهم.⁨ISO 32000-2⁩§8.3.4
يحفظ q حالة الرسوميات ويستعيدها Q، وهو ما يحصر نطاق التحويل.⁨ISO 32000-2⁩§8.4.2
أصل فضاء المستخدم الافتراضي هو الزاوية السفلية اليسرى؛ والوحدة الواحدة تساوي 1/72 بوصة.⁨ISO 32000-2⁩§8.3.2

تتبع هذه الوصفة بنود حالة الرسوميات والتحويل المُستشهَد بها من ⁨ISO 32000-2.⁩ ولا تدّعي مطابقةً شاملةً لـ⁨ISO 32000-2⁩؛ فالبنود المُستشهَد بها هي وحدها التي تستعملها هذه الوصفة.