Ir al contenido
getnextpdf.com

Pro edición

Diff

NextPDF\Pro\Diff compara dos documentos PDF e informa de lo que cambió. La ruta rápida produce una comparación de texto alineada por página; la ruta estructurada añade la detección de cambios de imagen y de metadatos y da formato al resultado como JSON o HTML.

Esta capacidad se incluye en NextPDF Pro (nextpdf/pro) y se activa con un sobre de licencia de nivel Pro. Un despliegue sin ese derecho no carga las clases de la capacidad. Compare las ediciones y obtenga una licencia.

Ningún indicador de capacidad en tiempo de ejecución restringe las clases de Diff; están presentes siempre que el paquete Pro esté instalado.

Ventana de terminal
composer require nextpdf/pro:^3

PdfDiffer::compare() extrae el texto por página de cada documento, lo divide en líneas y ejecuta una comparación de líneas de Myers por par de páginas, produciendo regiones añadidas, eliminadas y modificadas. La extracción de texto analiza los operadores de presentación de texto de ISO 32000-2:2020 §9.4 (Tj, TJ, ').

StructuredDiffer se basa en eso: agrupa las regiones de texto en cambios a nivel de párrafo, compara las imágenes incrustadas, compara los metadatos y produce un StructuredDiffResult con un resumen agregado. DiffFormatter serializa ese resultado a una cadena JSON o a un fragmento de informe HTML.

Cuando el lector de PDF opcional Artisan está instalado, la extracción de texto lo utiliza para obtener contenido preciso por página; de lo contrario, un recurso acotado a nivel de bytes escanea los flujos de contenido directamente.

El comparador compara el texto y la estructura extraídos, no los píxeles renderizados. Una comparación estructural es determinista, económica y se corresponde con los cambios editoriales que le importan a un revisor. En cambio, una comparación de píxeles señalaría como contenido el ruido del suavizado de bordes y del ajuste de fuentes. Como un PDF almacena glifos y posicionamiento, no caracteres listos para leer, cada comparación reconstruye primero el texto a partir del flujo de contenido. Ese paso de extracción es la razón por la que el lector Artisan afina la precisión, por la que el recurso acotado FlateDecode sacrifica cobertura por seguridad y por la que las páginas escaneadas apenas se comparan. La alineación de páginas se mantiene basada en el índice para dar previsibilidad, de modo que una página insertada se lee como un claro desplazamiento aguas abajo.

Contexto de diseño: Por qué el texto de un PDF no es realmente texto.

  • Entrada. Bytes de PDF en bruto para el origen y el destino. Un búfer que no empieza por %PDF genera InvalidArgumentException.
  • Salida (ruta rápida). DiffResult con las listas de regiones added, removed y modified más isIdentical(), hasDifferences(), totalChanges().
  • Salida (ruta estructurada). StructuredDiffResult con comparaciones de párrafos, comparaciones de imágenes, cambios de metadatos y un DiffSummary.
  • Salida de informe. DiffFormatter emite una cadena JSON o un fragmento HTML. No produce un PDF de revisión visual en paralelo con marcas.
  • Límites de recursos. El tamaño del flujo de contenido descomprimido está acotado para protegerse frente a las bombas de descompresión; el escáner a nivel de bytes evita el retroceso catastrófico de expresiones regulares en entradas manipuladas.
  • Determinismo. Para entradas idénticas, las regiones de comparación y la salida con formato son estables.
TipoCategoríaMiembros clave
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 classcomparación de texto, párrafos, imágenes, cambios de metadatos, resumen
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);
}
  • La comparación se alinea por índice de página. Insertar una página al principio desplaza todas las páginas posteriores e informa de grandes cambios aguas abajo: esto es lo esperado para una comparación alineada por índice.
  • La comparación de imágenes detecta imágenes incrustadas añadidas, eliminadas y modificadas; no es una comparación visual perceptual y no renderiza las páginas en píxeles.
  • Los PDF escaneados que solo contienen imágenes producen poca o ninguna comparación de texto porque no se realiza ningún OCR.
  • Sin el lector Artisan opcional, la extracción usa el recurso acotado; los documentos muy comprimidos pueden producir una cobertura de texto reducida.

La extracción de texto es lineal respecto a los bytes del documento; la comparación de Myers es casi lineal para documentos similares y cuadrática en el peor de los casos por par de páginas. El tope de descompresión acota la memoria. Consulte performance_budget.

El recurso a nivel de bytes usa un escaneo basado en strpos en lugar de expresiones regulares no acotadas para evitar el retroceso catastrófico en PDF manipulados, y acota la salida de descompresión. La comparación no ejecuta scripts incrustados. Consulte el modelo de seguridad de Core.

DeclaraciónCláusula del estándarEstado
Operador de texto Tj analizado para la extracciónISO 32000-2:2020 §9.4Verificado (conjunto unitario)
Operador de texto en array TJ analizado para la extracciónISO 32000-2:2020 §9.4Verificado (conjunto unitario)
Salida de PDF de revisión visual en paralelo con marcasNo admitido (solo JSON/HTML)

No existe ningún equivalente en Core para la comparación de documentos. El lector Artisan opcional mejora la precisión de la extracción cuando está instalado, pero no es obligatorio.

Es un detector de cambios de contenido. No es un analizador de diferencias forense y no produce informes probatorios ni de atribución de manipulaciones; esas cuestiones quedan fuera del alcance de este módulo.

Esta página documenta únicamente el comportamiento observable externamente y la superficie pública de la API compatible. Las rutas de espacios de nombres internas, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbook y los prefijos de tickets quedan fuera del alcance.