Pro editie
Diff — Diepe referentie
In het kort
Sectie met titel “In het kort”Deze pagina is de referentie op contractniveau voor de NextPDF Pro diff-module, NextPDF\Pro\Diff. De module vergelijkt twee PDF-documenten en rapporteert wijzigingen in tekst, afbeeldingen en metadata. PdfDiffer levert een pagina-uitgelijnde Myers-regeldiff. StructuredDiffer voegt alineagroepering, afbeeldingsvergelijking en metadatavergelijking toe. DiffFormatter serialiseert het gestructureerde resultaat naar JSON of een HTML-fragment. Deze pagina beschrijft de publieke API, het waarneembare gedragscontract, de resourcegrenzen en de foutmodi. Taakgerichte setup en voorbeelden staan op de Diff-capaciteitspagina.
Beschikbaarheid & licentie
Sectie met titel “Beschikbaarheid & licentie”Deze capaciteit wordt geleverd in NextPDF Pro (nextpdf/pro) en activeert met een licentie-envelope op Pro-niveau. Een deployment zonder die entitlement laadt de klassen van de capaciteit niet. Vergelijk edities en vraag een licentie aan.
Geen runtime-capaciteitsflag gate’t deze module. De diff-klassen zijn bruikbaar zodra nextpdf/pro geïnstalleerd en gelicentieerd is.
Publiek API-oppervlak
Sectie met titel “Publiek API-oppervlak”| Symbool | Parameters | Standaardgedrag | Retourneert | Gooit of faalt met | Opmerkingen |
|---|---|---|---|---|---|
PdfDiffer::compare() | string $sourcePdf, string $targetPdf | Extraheert tekst per pagina en vergelijkt vervolgens pagina i van de bron met pagina i van het doel | DiffResult | InvalidArgumentException wanneer een buffer de %PDF-header mist of de optionele reader niet kan parsen; OverflowException bij een resourcegrens | Statisch instappunt |
PdfDiffer::compareTexts() | array $sourcePages, array $targetPages (elk list<string>) | Vergelijkt vooraf geëxtraheerde paginateksten en slaat extractie over | DiffResult | OverflowException bij een resourcegrens | Statisch; gebruik dit wanneer de tekst al beschikbaar is |
PdfDiffer::extractText() | string $contentStream | Parse’t tekstweergeefoperatoren uit één ruwe content-stream | string | — (fouttolerant; onparsebare invoer levert een lege string op) | Statisch |
StructuredDiffer::__construct() | ?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null | null-argumenten construeren de standaard-differs | — | — | Constructor-injectie voor testen |
StructuredDiffer::compare() | string $sourcePdf, string $targetPdf | Voert tekst-, alinea-, afbeeldings- en metadatavergelijking uit en bouwt vervolgens een samenvatting | StructuredDiffResult | Propageert InvalidArgumentException en OverflowException vanuit het tekstpad | Orchestrator over de hele module |
DiffFormatter::toJson() | StructuredDiffResult $result | Pretty-printed JSON-document | string | JsonException wanneer encoderen mislukt | — |
DiffFormatter::toHtml() | StructuredDiffResult $result | HTML-fragment met samenvatting-, alinea- en metadatasecties; tekstwaarden worden entity-escaped | string | — | Alleen een fragment, geen volledig document |
DiffFormatter::toArray() | StructuredDiffResult $result | Serialisatie-array die toJson() ondersteunt | array<string, mixed> | — | Stabiele snake_case-sleutels |
ImageDiffer::diff() | string $sourcePdf, string $targetPdf | Hasht afbeeldings-XObjects en rapporteert toegevoegde, verwijderde en gewijzigde afbeeldingen | list<ImageDiff> | — (niet-decodeerbare structuren worden fail-closed overgeslagen) | Identiteit is paginabucket plus objectnummer |
MetadataDiffer::diff() | string $sourcePdf, string $targetPdf | Vergelijkt acht /Info-velden (Title, Author, Subject, Keywords, Creator, Producer, CreationDate, ModDate) | list<MetadataChange> | — (gooit nooit bij niet-conforme invoer) | Waarden worden vergeleken als gedecodeerde strings |
DiffEngine::diff() | array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = 10000 | Myers-regeldiff over twee regellijsten | list<DiffRegion> | OverflowException wanneer de gecombineerde regels $maxLines overschrijden of de edit-afstand de geheugengebonden limiet overschrijdt | Statisch; de regioproducent voor alle tekstpaden |
TextExtractor::fromContentStream() | string $contentStream | Tokeniseert de stream en draait de tekststatusmachine | list<TextBlock> | — | Statisch |
TextExtractor::fromOperations() | array $operations (list<ContentStreamOp>) | Draait de tekststatusmachine over vooraf geparsete operaties | list<TextBlock> | — | Statisch |
ContentStreamParser::parse() | constructor neemt string $data | Tokeniseert operatoren en operanden; slaat dictionaries en comments over; fouttolerant | list<ContentStreamOp> | — | Niet-herkende bytes worden overgeslagen, nooit fataal |
ContentStreamOp | string $operator, list<mixed> $operands | Readonly operatie-waardeobject; isTextOp() classificeert tekstgerelateerde operatoren | — | — | — |
DiffResult | list<DiffRegion> $regions, int $sourcePagesCount, int $targetPagesCount | Verdeelt regio’s over $added, $removed, $modified; biedt isIdentical(), hasDifferences(), totalChanges() | — | — | Readonly; Unchanged-regio’s blijven alleen in $regions |
StructuredDiffResult | tekstdiff, alinea’s, afbeeldingen, metadatawijzigingen, samenvatting | Samengesteld resultaat; hasDifferences(), isIdentical() delegeren naar de samenvatting | — | — | Readonly |
DiffSummary | tellingen per categorie plus paginatellingen | hasDifferences() en totalChanges() over tekst-, afbeeldings- en metadatatellingen | — | — | Readonly |
DiffRegion | DiffType $type, string $text, int $pageIndex, int $lineIndex, ?string $counterpartText = null | Eén wijziging op regelniveau | — | — | $counterpartText blijft null in de geleverde engine |
ParagraphDiff | type, tekst, paginaindex, start-/eindregel, regio’s | Opeenvolgende regio’s van hetzelfde type op één pagina; lineCount() | — | — | Readonly |
ImageDiff | type, paginaindex, bronhash, doelhash, object-id | Eén afbeeldingswijzigingsvermelding | — | — | Hashes zijn lege strings aan de afwezige kant |
MetadataChange | string $field, ?string $sourceValue, ?string $targetValue | Eén veldwijziging; isAdded(), isRemoved(), isModified() | — | — | null betekent dat het veld afwezig is |
TextBlock | tekst, x, y, fontnaam, fontgrootte, regelindex | Eén geëxtraheerde tekstrun met benaderende positie | — | — | Readonly |
DiffType | enum: Added, Removed, Modified, Unchanged | String-gebaseerde wijzigingsclassificatie voor tekst | — | — | Zie de Modified-opmerking in het gedragscontract |
ImageDiffType | enum: Added, Removed, Modified, Unchanged | String-gebaseerde wijzigingsclassificatie voor afbeeldingen | — | — | — |
Instappunt-signatures
Sectie met titel “Instappunt-signatures”public static function compare(string $sourcePdf, string $targetPdf): DiffResult
public static function compareTexts(array $sourcePages, array $targetPages): DiffResult
public static function extractText(string $contentStream): stringpublic function __construct( ?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null,)
public function compare(string $sourcePdf, string $targetPdf): StructuredDiffResultpublic function toJson(StructuredDiffResult $result): string
public function toHtml(StructuredDiffResult $result): string
public function toArray(StructuredDiffResult $result): arraypublic static function diff( array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = self::MAX_DIFF_LINES,): arrayGedragscontract
Sectie met titel “Gedragscontract”Pagina-uitlijning en regeldiff
Sectie met titel “Pagina-uitlijning en regeldiff”PdfDiffer::compare() extraheert de tekst per pagina en vergelijkt vervolgens pagina i van de bron met pagina i van het doel. Wanneer het aantal pagina’s verschilt, wordt de ontbrekende kant voor de overtollige pagina’s als lege tekst behandeld. Binnen elk paginapaar wordt de tekst op nieuwe regels gesplitst en draait er een Myers-regeldiff per pagina. De engine geeft Added-, Removed- en Unchanged-regio’s af. Een gewijzigde regel verschijnt als een Removed- plus een Added-regio; de geleverde engine geeft nooit Modified-tekstregio’s af. Het Modified-geval en de DiffResult::$modified-bucket dienen voor door de aanroeper geconstrueerde resultaten, omdat de constructor van DiffResult publiek is. totalChanges() telt toegevoegde, verwijderde en gewijzigde regio’s; ongewijzigde regio’s worden uitgesloten.
Extractiepaden
Sectie met titel “Extractiepaden”Extractie heeft twee paden:
- Optionele Artisan-reader aanwezig. Wanneer de optionele klasse
NextPDF\Parser\PdfReadergeïnstalleerd is, worden content-streams van pagina’s er via gelezen voor pagina-nauwkeurige tekst. Het aantal pagina’s uit de trailer bepaalt de lus. Een pagina die niet gelezen kan worden, draagt lege tekst bij in plaats van de vergelijking af te breken. - Fallback. Een begrensde scanner op byteniveau lokaliseert
stream/endstream-paren metstrpos, pakt FlateDecode-data uit met een harde uitvoerlimiet van 50 MB, en keert een PNG-predictor terug wanneer de stream-dictionary daar via/DecodeParmsom vraagt, conform ISO 32000-2:2020 §7.4.4.4. Een misvormde of niet-ondersteunde predictor laat de gedecodeerde bytes ongewijzigd. De fallback voegt alle herstelde tekst samen in één paginabucket, dus uitlijning op paginaniveau is alleen pagina-nauwkeurig op het readerpad.
Beide paden parsen de §9.4-tekstweergeefoperatoren Tj, TJ en '. De statusmachine houdt BT/ET, Tm (alleen oorsprong), Td/TD, T* en Tf bij.
Gestructureerde vergelijking
Sectie met titel “Gestructureerde vergelijking”StructuredDiffer::compare() draait de tekstdiff, groepeert opeenvolgende regio’s van hetzelfde type op dezelfde pagina tot alinea’s (ongewijzigde reeksen inbegrepen), draait vervolgens de afbeeldings- en metadatavergelijking en stelt een DiffSummary samen. De alineatellingen in de samenvatting dekken alleen toegevoegde, verwijderde en gewijzigde alinea’s.
Afbeeldingsvergelijking somt PDF-objecten structureel op. De omvang van een stream-body wordt bepaald door de bijbehorende /Length-entry conform §7.3.8.2, zodat binaire bytes die slechts op objectsyntaxis lijken, nooit als fantoomobjecten worden geregistreerd. Gecomprimeerde object-streams (/Type /ObjStm) worden gedecodeerd conform §7.5.7 zodat de daarin geneste afbeeldings-XObjects zichtbaar zijn. Elke gedetecteerde afbeelding wordt content-gehasht met de niet-cryptografische xxh128-functie; de identiteit is het paar van paginabucket en objectnummer. Afbeeldingen zonder eigenaarpagina in streamvolgorde worden aan pagina 0 toegewezen.
Metadatavergelijking herleidt de echte /Info-dictionary waar mogelijk via de trailer, zodat een lokkende veld-token binnen een content-stream niet wordt aangezien voor documentmetadata. Veldwaarden worden gedecodeerd als PDF-strings: de literale vorm conform §7.3.4.2 en de hexadecimale vorm conform §7.3.4.3. Zonder herleidbare trailer valt de zoekactie terug op de volledige invoer. Datums worden vergeleken als gedecodeerde strings, niet als geparsete timestamps.
Rapportuitvoer
Sectie met titel “Rapportuitvoer”DiffFormatter::toJson() retourneert pretty-printed JSON en encodeert met JSON_THROW_ON_ERROR, zodat een encoderingsfout een JsonException opgooit in plaats van false te retourneren. toHtml() retourneert een <div class="nextpdf-diff">-fragment; alineatekst en metadatawaarden gaan door HTML-entity-escaping. Er is geen visuele zij-aan-zij redline-PDF-uitvoer. Voor identieke invoer zijn de regio’s en de opgemaakte uitvoer deterministisch.
Randgevallen en foutmodi
Sectie met titel “Randgevallen en foutmodi”- Pagina-uitlijning is positioneel. Een enkele ingevoegde of verwijderde pagina verschuift de uitlijning voor alle volgende pagina’s en blaast stroomafwaartse wijzigingstellingen op.
- Op het fallback-extractiepad belandt alle tekst op paginaindex 0. Een via de reader geëxtraheerd document vergelijken met verwachtingen uit het fallbackpad levert een andere pagina-toewijzing op.
- Een bron- of doelbuffer die niet met
%PDFbegint, faalt metInvalidArgumentExceptionvóór enige vergelijking. - Meer dan 10,000 gecombineerde regels in één paginapaar faalt met
OverflowException(regelaantalgrens). - Twee paginateksten die te weinig regels delen, falen met
OverflowExceptionzodra de Myers-edit-afstand de geheugengebonden limiet overschrijdt. Legitieme revisies delen de meeste regels en blijven onaangetast; vijandige invoer met weinig gemeenschappelijkheid activeert de grens. - Gedecomprimeerde fallback-stream-uitvoer groter dan 50 MB faalt met
OverflowException(decompressiebom-grens). De scanner gebruiktstrpos, geen onbegrensde regex, dus geprepareerde invoer kan geen catastrofaal backtracking veroorzaken. - De
"-tekstweergeefoperator wordt getokeniseerd maar produceert geen tekstblok in 3.1.0; tekst die alleen via"wordt getoond, neemt niet deel aan de diff. - Gescande, alleen-afbeelding-PDF’s produceren weinig tot geen tekstdiff. Er draait geen OCR.
- Detectie van afbeeldingswijzigingen is structureel, niet perceptueel. Het rasteriseert pagina’s niet, en een afbeelding die met identieke pixels opnieuw is geëncodeerd, wordt als gewijzigd gerapporteerd wanneer de bytes verschillen.
- Een afbeelding waarvan de paginabucket of het objectnummer tussen revisies verandert, wordt gerapporteerd als een verwijderd-plus-toegevoegd-paar, niet als gewijzigd.
- Object-streams die met andere filters dan FlateDecode zijn gecomprimeerd, worden fail-closed overgeslagen; hun onderdeel-afbeeldingen worden niet vergeleken.
- In deze module vindt geen cryptografische bewerking plaats, dus er is geen FIPS-modusspecifiek gedrag. De afbeeldingshash is uitsluitend bedoeld voor wijzigingsdetectie en heeft geen integriteits- of bewijswaarde.
Conformiteit
Sectie met titel “Conformiteit”| Bewering | Standaard | Clausule |
|---|---|---|
Tj- en TJ-tekstweergeefoperatoren worden geparsed voor extractie | ISO 32000-2:2020 | §9.4 |
Fallback-stream-data begint na de CRLF of LF die volgt op het stream-keyword | ISO 32000-2:2020 | §7.3.8.1 |
De omvang van gescande streams wordt bepaald door de /Length-entry van de dictionary | ISO 32000-2:2020 | §7.3.8.2 |
Onderdelen van object-streams worden gelokaliseerd via de /N-paartabel en de /First-offset | ISO 32000-2:2020 | §7.5.7 |
Het terugdraaien van de PNG-predictor volgt de /DecodeParms-parameter Predictor | ISO 32000-2:2020 | §7.4.4.4 |
| Metadatawaarden decoderen de literale en hexadecimale stringvormen | ISO 32000-2:2020 | §7.3.4.2, §7.3.4.3 |
| Visuele zij-aan-zij redline-PDF-uitvoer | — | Niet ondersteund (alleen JSON/HTML) |
Alle clausules zijn geparafraseerd; NextPDF reproduceert geen normatieve tekst. Dit zijn capaciteitsverklaringen, geen certificeringen; NextPDF bezit geen certificering en verleent er geen. Tekstherstel reconstrueert regeltekst uit tekstweergeefoperatoren. Het draait niet de volledige §9.4-tekststatusmachine, dus de diff is op contentniveau, niet op geometrieniveau.
Ontwikkelnotities
Sectie met titel “Ontwikkelnotities”- Beschikbaarheid binnen het Pro-pakket:
PdfDiffer,DiffEngine,TextExtractoren hun waardeobjecten sinds 1.8.0;StructuredDiffer,DiffFormatter,ImageDiffer,MetadataDifferen die van hen sinds 2.2.0. Alle zijn actueel innextpdf/pro3.1.0. - Geef de voorkeur aan
PdfDiffer::compareTexts()wanneer de paginatekst al beschikbaar is; het slaat extractie en de bijbehorende foutmodi volledig over. - De optionele Artisan-reader verbetert de extractienauwkeurigheid en pagina-toewijzing. Het wordt tijdens runtime gedetecteerd en is nooit vereist.
- Vang
OverflowExceptionaf bij het diffen van niet-vertrouwde invoer; de grenzen zijn bewuste fail-closed-afwijzingen, geen tijdelijke fouten. DiffFormatter::toHtml()geeft klassenamen af (diff-added,diff-removed,diff-modified,diff-unchanged) maar geen stylesheet; lever je eigen CSS.- Construeer
StructuredDiffermet stub-differs in tests om het tekstpad te isoleren van afbeeldings- en metadatascanning.
Publicatiegrens
Sectie met titel “Publicatiegrens”Deze pagina documenteert uitsluitend extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helperklassen, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.
Zie ook
Sectie met titel “Zie ook”- Diff (capaciteit) — installatie, snelstart en productievoorbeelden.
- Converter — Diepe referentie
- Filter — Diepe referentie