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

กราฟิก: พรีมิทีฟสำหรับเส้นทาง การไล่เฉดสี และการแปลง

โมดูล Graphics แปลงเจตนาในการวาดให้เป็นตัวดำเนินการกราฟิกของ Portable Document Format (PDF) ครอบคลุมเส้นทาง สไตล์เส้น ปริภูมิสี การแปลง การไล่เฉดสี ลวดลาย ฮาล์ฟโทน และการโหลดรูปภาพ

Terminal window
composer require nextpdf/core:^3

Graphics คือเลเยอร์สำหรับการวาดแบบเวกเตอร์และแรสเตอร์ โมดูลนี้สร้างลำดับตัวดำเนินการที่โมดูล ContentStream และ Writer จะซีเรียลไลซ์ลงในไฟล์ PDF คอนเทนต์สตรีมเข้ารหัสเนื้อหาของหน้าเป็นลำดับตัวดำเนินการกราฟิกตามลำดับภายใต้ International Organization for Standardization (ISO) 32000-2 §8 โมดูลนี้ปล่อยตัวดำเนินการเหล่านั้น แต่ไม่ได้เขียนไฟล์โดยตรง

DrawingEngine คืออินเทอร์เฟซการเขียนโปรแกรมประยุกต์ (API) หลัก เป็นตัวสร้าง (builder) แบบ fluent ที่มีสถานะ ตัวกำหนดค่า (setter) แต่ละตัวจะคืนค่า self บันทึกการเปลี่ยนแปลงสถานะกราฟิกหรือตัวดำเนินการสำหรับลงสีเส้นทาง แล้วผนวกเข้ากับบัฟเฟอร์ภายในที่อ่านได้ด้วย getStream() เอนจินจำลองสถานะกราฟิกของ PDF โดยตรง ได้แก่ ความกว้างเส้น สไตล์เส้น สีเส้นและสีเติม อัลฟาและโหมดผสมสี ขีดจำกัดมุมแหลม ซอฟต์มาสก์ การตัดขอบ การพิมพ์ทับ ความราบเรียบ ความเรียบเนียน เจตนาการเรนเดอร์ การสร้างสีดำ และการลบสีรองพื้น แต่ละรายการจับคู่กับตัวดำเนินการที่มีการบันทึกไว้ ตัวกำหนดสีรับค่าออบเจกต์ค่า Color หรือ ColorSpace ที่ระบุไว้อย่างชัดเจน ดังนั้นปริภูมิแบบอุปกรณ์และปริภูมิที่อิงตาม International Commission on Illumination (CIE) จึงใช้รูปแบบการเรียกเดียวกัน

มีตระกูลหลักสามกลุ่มที่ทำงานคู่กับเอนจิน กลุ่มแรกคืออินพุตรูปภาพ ImageLoader ถอดรหัสไฟล์หรือบล็อบในหน่วยความจำให้เป็น ImageLoadResult ส่วน ImageRegistry กำจัดข้อมูลซ้ำและติดตามรูปภาพที่ถอดรหัสแล้วพร้อม MemoryReport เพื่อให้เอกสารขนาดใหญ่ยังอยู่ภายในงบประมาณหน่วยความจำ สำหรับการนำเข้าแบบเวกเตอร์ SvgParser และ EpsParser จะแปลอินพุต Scalable Vector Graphics (SVG) และ Encapsulated PostScript (EPS) ให้เป็นสตรีมตัวดำเนินการเดียวกัน โดยเปิดเผย getBoundingBox() ไว้สำหรับการจัดวาง กลุ่มที่สามคือความเที่ยงตรงของสีระดับอุปกรณ์ ได้แก่ การไล่เฉดสี (ShadingManager ตระกูล Type2/Type3 และตระกูลเมช) ลวดลาย (PatternFill) ฮาล์ฟโทน (Type1/Type5/Type6/Type10/Type16) ฟังก์ชันการถ่ายโอน และปริภูมิสีที่อิงตาม International Color Consortium (ICC)

TransformEngine เป็นตัวช่วยเฉพาะทางสำหรับการแปลงพิกัด โดยห่อหุ้มการแปลงด้วย startTransform() และ stopTransform() ซึ่งปล่อยคู่ save/restore q และ Q มีตัวช่วยอัฟไฟน์แบบมีชื่อให้ใช้ ได้แก่ scale, translate, rotate, skew, mirrorH และ mirrorV ตัวช่วยแต่ละตัวรับจุดหมุน (pivot) ที่เป็นทางเลือกได้ เมทริกซ์การแปลงจะจับคู่ปริภูมิพิกัดภายในกับปริภูมิพิกัดเป้าหมาย ซึ่งเป็นแบบจำลองเดียวกับที่ ISO 32000-2 ใช้กับโดเมนการไล่เฉดสี — §8.7.4

