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

Pro รุ่น

Diff — การอ้างอิงเชิงลึก

หน้านี้คือการอ้างอิงระดับสัญญาของโมดูล diff ใน NextPDF Pro คือ NextPDF\Pro\Diff โมดูลนี้เปรียบเทียบเอกสาร PDF สองฉบับและรายงานการเปลี่ยนแปลงของข้อความ ภาพ และเมทาดาทา PdfDiffer สร้าง Myers line diff ที่จัดแนวตามหน้า StructuredDiffer เพิ่มการจัดกลุ่มย่อหน้า การเปรียบเทียบภาพ และการเปรียบเทียบเมทาดาทา DiffFormatter ทำให้ผลลัพธ์แบบมีโครงสร้างเป็นอนุกรมในรูป JSON หรือส่วนย่อย HTML หน้านี้ระบุ API สาธารณะ สัญญาพฤติกรรมที่สังเกตได้ ขอบเขตทรัพยากร และโหมดความล้มเหลว การตั้งค่าเชิงงานและตัวอย่างอยู่ในหน้าความสามารถ Diff

ความสามารถนี้มาพร้อมกับ NextPDF Pro (nextpdf/pro) และเปิดใช้งานด้วยซองใบอนุญาตระดับ Pro การติดตั้งที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและขอใบอนุญาต

ไม่มีแฟล็กความสามารถขณะรันที่จำกัดโมดูลนี้ คลาส diff ใช้งานได้เมื่อใดก็ตามที่ติดตั้งและมีใบอนุญาต nextpdf/pro

