Eine einfache Java-Bibliothek zum Vergleichen zweier PDF-Dateien. Dateien werden Pixel für Pixel gerendert und verglichen. Es gibt keinen Textvergleich.
Fügen Sie es einfach als Abhängigkeit ein. Bitte überprüfen Sie die aktuellste verfügbare Version:
< dependencies >
< dependency >
< groupId >de.redsix</ groupId >
< artifactId >pdfcompare</ artifactId >
< version >...</ version > <!-- see current version in the maven central tag above -->
</ dependency >
</ dependencies >
Es gibt eine einfache interaktive Benutzeroberfläche, wenn Sie die JAR-Datei ohne zusätzliche Argumente starten (wodurch die Klasse de.redsix.pdfcompare.Main gestartet wird). Es ermöglicht Ihnen, Dateien zum Vergleichen auszuwählen, Bereiche zu markieren, die ignoriert werden sollen, und diese in eine Ignorierdatei zu schreiben.
Neben der Benutzeroberfläche können Sie über eine CLI eine erwartete und tatsächliche Datei sowie zusätzliche Parameter bereitstellen. Um eine Hilfe für die CLI zu erhalten, verwenden Sie die Option -h oder --help-.
usage: java -jar pdfcompare-x.x.x-full.jar [EXPECTED] [ACTUAL]
-h,--help Displays this text and exit
...
Der Fokus von PdfCompare liegt jedoch auf der eingebetteten Nutzung als Bibliothek.
new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
Dadurch wird ein Ausgabe-PDF erstellt, das möglicherweise Markierungen für gefundene Unterschiede enthält. PdfCompare rendert eine Seite aus der erwarteten PDF-Datei und dieselbe Seite aus der tatsächlichen PDF-Datei in ein Bitmap-Bild und vergleicht diese beiden Bilder Pixel für Pixel. Gleiche Pixel werden etwas verblasst. Abweichende Pixel werden rot und grün markiert. Grün für Pixel, die in der erwarteten PDF-Datei vorhanden waren, in der tatsächlichen PDF-Datei jedoch nicht vorhanden sind. Rot für Pixel, die in der tatsächlichen PDF-Datei vorhanden sind, aber nicht in der erwarteten PDF-Datei. Und am Rand des Papiers befinden sich Markierungen in Magenta, um schnell unterschiedliche Stellen zu finden. Ignorierte Bereiche werden mit einem gelben Hintergrund markiert. Seiten, die erwartet, aber nicht geliefert wurden, sind mit einem roten Rand gekennzeichnet. Seiten, die erscheinen, aber nicht erwartet wurden, werden mit einem grünen Rand markiert.
Die Vergleichsmethode gibt ein CompareResult zurück, das abgefragt werden kann:
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
Der Einfachheit halber gibt writeTo auch den Gleichheitsstatus zurück:
boolean isEquals = new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
if (! isEquals ) {
System . out . println ( "Differences found!" );
}
Die Vergleichsmethode kann mit Dateinamen wie Strings, Files, Paths oder InputStreams aufgerufen werden.
Es ist auch möglich, rechteckige Bereiche zu definieren, die beim Vergleich ignoriert werden. Dazu muss eine Datei erstellt werden, die zu ignorierende Bereiche definiert. Das Dateiformat ist JSON (oder eigentlich eine Obermenge namens HOCON) und hat die folgende Form:
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.
}
]
Wenn die bereitgestellte Ausschlussdatei nicht gefunden wird, wird sie ignoriert und der Vergleich wird ohne die Ausschlüsse durchgeführt.
Ausschlüsse werden im Code wie folgt bereitgestellt:
new PdfComparator ( "expected.pdf" , "actual.pdf" ). withIgnore ( "ignore.conf" ). compare ();
Alternativ kann ein Ausschluss über die API wie folgt hinzugefügt werden:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withIgnore ( new PageArea ( 1 , 230 , 350 , 450 , 420 ))
. withIgnore ( new PageArea ( 2 ))
. compare ();
Wenn Sie passwortgeschützte PDF-Dateien vergleichen möchten, können Sie dem Comparator das Passwort über die Methoden withExpectedPassword(String-Passwort) bzw. withActualPassword(String-Passwort) übergeben.
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withExpectedPassword ( "somePwd" )
. withActualPassword ( "anotherPwd" )
. compare ();
PDFCompare kann mit einer Konfigurationsdatei konfiguriert werden. Die Standardkonfigurationsdatei heißt „application.conf“ und muss sich im Stammverzeichnis des Klassenpfads befinden.
PdfCompare verwendet Lightbend Config (früher TypeSafe Config genannt), um seine Konfigurationsdateien zu lesen. Wenn Sie eine andere Konfigurationsdatei angeben möchten, können Sie hier mehr darüber erfahren: https://github.com/lightbend/config#standard-behavior. Insbesondere können Sie eine Ersatzkonfigurationsdatei mit dem Befehlszeilenargument -Dconfig.file=path/to/file angeben.
Alternativ können Sie Parameter entweder über Systemumgebungsvariablen oder als JVM-Parameter mit -DvariableName= angeben
Eine andere Möglichkeit, programmgesteuert einen anderen Konfigurationsspeicherort anzugeben, besteht darin, ein neues ConfigFileEnvironment(...) zu erstellen und es an PdfCompare.withEnvironment(...) zu übergeben.
Alle Einstellungen, die über die Datei application.conf geändert werden können, können auch programmgesteuert über die API geändert werden. Dazu können Sie den folgenden Code verwenden:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withEnvironment ( new SimpleEnvironment ()
. setActualColor ( Color . green )
. setExpectedColor ( Color . blue ))
. compare ();
Die SimpleEnvironment delegiert alle Einstellungen, die nicht zugewiesen wurden, an die Standardumgebung.
Über die Umgebung können Sie die Speichereinstellungen (siehe oben) und die folgenden Einstellungen konfigurieren:
DPI=300
Legt die DPI fest, mit der PDF-Seiten gerendert werden. Der Standardwert ist 300.
erwartete Farbe = 00B400 (GRÜN)
Die erwartete Farbe ist die Farbe, die für erwartete, aber nicht vorhandene Pixel verwendet wird. Die Farben werden im HTML-Stil (ohne führendes „#“) angegeben: Die ersten beiden Zeichen definieren den Rotanteil der Farbe im Hexadezimalformat. Die nächsten beiden Zeichen definieren den Grünanteil der Farbe. Die letzten beiden Zeichen definieren den Blauanteil der zu verwendenden Farbe.
currentColor=D20000 (ROT)
Die tatsächliche Farbe ist die Farbe, die für Pixel verwendet wird, die vorhanden sind, aber nicht erwartet wurden. Die Farben werden im HTML-Stil (ohne führendes „#“) angegeben: Die ersten beiden Zeichen definieren den Rotanteil der Farbe im Hexadezimalformat. Die nächsten beiden Zeichen definieren den Grünanteil der Farbe. Die letzten beiden Zeichen definieren den Blauanteil der zu verwendenden Farbe.
tempDir=System.property("java.io.tmpdir")
Legt das Verzeichnis fest, in das temporäre Dateien geschrieben werden sollen. Standardmäßig wird der Java-Standard für java.io.tmpdir verwendet, der normalerweise einen systemspezifischen Standard bestimmt, wie z. B. /tmp auf den meisten Unix-Systemen.
erlaubtDifferenceInPercentPerPage=0,2
Prozentsatz der Pixel, die pro Seite unterschiedlich sein können. Der Standardwert ist 0. Wenn Ihr Rendering aus irgendeinem Grund etwas abweicht oder Sie eine gewisse Fehlermarge zulassen, können Sie einen Prozentsatz der Pixel konfigurieren, die beim Vergleich ignoriert werden. Auf diese Weise wird ein Unterschied nur dann gemeldet, wenn sich mehr als der angegebene Prozentsatz an Pixeln unterscheiden. Der Prozentsatz wird pro Seite berechnet. Nicht, dass die Unterschiede noch in der Ausgabedatei markiert sind, wenn Sie EqualPagesToResult hinzufügen.
parallelProcessing=true
Bei Festlegung auf „false“ wird die gesamte parallele Verarbeitung deaktiviert und alles in einem einzelnen Thread verarbeitet.
addEqualPagesToResult=true
Bei der Einstellung „false“ werden nur Seiten mit Unterschieden zum Ergebnis hinzugefügt und dies ist das resultierende Differenz-PDF-Dokument.
failOnMissingIgnoreFile=false
Wenn der Wert auf „true“ gesetzt ist, führt eine fehlende Ignorierdatei zu einer Ausnahme. Andernfalls wird es ignoriert und es werden nur Protokollmeldungen auf Infoebene geschrieben.
Es gibt einige verschiedene Implementierungen von CompareResults mit unterschiedlichen Eigenschaften. Damit lassen sich bestimmte Aspekte des Systemverhaltens steuern, insbesondere der Speicherverbrauch.
Es ist gut, einige Interna zu kennen, wenn Sie PdfCompare verwenden. Hier ist kurz zusammengefasst, was PdfCompare macht, wenn es zwei PDFs vergleicht.
PdfCompare verwendet die Apache PdfBox-Bibliothek zum Lesen und Schreiben von PDFs.
Der Vergleich großer PDFs kann daher viel Speicher verbrauchen. Ich habe noch keine Möglichkeit gefunden, die Differenz-PDF-Datei mit PdfBox Seite für Seite inkrementell zu schreiben, aber es gibt einige Problemumgehungen.
Derzeit gibt es zwei verschiedene CompareResults, die unterschiedliche Strategien zum Auslagern von Seiten auf die Festplatte und dadurch zur Begrenzung des Speicherverbrauchs haben.
Eine andere CompareResult-Implementierung kann wie folgt verwendet werden:
new PdfComparator ( "expected.pdf" , "actual.pdf" , new CompareResultWithPageOverflow ()). compare ();
Außerdem gibt es einige interne Einstellungen für Speicherlimits, die geändert werden können. Fügen Sie einfach eine Datei mit dem Namen „application.conf“ zum Stammverzeichnis des Klassenpfads hinzu. Diese Datei kann einige oder alle der folgenden Einstellungen haben, um die hier angegebenen Standardeinstellungen zu überschreiben:
imageCacheSizeCount=30
Wie viele Bilder werden von PdfBox zwischengespeichert?
maxImageSizeInCache=100000
Eine ungefähre maximale Größe der zwischengespeicherten Bilder, um zu verhindern, dass sehr große Bilder zwischengespeichert werden
mergeCacheSizeMB=100
Wenn PDFs teilweise geschrieben und später zusammengeführt werden, ist dies der Speichercache, der für die PdfBox-Instanz konfiguriert wird, die die Zusammenführung durchführt.
swapCacheSizeMB=100
Wenn PDFs teilweise geschrieben werden, ist dies der Speichercache, der für die PdfBox-Instanz konfiguriert wird, die die teilweisen Schreibvorgänge durchführt.
documentCacheSizeMB=200
Dies ist die für die PdfBox-Instanz konfigurierte Cache-Größe, die die verglichenen Dokumente lädt.
parallelProcessing=true
Bei Festlegung auf „false“ wird die gesamte parallele Verarbeitung deaktiviert und alles in einem einzelnen Thread verarbeitet.
OverallTimeoutInMinutes=15
Legen Sie das Gesamt-Timeout fest. Dies ist eine Sicherheitsmaßnahme, um mögliche Deadlocks zu erkennen. Komplexe Vergleiche können länger dauern, daher muss dieser Wert möglicherweise erhöht werden.
executorTimeoutInSeconds=60
Legt den Timeout fest, um auf den Abschluss der Executoren zu warten, nachdem der OverallTimeout erreicht wurde. Es ist unwahrscheinlich, dass Sie dies jemals ändern müssen.
In dieser Standardkonfiguration sollte PdfBox also bis zu 400 MB RAM für seine Caches verwenden, bevor es auf die Festplatte verschoben wird. Ich habe gute Erfahrungen mit der Gewährung von 2 GB Heap-Speicherplatz für die JVM.
Vielen Dank an Chethan Rao [email protected] für die Hilfe bei der Diagnose von Speicherproblemen und die Bereitstellung der Idee für Teilschreibvorgänge und Zusammenführung der generierten PDFs.