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

Pro รุ่น

Diff

NextPDF\Pro\Diff เปรียบเทียบเอกสาร PDF สองฉบับและรายงานสิ่งที่เปลี่ยนแปลง เส้นทางแบบเร็วผลิตการเปรียบเทียบข้อความที่จัดเรียงตามหน้า เส้นทางแบบมีโครงสร้างเพิ่มการตรวจจับการเปลี่ยนแปลงของภาพและเมทาดาทา และจัดรูปแบบผลลัพธ์เป็น JSON หรือ HTML

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

ไม่มีแฟล็กความสามารถรันไทม์ที่ควบคุมคลาส Diff คลาสเหล่านี้มีอยู่เสมอเมื่อติดตั้งแพ็กเกจ Pro แล้ว

Terminal window
composer require nextpdf/pro:^3

PdfDiffer::compare() สกัดข้อความต่อหน้าจากเอกสารแต่ละฉบับ แบ่งออกเป็นบรรทัด และรัน Myers line diff ต่อคู่หน้า โดยผลิตบริเวณที่เพิ่ม ลบ และแก้ไข การสกัดข้อความแจงตัวดำเนินการแสดงข้อความของ ISO 32000-2:2020 §9.4 (Tj, TJ, ')

StructuredDiffer ต่อยอดจากนั้น โดยจัดกลุ่มบริเวณข้อความเป็นการเปลี่ยนแปลงระดับย่อหน้า เปรียบเทียบภาพที่ฝังอยู่ เปรียบเทียบเมทาดาทา และผลิต StructuredDiffResult พร้อมสรุปรวม DiffFormatter ทำให้ผลลัพธ์นั้นเป็นอนุกรมเป็นสตริง JSON หรือชิ้นส่วนรายงาน HTML

เมื่อมีการติดตั้งตัวอ่าน PDF Artisan แบบเลือกได้ การสกัดข้อความจะใช้ตัวอ่านนั้นเพื่อเนื้อหาที่แม่นยำต่อหน้า มิฉะนั้นทางสำรองระดับไบต์ที่มีขอบเขตจะสแกนสตรีมเนื้อหาโดยตรง

ตัวเปรียบเทียบเทียบข้อความและโครงสร้างที่สกัดได้ ไม่ใช่พิกเซลที่เรนเดอร์แล้ว การเปรียบเทียบเชิงโครงสร้างมีความแน่นอน ต้นทุนต่ำ และสอดคล้องกับการเปลี่ยนแปลงเชิงบรรณาธิการที่ผู้ตรวจทานให้ความสำคัญ ในทางกลับกันการเปรียบเทียบพิกเซลจะรายงานสัญญาณรบกวนจาก antialiasing และ font-hinting เป็นเนื้อหา เนื่องจาก PDF เก็บ glyph และการจัดตำแหน่ง ไม่ใช่อักขระที่พร้อมอ่าน ทุกการเปรียบเทียบจึงสร้างข้อความขึ้นใหม่จากสตรีมเนื้อหาก่อน ขั้นตอนการสกัดนั้นคือเหตุผลที่ตัวอ่าน Artisan เพิ่มความแม่นยำ ที่ทางสำรอง FlateDecode ที่มีขอบเขตแลกความครอบคลุมกับความปลอดภัย และที่หน้าสแกนแทบไม่เกิดการเปรียบเทียบ การจัดเรียงหน้ายังคงอิงดัชนีเพื่อความคาดเดาได้ ดังนั้นหน้าที่ถูกแทรกจึงอ่านเป็นการเลื่อนปลายน้ำที่ชัดเจน

เบื้องหลังการออกแบบ: เหตุใดข้อความใน PDF จึงไม่ใช่ข้อความจริง ๆ

  • อินพุต ไบต์ PDF ดิบสำหรับต้นทางและปลายทาง บัฟเฟอร์ที่ไม่ขึ้นต้นด้วย %PDF จะทำให้เกิด InvalidArgumentException
  • เอาต์พุต (เส้นทางเร็ว) DiffResult พร้อมรายการบริเวณ added, removed, modified บวก isIdentical(), hasDifferences(), totalChanges()
  • เอาต์พุต (เส้นทางมีโครงสร้าง) StructuredDiffResult พร้อมการเปรียบเทียบย่อหน้า การเปรียบเทียบภาพ การเปลี่ยนแปลงเมทาดาทา และ DiffSummary
  • เอาต์พุตรายงาน DiffFormatter ปล่อยสตริง JSON หรือชิ้นส่วน HTML โดยไม่ผลิต PDF redline แบบเทียบเคียงทางสายตา
  • ขอบเขตทรัพยากร ขนาดสตรีมเนื้อหาที่คลายการบีบอัดถูกจำกัดเพดานเพื่อป้องกันระเบิดการคลายการบีบอัด ตัวสแกนระดับไบต์หลีกเลี่ยงการ backtrack ของ regex แบบหายนะบนอินพุตที่ถูกประดิษฐ์ขึ้น
  • ความแน่นอน สำหรับอินพุตเดียวกัน บริเวณการเปรียบเทียบและเอาต์พุตที่จัดรูปแบบจะเสถียร
TypeKindKey members
NextPDF\Pro\Diff\PdfDifferfinal classstatic compare(string $sourcePdf, string $targetPdf): DiffResult, static compareTexts(array $sourcePages, array $targetPages): DiffResult, static extractText(string $contentStream): string
NextPDF\Pro\Diff\StructuredDifferfinal class__construct(?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null), compare(string $sourcePdf, string $targetPdf): StructuredDiffResult
NextPDF\Pro\Diff\DiffFormatterfinal classtoJson(StructuredDiffResult $result): string, toHtml(StructuredDiffResult $result): string
NextPDF\Pro\Diff\DiffResultfinal readonly classarray $added, array $removed, array $modified, isIdentical(): bool, hasDifferences(): bool, totalChanges(): int
NextPDF\Pro\Diff\StructuredDiffResultfinal readonly classtext diff, paragraphs, images, metadata changes, summary
NextPDF\Pro\Diff\DiffTypeenumAdded, Removed, Modified, Unchanged
<?php
declare(strict_types=1);
use NextPDF\Pro\Diff\PdfDiffer;
$diff = PdfDiffer::compare(
file_get_contents('v1.pdf'),
file_get_contents('v2.pdf'),
);
if ($diff->hasDifferences()) {
echo $diff->totalChanges(), " text changes detected\n";
}
<?php
declare(strict_types=1);
use NextPDF\Pro\Diff\DiffFormatter;
use NextPDF\Pro\Diff\StructuredDiffer;
function reviewReport(string $oldPdf, string $newPdf): string
{
$result = (new StructuredDiffer())->compare($oldPdf, $newPdf);
// JSON for machine consumption; toHtml() for a review UI fragment.
return (new DiffFormatter())->toJson($result);
}
  • การเปรียบเทียบจัดเรียงตามดัชนีหน้า การแทรกหน้าก่อนหน้าจะเลื่อนหน้าถัดมาทั้งหมดและรายงานการเปลี่ยนแปลงปลายน้ำจำนวนมาก นี่เป็นสิ่งที่คาดหมายได้สำหรับการเปรียบเทียบที่จัดเรียงตามดัชนี
  • การเปรียบเทียบภาพตรวจจับภาพที่ฝังอยู่ซึ่งถูกเพิ่ม ลบ และแก้ไข โดยไม่ใช่การเปรียบเทียบทางสายตาเชิงการรับรู้และไม่เรนเดอร์หน้าเป็นพิกเซล
  • PDF ที่เป็นภาพล้วน (สแกน) จะให้การเปรียบเทียบข้อความน้อยหรือไม่มีเลยเพราะไม่มีการทำ OCR
  • หากไม่มีตัวอ่าน Artisan แบบเลือกได้ การสกัดจะใช้ทางสำรองที่มีขอบเขต เอกสารที่บีบอัดหนักอาจให้ความครอบคลุมข้อความที่ลดลง

การสกัดข้อความเป็นเชิงเส้นตามไบต์ของเอกสาร Myers diff เกือบเป็นเชิงเส้นสำหรับเอกสารที่คล้ายกันและเป็นกำลังสองในกรณีเลวร้ายสุดต่อคู่หน้า เพดานการคลายการบีบอัดเป็นตัวกำหนดขอบเขตของหน่วยความจำ ดู performance_budget

ทางสำรองระดับไบต์ใช้การสแกนแบบ strpos แทน regex ที่ไม่มีขอบเขตเพื่อหลีกเลี่ยงการ backtrack แบบหายนะบน PDF ที่ถูกประดิษฐ์ขึ้น และกำหนดขอบเขตเอาต์พุตการคลายการบีบอัด การเปรียบเทียบไม่รันสคริปต์ที่ฝังอยู่ ดูแบบจำลองความปลอดภัยของ Core

ClaimSpec clauseStatus
Tj text operator parsed for extractionISO 32000-2:2020 §9.4Verified (unit suite)
TJ array text operator parsed for extractionISO 32000-2:2020 §9.4Verified (unit suite)
Visual side-by-side redline PDF outputNot supported (JSON/HTML only)

ไม่มีสิ่งเทียบเท่าใน Core สำหรับการเปรียบเทียบเอกสาร ตัวอ่าน Artisan แบบเลือกได้ช่วยเพิ่มความแม่นยำของการสกัดเมื่อติดตั้งแต่ไม่ได้จำเป็น

นี่คือตัวตรวจจับการเปลี่ยนแปลงเนื้อหา โดยไม่ใช่ตัววิเคราะห์ความแตกต่างเชิงนิติวิทยาและไม่ผลิตรายงานเชิงพยานหลักฐานหรือการระบุการแก้ไขปลอมแปลง เรื่องเหล่านั้นอยู่นอกขอบเขตของโมดูลนี้

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