การจัดการสีเป็นไปตาม Architectural Decision Record (ADR)-012: ปริภูมิสี ICCBased และปริภูมิสีที่อิงตาม CIE จะปล่อยตัวดำเนินการคอนเทนต์สตรีม cs/CS อย่างชัดเจน แทนที่จะพึ่งพาการถอยกลับไปใช้สีแบบอุปกรณ์ โปรไฟล์ ICC จะถูกห่อหุ้มเป็นสตรีม ICCBased พร้อมจำนวนองค์ประกอบที่ถูกต้องตาม ISO 32000-2 §8.6.5.5

คลาสเมทอดหลักบทบาท
DrawingEnginegetStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient()ตัวสร้างตัวดำเนินการเส้นทางและสถานะกราฟิกแบบมีสถานะ
TransformEnginestartTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream()การแปลงพิกัดแบบอัฟไฟน์
ImageLoaderload(string $filePath), loadFromString(string $data, string $mimeType)ถอดรหัสรูปภาพให้เป็น ImageLoadResult
ImageRegistryload(), loadFromString(), getMetadata(), memoryUsage(), reset()แคชรูปภาพแบบกำจัดข้อมูลซ้ำพร้อมการรายงานหน่วยความจำ
SvgParserparse(), parseFile()แปล SVG ให้เป็นสตรีมตัวดำเนินการ
EpsParserparse(), parseFile(), getBoundingBox()แปล EPS ให้เป็นสตรีมตัวดำเนินการ
ShadingManagerการลงทะเบียนการไล่เฉดสี + การปล่อยดิกชันนารีการไล่เฉดสีแบบแกน แบบรัศมี และแบบเมช
Halftone (นามธรรม)halftoneType(), toDict(), hasStream(), getStream()Type 1/5/6/10/16 สกรีนฮาล์ฟโทน

เรียกใช้ composer docs:generate-api-php -- --module=Graphics เพื่อสร้างตาราง PHPDoc แบบเต็ม

ที่มา: examples/06-colors-and-drawing.php

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\Color;
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\LineStyle;
$engine = new DrawingEngine();
$engine
->setLineWidth(1.5)
->setDrawColor(Color::rgb(0, 51, 102))
->setFillColor(Color::rgb(230, 240, 250))
->rect(20.0, 20.0, 160.0, 80.0)
->line(20.0, 110.0, 180.0, 110.0, new LineStyle(dash: [3.0, 2.0]));
$contentStreamBytes = $engine->getStream();

ตัวอย่างนี้เชื่อมต่อรีจิสทรีรูปภาพที่มีการรายงานหน่วยความจำเข้ากับวงเล็บการแปลง และสะท้อนโครงสร้างที่ใช้ใน examples/07-images.php และ examples/21-transforms.php

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Graphics\TransformEngine;
$registry = new ImageRegistry();
$image = $registry->load('/srv/assets/logo.png');
$report = $registry->memoryUsage();
if ($report->bytes > 32 * 1024 * 1024) {
// Decoded image cache exceeded the budget — reset before the next page.
$registry->reset();
}
$transform = new TransformEngine();
$transform
->startTransform()
->translate(40.0, 700.0)
->scale(0.5, 0.5)
->stopTransform();
$engine = new DrawingEngine();
$engine->reset();
$page = $transform->getStream() . $engine->getStream();
  • DrawingEngine มีสถานะ เรียก reset() ระหว่างหน้าที่เป็นอิสระต่อกัน เพื่อไม่ให้สถานะกราฟิกก่อนหน้ารั่วไหลเข้าสู่สตรีมถัดไป
  • TransformEngine ต้องมีคู่ startTransform()/stopTransform() ที่จับคู่กัน วงเล็บที่ไม่สมดุลจะทิ้ง q ที่ค้างอยู่ และทำให้สแตก save/restore เสียหายในขั้นถัดไปของ Writer
  • setSoftMask(), setOverprint(), setBlackGeneration() และ setUnderColorRemoval() เขียนมาร์กเกอร์สถานะกราฟิกแบบขยาย ภายใต้โปรไฟล์ที่ปฏิเสธคุณลักษณะนี้ มาร์กเกอร์เหล่านั้นจะไม่มีผล โปรดตรวจสอบตัวป้องกันของโปรไฟล์ก่อนพึ่งพาผลลัพธ์ทางภาพ
  • ImageRegistry กำจัดข้อมูลซ้ำตามเนื้อหา เส้นทางสองเส้นที่มีไบต์เหมือนกันจะใช้ออบเจกต์ร่วมกันหนึ่งตัว อย่าสันนิษฐานว่ามีรูปภาพ PDF หนึ่งภาพต่อการเรียก load() หนึ่งครั้ง
  • EpsParser::getBoundingBox() คืนค่ากรอบขอบเขตที่แจงแล้ว ไม่ใช่กรอบหน้า ใช้การตัดขอบของคุณเองหากภาพ EPS ล้นออกนอกสี่เหลี่ยมเป้าหมาย
  • การชดเชยจุดดำเป็นเพียงคำแนะนำและอิงตามมาร์กเกอร์ การชดเชยนี้ไม่ได้แปลงพิกเซลด้วยตัวเอง