สัญลักษณ์พารามิเตอร์พฤติกรรมเริ่มต้นคืนค่าโยนข้อยกเว้นหรือล้มเหลวด้วยหมายเหตุ
PdfDiffer::compare()string $sourcePdf, string $targetPdfสกัดข้อความรายหน้า แล้วเปรียบเทียบหน้า i ของต้นทางกับหน้า i ของปลายทางDiffResultInvalidArgumentException เมื่อบัฟเฟอร์ไม่มีส่วนหัว %PDF หรือตัวอ่านที่เลือกได้แจงไม่สำเร็จ; OverflowException เมื่อชนขอบเขตทรัพยากรจุดเข้าใช้งานแบบ static
PdfDiffer::compareTexts()array $sourcePages, array $targetPages (แต่ละตัวเป็น list<string>)diff ข้อความหน้าที่สกัดไว้ล่วงหน้า โดยข้ามการสกัดDiffResultOverflowException เมื่อชนขอบเขตทรัพยากรstatic; ใช้เมื่อมีข้อความอยู่แล้ว
PdfDiffer::extractText()string $contentStreamแจงตัวดำเนินการแสดงข้อความจากสตรีมเนื้อหาดิบหนึ่งสตรีมstring— (ทนต่อความผิดพลาด; อินพุตที่แจงไม่ได้จะให้สตริงว่าง)static
StructuredDiffer::__construct()?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = nullอาร์กิวเมนต์ null จะสร้าง differ เริ่มต้นการฉีดผ่านคอนสตรัคเตอร์สำหรับการทดสอบ
StructuredDiffer::compare()string $sourcePdf, string $targetPdfรันการเปรียบเทียบข้อความ ย่อหน้า ภาพ และเมทาดาทา แล้วสร้างสรุปStructuredDiffResultส่งต่อ InvalidArgumentException และ OverflowException จากเส้นทางข้อความตัวควบคุมทั่วทั้งโมดูล
DiffFormatter::toJson()StructuredDiffResult $resultเอกสาร JSON ที่จัดรูปสวยงามstringJsonException เมื่อเข้ารหัสล้มเหลว
DiffFormatter::toHtml()StructuredDiffResult $resultส่วนย่อย HTML ที่มีส่วนสรุป ย่อหน้า และเมทาดาทา; ค่าข้อความถูก escape เป็นเอนทิตีstringเป็นส่วนย่อยเท่านั้น ไม่ใช่เอกสารเต็ม
DiffFormatter::toArray()StructuredDiffResult $resultอาร์เรย์การทำอนุกรมที่หนุนหลัง toJson()array<string, mixed>คีย์ snake_case ที่เสถียร
ImageDiffer::diff()string $sourcePdf, string $targetPdfแฮช image XObject และรายงานภาพที่เพิ่ม ลบ และแก้ไขlist<ImageDiff>— (โครงสร้างที่ถอดรหัสไม่ได้จะถูกข้ามแบบ fail-closed)อัตลักษณ์คือบัคเก็ตหน้าบวกหมายเลขวัตถุ
MetadataDiffer::diff()string $sourcePdf, string $targetPdfเปรียบเทียบฟิลด์ /Info แปดฟิลด์ (Title, Author, Subject, Keywords, Creator, Producer, CreationDate, ModDate)list<MetadataChange>— (ไม่โยนข้อยกเว้นกับอินพุตที่ไม่สอดคล้อง)ค่าถูกเปรียบเทียบเป็นสตริงที่ถอดรหัสแล้ว
DiffEngine::diff()array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = 10000Myers line diff บนรายการบรรทัดสองชุดlist<DiffRegion>OverflowException เมื่อบรรทัดรวมกันเกิน $maxLines หรือระยะแก้ไขเกินเพดานที่จำกัดด้วยหน่วยความจำstatic; ตัวสร้างบริเวณสำหรับทุกเส้นทางข้อความ
TextExtractor::fromContentStream()string $contentStreamแปลงสตรีมเป็นโทเคนและรันสเตตแมชชีนของข้อความlist<TextBlock>static
TextExtractor::fromOperations()array $operations (list<ContentStreamOp>)รันสเตตแมชชีนของข้อความบนตัวดำเนินการที่แจงไว้ล่วงหน้าlist<TextBlock>static
ContentStreamParser::parse()คอนสตรัคเตอร์รับ string $dataแปลงตัวดำเนินการและตัวถูกดำเนินการเป็นโทเคน; ข้ามพจนานุกรมและคอมเมนต์; ทนต่อความผิดพลาดlist<ContentStreamOp>ไบต์ที่ไม่รู้จักจะถูกข้าม ไม่ทำให้ล้มเหลว
ContentStreamOpstring $operator, list<mixed> $operandsวัตถุค่าของการดำเนินการแบบ readonly; isTextOp() จำแนกตัวดำเนินการที่เกี่ยวกับข้อความ
DiffResultlist<DiffRegion> $regions, int $sourcePagesCount, int $targetPagesCountจัดบริเวณลงบัคเก็ต $added, $removed, $modified; เปิดเผย isIdentical(), hasDifferences(), totalChanges()readonly; บริเวณ Unchanged คงอยู่ใน $regions เท่านั้น
StructuredDiffResulttext diff, ย่อหน้า, ภาพ, การเปลี่ยนแปลงเมทาดาทา, สรุปผลลัพธ์รวม; hasDifferences(), isIdentical() มอบหมายให้สรุปreadonly
DiffSummaryจำนวนรายหมวดบวกจำนวนหน้าhasDifferences() และ totalChanges() บนจำนวนข้อความ ภาพ และเมทาดาทาreadonly
DiffRegionDiffType $type, string $text, int $pageIndex, int $lineIndex, ?string $counterpartText = nullการเปลี่ยนแปลงระดับบรรทัดหนึ่งรายการ$counterpartText คงเป็น null บนเอนจินที่จัดส่ง
ParagraphDiffชนิด, ข้อความ, ดัชนีหน้า, บรรทัดเริ่ม/สิ้นสุด, บริเวณบริเวณชนิดเดียวกันที่ติดต่อกันบนหน้าเดียว; lineCount()readonly
ImageDiffชนิด, ดัชนีหน้า, แฮชต้นทาง, แฮชปลายทาง, id วัตถุรายการการเปลี่ยนแปลงภาพหนึ่งรายการแฮชเป็นสตริงว่างบนฝั่งที่ขาดหายไป
MetadataChangestring $field, ?string $sourceValue, ?string $targetValueการเปลี่ยนแปลงฟิลด์หนึ่งรายการ; isAdded(), isRemoved(), isModified()null หมายถึงฟิลด์ไม่มีอยู่
TextBlockข้อความ, x, y, ชื่อฟอนต์, ขนาดฟอนต์, ดัชนีบรรทัดข้อความที่สกัดมาหนึ่งช่วงพร้อมตำแหน่งโดยประมาณreadonly
DiffTypeenum: Added, Removed, Modified, Unchangedการจำแนกการเปลี่ยนแปลงแบบมีสตริงหนุนหลังสำหรับข้อความดูหมายเหตุ Modified ในสัญญาพฤติกรรม
ImageDiffTypeenum: Added, Removed, Modified, Unchangedการจำแนกการเปลี่ยนแปลงแบบมีสตริงหนุนหลังสำหรับภาพ
public static function compare(string $sourcePdf, string $targetPdf): DiffResult
public static function compareTexts(array $sourcePages, array $targetPages): DiffResult
public static function extractText(string $contentStream): string
public function __construct(
?ImageDiffer $imageDiffer = null,
?MetadataDiffer $metadataDiffer = null,
)
public function compare(string $sourcePdf, string $targetPdf): StructuredDiffResult
public function toJson(StructuredDiffResult $result): string
public function toHtml(StructuredDiffResult $result): string
public function toArray(StructuredDiffResult $result): array
public static function diff(
array $sourceLines,
array $targetLines,
int $pageIndex = 0,
int $maxLines = self::MAX_DIFF_LINES,
): array

