我正在寻找一款Linux命令行工具,用于比较两个PDF文件并将差异保存到PDF输出文件中。该工具应该能够批处理创建diff-pdf。由于PDF文件是建筑设计图纸,因此纯文本比较无法完成。
类似这样的:
<tool> file1.pdf file2.pdf -o diff-out.pdf
我发现大部分工具都将PDF转换为图像并在GUI中进行比较。
其他任何解决方案也欢迎。
我正在寻找一款Linux命令行工具,用于比较两个PDF文件并将差异保存到PDF输出文件中。该工具应该能够批处理创建diff-pdf。由于PDF文件是建筑设计图纸,因此纯文本比较无法完成。
类似这样的:
<tool> file1.pdf file2.pdf -o diff-out.pdf
我发现大部分工具都将PDF转换为图像并在GUI中进行比较。
其他任何解决方案也欢迎。
compare
命令pdftk
实用程序(如果您有多页 PDF)md5sum
(可选).bat
批处理文件中。pdftk file_1.pdf burst output somewhere/file_1---page_%03d.pdf
pdftk file_2.pdf burst output somewhere/file_2---page_%03d.pdf
如果你只比较单页PDF,那么这个构建块是可选的。考虑到你谈论的是“施工计划”,很可能是这种情况。
使用来自ImageMagick的命令行实用程序创建每个页面的“diff” PDF 页面:
compare \
-verbose \
-debug coder \
-log "%u %m:%l %e" \
somewhere/file_1---page_001.pdf \
somewhere/file_2---page_001.pdf \
-compose src \
somewhereelse/file_1--file_2---diff_page_001.pdf
由于自动插入的元数据(例如当前日期+时间等),PDF输出在基于MD5哈希的文件比较中效果不佳。
如果您想要自动发现所有差异PDF仅由纯白页组成的情况,您应该使用输出设备将PDF页面转换为无元数据的位图格式。您可以像这样执行:
首先,找出您的PDF的页面大小格式。同样,这个小工具identify
作为任何ImageMagick安装的一部分提供:
identify \
-format "%[fx:(w)]x%[fx:(h)]" \
somewhereelse/file_1--file_2---diff_page_001.pdf
您可以像这样将此值存储在环境变量中:
export my_size=$(identify \
-format "%[fx:(w)]x%[fx:(h)]" \
somewhereelse/file_1--file_2---diff_page_001.pdf)
现在Ghostscript登场,使用包含上述发现的页面大小变量的命令行:
gs \
-o somewhereelse/file_1--file_2---diff_page_001.ppm \
-sDEVICE=ppmraw \
-r72 \
-g${my_size} \
somewhereelse/file_1--file_2---diff_page_001.pdf
这将为您提供一个分辨率为72 dpi的PPM(Portable PixMap),其基于原始PDF页面生成。72 dpi通常足够满足我们的需求...接下来,创建一个纯白色的PPM页面,其大小与原始页面相同:
gs \
-o somewhereelse/file_1--file_2---whitepage_001.ppm \
-sDEVICE=ppmraw \
-r72 \
-g${my_size} \
-c "showpage"
-c "showpage"
是一个PostScript命令,它告诉Ghostscript仅发出一个空白页面。
使用MD5哈希来自动比较原始PPM和白页PPM。如果它们相同,您可以安全地假定PDF之间没有差异,因此可以重命名或删除diff-PDF:
MD5_1=$(md5sum somewhereelse/file_1--file_2---diff_page_001.ppm | awk '{print $1}')
MD5_2=$(md5sum somewhereelse/file_1--file_2---whitepage_001.ppm | awk '{print $1}')
if [ "x${MD5_1}" == "x${MD5_2}" ]; then
mv \
somewhereelse/file_1--file_2---diff_page_001.pdf \
somewhereelse/file_1--file_2---NODIFFERENCE_page_001.pdf # rename all-white PDF
rm \
somewhereelse/file_1--file_2---*_page_001.ppm # delete both PPMs
fi
这样可以避免您需要视觉检查那些没有任何差异的“diff PDF”。
convert file.pdf -format %c histogram:info: | grep -Ev '^$|255,255,255,' > /dev/null
如果页面上除了白色以外还有其他颜色,则会返回 0
。您也可以使用订阅直接使用 compare
比较 PDF 页面:compare file1.pdf[42] file2.pdf[42] -compose src output.png
。现在全部在一起:如果这些 PDF 中的第 i 页不同,则 compare "$src[$i]" "$dst[$i]" -compose src -format %c histogram:info: | grep -Ev '^$|255,255,255,' > /dev/null
将给您成功。 - Yorik.sar255,255,255
或 65535,65535,65535
取决于您安装的ImageMagick/compare版本。运行 compare -version
并检查返回的版本字符串中是否有 Q8
或 Q16
。 Q16适用于ImageMagick进行每个颜色分量每像素16位处理,而Q8适用于每个像素8位处理... - Kurt Pfeifle这里有一个技巧可以实现。
pdftotext file1.pdf
pdftotext file2.pdf
diff file1.txt file2.txt
vimdiff <(pdftotext /path/to/pdf-file-1 -) <(pdftotext /path/to/pdf-file-2 -)
- joker使用(万能的)ImageMagick和pdftk仅需2行即可完成:
compare -verbose -debug coder $PDF_1 $PDF_2 -compose src $OUT_FILE.tmp
pdftk $OUT_FILE.tmp background $PDF_1 output $OUT_FILE
-verbose和-debug选项是可选的。
compare
直接应用于PDF文件的答案对我不起作用。似乎这个命令不再正确处理PDF文件了。compare
确实有效。ComparePdfs.sh
和ComparePdfs2.sh
,可在命令行上执行。这两个脚本列在本答案的末尾。如何判断两个(PDF或其他格式的)文件内容是否完全相同
我所知道的另一种比较方法是让我们知道两个PDF文件的内容是否在每个方面都是完全相同的,包括各种嵌入式元数据(如创建日期、文档标题(与第一页显示的任何标题无关)、用于创建PDF的程序等)。
这是检查任何两个文件(PDF或其他类型)是否按位完全相同的相同方法。
要做到这一点,您只需计算并比较两个文件的校验和。我也包含了一个名为AreIdentical.sh
的脚本,在本问题的最后列出。以下是如何使用它。
AreIdentical.sh my_first_PDF_file.pdf another_PDF_file.pdf
ls -l
返回的创建日期(而不是PDF嵌入式元数据中的日期)也不会在计算校验和时被考虑在内,原因相同。
如何使用脚本ComparePdfs.sh
和ComparePdfs2.sh
我们假设要(纯粹地视觉上)比较的两个PDF文件file1.pdf和file2.pdf位于工作目录中。ComparePdfs2.sh file1.pdf file2.pdf dif_in_files.pdf
我选择了一个特定的名称dif_in_files.pdf
作为输出文件名。执行过程需要一些时间,因为对于每个输入PDF文件,必须将每个单独的页面转换为PNG格式。当前处理的页面会在终端上打印出来。最后,在工作目录中,脚本将生成包含所有差异页面的文件dif_in_files.pdf
,任何差异都会用红色突出显示。
如果我们只对查看不同的页面感兴趣,或者只对是否有差异感兴趣,那么我们使用ComparePdfs.sh
。
在命令行中,我们执行:
ComparePdfs.sh file1.pdf file2.pdf
page_001: same
page_002: same
page_003: different
page_004: same
对于那些不同的页面,仅针对这些页面,脚本将创建突出显示差异之处的文件。在上面的示例中,脚本将生成一个名为difference_page_003.png
的文件。
ComparePdfs.sh
的工作原理
对于两个pdf文件中的每一个,我们使用pdftk将其拆分为单个页面,然后将每个页面转换为PNG格式。现在考虑两个文件的第一页的PNG文件。我们为每个文件创建检验和(我选择使用b2sum
完成此操作)。
如果检验和相同,则认为两个文件的第一页相同。
如果检验和不同,则认为两个文件的第一页不同,并使用compare
为它们生成一个差异PNG文件。
我们对每个页面都重复此过程。最后,我们删除所有单个页面的.pdf和.png文件,除了差异文件以外。
脚本
这是ComparePdfs2.sh
。
#!/bin/bash
file_1="$1"
file_2="$2"
outfile="$3"
# here we set the DPI resolution for the pdftoppm command, which will convert PDF to PNG
resolution=150
# bursting the files into individual pages
pdftk $file_1 burst output ${file_1%.*}---page_%03d.pdf
pdftk $file_2 burst output ${file_2%.*}---page_%03d.pdf
# this will be a string variable in which we collect that names of .png files to be converted to a single .pdf file
DiffFiles=""
# we loop over the individual pages of the first file
for f1 in `echo ${file_1%.*}---`*.pdf
do
# f2 is the name of the PDF of the corresponding page of the second file
f2="${f1/${file_1%.*}/${file_2%.*}}"
# 'b' is an auxilliary varable used to create the variable 'page'
b="${f1/${file_1%.*}---/""}"
# 'page' hold the current page number, e.g. 'page_003'
page="${b/.pdf/}"
# print the current page being processed
echo -n "$page "
# convert the individual page PDFs to PNGs
pdftoppm "$f1" "${f1%.*}" -png -r $resolution
pdftoppm "$f2" "${f2%.*}" -png -r $resolution
# 'g1' and 'g2' are the names of the two PNG files we just created
g1=${f1%.*}-1.png
g2=${f2%.*}-1.png
# create the difference file for this page
compare "$g1" "$g2" ${outfile%.*}_"$page".png
# add the latest name of the difference .png file to the DiffFiles variable
DiffFiles=$DiffFiles""${outfile%.*}_"$page".png" "
done
echo
# convert the .png difference files to a single .pdf file
convert $DiffFiles $outfile
# clean up
rm -f `echo ${file_1%.*}---page_`* `echo ${file_2%.*}---page_`* `echo ${outfile%.*}_page_`* doc_data.txt
ComparePdfs.sh
。#!/bin/bash
file_1="$1"
file_2="$2"
# here we set the DPI resolution for the pdftoppm command, which will convert PDF to PNG
resolution=150
# bursting the files into individual pages
pdftk $file_1 burst output ${file_1%.*}---page_%03d.pdf
pdftk $file_2 burst output ${file_2%.*}---page_%03d.pdf
# we loop over the individual pages of the first file
for f1 in `echo ${file_1%.*}---`*.pdf
do
# f2 is the name of the PDF of the corresponding page of the second file
f2="${f1/${file_1%.*}/${file_2%.*}}"
# 'b' is an auxilliary varable used to create the variable 'page'
b="${f1/${file_1%.*}---/""}"
# 'page' hold the current page number, e.g. 'page_003'
page="${b/.pdf/}"
# convert the individual page PDFs to PNGs
pdftoppm "$f1" "${f1%.*}" -png -r $resolution
pdftoppm "$f2" "${f2%.*}" -png -r $resolution
# 'g1' and 'g2' are the names of the two PNG files we just created
g1=${f1%.*}-1.png
g2=${f2%.*}-1.png
# create the checksums for the two PNG files
B2S_1=$(b2sum "$g1" | awk '{print $1}')
B2S_2=$(b2sum "$g2" | awk '{print $1}')
# now we compare the checksums
if [ "$B2S_1" = "$B2S_2" ]; then
echo "$page: same";
else
echo "$page: different";
# if the checksums are different, create a difference PNG image
compare "$g1" "$g2" difference_"$page".png
fi
done
# clean up
rm -f `echo ${file_1%.*}---page_`* `echo ${file_2%.*}---page_`* doc_data.txt
最后,这是AreIdentical.sh
:
#!/bin/bash
file_1="$1"
file_2="$2"
B2S_1=$(b2sum $file_1 | awk '{print $1}')
B2S_2=$(b2sum $file_2 | awk '{print $1}')
if [ "$B2S_1" = "$B2S_2" ]; then echo "same"; else echo "different"; fi
这里有一个完成的脚本,名为“cmppdf”,基于linguisticturn的代码,增加了对比PDF中文本的支持和一些优化:
https://abhweb.org/jima/cmppdf
文档:
NAME
cmppdf -- Compare the visual appearance or text of PDF files
SYNOPSIS
cmppdf [-o BASEPATH] [-q] [-d] FILE1 FILE2
cmppdf --text [-o BASEPATH] [-q] [-d] FILE1 FILE2
EXIT STATUS
0 if no differences found
1 if differences found
2+ if trouble
OPTIONS
-t, --text Compare the text in the PDFs, ignoring grapical appearance.
-o, --output BASEPATH
With this option a "difference file" named BASEPATH_page_NNN.png
or .txt is created for each page which has differences.
With visual comparison (the default), the files will be .png images with
changed parts highlighted in RED. With text comparison (--text option),
the files will contain output from the 'diff' command, or if BASEPATH
is '-' then all diffs are written to stdout.
--diff diff-option1,diff-option2, ...
Specify options to pass to the 'diff' command, separated by commas.
The default is '-u'. --text is implied by --diff.
-q, --quiet Suppress all progress messages
-d, --debug Show detailed information about commands run