Pro edición
Diff
De un vistazo
Sección titulada «De un vistazo»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.
Disponibilidad y licencias
Sección titulada «Disponibilidad y licencias»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.
Instalación
Sección titulada «Instalación»composer require nextpdf/pro:^3Descripción conceptual
Sección titulada «Descripción conceptual»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.
Por qué funciona así
Sección titulada «Por qué funciona así»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.
Contrato de comportamiento
Sección titulada «Contrato de comportamiento»- Entrada. Bytes de PDF en bruto para el origen y el destino. Un búfer que no
empieza por
%PDFgeneraInvalidArgumentException. - Salida (ruta rápida).
DiffResultcon las listas de regionesadded,removedymodifiedmásisIdentical(),hasDifferences(),totalChanges(). - Salida (ruta estructurada).
StructuredDiffResultcon comparaciones de párrafos, comparaciones de imágenes, cambios de metadatos y unDiffSummary. - Salida de informe.
DiffFormatteremite 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.
Superficie pública de la API
Sección titulada «Superficie pública de la API»| Tipo | Categoría | Miembros clave |
|---|---|---|
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 | comparación de texto, párrafos, imágenes, cambios de metadatos, resumen |
NextPDF\Pro\Diff\DiffType | enum | Added, Removed, Modified, Unchanged |
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»<?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";}Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producció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);}Casos límite y trampas
Sección titulada «Casos límite y trampas»- 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.
Rendimiento
Sección titulada «Rendimiento»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.
Notas de seguridad
Sección titulada «Notas de seguridad»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.
Conformidad
Sección titulada «Conformidad»| Declaración | Cláusula del estándar | Estado |
|---|---|---|
Operador de texto Tj analizado para la extracción | ISO 32000-2:2020 §9.4 | Verificado (conjunto unitario) |
Operador de texto en array TJ analizado para la extracción | ISO 32000-2:2020 §9.4 | Verificado (conjunto unitario) |
| Salida de PDF de revisión visual en paralelo con marcas | — | No admitido (solo JSON/HTML) |
Alternativa / recurso de Core
Sección titulada «Alternativa / recurso de Core»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.
Nota sobre el límite de Enterprise
Sección titulada «Nota sobre el límite de Enterprise»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.
Límite de publicación
Sección titulada «Límite de publicación»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.