PdfDiffer::compare() สกัดข้อความรายหน้า แล้วเปรียบเทียบหน้า i ของต้นทางกับหน้า i ของปลายทาง เมื่อจำนวนหน้าต่างกัน ฝั่งที่ขาดจะถูกถือว่าเป็นข้อความว่างสำหรับหน้าที่เกินมา ภายในแต่ละคู่หน้า ข้อความจะแบ่งตามการขึ้นบรรทัดใหม่และรัน Myers line diff รายหน้า เอนจินปล่อยบริเวณ Added, Removed และ Unchanged บรรทัดที่เปลี่ยนแปลงจะปรากฏเป็นบริเวณ Removed บวกกับ Added เอนจินที่จัดส่งจะไม่ปล่อยบริเวณข้อความ Modified เลย กรณี Modified และบัคเก็ต DiffResult::$modified มีไว้สำหรับผลลัพธ์ที่ผู้เรียกสร้างขึ้น เนื่องจากคอนสตรัคเตอร์ของ DiffResult เป็นสาธารณะ totalChanges() นับบริเวณที่เพิ่ม ลบ และแก้ไข ส่วนบริเวณที่ไม่เปลี่ยนแปลงจะถูกยกเว้น

การสกัดมีสองเส้นทาง:

  • มีตัวอ่าน Artisan ที่เลือกได้ เมื่อติดตั้งคลาส NextPDF\Parser\PdfReader ที่เลือกได้ สตรีมเนื้อหาของหน้าจะถูกอ่านผ่านคลาสนั้นเพื่อให้ได้ข้อความที่ถูกต้องตามหน้า จำนวนหน้าใน trailer เป็นตัวขับลูป หน้าที่อ่านไม่สำเร็จจะให้ข้อความว่างแทนที่จะยกเลิกการเปรียบเทียบ
  • การถอยกลับ ตัวสแกนระดับไบต์ที่มีขอบเขตจะระบุคู่ stream/endstream ด้วย strpos คลายข้อมูล FlateDecode ด้วยเพดานเอาต์พุตตายตัวที่ 50 MB และย้อนฟิลเตอร์ตัวทำนาย PNG เมื่อพจนานุกรมสตรีมร้องขอผ่าน /DecodeParms ตาม ISO 32000-2:2020 §7.4.4.4 ตัวทำนายที่ผิดรูปหรือไม่รองรับจะทำให้ไบต์ที่คลายแล้วคงเดิม การถอยกลับเชื่อมข้อความที่กู้คืนมาทั้งหมดเข้าเป็นบัคเก็ตหน้าเดียว ดังนั้นการจัดแนวระดับหน้าจะถูกต้องตามหน้าเฉพาะบนเส้นทางตัวอ่านเท่านั้น

