ข้ามไปยังเนื้อหา

แปลงปริภูมิพิกัด: หมุน ปรับขนาด เอียง และสะท้อน

แปลงปริภูมิพิกัดสำหรับการวาดรอบจุดหมุนที่คุณเลือก วิธีนี้ครอบคลุมการหมุน การปรับขนาด การเอียง และการสะท้อน การแปลงแต่ละครั้งจะถูกแยกไว้ในบล็อกสถานะกราฟิกที่บันทึกไว้ จึงไม่ส่งผลต่อเนื้อหาที่ตามมา โดยใช้ examples/21-transforms.php เป็นต้นแบบ

Terminal window
composer require nextpdf/core:^3

คุณไม่จำเป็นต้องใช้แพ็กเกจ Pro หรือ Enterprise เพราะ application programming interface (API) สำหรับการแปลงมาพร้อมกับ Core และทำงานบน PHP 8.1 ถึง 8.4

เนื้อหา Portable Document Format (PDF) จะถูกวาดใน user space ตามค่าเริ่มต้น user space มีจุดกำเนิดอยู่ที่มุมล่างซ้ายของหน้า และหนึ่งหน่วยเท่ากับ 1/72 นิ้ว (ISO 32000-2 §8.3.2) การแปลงจะคูณ current transformation matrix (CTM) ด้วยเมทริกซ์ใหม่ผ่านตัวดำเนินการ cm (§8.3.4) การแปลงหลายรายการประกอบกันด้วยการต่อเมทริกซ์ ลำดับจึงมีความสำคัญ

NextPDF ให้คุณทำงานในระบบพิกัดของผู้เขียนที่มีจุดกำเนิดอยู่ที่มุมบนซ้าย ภายใน NextPDF ระบบนี้จะถูกแปลงไปเป็น user space แบบ native ที่มีจุดกำเนิดอยู่ที่มุมล่างซ้ายผ่านการฉาย toY() ในเมท็อดการแปลง ตำแหน่งใช้หน่วยของ user space คือ PDF point โดยที่ 1 pt เท่ากับ 1/72 นิ้ว เมื่อต้องการจำกัดขอบเขตการแปลง ให้ครอบการแปลงไว้ระหว่าง startTransform() และ stopTransform() เมท็อดเหล่านี้จะเขียนตัวดำเนินการสถานะกราฟิก q (บันทึก) และ Q (คืนค่า) (§8.4.2) ทุกอย่างที่วาดระหว่างเมท็อดทั้งสองจะสืบทอดการแปลงนั้น ส่วนที่วาดหลังจาก stopTransform() จะกลับไปใช้ CTM ก่อนหน้า การเรียก rotate()/scale()/skewX()/mirrorH() แต่ละครั้งจะรับจุดหมุนอย่างชัดเจน การแปลงจึงยึดอยู่ที่ตำแหน่งที่คุณคาดหวัง แทนที่จะยึดกับจุดกำเนิดของหน้า

ส่วนติดต่อ 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";

โปรแกรมตัวอย่างแบบครบในไฟล์เดียวนี้ทำงานภายใต้ฮาร์เนสของ cookbook และสะท้อนส่วนการปรับขนาดของ 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 จะฉายค่านั้นไปยัง user space แบบ native การผสมพิกัด PDF แบบดิบกับ API ของผู้เขียนจะทำให้ผลลัพธ์ถูกสะท้อนกลับ
  • การรั่วไหลของสถานะ สี ฟอนต์ และความกว้างของเส้นที่ตั้งค่าไว้ภายในบล็อกการแปลงจะคงอยู่หลังจาก stopTransform() เนื่องจากในส่วนติดต่อ API นี้ Q จะคืนค่าเฉพาะ CTM เท่านั้น รีเซ็ตค่าเหล่านี้อย่างชัดเจนหากส่วนถัดไปต้องไม่สืบทอดค่าเหล่านั้น เช่นเดียวกับที่ตัวอย่างใช้งานจริงทำ

การแปลงจะเขียนตัวดำเนินการ cm หนึ่งตัว บวกกับคู่ q/Q แต่ละส่วนมีขนาดเพียงไม่กี่ไบต์และไม่เพิ่มต้นทุนเวลาทำงานที่วัดได้ วิธีนี้จึงอยู่ภายในงบประมาณ 1500 ms / 96 MB โปรไฟล์การทำซ้ำได้เป็นแบบ structural เอาต์พุตมีอาร์เรย์ /ID ใน trailer และเมทาดาทาการสร้างที่ไม่คงที่ในการทำงานแต่ละครั้ง คุณจึงต้องทำให้เป็นมาตรฐานก่อนการเปรียบเทียบ stream การแปลงเองให้ผลแบบกำหนดแน่นอน

  • Data Residency และมาตรการลดความเสี่ยงของ Personally Identifiable Information (PII) ไม่เกี่ยวข้อง เพราะวิธีนี้วาดรูปทรงเรขาคณิตพื้นฐานและป้ายกำกับสั้นๆ โดยไม่ประมวลผลข้อมูลภายนอกหรือข้อมูลส่วนบุคคล
  • Telemetry ที่ปลอดภัยและการล้างข้อมูลใน Log วิธีนี้เขียนบรรทัดแสดงความคืบหน้าแบบตายตัวหนึ่งบรรทัด และไม่บันทึกเนื้อหาเอกสารลงใน log
  • แบบจำลองภัยคุกคาม ไม่เกี่ยวข้อง ไม่มีการแยกวิเคราะห์อินพุต ไม่มีการเข้ารหัสลับ และไม่มีขอบเขตความเชื่อถือ การแปลงเป็นเพียงการเขียน content stream ล้วนๆ
  • พฤติกรรมในโหมด Federal Information Processing Standards (FIPS) ไม่เกี่ยวข้อง ไม่มีการดำเนินการเข้ารหัสลับ
ข้อความระบุข้อกำหนดข้อรหัสอ้างอิง (reference_id)
การแปลงจะต่อเมทริกซ์เข้ากับ CTM โดยใช้ตัวดำเนินการ cmISO 32000-2§8.3.4
การแปลงประกอบกันด้วยการต่อเมทริกซ์ และลำดับมีความสำคัญISO 32000-2§8.3.4
q บันทึกสถานะกราฟิก และ Q คืนค่าสถานะกราฟิก จึงกำหนดขอบเขตให้กับการแปลงISO 32000-2§8.4.2
จุดกำเนิดของ user space ตามค่าเริ่มต้นอยู่ที่มุมล่างซ้าย หนึ่งหน่วยคือ 1/72 นิ้วISO 32000-2§8.3.2

วิธีนี้สอดคล้องกับข้อกำหนดเรื่องสถานะกราฟิกและการแปลงของ ISO 32000-2 ที่อ้างถึง แต่ไม่ได้ยืนยันความสอดคล้องกับ ISO 32000-2 แบบครอบคลุมทั้งหมด มีเพียงข้อที่อ้างถึงเท่านั้นที่วิธีนี้นำมาใช้