Una biblioteca Java sencilla para comparar dos archivos PDF. Los archivos se procesan y comparan píxel por píxel. No hay comparación de texto.
Simplemente inclúyalo como una dependencia. Por favor verifique la versión más reciente disponible:
< dependencies >
< dependency >
< groupId >de.redsix</ groupId >
< artifactId >pdfcompare</ artifactId >
< version >...</ version > <!-- see current version in the maven central tag above -->
</ dependency >
</ dependencies >
Hay una interfaz de usuario interactiva simple, cuando inicia el archivo jar sin ningún argumento adicional (que inicia la clase de.redsix.pdfcompare.Main). Le permite elegir archivos para comparar y también marcar áreas para ignorar y escribirlas en un archivo ignorado.
Junto a la interfaz de usuario, puede proporcionar un archivo real y esperado y un parámetro adicional a través de una CLI. Para obtener ayuda para la CLI, utilice la opción -h o --help-.
usage: java -jar pdfcompare-x.x.x-full.jar [EXPECTED] [ACTUAL]
-h,--help Displays this text and exit
...
Pero el objetivo de PdfCompare está en el uso integrado como biblioteca.
new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
Esto producirá un PDF de salida que puede incluir marcas para las diferencias encontradas. PdfCompare representa una página del archivo esperado.pdf y la misma página del archivo actual.pdf en una imagen de mapa de bits y compara estas dos imágenes píxel por píxel. Los píxeles iguales aparecen un poco descoloridos. Los píxeles que difieren están marcados en rojo y verde. Verde para píxeles que estaban en el.pdf esperado, pero que no están presentes en el.pdf real. Rojo para los píxeles que están presentes en el.pdf actual, pero que no estaban en el.pdf esperado. Y hay marcas en el borde del papel en magenta para encontrar áreas que difieren rápidamente. Las áreas ignoradas están marcadas con un fondo amarillo. Las páginas que se esperaban pero que no llegaron están marcadas con un borde rojo. Las páginas que aparecen, pero que no se esperaban, están marcadas con un borde verde.
El método de comparación devuelve un CompareResult, que se puede consultar:
final CompareResult result = new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare ();
if ( result . isNotEqual ()) {
System . out . println ( "Differences found!" );
}
if ( result . isEqual ()) {
System . out . println ( "No Differences found!" );
}
if ( result . hasDifferenceInExclusion ()) {
System . out . println ( "Differences in excluded areas found!" );
}
result . getDifferences (); // returns page areas, where differences were found
Por conveniencia, writeTo también devuelve el estado igual:
boolean isEquals = new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
if (! isEquals ) {
System . out . println ( "Differences found!" );
}
El método de comparación se puede llamar con nombres de archivos como cadenas, archivos, rutas o flujos de entrada.
También es posible definir áreas rectangulares que se ignoran durante la comparación. Para eso, es necesario crear un archivo que defina las áreas a ignorar. El formato del archivo es JSON (o en realidad un superconjunto llamado HOCON) y tiene la siguiente forma:
exclusions: [
{
page : 2
x1 : 300 // entries without a unit are in pixels. Pdfs are rendered by default at 300DPI
y1 : 1000
x2 : 550
y2 : 1300
} ,
{
// page is optional. When not given, the exclusion applies to all pages.
x1 : 130.5 mm // entries can also be given in units of cm, mm or pt (DTP-Point defined as 1/72 Inches)
y1 : 3.3 cm
x2 : 190 mm
y2 : 3.7 cm
} ,
{
page : 7
// coordinates are optional. When not given, the whole page is excluded.
}
]
Cuando no se encuentra el archivo de exclusión proporcionado, se ignora y la comparación se realiza sin las exclusiones.
Las exclusiones se proporcionan en el código de la siguiente manera:
new PdfComparator ( "expected.pdf" , "actual.pdf" ). withIgnore ( "ignore.conf" ). compare ();
Alternativamente, se puede agregar una exclusión a través de la API de la siguiente manera:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withIgnore ( new PageArea ( 1 , 230 , 350 , 450 , 420 ))
. withIgnore ( new PageArea ( 2 ))
. compare ();
Cuando desee comparar archivos PDF protegidos con contraseña, puede proporcionar la contraseña al Comparador mediante los métodos withExpectedPassword (contraseña de cadena) o withActualPassword (contraseña de cadena) respectivamente.
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withExpectedPassword ( "somePwd" )
. withActualPassword ( "anotherPwd" )
. compare ();
PdfCompare se puede configurar con un archivo de configuración. El archivo de configuración predeterminado se llama "application.conf" y debe estar ubicado en la raíz del classpath.
PdfCompare utiliza Lightbend Config (anteriormente llamado TypeSafe Config) para leer sus archivos de configuración. Si desea especificar otro archivo de configuración, puede obtener más información al respecto aquí: https://github.com/lightbend/config#standard-behavior. En particular, puede especificar un archivo de configuración de reemplazo con el argumento de línea de comando -Dconfig.file=ruta/al/archivo.
Alternativamente, puede especificar parámetros a través de variables de entorno del sistema o como un parámetro Jvm con -DvariableName=
Otra forma de especificar una ubicación de configuración diferente mediante programación es crear un nuevo ConfigFileEnvironment(...) y pasarlo a PdfCompare.withEnvironment(...).
Todas las configuraciones que se pueden cambiar a través del archivo application.conf también se pueden cambiar mediante programación a través de la API. Para hacerlo puedes utilizar el siguiente código:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withEnvironment ( new SimpleEnvironment ()
. setActualColor ( Color . green )
. setExpectedColor ( Color . blue ))
. compare ();
SimpleEnvironment delega todas las configuraciones que no fueron asignadas al entorno predeterminado.
A través del entorno puede configurar los ajustes de la memoria (ver arriba) y los siguientes ajustes:
ppp=300
Establece el DPI con el que se procesan las páginas PDF. El valor predeterminado es 300.
Color esperado = 00B400 (VERDE)
El color esperado es el color que se utiliza para los píxeles que se esperaban, pero que no están ahí. Los colores se especifican en formato HTML-Stlye (sin un '#' inicial): Los dos primeros caracteres definen la parte roja del color en hexadecimal. Los dos caracteres siguientes definen la parte verde del color. Los dos últimos caracteres definen la parte azul del color a utilizar.
Color actual=D20000 (ROJO)
El color real es el color que se utiliza para los píxeles que están ahí, pero que no se esperaban. Los colores se especifican en formato HTML-Stlye (sin un '#' inicial): Los dos primeros caracteres definen la parte roja del color en hexadecimal. Los dos caracteres siguientes definen la parte verde del color. Los dos últimos caracteres definen la parte azul del color a utilizar.
tempDir=System.property("java.io.tmpdir")
Establece el directorio donde escribir archivos temporales. El valor predeterminado es el valor predeterminado de Java para java.io.tmpdir, que generalmente determina un valor predeterminado específico del sistema, como /tmp en la mayoría de los sistemas Unix.
Diferencia permitida en porcentaje por página = 0,2
Porcentaje de píxeles que pueden diferir por página. El valor predeterminado es 0. Si por alguna razón su renderizado está un poco fuera de lugar o permite algún margen de error, puede configurar un porcentaje de píxeles que se ignoran durante la comparación. De esta manera, solo se informa una diferencia cuando difieren más del porcentaje de píxeles indicado. El porcentaje se calcula por página. No es que las diferencias todavía estén marcadas en el archivo de salida, cuando agrega EqualPagesToResult.
procesamiento paralelo = verdadero
Cuando se establece en falso, deshabilita todo el procesamiento paralelo y procesa todo en un solo subproceso.
addEqualPagesToResult=verdadero
Cuando se establece en falso, solo se agregan al resultado las páginas con diferencias y este es el documento PDF de diferencias resultante.
failOnMissingIgnoreFile=falso
Cuando se establece en verdadero, un archivo ignorado que falta genera una excepción. De lo contrario, se ignora y solo se escriben mensajes de registro de nivel de información.
Existen algunas implementaciones diferentes de CompareResults con diferentes características. Se puede utilizar para controlar ciertos aspectos del comportamiento del sistema, en particular el consumo de memoria.
Es bueno conocer algunos aspectos internos al utilizar PdfCompare. Esto es, en pocas palabras, lo que hace PdfCompare cuando compara dos archivos PDF.
PdfCompare utiliza la biblioteca Apache PdfBox para leer y escribir archivos PDF.
Por lo tanto, comparar archivos PDF de gran tamaño puede consumir mucha memoria. Todavía no encontré una manera de escribir la diferencia Pdf página por página de forma incremental con PdfBox, pero existen algunas soluciones.
Actualmente existen dos CompareResults diferentes, que tienen diferentes estrategias para intercambiar páginas en el disco y, por lo tanto, limitar el consumo de memoria.
Se puede utilizar una implementación CompareResult diferente de la siguiente manera:
new PdfComparator ( "expected.pdf" , "actual.pdf" , new CompareResultWithPageOverflow ()). compare ();
También hay algunas configuraciones internas para los límites de memoria que se pueden cambiar. Simplemente agregue un archivo llamado "application.conf" a la raíz del classpath. Este archivo puede tener algunas o todas las siguientes configuraciones para sobrescribir los valores predeterminados aquí:
imageCacheSizeCount=30
¿Cuántas imágenes almacena en caché PdfBox?
maxImageSizeInCache=100000
Un tamaño máximo aproximado de las imágenes que se almacenan en caché, para evitar que se almacenen en caché imágenes muy grandes.
fusionarCacheSizeMB=100
Cuando los archivos PDF se escriben parcialmente y luego se fusionan, esta es la memoria caché configurada para la instancia de PdfBox que realiza la fusión.
swapCacheSizeMB=100
Cuando los archivos PDF se escriben parcialmente, esta es la memoria caché que está configurada para la instancia de PdfBox que realiza las escrituras parciales.
documentoCacheSizeMB=200
Este es el tamaño de caché configurado para la instancia de PdfBox, que carga los documentos que se comparan.
procesamiento paralelo = verdadero
Cuando se establece en falso, deshabilita todo el procesamiento paralelo y procesa todo en un solo subproceso.
tiempo de espera general en minutos = 15
Establezca el tiempo de espera general. Esta es una medida de seguridad para detectar posibles interbloqueos. Las comparaciones complejas pueden llevar más tiempo, por lo que es posible que sea necesario aumentar este valor.
ejecutorTimeoutInSeconds=60
Establece el tiempo de espera para esperar a que los ejecutores finalicen después de que se alcance el tiempo de espera general. Es poco probable que alguna vez necesites cambiar esto.
Entonces, en esta configuración predeterminada, PdfBox debería usar hasta 400 MB de RAM para sus cachés, antes de cambiar al disco. Tengo buena experiencia otorgando un espacio de almacenamiento dinámico de 2 GB a la JVM.
Muchas gracias a Chethan Rao [email protected] por ayudarme a diagnosticar problemas de falta de memoria y brindarme la idea de escrituras parciales y fusión de los archivos PDF generados.