ทั้งสองเส้นทางแจงตัวดำเนินการแสดงข้อความ §9.4 คือ Tj, TJ และ ' สเตตแมชชีนติดตาม BT/ET, Tm (เฉพาะจุดกำเนิด), Td/TD, T* และ Tf

StructuredDiffer::compare() รันการ diff ข้อความ จัดกลุ่มบริเวณชนิดเดียวกันที่ติดต่อกันบนหน้าเดียวกันให้เป็นย่อหน้า (รวมช่วงที่ไม่เปลี่ยนแปลง) แล้วรันการเปรียบเทียบภาพและเมทาดาทา จากนั้นประกอบเป็น DiffSummary จำนวนย่อหน้าในสรุปครอบคลุมเฉพาะย่อหน้าที่เพิ่ม ลบ และแก้ไขเท่านั้น

การเปรียบเทียบภาพจะแจงนับวัตถุ PDF เชิงโครงสร้าง ขอบเขตของเนื้อสตรีมถูกกำกับด้วยรายการ /Length ตาม §7.3.8.2 ดังนั้นไบต์ไบนารีที่เพียงแค่คล้ายไวยากรณ์วัตถุจะไม่ถูกลงทะเบียนเป็นวัตถุหลอก สตรีมวัตถุที่บีบอัด (/Type /ObjStm) จะถูกถอดรหัสตาม §7.5.7 เพื่อให้ image XObject ที่ซ้อนอยู่ภายในมองเห็นได้ ภาพที่ตรวจพบแต่ละภาพจะถูกแฮชเนื้อหาด้วยฟังก์ชัน xxh128 ที่ไม่ใช่การเข้ารหัสลับ อัตลักษณ์คือคู่ของบัคเก็ตหน้าและหมายเลขวัตถุ ภาพที่ไม่มีหน้าเจ้าของในลำดับสตรีมจะถูกกำหนดให้เป็นหน้า 0

การเปรียบเทียบเมทาดาทาจะระบุพจนานุกรม /Info ที่แท้จริงผ่าน trailer เมื่อทำได้ ดังนั้นโทเคนฟิลด์ลวงภายในสตรีมเนื้อหาจะไม่ถูกเข้าใจผิดว่าเป็นเมทาดาทาของเอกสาร ค่าฟิลด์จะถูกถอดรหัสเป็นสตริง PDF: รูปแบบลิเทอรัลตาม §7.3.4.2 และรูปแบบเลขฐานสิบหกตาม §7.3.4.3 หากไม่มี trailer ที่ระบุได้ การค้นหาจะถอยกลับไปยังอินพุตทั้งหมด วันที่จะถูกเปรียบเทียบเป็นสตริงที่ถอดรหัสแล้ว ไม่ใช่ไทม์สแตมป์ที่แจงแล้ว

