Pro редакция
Diff
Краткий обзор
Заголовок раздела «Краткий обзор»NextPDF\Pro\Diff сравнивает два документа PDF и сообщает, что изменилось.
Быстрый путь даёт постранично выровненное сравнение текста; структурированный
путь добавляет обнаружение изменений изображений и метаданных и форматирует
результат как JSON или HTML.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в составе NextPDF Pro (nextpdf/pro) и
активируется лицензионным конвертом уровня Pro. Развёртывание без этого права
не загружает классы возможности. Сравнить редакции и получить
лицензию.
Никакой флаг возможности времени выполнения не ограничивает классы Diff; они присутствуют всегда, когда установлен пакет Pro.
Установка
Заголовок раздела «Установка»composer require nextpdf/pro:^3Концептуальный обзор
Заголовок раздела «Концептуальный обзор»PdfDiffer::compare() извлекает текст постранично из каждого документа,
разбивает его на строки и выполняет построчное сравнение Майерса для каждой
пары страниц, формируя области добавления, удаления и изменения. Извлечение
текста разбирает операторы вывода текста ISO 32000-2:2020 §9.4 (Tj, TJ,
').
StructuredDiffer строится на этом: он группирует текстовые области в
изменения уровня абзацев, сравнивает встроенные изображения, сравнивает
метаданные и формирует StructuredDiffResult со сводным итогом. DiffFormatter
сериализует этот результат в строку JSON или фрагмент отчёта HTML.
Когда установлен необязательный модуль чтения PDF Artisan, извлечение текста использует его для постранично точного содержимого; иначе ограниченный побайтовый резервный механизм сканирует потоки содержимого напрямую.
Почему это работает именно так
Заголовок раздела «Почему это работает именно так»Сравнение анализирует извлечённый текст и структуру, а не отрисованные пиксели.
Структурное сравнение детерминировано, дёшево и отображается на редакторские
изменения, которые важны рецензенту. Пиксельное сравнение вместо этого помечало
бы сглаживание и хинтинг шрифтов как содержимое. Поскольку PDF хранит глифы и
позиционирование, а не готовые к чтению символы, каждое сравнение сначала
восстанавливает текст из потока содержимого. Именно этот шаг извлечения — причина
того, почему модуль чтения Artisan повышает точность, почему ограниченный
резервный механизм FlateDecode жертвует покрытием ради безопасности и почему
отсканированные страницы почти не дают различий. Выравнивание страниц остаётся
основанным на индексе ради предсказуемости, поэтому вставленная страница
читается как явный сдвиг ниже по документу.
Проектная предыстория: Почему текст в PDF не совсем текст.
Контракт поведения
Заголовок раздела «Контракт поведения»- Вход. Исходные байты PDF для источника и цели. Буфер, не начинающийся с
%PDF, вызываетInvalidArgumentException. - Выход (быстрый путь).
DiffResultсо списками областейadded,removed,modifiedплюсisIdentical(),hasDifferences(),totalChanges(). - Выход (структурированный путь).
StructuredDiffResultс различиями по абзацам, различиями изображений, изменениями метаданных иDiffSummary. - Вывод отчёта.
DiffFormatterвыводит строку JSON или фрагмент HTML. Он не создаёт визуальный PDF с параллельным выделением правок. - Ограничения ресурсов. Размер распакованного потока содержимого ограничивается для защиты от бомб распаковки; побайтовый сканер избегает катастрофического возврата регулярных выражений на специально подготовленном вводе.
- Детерминированность. Для одинакового ввода области различий и форматированный вывод стабильны.
Поверхность публичного API
Заголовок раздела «Поверхность публичного API»| Тип | Вид | Ключевые члены |
|---|---|---|
NextPDF\Pro\Diff\PdfDiffer | final class | static compare(string $sourcePdf, string $targetPdf): DiffResult, static compareTexts(array $sourcePages, array $targetPages): DiffResult, static extractText(string $contentStream): string |
NextPDF\Pro\Diff\StructuredDiffer | final class | __construct(?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null), compare(string $sourcePdf, string $targetPdf): StructuredDiffResult |
NextPDF\Pro\Diff\DiffFormatter | final class | toJson(StructuredDiffResult $result): string, toHtml(StructuredDiffResult $result): string |
NextPDF\Pro\Diff\DiffResult | final readonly class | array $added, array $removed, array $modified, isIdentical(): bool, hasDifferences(): bool, totalChanges(): int |
NextPDF\Pro\Diff\StructuredDiffResult | final readonly class | text diff, paragraphs, images, metadata changes, summary |
NextPDF\Pro\Diff\DiffType | enum | Added, 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 извлечение использует ограниченный резервный механизм; сильно сжатые документы могут давать сниженное покрытие текста.
Производительность
Заголовок раздела «Производительность»Извлечение текста линейно по байтам документа; сравнение Майерса почти линейно
для похожих документов и квадратично в худшем случае на пару страниц.
Ограничение распаковки ограничивает память. См. performance_budget.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Побайтовый резервный механизм использует сканирование на основе strpos вместо
неограниченных регулярных выражений, чтобы избежать катастрофического возврата
на специально подготовленных PDF, и ограничивает вывод распаковки. Сравнение не
выполняет встроенные скрипты. См. модель безопасности Core.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Пункт стандарта | Статус |
|---|---|---|
Текстовый оператор Tj разбирается для извлечения | ISO 32000-2:2020 §9.4 | Проверено (набор модульных тестов) |
Оператор массива TJ разбирается для извлечения | ISO 32000-2:2020 §9.4 | Проверено (набор модульных тестов) |
| Визуальный вывод PDF с параллельным выделением правок | — | Не поддерживается (только JSON/HTML) |
Резервный вариант Core / альтернатива
Заголовок раздела «Резервный вариант Core / альтернатива»В Core нет аналога для сравнения документов. Необязательный модуль чтения Artisan повышает точность извлечения, когда установлен, но не обязателен.
Примечание о границе Enterprise
Заголовок раздела «Примечание о границе Enterprise»Это детектор изменений содержимого. Это не криминалистический анализатор различий, и он не создаёт доказательных отчётов или отчётов об атрибуции вмешательства; эти задачи вне области применения этого модуля.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую поверхность публичного API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов инструкций и префиксы тикетов вне области применения.