Перейти к содержимому
getnextpdf.com

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 с параллельным выделением правок.
  • Ограничения ресурсов. Размер распакованного потока содержимого ограничивается для защиты от бомб распаковки; побайтовый сканер избегает катастрофического возврата регулярных выражений на специально подготовленном вводе.
  • Детерминированность. Для одинакового ввода области различий и форматированный вывод стабильны.
ТипВидКлючевые члены
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 извлечение использует ограниченный резервный механизм; сильно сжатые документы могут давать сниженное покрытие текста.

Извлечение текста линейно по байтам документа; сравнение Майерса почти линейно для похожих документов и квадратично в худшем случае на пару страниц. Ограничение распаковки ограничивает память. См. performance_budget.

Побайтовый резервный механизм использует сканирование на основе strpos вместо неограниченных регулярных выражений, чтобы избежать катастрофического возврата на специально подготовленных PDF, и ограничивает вывод распаковки. Сравнение не выполняет встроенные скрипты. См. модель безопасности Core.

УтверждениеПункт стандартаСтатус
Текстовый оператор Tj разбирается для извлеченияISO 32000-2:2020 §9.4Проверено (набор модульных тестов)
Оператор массива TJ разбирается для извлеченияISO 32000-2:2020 §9.4Проверено (набор модульных тестов)
Визуальный вывод PDF с параллельным выделением правокНе поддерживается (только JSON/HTML)

В Core нет аналога для сравнения документов. Необязательный модуль чтения Artisan повышает точность извлечения, когда установлен, но не обязателен.

Это детектор изменений содержимого. Это не криминалистический анализатор различий, и он не создаёт доказательных отчётов или отчётов об атрибуции вмешательства; эти задачи вне области применения этого модуля.

Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую поверхность публичного API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов инструкций и префиксы тикетов вне области применения.