DiffFormatter::toJson() คืน JSON ที่จัดรูปสวยงามและเข้ารหัสด้วย JSON_THROW_ON_ERROR ดังนั้นความล้มเหลวในการเข้ารหัสจะยก JsonException แทนที่จะคืน false toHtml() คืนส่วนย่อย <div class="nextpdf-diff"> ข้อความย่อหน้าและค่าเมทาดาทาจะผ่านการ escape เอนทิตี HTML ไม่มีเอาต์พุต PDF แบบ redline เทียบกันสองด้านในเชิงภาพ สำหรับอินพุตที่เหมือนกัน บริเวณและเอาต์พุตที่จัดรูปแล้วจะมีผลลัพธ์แน่นอน

  • การจัดแนวหน้าอิงตำแหน่ง การแทรกหรือลบหน้าเพียงหน้าเดียวจะเลื่อนการจัดแนวของทุกหน้าถัดไปและทำให้จำนวนการเปลี่ยนแปลงปลายทางพองตัว
  • บนเส้นทางการสกัดแบบถอยกลับ ข้อความทั้งหมดจะตกอยู่ที่ดัชนีหน้า 0 การ diff เอกสารที่สกัดด้วยตัวอ่านเทียบกับความคาดหวังจากเส้นทางถอยกลับจะให้การกำหนดหน้าที่ต่างกัน
  • บัฟเฟอร์ต้นทางหรือปลายทางที่ไม่ได้ขึ้นต้นด้วย %PDF จะล้มเหลวด้วย InvalidArgumentException ก่อนการเปรียบเทียบใด ๆ
  • บรรทัดรวมกันมากกว่า 10,000 บรรทัดในคู่หน้าเดียวจะล้มเหลวด้วย OverflowException (ขอบเขตจำนวนบรรทัด)
  • ข้อความสองหน้าที่มีบรรทัดร่วมกันน้อยเกินไปจะล้มเหลวด้วย OverflowException เมื่อระยะแก้ไขแบบ Myers เกินเพดานที่จำกัดด้วยหน่วยความจำ การแก้ไขที่ถูกต้องมักมีบรรทัดร่วมกันเป็นส่วนใหญ่และไม่ได้รับผลกระทบ ส่วนอินพุตที่เป็นภัยซึ่งมีความร่วมกันต่ำจะไปชนขอบเขต
  • เอาต์พุตสตรีมถอยกลับที่คลายแล้วใหญ่กว่า 50 MB จะล้มเหลวด้วย OverflowException (ขอบเขต decompression-bomb) ตัวสแกนใช้ strpos ไม่ใช่ regex ที่ไร้ขอบเขต ดังนั้นอินพุตที่ถูกประดิษฐ์ขึ้นจึงไม่สามารถกระตุ้นการย้อนรอยแบบหายนะได้
  • ตัวดำเนินการแสดงข้อความ " ถูกแปลงเป็นโทเคนแต่ไม่สร้างบล็อกข้อความใน 3.1.0 ข้อความที่แสดงผ่าน " เพียงอย่างเดียวจะไม่เข้าร่วมใน diff
  • PDF ที่สแกนมาและมีแต่ภาพจะให้ text diff น้อยหรือไม่มีเลย ไม่มีการรัน OCR
  • การตรวจจับการเปลี่ยนแปลงภาพเป็นเชิงโครงสร้าง ไม่ใช่เชิงการรับรู้ ระบบไม่แรสเตอร์ไรซ์หน้า และภาพที่ถูกเข้ารหัสใหม่ด้วยพิกเซลเหมือนเดิมจะถูกรายงานว่าแก้ไขเมื่อไบต์ต่างกัน
  • ภาพที่บัคเก็ตหน้าหรือหมายเลขวัตถุเปลี่ยนไประหว่างการแก้ไขจะถูกรายงานเป็นคู่ลบบวกเพิ่ม ไม่ใช่แก้ไข
  • สตรีมวัตถุที่บีบอัดด้วยฟิลเตอร์อื่นนอกจาก FlateDecode จะถูกข้ามแบบ fail-closed ภาพสมาชิกของสตรีมนั้นจะไม่ถูกเปรียบเทียบ
  • ไม่มีการดำเนินการเข้ารหัสลับเกิดขึ้นในโมดูลนี้ จึงไม่มีพฤติกรรมเฉพาะของโหมด FIPS การแฮชภาพมีไว้เพื่อการตรวจจับการเปลี่ยนแปลงเท่านั้น และไม่มีน้ำหนักด้านความสมบูรณ์หรือหลักฐาน
