Pro รุ่น
Writer — เอกสารอ้างอิงเชิงลึก
ภาพรวมโดยสรุป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสรุป”โมดูล Writer เขียน revision แบบ incremental-update ของ PDF และแพ็กออบเจกต์ขนาดเล็กลงใน Object Stream ตัวเขียน incremental บังคับกฎ append-only แบบ fail-closed คือทุกไบต์ที่บัฟเฟอร์ถือไว้ก่อน revision ต้องคงเดิมไม่เปลี่ยนหลังจากนั้น ตัวสร้าง Object Stream รวมออบเจกต์ที่มีสิทธิ์เข้าเป็นออบเจกต์ /Type /ObjStm เดียวที่บีบอัดด้วย FlateDecode ภายใต้ขนาดที่จำกัด
ความพร้อมใช้งานและการอนุญาต
หัวข้อที่มีชื่อว่า “ความพร้อมใช้งานและการอนุญาต”ความสามารถนี้มาพร้อมกับ NextPDF Pro ( nextpdf/pro ) และเปิดใช้งานด้วย envelope ใบอนุญาตระดับ Pro การติดตั้งที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและรับใบอนุญาต ไม่มีแฟล็กใบอนุญาตต่อฟีเจอร์ โค้ดมาพร้อมกับรุ่น Pro
พื้นผิว API สาธารณะ
หัวข้อที่มีชื่อว่า “พื้นผิว API สาธารณะ”โมดูลอยู่ภายใต้ namespace NextPDF\Pro\Writer สัญลักษณ์สาธารณะทั้งหมดแสดงไว้ด้านล่าง value object เป็นคลาส final readonly แบบไม่เปลี่ยนแปลง
| Symbol | Parameters | Default behavior | Returns | Throws or fails with | Notes |
|---|---|---|---|---|---|
IncrementalUpdateWriter::writeRevision | BinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileId | Static เขียน catalog ใหม่ด้วยรายการที่ผสานแล้ว ต่อท้าย cross-reference table แบบดั้งเดิมสำหรับออบเจกต์ใหม่และที่แก้ไข และเขียน trailer ที่มี /Size, /Root, /Prev และ /ID ตรวจสอบว่า prefix ก่อน revision เท่ากันแบบไบต์ต่อไบต์หลังจากนั้น | int — byte offset ของ cross-reference table ใหม่ | \NextPDF\Exception\WriterException เมื่อการตรวจ append-only prefix ล้มเหลว; getWriterState() คืนค่า dss-append-only-invariant | จุดเข้าแบบ static ไม่มีผลลัพธ์ที่ใช้งานได้เมื่อละเมิด |
ObjectStreamWriter::addObject | int $objectNumber, string $content | ต่อท้ายออบเจกต์หนึ่งรายการเข้ากับ stream ที่ค้างอยู่หลังตรวจขนาด | void | OverflowException เมื่อ index รวมกับ body จะเกิน 65,536 ไบต์ | $content ไม่รวม wrapper N 0 obj / endobj |
ObjectStreamWriter::canAccept | string $content | ประมาณ overhead ของ index และทดสอบยอดรวมสะสมกับค่าสูงสุด | bool | ไม่ยกข้อยกเว้น | predicate ล้วน ไม่เปลี่ยนสถานะ |
ObjectStreamWriter::build | none | สร้าง index ต่อ body เข้าด้วยกัน บีบอัดด้วย FlateDecode และห่อพจนานุกรม /Type /ObjStm | string — เนื้อหา Object Stream ดิบ | ObjectStreamWriteException เมื่อไม่มีออบเจกต์ถูกเพิ่ม หรือเมื่อการบีบอัด zlib ล้มเหลว | ผู้เรียกใช้กำหนดหมายเลขออบเจกต์และห่อ marker |
ObjectStreamWriter::getEntries | none | คำนวณ offset สัมพัทธ์กับ body ใหม่สำหรับออบเจกต์ที่สะสมไว้ | list<ObjectStreamEntry> | ไม่ยกข้อยกเว้น | offset สัมพัทธ์กับส่วน body |
ObjectStreamWriter::count | none | รายงานจำนวนออบเจกต์ที่สะสมไว้ | int | ไม่ยกข้อยกเว้น | — |
ObjStmCompressor::__construct | int $maxStreamSize = 65536, int $maxObjectsPerStream = 200 | เก็บขีดจำกัดขนาดและจำนวนออบเจกต์ที่ใช้ในการจัดกลุ่ม | — | ไม่ยกข้อยกเว้น | ค่าเริ่มต้นตรงกับการปรับแต่ง Object Stream ของโมดูล |
ObjStmCompressor::groupObjects | list<array{number: int, generation?: int, content: string}> $objects | กรองออบเจกต์ที่ไม่มีสิทธิ์ออก แล้วแพ็กที่เหลือลงใน writer ภายในขีดจำกัดขนาดและจำนวน | list<ObjectStreamWriter> | ไม่ยกข้อยกเว้น; ออบเจกต์ที่ไม่มีสิทธิ์ถูกข้าม | ออบเจกต์ที่ generation ไม่ใช่ศูนย์จะตกไปยัง serialization ปกติ |
ObjStmCompressor::isEligible | string $content, int $generation = 0 | ปฏิเสธ stream object, /Encrypt, /XRef, /Catalog และ generation ที่ไม่ใช่ศูนย์ใด ๆ | bool | ไม่ยกข้อยกเว้น | การจับคู่ /Type ทนต่อ whitespace และ escape #xx |
ObjStmCompressor::writeToBuffer | list<ObjectStreamWriter> $streams, BinaryBuffer $buffer, ObjectRegistry $registry | จัดสรร carrier object ต่อ stream ลงทะเบียน type-2 compressed entry และเขียนบล็อก ObjStm แต่ละบล็อก | list<int> — หมายเลข carrier object | ส่งต่อ ObjectStreamWriteException จาก build() เมื่อการบีบอัดล้มเหลวในกรณีที่พบยาก | รันหลังจากเขียนออบเจกต์ที่ไม่มีสิทธิ์แล้ว และก่อนที่ cross-reference จะถูก emit |
ObjStmCompressor::estimateSavings | list<ObjectStreamWriter> $streams, int $originalSize | สร้างแต่ละ stream เพื่อวัดขนาดที่บีบอัดเทียบกับต้นฉบับ | ObjStmCompressionResult | ส่งต่อ ObjectStreamWriteException จาก build() เมื่อการบีบอัดล้มเหลวในกรณีที่พบยาก | ตัวช่วยวัดค่าแบบอ่านอย่างเดียว |
ObjectStreamEntry::__construct | int $objectNumber, string $content, int $offset | เรกคอร์ดแบบไม่เปลี่ยนแปลงของออบเจกต์ที่แพ็กหนึ่งรายการและ body offset ของมัน | — | ไม่ยกข้อยกเว้น | final readonly; property สาธารณะ |
ObjStmCompressionResult::__construct | int $originalObjectCount, int $streamCount, int $estimatedOriginalSize, int $estimatedCompressedSize | ตัวเก็บ metric แบบไม่เปลี่ยนแปลง | — | ไม่ยกข้อยกเว้น | final readonly; property สาธารณะ |
ObjStmCompressionResult::savedBytes | none | คืนค่าขนาดต้นฉบับลบขนาดที่บีบอัด | int | ไม่ยกข้อยกเว้น | อาจเป็นค่าลบเมื่อการแพ็กทำให้ข้อมูลขยายขึ้น |
ObjStmCompressionResult::savedPercent | none | คืนค่าเปอร์เซ็นต์การลดขนาด | float | ไม่ยกข้อยกเว้น | คืนค่า 0.0 เมื่อขนาดต้นฉบับเป็นศูนย์ |
ObjStmCompressionResult::compressionRatio | none | คืนค่าขนาดที่บีบอัดหารด้วยต้นฉบับ | float | ไม่ยกข้อยกเว้น | คืนค่า 1.0 เมื่อขนาดต้นฉบับเป็นศูนย์ |
ObjectStreamWriteException | — | ส่งสัญญาณความล้มเหลวในการสร้าง Object Stream | — | สืบทอดจาก RuntimeException | ยกโดย build(); ดักจับได้ผ่าน RuntimeException เพื่อความเข้ากันได้ย้อนหลัง |
ลายเซ็นจุดเข้าใช้งาน
หัวข้อที่มีชื่อว่า “ลายเซ็นจุดเข้าใช้งาน”final class IncrementalUpdateWriter{ public static function writeRevision( BinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileId, ): int;}final class ObjectStreamWriter{ public function addObject(int $objectNumber, string $content): void; public function canAccept(string $content): bool; public function build(): string; /** @return list<ObjectStreamEntry> */ public function getEntries(): array; public function count(): int;}final class ObjStmCompressor{ public function __construct( int $maxStreamSize = 65536, int $maxObjectsPerStream = 200, );
/** * @param list<array{number: int, generation?: int, content: string}> $objects * @return list<ObjectStreamWriter> */ public function groupObjects(array $objects): array;
public function isEligible(string $content, int $generation = 0): bool;
/** * @param list<ObjectStreamWriter> $streams * @return list<int> */ public function writeToBuffer(array $streams, BinaryBuffer $buffer, ObjectRegistry $registry): array;
/** @param list<ObjectStreamWriter> $streams */ public function estimateSavings(array $streams, int $originalSize): ObjStmCompressionResult;}สัญญาพฤติกรรม
หัวข้อที่มีชื่อว่า “สัญญาพฤติกรรม”writeRevision เขียน revision แบบ incremental-update หนึ่งรายการ มันทำ snapshot ของ prefix ของบัฟเฟอร์ที่มีอยู่ก่อนเขียน มันเขียน catalog ใหม่ด้วยรายการที่ผสานแล้ว ลงทะเบียน offset ของออบเจกต์ใหม่ เขียน cross-reference table แบบดั้งเดิมที่จัดกลุ่มเป็น subsection ที่ต่อเนื่องกัน และเขียน trailer ที่มี /Size, /Root, /Prev และ /ID หลังจากเขียนแล้ว มันเปรียบเทียบ prefix อีกครั้ง หากไบต์ก่อนหน้าใดเปลี่ยนไป มันจะยก WriterException ที่พกสถานะ append-only-violation และไม่คืนผลลัพธ์ที่ใช้งานได้ เมื่อสำเร็จ มันจะคืนค่า byte offset ของ cross-reference table ใหม่เพื่อร้อยต่อ revision เพิ่มเติม การผสม cross-reference table และ stream ข้าม revision ต่าง ๆ เป็นที่อนุญาต
ObjectStreamWriter สะสมออบเจกต์ addObject ยกข้อผิดพลาด overflow เมื่อ index และ body รวมกันจะเกินค่าสูงสุด 65,536 ไบต์แบบไม่บีบอัด build ยกข้อผิดพลาดสำหรับ stream ที่ว่าง มิฉะนั้นมันจะบีบอัด index บวก body และคืนเนื้อหา Object Stream พร้อมรายการ /Type /ObjStm, /N, /First, /Length และ /Filter /FlateDecode ผู้เรียกใช้เป็นผู้กำหนดหมายเลขออบเจกต์และห่อ marker N 0 obj / endobj
ObjStmCompressor ตัดสินว่าออบเจกต์ใดจะถูกแพ็ก มันยกเว้น stream object, พจนานุกรมการเข้ารหัส, cross-reference stream, document catalog และออบเจกต์ใดที่มีหมายเลข generation ไม่ใช่ศูนย์ writeToBuffer จัดสรร carrier object ต่อ stream ลงทะเบียนออบเจกต์ที่แพ็กแต่ละตัวเป็น type-2 compressed cross-reference entry และเขียนบล็อก ObjStm ที่ offset ปัจจุบันของบัฟเฟอร์ estimateSavings สร้างแต่ละ stream เพื่อคำนวณ metric ขนาดโดยไม่เปลี่ยนแปลงบัฟเฟอร์
กรณีขอบและโหมดความล้มเหลว
หัวข้อที่มีชื่อว่า “กรณีขอบและโหมดความล้มเหลว”- การตรวจ append-only ทำสำเนา prefix ที่มีอยู่ ต้นทุนของมันเพิ่มตามขนาดของเอกสารที่เขียนไปแล้ว ต้นทุนนี้เป็นความตั้งใจและปกป้องไบต์ที่ลงนามแล้ว
- ขีดจำกัดของ Object Stream ใช้กับ index บวก body แบบไม่บีบอัด ให้วางพจนานุกรมการเข้ารหัสและชนิดออบเจกต์อื่นที่ถูกยกเว้นเป็น direct indirect object
- การยกเว้น
/Typeทนต่อ whitespace ระหว่าง token ตามอำเภอใจและ hex escape#xxรูปแบบเช่น/Type /Encrypt,/Type\n/Encryptและ/Type /#45ncryptทั้งหมดถูกปฏิเสธ ไม่ใช่เพียงการสะกดตัวอักษรตามรูปแบบมาตรฐานเท่านั้น - ออบเจกต์ใดที่พกหมายเลข generation ไม่ใช่ศูนย์จะถูกถือว่าไม่มีสิทธิ์ และตกไปยัง serialization
N G obj … endobjปกติ เพราะ generation ของออบเจกต์ที่บีบอัดเป็นศูนย์โดยปริยาย writeToBufferต้องรันหลังจากเขียนออบเจกต์ที่ไม่มีสิทธิ์ทั้งหมดแล้ว และก่อนที่ cross-reference จะถูก emit ออบเจกต์ที่แพ็กแล้วต้องไม่ถูก serialize แยกอีกด้วย
พฤติกรรมในโหมด FIPS
หัวข้อที่มีชื่อว่า “พฤติกรรมในโหมด FIPS”โมดูล Writer ไม่ทำการดำเนินการเชิงการเข้ารหัสลับใด ๆ มันปกป้องไบต์ที่ลงนามแล้วโดยปฏิเสธที่จะ emit เมื่อไบต์ก่อนหน้าจะเปลี่ยนไป ซึ่งเป็นการทดสอบความเท่ากันของไบต์มากกว่าการทดสอบเชิงการเข้ารหัสลับ การเลือกอัลกอริทึม FIPS สำหรับการลงนามและการแฮชถูกกำกับโดยโมดูลการลงนาม ไม่ใช่โดย writer นี้ การเปิดหรือปิดโหมด FIPS ไม่เปลี่ยนพฤติกรรมของเมธอด Writer ใด ๆ
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”NextPDF ทำการ implement โมดูลนี้ตาม ISO 32000-2:2020 ตัวเขียน incremental ทำตามไวยากรณ์ incremental-update ของ §7.5.6 คือแต่ละ revision ต่อท้าย cross-reference section ที่ครอบคลุมเฉพาะออบเจกต์ที่ใหม่ เปลี่ยนแปลง หรือถูกลบ และ trailer ที่ /Prev ให้ offset ของ cross-reference ก่อนหน้า ตัวสร้าง Object Stream ทำตามแบบจำลอง object-stream ของ §7.5.7 คือ index ของคู่หมายเลขออบเจกต์และ offset ที่ offset วัดจากรายการ /First โดยเรียงเพิ่มขึ้น นำหน้า body ของออบเจกต์ที่แพ็กไว้ การอ้างอิงข้อกำหนดทั้งสองถูกตรวจสอบเทียบกับคอร์ปัส ISO 32000-2:2020 การร้อยต่อ revision สำหรับ workflow PAdES B-LT และ B-LTA ทำตาม ETSI EN 319 142-1 §5.4 ตามที่ระบุไว้ในซอร์ส การรองรับข้อกำหนดหนึ่งเป็นคำแถลงความสามารถเชิงวิศวกรรม ไม่ใช่การรับรอง NextPDF ไม่ถือใบรับรองความสอดคล้องอย่างเป็นทางการใด ๆ
หมายเหตุการพัฒนา
หัวข้อที่มีชื่อว่า “หมายเหตุการพัฒนา”- ติดตั้งแพ็กเกจด้วย
composer require nextpdf/pro:^3คลาสจะ resolve ภายใต้NextPDF\Pro\Writer IncrementalUpdateWriter::writeRevisionเป็นจุดเข้าแบบ static มันไม่ถือสถานะ instance ระหว่าง revisionObjectStreamEntry,ObjStmCompressionResult,IncrementalUpdateWriterและ compressor รวมกันเป็นพื้นผิวสาธารณะของโมดูล; repository ไม่มีตัวอย่างที่รันได้สำหรับมันWriterExceptionจากwriteRevisionบ่งชี้การละเมิด append-only ให้ถือเป็นความล้มเหลวขั้นรุนแรงและทิ้งบัฟเฟอร์- Object Stream carrier เป็น indirect object; ผู้เรียกใช้กำหนดหมายเลขออบเจกต์ผ่าน registry
ขอบเขตการเผยแพร่
หัวข้อที่มีชื่อว่า “ขอบเขตการเผยแพร่”หน้านี้บันทึกเฉพาะพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว public API ที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และ prefix ของ ticket อยู่นอกขอบเขต