Pro edycja
Diff — pełna dokumentacja referencyjna
W skrócie
Dział zatytułowany „W skrócie”Ta strona jest referencją na poziomie kontraktu dla modułu różnic NextPDF Pro, NextPDF\Pro\Diff. Moduł porównuje dwa dokumenty PDF i raportuje zmiany tekstu, obrazów oraz metadanych. PdfDiffer tworzy różnicę wierszową Myersa wyrównaną do stron. StructuredDiffer dodaje grupowanie akapitów, porównanie obrazów i porównanie metadanych. DiffFormatter serializuje wynik strukturalny do JSON lub do fragmentu HTML. Ta strona określa publiczne API, obserwowalny kontrakt zachowania, limity zasobów oraz tryby awarii. Konfiguracja zorientowana na zadania i przykłady znajdują się na stronie możliwości Diff.
Dostępność i licencjonowanie
Dział zatytułowany „Dostępność i licencjonowanie”Ta możliwość jest dostarczana w NextPDF Pro (nextpdf/pro) i aktywuje się dzięki kopercie licencyjnej poziomu Pro. Wdrożenie bez tego uprawnienia nie ładuje klas tej możliwości. Porównaj edycje i uzyskaj licencję.
Żadna flaga możliwości czasu wykonania nie bramkuje tego modułu. Klasy różnic są dostępne zawsze, gdy nextpdf/pro jest zainstalowany i licencjonowany.
Powierzchnia publicznego API
Dział zatytułowany „Powierzchnia publicznego API”| Symbol | Parametry | Zachowanie domyślne | Zwraca | Zgłasza lub kończy się błędem | Uwagi |
|---|---|---|---|---|---|
PdfDiffer::compare() | string $sourcePdf, string $targetPdf | Wyodrębnia tekst dla każdej strony, następnie porównuje różnicę strony i źródła ze stroną i celu | DiffResult | InvalidArgumentException, gdy bufor nie zawiera nagłówka %PDF lub opcjonalny czytnik nie sparsuje danych; OverflowException przy przekroczeniu limitu zasobów | Statyczny punkt wejścia |
PdfDiffer::compareTexts() | array $sourcePages, array $targetPages (każdy list<string>) | Porównuje wcześniej wyodrębnione teksty stron, pomijając ekstrakcję | DiffResult | OverflowException przy przekroczeniu limitu zasobów | Statyczny; użyj, gdy tekst jest już dostępny |
PdfDiffer::extractText() | string $contentStream | Parsuje operatory pokazywania tekstu z jednego surowego strumienia zawartości | string | — (odporny na błędy; niesparsowalne wejście daje pusty ciąg) | Statyczny |
StructuredDiffer::__construct() | ?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null | Argumenty null tworzą domyślne komparatory | — | — | Wstrzykiwanie przez konstruktor na potrzeby testów |
StructuredDiffer::compare() | string $sourcePdf, string $targetPdf | Uruchamia porównanie tekstu, akapitów, obrazów i metadanych, następnie buduje podsumowanie | StructuredDiffResult | Propaguje InvalidArgumentException i OverflowException ze ścieżki tekstowej | Orkiestrator całego modułu |
DiffFormatter::toJson() | StructuredDiffResult $result | Sformatowany dokument JSON | string | JsonException, gdy kodowanie się nie powiedzie | — |
DiffFormatter::toHtml() | StructuredDiffResult $result | Fragment HTML z sekcjami podsumowania, akapitów i metadanych; wartości tekstowe są escapowane jako encje | string | — | Tylko fragment, nie pełny dokument |
DiffFormatter::toArray() | StructuredDiffResult $result | Tablica serializacji stojąca za toJson() | array<string, mixed> | — | Stabilne klucze snake_case |
ImageDiffer::diff() | string $sourcePdf, string $targetPdf | Haszuje obiekty XObject obrazów i raportuje dodane, usunięte oraz zmodyfikowane obrazy | list<ImageDiff> | — (niedekodowalne struktury są pomijane fail-closed) | Tożsamość to kubełek strony plus numer obiektu |
MetadataDiffer::diff() | string $sourcePdf, string $targetPdf | Porównuje osiem pól /Info (Title, Author, Subject, Keywords, Creator, Producer, CreationDate, ModDate) | list<MetadataChange> | — (nigdy nie zgłasza wyjątku na niezgodnym wejściu) | Wartości porównywane jako zdekodowane ciągi |
DiffEngine::diff() | array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = 10000 | Różnica wierszowa Myersa na dwóch listach wierszy | list<DiffRegion> | OverflowException, gdy łączna liczba wierszy przekracza $maxLines lub odległość edycyjna przekracza limit narzucony przez pamięć | Statyczny; producent regionów dla wszystkich ścieżek tekstowych |
TextExtractor::fromContentStream() | string $contentStream | Tokenizuje strumień i uruchamia maszynę stanu tekstu | list<TextBlock> | — | Statyczny |
TextExtractor::fromOperations() | array $operations (list<ContentStreamOp>) | Uruchamia maszynę stanu tekstu na wcześniej sparsowanych operacjach | list<TextBlock> | — | Statyczny |
ContentStreamParser::parse() | konstruktor przyjmuje string $data | Tokenizuje operatory i operandy; pomija słowniki i komentarze; odporny na błędy | list<ContentStreamOp> | — | Nierozpoznane bajty są pomijane, nigdy nie są krytyczne |
ContentStreamOp | string $operator, list<mixed> $operands | Tylko-do-odczytu obiekt wartości operacji; isTextOp() klasyfikuje operatory związane z tekstem | — | — | — |
DiffResult | list<DiffRegion> $regions, int $sourcePagesCount, int $targetPagesCount | Rozdziela regiony do $added, $removed, $modified; udostępnia isIdentical(), hasDifferences(), totalChanges() | — | — | Tylko-do-odczytu; regiony Unchanged pozostają wyłącznie w $regions |
StructuredDiffResult | różnica tekstu, akapity, obrazy, zmiany metadanych, podsumowanie | Wynik zbiorczy; hasDifferences(), isIdentical() delegują do podsumowania | — | — | Tylko-do-odczytu |
DiffSummary | liczniki dla każdej kategorii plus liczby stron | hasDifferences() i totalChanges() na licznikach tekstu, obrazów i metadanych | — | — | Tylko-do-odczytu |
DiffRegion | DiffType $type, string $text, int $pageIndex, int $lineIndex, ?string $counterpartText = null | Jedna zmiana na poziomie wiersza | — | — | $counterpartText pozostaje null w dostarczanym silniku |
ParagraphDiff | typ, tekst, indeks strony, wiersz początkowy/końcowy, regiony | Kolejne regiony tego samego typu na jednej stronie; lineCount() | — | — | Tylko-do-odczytu |
ImageDiff | typ, indeks strony, hasz źródła, hasz celu, identyfikator obiektu | Jeden wpis zmiany obrazu | — | — | Hasze są pustymi ciągami po nieobecnej stronie |
MetadataChange | string $field, ?string $sourceValue, ?string $targetValue | Jedna zmiana pola; isAdded(), isRemoved(), isModified() | — | — | null oznacza, że pole jest nieobecne |
TextBlock | tekst, x, y, nazwa czcionki, rozmiar czcionki, indeks wiersza | Jeden wyodrębniony fragment tekstu z przybliżoną pozycją | — | — | Tylko-do-odczytu |
DiffType | enum: Added, Removed, Modified, Unchanged | Klasyfikacja zmian dla tekstu oparta na łańcuchach znaków | — | — | Zobacz uwagę o Modified w kontrakcie zachowania |
ImageDiffType | enum: Added, Removed, Modified, Unchanged | Klasyfikacja zmian dla obrazów oparta na łańcuchach znaków | — | — | — |
Sygnatury punktów wejścia
Dział zatytułowany „Sygnatury punktów wejścia”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,): arrayKontrakt zachowania
Dział zatytułowany „Kontrakt zachowania”Wyrównanie stron i różnica wierszowa
Dział zatytułowany „Wyrównanie stron i różnica wierszowa”PdfDiffer::compare() wyodrębnia tekst dla każdej strony, następnie porównuje różnicę strony i źródła ze stroną i celu. Gdy liczby stron się różnią, brakująca strona jest traktowana jako pusty tekst dla nadliczbowych stron. W obrębie każdej pary stron tekst jest dzielony na znakach nowej linii, a różnica wierszowa Myersa działa dla każdej strony. Silnik emituje regiony Added, Removed i Unchanged. Zmieniony wiersz pojawia się jako region Removed plus region Added; dostarczany silnik nigdy nie emituje regionów tekstowych Modified. Przypadek Modified oraz kubełek DiffResult::$modified służą wynikom konstruowanym przez wywołującego, ponieważ konstruktor DiffResult jest publiczny. totalChanges() liczy regiony dodane, usunięte i zmodyfikowane; regiony niezmienione są wykluczone.
Ścieżki ekstrakcji
Dział zatytułowany „Ścieżki ekstrakcji”Ekstrakcja ma dwie ścieżki:
- Obecny opcjonalny czytnik Artisan. Gdy zainstalowana jest opcjonalna klasa
NextPDF\Parser\PdfReader, strumienie zawartości stron są odczytywane przez nią, aby uzyskać dokładny stronowo tekst. Liczba stron z trailera steruje pętlą. Strona, której nie uda się odczytać, wnosi pusty tekst zamiast przerywać porównanie. - Rozwiązanie awaryjne. Ograniczony skaner bajtowy lokalizuje pary
stream/endstreamza pomocąstrpos, dekompresuje dane FlateDecode ze sztywnym pułapem wyjścia 50 MB oraz odwraca filtr predyktora PNG, gdy słownik strumienia żąda go przez/DecodeParmszgodnie z ISO 32000-2:2020 §7.4.4.4. Zniekształcony lub nieobsługiwany predyktor pozostawia zdekodowane bajty bez zmian. Rozwiązanie awaryjne łączy cały odzyskany tekst w pojedynczy kubełek strony, więc wyrównanie na poziomie stron jest dokładne stronowo tylko na ścieżce czytnika.
Obie ścieżki parsują operatory pokazywania tekstu z §9.4: Tj, TJ i '. Maszyna stanu śledzi BT/ET, Tm (tylko punkt początkowy), Td/TD, T* oraz Tf.
Porównanie strukturalne
Dział zatytułowany „Porównanie strukturalne”StructuredDiffer::compare() uruchamia różnicę tekstu, grupuje kolejne regiony tego samego typu na tej samej stronie w akapity (włącznie z ciągami niezmienionymi), następnie uruchamia porównanie obrazów i metadanych oraz składa DiffSummary. Liczniki akapitów w podsumowaniu obejmują wyłącznie akapity dodane, usunięte i zmodyfikowane.
Porównanie obrazów wylicza obiekty PDF strukturalnie. Zasięg ciała strumienia jest wyznaczany przez jego wpis /Length zgodnie z §7.3.8.2, więc bajty binarne, które jedynie przypominają składnię obiektu, nigdy nie rejestrują się jako fantomowe obiekty. Skompresowane strumienie obiektów (/Type /ObjStm) są dekodowane zgodnie z §7.5.7, aby zagnieżdżone w nich obiekty XObject obrazów były widoczne. Każdy wykryty obraz jest haszowany po zawartości niekryptograficzną funkcją xxh128; tożsamością jest para kubełka strony i numeru obiektu. Obrazy bez strony właścicielskiej w kolejności strumienia są przypisywane do strony 0.
Porównanie metadanych rozwiązuje prawdziwy słownik /Info przez trailer, gdy to możliwe, więc zwodniczy token pola wewnątrz strumienia zawartości nie jest mylony z metadanymi dokumentu. Wartości pól są dekodowane jako ciągi PDF: forma literalna zgodnie z §7.3.4.2 oraz forma szesnastkowa zgodnie z §7.3.4.3. Bez możliwego do rozwiązania trailera wyszukiwanie sięga do całego wejścia. Daty są porównywane jako zdekodowane ciągi, a nie sparsowane znaczniki czasu.
Wynik raportu
Dział zatytułowany „Wynik raportu”DiffFormatter::toJson() zwraca sformatowany JSON i koduje z JSON_THROW_ON_ERROR, więc niepowodzenie kodowania zgłasza JsonException zamiast zwracać false. toHtml() zwraca fragment <div class="nextpdf-diff">; tekst akapitów i wartości metadanych przechodzą przez escapowanie encji HTML. Nie ma wizualnego wyniku PDF z korektą zestawioną obok siebie. Dla identycznych danych wejściowych regiony i sformatowany wynik są deterministyczne.
Przypadki brzegowe i tryby awarii
Dział zatytułowany „Przypadki brzegowe i tryby awarii”- Wyrównanie stron jest pozycyjne. Pojedyncza wstawiona lub usunięta strona przesuwa wyrównanie dla wszystkich kolejnych stron i zawyża liczbę zmian w dalszej części.
- Na awaryjnej ścieżce ekstrakcji cały tekst trafia na stronę o indeksie 0. Porównanie dokumentu wyodrębnionego przez czytnik z oczekiwaniami ze ścieżki awaryjnej daje inne przypisanie stron.
- Bufor źródła lub celu, który nie zaczyna się od
%PDF, kończy się błędemInvalidArgumentExceptionprzed jakimkolwiek porównaniem. - Ponad 10,000 łącznych wierszy w jednej parze stron kończy się błędem
OverflowException(limit liczby wierszy). - Dwa teksty stron dzielące zbyt mało wspólnych wierszy kończą się błędem
OverflowException, gdy odległość edycyjna Myersa przekroczy limit narzucony przez pamięć. Legalne wersje dzielą większość wierszy i pozostają nienaruszone; wrogie wejścia o niskiej wspólności naruszają ten limit. - Zdekompresowany wynik strumienia awaryjnego większy niż 50 MB kończy się błędem
OverflowException(limit bomby dekompresyjnej). Skaner używastrpos, a nie nieograniczonego wyrażenia regularnego, więc spreparowane wejście nie może wywołać katastroficznego nawracania. - Operator pokazywania tekstu
"jest tokenizowany, ale nie tworzy bloku tekstu w 3.1.0; tekst pokazany wyłącznie przez"nie uczestniczy w różnicy. - Zeskanowane pliki PDF zawierające tylko obrazy dają niewielką różnicę tekstu lub jej brak. Nie działa żaden OCR.
- Wykrywanie zmian obrazów jest strukturalne, nie percepcyjne. Nie rasteryzuje stron, a obraz ponownie zakodowany z identycznymi pikselami jest raportowany jako zmodyfikowany, gdy jego bajty się różnią.
- Obraz, którego kubełek strony lub numer obiektu zmienia się między wersjami, jest raportowany jako para usunięcie-plus-dodanie, a nie jako zmodyfikowany.
- Strumienie obiektów skompresowane filtrami innymi niż FlateDecode są pomijane fail-closed; ich obrazy członkowskie nie są porównywane.
- W tym module nie zachodzi żadna operacja kryptograficzna, więc nie istnieje zachowanie specyficzne dla trybu FIPS. Hasz obrazu służy wyłącznie do wykrywania zmian i nie ma żadnej wagi integralności ani dowodowej.
Konformancja
Dział zatytułowany „Konformancja”| Twierdzenie | Standard | Klauzula |
|---|---|---|
Operatory pokazywania tekstu Tj i TJ są parsowane na potrzeby ekstrakcji | ISO 32000-2:2020 | §9.4 |
Dane strumienia awaryjnego zaczynają się po CRLF lub LF następującym po słowie kluczowym stream | ISO 32000-2:2020 | §7.3.8.1 |
Zasięgi strumieni w skanowaniu obrazów są wyznaczane przez wpis słownika /Length | ISO 32000-2:2020 | §7.3.8.2 |
Członkowie strumienia obiektów są lokalizowani przez tabelę par /N i przesunięcie /First | ISO 32000-2:2020 | §7.5.7 |
Odwrócenie predyktora PNG podąża za parametrem Predictor w /DecodeParms | ISO 32000-2:2020 | §7.4.4.4 |
| Wartości metadanych dekodują literalną i szesnastkową formę ciągu | ISO 32000-2:2020 | §7.3.4.2, §7.3.4.3 |
| Wizualny wynik PDF z korektą zestawioną obok siebie | — | Nieobsługiwane (tylko JSON/HTML) |
Wszystkie klauzule są parafrazowane; NextPDF nie odtwarza tekstu normatywnego. Są to oświadczenia o możliwościach, a nie certyfikaty; NextPDF nie posiada żadnego certyfikatu ani go nie udziela. Odzyskiwanie tekstu rekonstruuje tekst wierszy z operatorów pokazywania tekstu. Nie uruchamia pełnej maszyny stanu tekstu z §9.4, więc różnica jest na poziomie zawartości, a nie geometrii.
Uwagi dla programistów
Dział zatytułowany „Uwagi dla programistów”- Dostępność w pakiecie Pro:
PdfDiffer,DiffEngine,TextExtractororaz ich obiekty wartości od 1.8.0;StructuredDiffer,DiffFormatter,ImageDiffer,MetadataDifferoraz ich obiekty od 2.2.0. Wszystkie są aktualne wnextpdf/pro3.1.0. - Preferuj
PdfDiffer::compareTexts(), gdy tekst strony jest już dostępny; całkowicie pomija ekstrakcję i jej tryby awarii. - Opcjonalny czytnik Artisan poprawia dokładność ekstrakcji i przypisanie stron. Jest wykrywany w czasie wykonania i nigdy nie jest wymagany.
- Przechwytuj
OverflowExceptionprzy porównywaniu niezaufanego wejścia; limity są celowymi odrzuceniami fail-closed, a nie błędami przejściowymi. DiffFormatter::toHtml()emituje nazwy klas (diff-added,diff-removed,diff-modified,diff-unchanged), ale nie arkusz stylów; dostarcz własny CSS.- Konstruuj
StructuredDifferz zaślepkami komparatorów w testach, aby odizolować ścieżkę tekstową od skanowania obrazów i metadanych.
Granica publikacji
Dział zatytułowany „Granica publikacji”Ta strona dokumentuje wyłącznie zachowanie obserwowalne z zewnątrz oraz obsługiwaną powierzchnię publicznego API. Wewnętrzne ścieżki przestrzeni nazw, klasy pomocnicze, tabele mechanizmów, nazwy plików runbooków oraz prefiksy zgłoszeń są poza zakresem.
Zobacz także
Dział zatytułowany „Zobacz także”- Diff (możliwość) — instalacja, szybki start i przykłady produkcyjne.
- Converter — pełna dokumentacja referencyjna
- Filter — pełna dokumentacja referencyjna