ข้อกล่าวอ้างมาตรฐานข้อ
ตัวดำเนินการแสดงข้อความ Tj และ TJ ถูกแจงเพื่อการสกัดISO 32000-2:2020§9.4
ข้อมูลสตรีมในการถอยกลับเริ่มหลัง CRLF หรือ LF ที่ตามหลังคีย์เวิร์ด streamISO 32000-2:2020§7.3.8.1
ขอบเขตสตรีมในการสแกนภาพถูกกำกับด้วยรายการ /Length ในพจนานุกรมISO 32000-2:2020§7.3.8.2
สมาชิกของสตรีมวัตถุถูกระบุตำแหน่งผ่านตาราง /N และออฟเซ็ต /FirstISO 32000-2:2020§7.5.7
การย้อนตัวทำนาย PNG เป็นไปตามพารามิเตอร์ Predictor ใน /DecodeParmsISO 32000-2:2020§7.4.4.4
ค่าเมทาดาทาถอดรหัสสตริงรูปแบบลิเทอรัลและเลขฐานสิบหกISO 32000-2:2020§7.3.4.2, §7.3.4.3
เอาต์พุต PDF แบบ redline เทียบกันสองด้านในเชิงภาพไม่รองรับ (JSON/HTML เท่านั้น)

ข้อทั้งหมดเป็นการถอดความ NextPDF ไม่ได้ทำซ้ำข้อความเชิงบรรทัดฐาน สิ่งเหล่านี้เป็นคำแถลงความสามารถ ไม่ใช่การรับรอง NextPDF ไม่ได้ถือการรับรองใด ๆ และไม่ได้มอบให้ การกู้คืนข้อความสร้างข้อความบรรทัดขึ้นใหม่จากตัวดำเนินการแสดงข้อความ โดยไม่ได้รันสเตตแมชชีนของข้อความ §9.4 อย่างครบถ้วน ดังนั้นการ diff จึงอยู่ในระดับเนื้อหา ไม่ใช่ระดับเรขาคณิต

  • ความพร้อมใช้งานภายในแพ็กเกจ Pro: PdfDiffer, DiffEngine, TextExtractor และวัตถุค่าของสิ่งเหล่านี้ตั้งแต่ 1.8.0; StructuredDiffer, DiffFormatter, ImageDiffer, MetadataDiffer และของสิ่งเหล่านี้ตั้งแต่ 2.2.0 ทั้งหมดเป็นเวอร์ชันปัจจุบันใน nextpdf/pro 3.1.0
  • ควรใช้ PdfDiffer::compareTexts() เมื่อมีข้อความของหน้าอยู่แล้ว เพราะจะข้ามการสกัดและโหมดความล้มเหลวของมันทั้งหมด
  • ตัวอ่าน Artisan ที่เลือกได้ช่วยเพิ่มความแม่นยำในการสกัดและการกำหนดหน้า ระบบตรวจพบขณะรันและไม่จำเป็นต้องมีเสมอ
  • ควรจับ OverflowException เมื่อ diff อินพุตที่ไม่น่าเชื่อถือ ขอบเขตเหล่านี้เป็นการปฏิเสธแบบ fail-closed โดยเจตนา ไม่ใช่ข้อผิดพลาดชั่วคราว
  • DiffFormatter::toHtml() ปล่อยชื่อคลาส (diff-added, diff-removed, diff-modified, diff-unchanged) แต่ไม่มีสไตล์ชีต ให้จัดเตรียม CSS ของคุณเอง
  • สร้าง StructuredDiffer ด้วย differ ปลอมในการทดสอบเพื่อแยกเส้นทางข้อความออกจากการสแกนภาพและเมทาดาทา

หน้านี้บันทึกเฉพาะพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว API สาธารณะที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และคำนำหน้าตั๋วอยู่นอกขอบเขต