การตรวจสอบความถูกต้องและการจัดการข้อผิดพลาด

หัวข้อที่มีชื่อว่า “การตรวจสอบความถูกต้องและการจัดการข้อผิดพลาด”

การเปลี่ยนแปลงฝั่งผู้ผลิตสองรายการเป็นการเปลี่ยนแปลงที่ทำให้เข้ากันไม่ได้ (breaking) ทั้งสองรายการเปลี่ยนความเสียหายที่เคยเกิดขึ้นอย่างเงียบๆ ให้เป็นความล้มเหลวที่ชัดเจน ณ จุดที่เรียกใช้

การตรวจสอบความถูกต้องของอินพุตจะโยนข้อยกเว้นแล้ว (หมายเหตุการย้ายระบบ) อินพุตการวาดจะถูกตรวจสอบความถูกต้องก่อนถึงสตรีมตัวดำเนินการ และค่าที่ไม่ถูกต้องจะถูกปฏิเสธด้วย InvalidArgumentException ผู้เรียกที่ส่ง NaN, Infinity หรือค่านอกช่วงเคยสร้างตัวดำเนินการที่เสียหายอย่างเงียบๆ แต่อินพุตเดียวกันนี้ในตอนนี้จะทำให้เกิดข้อยกเว้น ข้อจำกัดที่ตรวจสอบความถูกต้องมีดังนี้:

  • อัลฟาของสีต้องเป็นค่าจำกัดและอยู่ภายใน [0, 1]
  • ตัวถูกดำเนินการของเมทริกซ์การแปลงปัจจุบัน (CTM) มิติของเทมเพลต พิกัดจุดยอดการไล่ระดับสี และพิกัดแพตช์เมช ต้องเป็นค่าจำกัด — ไม่มี NaN หรือ Infinity
  • แฟล็กขอบของแพตช์การไล่ระดับสีต้องเป็นหนึ่งใน {0, 1, 2, 3}
  • พารามิเตอร์ฟังก์ชัน Type 2/3/4 และพารามิเตอร์ฮาล์ฟโทนได้รับการตรวจสอบขอบเขต
  • ชื่อสารให้สี (colourant) ได้รับการ escape
  • ชื่อเลเยอร์ของกลุ่มเนื้อหาที่เป็นทางเลือก (OCG) ต้องไม่ว่างเปล่า

โปรดตรวจสอบจุดที่เรียกซึ่งคำนวณพิกัดหรืออัลฟาจากข้อมูลต้นทางก่อนอัปเกรด: ค่าที่เคยผ่านได้ในอดีตตอนนี้จะกลายเป็นข้อผิดพลาดร้ายแรง

ICCBased /N เป็นแบบ fail-closed โดยค่าเริ่มต้น เอาต์พุต PDF แบบธรรมดาจะปฏิเสธปริภูมิสี ICCBased ที่มีจำนวนองค์ประกอบ /N อยู่นอก {1, 3, 4} และกระทบยอด /N ที่ประกาศไว้กับโปรไฟล์ที่ฝังอยู่และปริภูมิ /Alternate ลักษณะการทำงานนี้เป็นไปตามกฎ ISO 32000-2 §8.6.5.5 สำหรับสตรีม ICCBased ซึ่งมี /N อยู่ควบคู่กับปริภูมิ /Alternate โปรไฟล์ ICC แบบ N ช่อง เช่น โปรไฟล์เฮกซะโครมที่มี N = 6 จะถูกคงไว้เฉพาะเมื่อมีโปรไฟล์ PDF/A หรือ PDF/X ที่ใช้งานอยู่ โดยเลือกเปิดใช้ผ่าน IccConformancePolicy::ProfileGated นี่เป็นเกตเชิงโครงสร้างตามจำนวนองค์ประกอบ ไม่ใช่การกล่าวอ้างถึงการรับรอง PDF/A หรือ PDF/X

