一个简单的 Java 库,用于比较两个 PDF 文件。文件逐像素渲染和比较。没有文字比较。
只需将其作为依赖项包含即可。请检查可用的最新版本:
< dependencies >
< dependency >
< groupId >de.redsix</ groupId >
< artifactId >pdfcompare</ artifactId >
< version >...</ version > <!-- see current version in the maven central tag above -->
</ dependency >
</ dependencies >
当您启动不带任何其他参数的 jar 文件(启动类 de.redsix.pdfcompare.Main)时,有一个简单的交互式 UI。它允许您选择要比较的文件,还可以标记要忽略的区域并将其写入忽略文件。
在 UI 旁边,您可以通过 CLI 提供预期的和实际的文件以及附加参数。要获取 CLI 帮助,请使用 -h 或 --help 选项-。
usage: java -jar pdfcompare-x.x.x-full.jar [EXPECTED] [ACTUAL]
-h,--help Displays this text and exit
...
但 PdfCompare 的重点是作为库的嵌入式使用。
new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
这将生成一个输出 PDF,其中可能包含所发现差异的标记。 PdfCompare 将预期 .pdf 中的页面和实际 .pdf 中的同一页面渲染为位图图像,并逐像素比较这两个图像。相等的像素会稍微褪色。不同的像素用红色和绿色标记。绿色表示出现在预期 .pdf 中但不出现在实际 .pdf 中的像素。红色表示实际 .pdf 中存在但预期 .pdf 中不存在的像素。纸张边缘有洋红色标记,可以快速找到不同的区域。被忽略的区域用黄色背景标记。预期但未出现的页面标有红色边框。出现但未预期出现的页面标有绿色边框。
比较方法返回一个CompareResult,可以查询:
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
为了方便起见,writeTo 还返回 equals 状态:
boolean isEquals = new PdfComparator ( "expected.pdf" , "actual.pdf" ). compare (). writeTo ( "diffOutput" );
if (! isEquals ) {
System . out . println ( "Differences found!" );
}
可以使用字符串、文件、路径或输入流等文件名来调用比较方法。
还可以定义在比较过程中忽略的矩形区域。为此,需要创建一个文件,其中定义要忽略的区域。文件格式为 JSON(或者实际上是称为 HOCON 的超集),并具有以下形式:
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.
}
]
如果未找到提供的排除文件,则会忽略该文件并在不排除排除的情况下进行比较。
代码中提供的排除如下:
new PdfComparator ( "expected.pdf" , "actual.pdf" ). withIgnore ( "ignore.conf" ). compare ();
或者,可以通过 API 添加排除项,如下所示:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withIgnore ( new PageArea ( 1 , 230 , 350 , 450 , 420 ))
. withIgnore ( new PageArea ( 2 ))
. compare ();
当您想要比较受密码保护的 PDF 文件时,您可以分别通过 withExpectedPassword(String password) 或 withActualPassword(String password) 方法将密码提供给比较器。
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withExpectedPassword ( "somePwd" )
. withActualPassword ( "anotherPwd" )
. compare ();
PdfCompare 可以使用配置文件进行配置。默认配置文件称为“application.conf”,它必须位于类路径的根目录中。
PdfCompare 使用 Lightbend Config(以前称为 TypeSafe Config)来读取其配置文件。如果您想指定另一个配置文件,可以在此处了解更多信息:https://github.com/lightbend/config#standard-behavior。特别是,您可以使用 -Dconfig.file=path/to/file 命令行参数指定替换配置文件。
或者,您可以通过系统环境变量或使用 -DvariableName= 作为 Jvm 参数来指定参数
以编程方式指定不同配置位置的另一种方法是创建一个新的 ConfigFileEnvironment(...) 并将其传递给 PdfCompare.withEnvironment(...)。
所有可以通过 application.conf 文件更改的设置也可以通过 API 以编程方式更改。为此,您可以使用以下代码:
new PdfComparator ( "expected.pdf" , "actual.pdf" )
. withEnvironment ( new SimpleEnvironment ()
. setActualColor ( Color . green )
. setExpectedColor ( Color . blue ))
. compare ();
SimpleEnvironment 将所有未分配的设置委托给默认环境。
通过环境您可以配置内存设置(见上文)和以下设置:
分辨率=300
设置呈现 Pdf 页面的 DPI。默认值为 300。
预期颜色=00B400(绿色)
预期颜色是用于预期但不存在的像素的颜色。颜色以 HTML-Stlye 格式指定(不带前导“#”):前两个字符以十六进制定义颜色的红色部分。接下来的两个字符定义颜色的绿色部分。最后两个字符定义要使用的颜色的蓝色部分。
实际颜色=D20000(红色)
实际颜色是用于存在但不是预期的像素的颜色。颜色以 HTML-Stlye 格式指定(不带前导“#”):前两个字符以十六进制定义颜色的红色部分。接下来的两个字符定义颜色的绿色部分。最后两个字符定义要使用的颜色的蓝色部分。
tempDir=System.property("java.io.tmpdir")
设置写入临时文件的目录。默认为 java.io.tmpdir 的 java 默认值,它通常确定系统特定的默认值,例如大多数 UNIX 系统上的 /tmp。
allowedDifferenceInPercentPerPage=0.2
每页可能不同的像素百分比。默认值为 0。如果由于某种原因您的渲染有点偏离或者您允许一定的误差范围,您可以配置在比较期间忽略的像素百分比。这样,只有当超过给定百分比的像素差异时,才会报告差异。百分比按每页计算。当您 addEqualPagesToResult 时,差异仍然会标记在输出文件中。
并行处理=true
当设置为 false 时,禁用所有并行处理并在单个线程中处理所有内容。
addEqualPagesToResult=true
当设置为 false 时,仅将有差异的页面添加到结果中,这就是生成的差异 PDF 文档。
failOnMissingIgnoreFile=false
当设置为 true 时,丢失的忽略文件会导致异常。否则它会被忽略,并且只写入信息级别的日志消息。
CompareResults 有几种不同的实现,具有不同的特征。可用于控制系统行为的某些方面,特别是内存消耗。
使用 PdfCompare 时,了解一些内部原理是有好处的。简而言之,PdfCompare 在比较两个 PDF 时会做什么。
PdfCompare 使用 Apache PdfBox 库来读取和写入 Pdf。
因此比较大的 Pdf 会占用大量内存。我还没有找到一种方法来使用 PdfBox 逐页增量地编写差异 Pdf,但有一些解决方法。
当前有两种不同的 CompareResults,它们具有不同的将页面交换到磁盘的策略,从而限制内存消耗。
可以使用不同的 CompareResult 实现,如下所示:
new PdfComparator ( "expected.pdf" , "actual.pdf" , new CompareResultWithPageOverflow ()). compare ();
还有一些内存限制的内部设置可以更改。只需将名为“application.conf”的文件添加到类路径的根目录即可。该文件可以具有以下部分或全部设置来覆盖此处给出的默认设置:
图像缓存大小计数=30
PdfBox 缓存了多少图像
maxImageSizeInCache=100000
缓存图像的粗略最大大小,以防止缓存非常大的图像
合并缓存大小MB=100
当 Pdf 部分写入并稍后合并时,这是为执行合并的 PdfBox 实例配置的内存缓存。
交换缓存大小MB=100
当 Pdf 被部分写入时,这是为执行部分写入的 PdfBox 实例配置的内存缓存。
文档缓存大小MB=200
这是为 PdfBox 实例配置的缓存大小,用于加载比较的文档。
并行处理=true
当设置为 false 时,禁用所有并行处理并在单个线程中处理所有内容。
总体超时时间=15
设置总超时时间。这是检测可能的死锁的安全措施。复杂的比较可能需要更长的时间,因此可能需要增加该值。
执行者超时时间=60
设置达到总体超时后等待执行程序完成的超时。您不太可能需要更改此设置。
因此,在此默认配置中,PdfBox 在交换到磁盘之前应使用最多 400MB 的 RAM 作为缓存。我在向 JVM 授予 2GB 堆空间方面拥有丰富的经验。
非常感谢 Chethan Rao [email protected] 帮助我诊断内存不足问题并提供部分写入和合并生成的 PDF 的想法。