แปลงปริภูมิพิกัด: หมุน ปรับขนาด เอียง และสะท้อน
โดยสรุป
หัวข้อที่มีชื่อว่า “โดยสรุป”แปลงปริภูมิพิกัดสำหรับการวาดรอบจุดหมุนที่คุณเลือก วิธีนี้ครอบคลุมการหมุน การปรับขนาด การเอียง และการสะท้อน การแปลงแต่ละครั้งจะถูกแยกไว้ในบล็อกสถานะกราฟิกที่บันทึกไว้ จึงไม่ส่งผลต่อเนื้อหาที่ตามมา โดยใช้ examples/21-transforms.php เป็นต้นแบบ
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”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
หัวข้อที่มีชื่อว่า “ส่วนติดต่อ 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): staticDocument::scale(float $sx, float $sy, float $x = 0, float $y = 0): staticDocument::skewX(float $angle, float $x = 0, float $y = 0): static/skewY(...)Document::mirrorH(float $x = 0): static/mirrorV(float $y = 0): staticDocument::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 โดยใช้ตัวดำเนินการ cm | ISO 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 แบบครอบคลุมทั้งหมด มีเพียงข้อที่อ้างถึงเท่านั้นที่วิธีนี้นำมาใช้