การปล่อยตัวดำเนินการเป็นเชิงเส้นตามจำนวนการเรียกวาด: การผนวกแบบ O(n) เข้าสู่บัฟเฟอร์โดยไม่มีการจัดเรียงใหม่ ต้นทุนการถอดรหัสรูปภาพมาจากตัวแปลงรหัสและจำนวนพิกเซล ไม่ใช่จากรีจิสทรี การกำจัดข้อมูลซ้ำด้วยแฮชเนื้อหาของรีจิสทรีคือกลไกหลักสำหรับเอกสารขนาดใหญ่: สินทรัพย์ที่นำกลับมาใช้ซ้ำมีต้นทุนการถอดรหัสหนึ่งครั้งและออบเจกต์ PDF หนึ่งตัว performance_budget สำหรับเวิร์กโหลดอ้างอิงของโมดูลนี้คือ 1500 ms wall และ 64 MB peak ใช้ ImageRegistry::memoryUsage() เพื่อสังเกตรอยเท้าของรูปภาพที่ถอดรหัสแล้ว และใช้ reset() เพื่อปลดปล่อยรอยเท้านั้นระหว่างกลุ่มหน้า

SvgParser และ EpsParser รับอินพุตเวกเตอร์ที่ไม่น่าเชื่อถือ โปรดปฏิบัติต่อทั้งสองรายการในฐานะตัวแจงข้อมูลที่อาจเป็นอันตราย บังคับใช้ขีดจำกัดขนาดอินพุตก่อนเรียก parse() และเรียกใช้การแยกข้อมูลในเวิร์กเกอร์ที่ถูกจำกัดเมื่อแหล่งที่มามาจากผู้ใช้ EPS เป็นภาษาถิ่นของ PostScript ตัวแจงข้อมูลจะแปลชุดย่อยที่ถูกจำกัดและไม่ได้รันอินเทอร์พรีเตอร์ทั่วไป แต่ยังควรจำกัดขนาดอินพุตและเวลาในการแจง ตัวโหลดรูปภาพถอดรหัสผ่านตัวแปลงรหัสจากบุคคลภายนอก โปรดอัปเดตส่วนขยายรูปภาพของรันไทม์ให้เป็นปัจจุบันและจำกัดขนาดมิติที่ถอดรหัส ดูแบบจำลองภัยคุกคามของเอนจินใน /modules/core/security/ สำหรับขอบเขตความน่าเชื่อถือและแนวทางการแยกตัวของเวิร์กเกอร์

โมดูลนี้ปล่อยโครงสร้างตัวดำเนินการกราฟิก PDF ที่สอดคล้องกับ ISO 32000-2 §8 ดิกชันนารีปริภูมิสี ICCBased ตาม §8.6.5.5 และดิกชันนารีการไล่เฉดสีที่มี Domain, Function, Matrix และ BBox ตาม §8.7.4 ข้อความเหล่านี้เป็นข้อเท็จจริงของการนำไปใช้งาน: src/Graphics/ ผลิตรูปแบบของตัวดำเนินการและดิกชันนารี และ tests/Unit/Graphics/ พร้อมด้วยเบสไลน์ tests/Golden/PdfWriter/PdfWriterShadingGoldenBaselineSmokeTest และ PdfWriterExtGStateGoldenSmokeTest ทดสอบสิ่งเหล่านั้น ข้อความเหล่านี้ไม่ใช่การกล่าวอ้างถึงความสอดคล้อง PDF 2.0 หรือ PDF/X แบบครบวงจร ความสอดคล้องของเอกสารทั้งฉบับได้รับการตรวจสอบความถูกต้องแยกต่างหากโดยชุดทดสอบ oracle และ golden ที่อธิบายไว้ใน /modules/core/conformance/ พฤติกรรมของโปรไฟล์สำหรับ ICC OutputIntents ตัดสินโดย ADR-011 และ ADR-012 ไม่ใช่โดยโมดูลนี้เพียงลำพัง