Pro edición
Diff — Referencia detallada
De un vistazo
Sección titulada «De un vistazo»Esta página es la referencia a nivel de contrato del módulo de diff de NextPDF Pro, NextPDF\Pro\Diff. El módulo compara dos documentos PDF e informa de los cambios de texto, imágenes y metadatos. PdfDiffer produce un diff de líneas de Myers alineado por páginas. StructuredDiffer añade agrupación de párrafos, comparación de imágenes y comparación de metadatos. DiffFormatter serializa el resultado estructurado a JSON o a un fragmento HTML. Esta página expone la API pública, el contrato de comportamiento observable, los límites de recursos y los modos de fallo. La configuración orientada a tareas y los ejemplos están en la página de la capacidad Diff.
Disponibilidad y licencias
Sección titulada «Disponibilidad y licencias»Esta capacidad se distribuye 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. Comparar ediciones y obtener una licencia.
Ningún indicador de capacidad en tiempo de ejecución restringe este módulo. Las clases de diff son utilizables siempre que nextpdf/pro esté instalado y licenciado.
Superficie de la API pública
Sección titulada «Superficie de la API pública»| Símbolo | Parámetros | Comportamiento por defecto | Devuelve | Lanza o falla con | Notas |
|---|---|---|---|---|---|
PdfDiffer::compare() | string $sourcePdf, string $targetPdf | Extrae el texto por página y luego compara la página i del origen con la página i del destino | DiffResult | InvalidArgumentException cuando un búfer carece de la cabecera %PDF o el lector opcional no puede analizarlo; OverflowException al alcanzar un límite de recursos | Punto de entrada estático |
PdfDiffer::compareTexts() | array $sourcePages, array $targetPages (list<string> cada uno) | Compara textos de página ya extraídos, omitiendo la extracción | DiffResult | OverflowException al alcanzar un límite de recursos | Estático; usar cuando el texto ya está disponible |
PdfDiffer::extractText() | string $contentStream | Analiza los operadores de presentación de texto de un flujo de contenido en bruto | string | — (tolerante a fallos; una entrada no analizable produce una cadena vacía) | Estático |
StructuredDiffer::__construct() | ?ImageDiffer $imageDiffer = null, ?MetadataDiffer $metadataDiffer = null | Los argumentos null construyen los diferenciadores por defecto | — | — | Inyección por constructor para pruebas |
StructuredDiffer::compare() | string $sourcePdf, string $targetPdf | Ejecuta la comparación de texto, párrafos, imágenes y metadatos y luego construye un resumen | StructuredDiffResult | Propaga InvalidArgumentException y OverflowException desde la ruta de texto | Orquestador de todo el módulo |
DiffFormatter::toJson() | StructuredDiffResult $result | Documento JSON con formato legible | string | JsonException cuando la codificación falla | — |
DiffFormatter::toHtml() | StructuredDiffResult $result | Fragmento HTML con secciones de resumen, párrafos y metadatos; los valores de texto se escapan como entidades | string | — | Solo fragmento, no un documento completo |
DiffFormatter::toArray() | StructuredDiffResult $result | Array de serialización que respalda a toJson() | array<string, mixed> | — | Claves snake_case estables |
ImageDiffer::diff() | string $sourcePdf, string $targetPdf | Calcula el hash de los XObjects de imagen e informa de imágenes añadidas, eliminadas y modificadas | list<ImageDiff> | — (las estructuras no decodificables se omiten fail-closed) | La identidad es el cubo de página más el número de objeto |
MetadataDiffer::diff() | string $sourcePdf, string $targetPdf | Compara ocho campos de /Info (Title, Author, Subject, Keywords, Creator, Producer, CreationDate, ModDate) | list<MetadataChange> | — (nunca lanza excepción ante entradas no conformes) | Los valores se comparan como cadenas decodificadas |
DiffEngine::diff() | array $sourceLines, array $targetLines, int $pageIndex = 0, int $maxLines = 10000 | Diff de líneas de Myers sobre dos listas de líneas | list<DiffRegion> | OverflowException cuando el total de líneas supera $maxLines o la distancia de edición supera el tope acotado por memoria | Estático; el productor de regiones para todas las rutas de texto |
TextExtractor::fromContentStream() | string $contentStream | Tokeniza el flujo y ejecuta la máquina de estados de texto | list<TextBlock> | — | Estático |
TextExtractor::fromOperations() | array $operations (list<ContentStreamOp>) | Ejecuta la máquina de estados de texto sobre operaciones ya analizadas | list<TextBlock> | — | Estático |
ContentStreamParser::parse() | el constructor toma string $data | Tokeniza operadores y operandos; omite diccionarios y comentarios; tolerante a fallos | list<ContentStreamOp> | — | Los bytes no reconocidos se omiten, nunca son fatales |
ContentStreamOp | string $operator, list<mixed> $operands | Objeto de valor de operación de solo lectura; isTextOp() clasifica los operadores relacionados con texto | — | — | — |
DiffResult | list<DiffRegion> $regions, int $sourcePagesCount, int $targetPagesCount | Agrupa las regiones en $added, $removed, $modified; expone isIdentical(), hasDifferences(), totalChanges() | — | — | De solo lectura; las regiones Unchanged permanecen solo en $regions |
StructuredDiffResult | diff de texto, párrafos, imágenes, cambios de metadatos, resumen | Resultado agregado; hasDifferences(), isIdentical() delegan en el resumen | — | — | De solo lectura |
DiffSummary | recuentos por categoría más recuentos de páginas | hasDifferences() y totalChanges() sobre los recuentos de texto, imágenes y metadatos | — | — | De solo lectura |
DiffRegion | DiffType $type, string $text, int $pageIndex, int $lineIndex, ?string $counterpartText = null | Un cambio a nivel de línea | — | — | $counterpartText permanece null en el motor distribuido |
ParagraphDiff | tipo, texto, índice de página, línea inicial/final, regiones | Regiones consecutivas del mismo tipo en una página; lineCount() | — | — | De solo lectura |
ImageDiff | tipo, índice de página, hash de origen, hash de destino, id de objeto | Una entrada de cambio de imagen | — | — | Los hashes son cadenas vacías en el lado ausente |
MetadataChange | string $field, ?string $sourceValue, ?string $targetValue | Un cambio de campo; isAdded(), isRemoved(), isModified() | — | — | null significa que el campo está ausente |
TextBlock | texto, x, y, nombre de fuente, tamaño de fuente, índice de línea | Un fragmento de texto extraído con posición aproximada | — | — | De solo lectura |
DiffType | enum: Added, Removed, Modified, Unchanged | Clasificación de cambios respaldada por cadena para texto | — | — | Ver la nota sobre Modified en el contrato de comportamiento |
ImageDiffType | enum: Added, Removed, Modified, Unchanged | Clasificación de cambios respaldada por cadena para imágenes | — | — | — |
Firmas de los puntos de entrada
Sección titulada «Firmas de los puntos de entrada»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,): arrayContrato de comportamiento
Sección titulada «Contrato de comportamiento»Alineación de páginas y diff de líneas
Sección titulada «Alineación de páginas y diff de líneas»PdfDiffer::compare() extrae el texto por página y luego compara la página i del origen con la página i del destino. Cuando los recuentos de páginas difieren, el lado que falta se trata como texto vacío en las páginas sobrantes. Dentro de cada par de páginas, el texto se divide por saltos de línea y se ejecuta un diff de líneas de Myers por página. El motor emite regiones Added, Removed y Unchanged. Una línea modificada aparece como una región Removed más una Added; el motor distribuido nunca emite regiones de texto Modified. El caso Modified y el cubo DiffResult::$modified sirven a los resultados construidos por el llamador, ya que el constructor de DiffResult es público. totalChanges() cuenta las regiones añadidas, eliminadas y modificadas; las regiones sin cambios quedan excluidas.
Rutas de extracción
Sección titulada «Rutas de extracción»La extracción tiene dos rutas:
- Lector Artisan opcional presente. Cuando la clase opcional
NextPDF\Parser\PdfReaderestá instalada, los flujos de contenido de las páginas se leen a través de ella para obtener texto exacto por página. El recuento de páginas del trailer dirige el bucle. Una página que no puede leerse aporta texto vacío en lugar de abortar la comparación. - Alternativa. Un escáner acotado a nivel de bytes localiza los pares
stream/endstreammediantestrpos, infla los datos FlateDecode con un tope estricto de salida de 50 MB y aplica el filtrado inverso de un predictor PNG cuando el diccionario del flujo lo solicita a través de/DecodeParmssegún ISO 32000-2:2020 §7.4.4.4. Un predictor malformado o no soportado deja los bytes decodificados sin cambios. La alternativa concatena todo el texto recuperado en un único cubo de página, por lo que la alineación a nivel de página solo es exacta por página en la ruta del lector.
Ambas rutas analizan los operadores de presentación de texto de la §9.4: Tj, TJ y '. La máquina de estados rastrea BT/ET, Tm (solo origen), Td/TD, T* y Tf.
Comparación estructurada
Sección titulada «Comparación estructurada»StructuredDiffer::compare() ejecuta el diff de texto, agrupa las regiones consecutivas del mismo tipo en la misma página en párrafos (incluyendo las series sin cambios), luego ejecuta la comparación de imágenes y metadatos y ensambla un DiffSummary. Los recuentos de párrafos del resumen abarcan únicamente los párrafos añadidos, eliminados y modificados.
La comparación de imágenes enumera los objetos PDF de forma estructural. La extensión del cuerpo de un flujo se rige por su entrada /Length según §7.3.8.2, de modo que los bytes binarios que solo se asemejan a la sintaxis de objetos nunca se registran como objetos fantasma. Los flujos de objetos comprimidos (/Type /ObjStm) se decodifican según §7.5.7 para que los XObjects de imagen anidados en ellos sean visibles. Cada imagen detectada se somete a un hash de contenido con la función no criptográfica xxh128; la identidad es el par de cubo de página y número de objeto. Las imágenes sin una página propietaria en el orden del flujo se atribuyen a la página 0.
La comparación de metadatos resuelve el diccionario /Info real a través del trailer cuando es posible, de modo que un token de campo señuelo dentro de un flujo de contenido no se confunde con metadatos del documento. Los valores de los campos se decodifican como cadenas PDF: la forma literal según §7.3.4.2 y la forma hexadecimal según §7.3.4.3. Sin un trailer resoluble, la búsqueda recurre a toda la entrada. Las fechas se comparan como cadenas decodificadas, no como marcas de tiempo analizadas.
Salida del informe
Sección titulada «Salida del informe»DiffFormatter::toJson() devuelve JSON con formato legible y codifica con JSON_THROW_ON_ERROR, de modo que un fallo de codificación lanza JsonException en lugar de devolver false. toHtml() devuelve un fragmento <div class="nextpdf-diff">; el texto de los párrafos y los valores de metadatos pasan por el escape de entidades HTML. No hay salida visual de PDF con marcado de revisión en paralelo. Para entradas idénticas, las regiones y la salida formateada son deterministas.
Casos límite y modos de fallo
Sección titulada «Casos límite y modos de fallo»- La alineación de páginas es posicional. Una sola página insertada o eliminada desplaza la alineación de todas las páginas posteriores e infla los recuentos de cambios subsiguientes.
- En la ruta de extracción alternativa, todo el texto cae en el índice de página 0. Comparar un documento extraído por el lector con expectativas de la ruta alternativa produce una atribución de páginas distinta.
- Un búfer de origen o destino que no comienza con
%PDFfalla conInvalidArgumentExceptionantes de cualquier comparación. - Más de 10.000 líneas combinadas en un par de páginas falla con
OverflowException(límite de recuento de líneas). - Dos textos de página que comparten muy pocas líneas fallan con
OverflowExceptionuna vez que la distancia de edición de Myers supera el tope acotado por memoria. Las revisiones legítimas comparten la mayoría de las líneas y no se ven afectadas; las entradas adversarias de baja coincidencia disparan el límite. - Una salida de flujo alternativo descomprimida mayor de 50 MB falla con
OverflowException(límite de bomba de descompresión). El escáner usastrpos, no una expresión regular sin límites, por lo que una entrada manipulada no puede provocar retroceso catastrófico. - El operador de presentación de texto
"se tokeniza pero no produce ningún bloque de texto en 3.1.0; el texto mostrado solo a través de"no participa en el diff. - Los PDF escaneados, con solo imágenes, producen poco o ningún diff de texto. No se ejecuta OCR.
- La detección de cambios de imagen es estructural, no perceptual. No rasteriza las páginas, y una imagen recodificada con píxeles idénticos se informa como modificada cuando sus bytes difieren.
- Una imagen cuyo cubo de página o número de objeto cambia entre revisiones se informa como un par eliminado-más-añadido, no como modificada.
- Los flujos de objetos comprimidos con filtros distintos de FlateDecode se omiten fail-closed; sus imágenes miembro no se comparan.
- En este módulo no ocurre ninguna operación criptográfica, por lo que no existe ningún comportamiento específico del modo FIPS. El hash de imagen es solo para la detección de cambios y no tiene peso de integridad ni probatorio.
Conformidad
Sección titulada «Conformidad»| Afirmación | Estándar | Cláusula |
|---|---|---|
Los operadores de presentación de texto Tj y TJ se analizan para la extracción | ISO 32000-2:2020 | §9.4 |
Los datos del flujo alternativo comienzan después del CRLF o LF que sigue a la palabra clave stream | ISO 32000-2:2020 | §7.3.8.1 |
Las extensiones de flujo del escaneo de imágenes se rigen por la entrada /Length del diccionario | ISO 32000-2:2020 | §7.3.8.2 |
Los miembros del flujo de objetos se localizan mediante la tabla de pares /N y el desplazamiento /First | ISO 32000-2:2020 | §7.5.7 |
La reversión del predictor PNG sigue el parámetro Predictor de /DecodeParms | ISO 32000-2:2020 | §7.4.4.4 |
| Los valores de metadatos decodifican las formas de cadena literal y hexadecimal | ISO 32000-2:2020 | §7.3.4.2, §7.3.4.3 |
| Salida visual de PDF con marcado de revisión en paralelo | — | No soportado (solo JSON/HTML) |
Todas las cláusulas están parafraseadas; NextPDF no reproduce el texto normativo. Son declaraciones de capacidad, no certificaciones; NextPDF no posee ninguna certificación y no concede ninguna. La recuperación de texto reconstruye el texto de las líneas a partir de los operadores de presentación de texto. No ejecuta la máquina de estados de texto completa de la §9.4, por lo que el diff es a nivel de contenido, no a nivel de geometría.
Notas de desarrollo
Sección titulada «Notas de desarrollo»- Disponibilidad dentro del paquete Pro:
PdfDiffer,DiffEngine,TextExtractory sus objetos de valor desde 1.8.0;StructuredDiffer,DiffFormatter,ImageDiffer,MetadataDiffery los suyos desde 2.2.0. Todos están vigentes ennextpdf/pro3.1.0. - Preferir
PdfDiffer::compareTexts()cuando el texto de página ya está disponible; omite la extracción y sus modos de fallo por completo. - El lector Artisan opcional mejora la precisión de la extracción y la atribución de páginas. Se detecta en tiempo de ejecución y nunca es obligatorio.
- Capturar
OverflowExceptional comparar entradas no confiables; los límites son rechazos fail-closed deliberados, no errores transitorios. DiffFormatter::toHtml()emite nombres de clase (diff-added,diff-removed,diff-modified,diff-unchanged) pero ninguna hoja de estilos; proporcionar el CSS propio.- Construir
StructuredDiffercon diferenciadores de prueba en los tests para aislar la ruta de texto del escaneo de imágenes y metadatos.
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 de la API pública soportada. Las rutas de espacios de nombres internos, las clases auxiliares, las tablas de mecanismos, los nombres de archivo de runbooks y los prefijos de tickets están fuera del alcance.
Véase también
Sección titulada «Véase también»- Diff (capacidad) — instalación, inicio rápido y ejemplos de producción.
- Converter — Referencia detallada
- Filter — Referencia detallada