Linux命令行上的PDF比较[已关闭]

sqserrrh  于 2023-03-17  发布在  Linux
关注(0)|答案(5)|浏览(153)

**已关闭。**此问题正在寻求有关书籍、工具、软件库等的建议。它不符合Stack Overflow guidelines。当前不接受答案。

我们不允许问题寻求有关书籍、工具、软件库等的推荐。你可以编辑问题,以便可以使用事实和引用来回答问题。
3天前关闭。
社区在3天前审查了是否重新讨论此问题,并将其关闭:
原始关闭原因未解决
Improve this question
我正在寻找一个Linux命令行工具来比较两个PDF文件,并将差异保存到PDF输出文件。该工具应创建差异PDF的批处理过程。PDF文件是施工图,所以纯文本比较不工作。
比如:

<tool> file1.pdf file2.pdf -o diff-out.pdf

我找到的大多数工具都会将PDF转换为图像并进行比较,但只使用GUI。
任何其他解决办法也是受欢迎的。

mrwjdhj3

mrwjdhj31#

我自己写了一个脚本,它做的事情和你要求的差不多。这个脚本使用了4个工具来实现它的目标:

  1. ImageMagick的compare命令
  2. pdftk实用程序(如果您有多页PDF)
  3. Ghostscript(可选)
  4. md5sum(可选)
    将其移植到DOS/Windows的.bat批处理文件中应该非常容易。

**但首先,请注意:**这只适用于页面/介质大小相同的PDF。比较是在两个输入PDF之间逐像素进行的。结果文件是一个显示“差异”的图像,如下所示:

  • 每个保持不变的像素变为白色。
  • 每个被更改的像素都被涂成红色。

该差异图像被保存为新的PDF,以便在不同的操作系统平台上更好地访问。
例如,当PDF处理中的字体替换开始起作用时,我使用这个方法来发现最小的页面显示差异。
可能会发生这样的情况,即您的PDF之间没有可见的差异,尽管它们在MD5哈希和/或文件大小方面不同。在这种情况下,“diff”输出PDF页面将变为全白。您可以自动发现这种情况,因此您只需通过自动删除全白的PDF来直观地检查非白色PDF。
以下是构建模块:

pdf文件

使用此命令行实用程序将多页PDF文件拆分为多个单页PDF:

pdftk  file_1.pdf  burst  output  somewhere/file_1---page_%03d.pdf
pdftk  file_2.pdf  burst  output  somewhere/file_2---page_%03d.pdf

如果你只比较1页的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

代笔

由于自动插入的 meta数据(如当前日期+时间),PDF输出不能很好地用于基于MD5散列的文件比较。
如果你想自动发现所有的差异PDF包含纯白色页面的情况,你应该使用bmp256输出设备将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

这会从原始PDF页面生成一个分辨率为72 dpi的PPM(便携式像素Map)。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总和

使用MD5散列自动比较原始PPM和白页PPM。如果它们相同,您可以假定PDF之间没有差异,因此重命名或删除差异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”。

kupeojn6

kupeojn62#

这里有一个黑客做这件事。

pdftotext file1.pdf
pdftotext file2.pdf
diff file1.txt file2.txt
zzwlnbp8

zzwlnbp83#

用imagemagick和pdftk(全能版)完成了两行:

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,其中的差异显示为红色像素。
  • pdftk将差分pdf与背景PDF_1合并
axr492tv

axr492tv4#

2022年,基于将compare直接应用到PDF文件的答案对我来说不起作用,似乎这个命令不再能正确处理PDF。
但是,compare在应用于PNG文件时确实有效。
我从前面的答案中提取了一些片段来编写一个不同的脚本。事实上,这是两个不同的脚本,做的事情略有不同:ComparePdfs.shComparePdfs2.sh,将在命令行上执行。这两个脚本都列在此答案的末尾。

一些警告

这两个脚本 * 逐页 * 比较两个PDF文件,每对页面都是纯视觉比较(因为页面被转换为PNG)。所以脚本只对平面文本和平面图形敏感。如果两个PDF文件之间的唯一区别涉及一些其他类型的PDF内容-例如逻辑结构元素、注解、表单域、层、视频,3D对象(U3D或PRC)等-两个脚本仍将报告两个PDF相同。
我还没有试图比较PDF文件具体至于一些这种'额外'的内容。

如何判断两个文件(PDF或非PDF)是否具有 * 完全 * 相同的内容

我知道的唯一一种比较是让我们知道两个PDF文件的内容是否在各个方面都完全相同,包括various embedded metadata,如创建日期、文档标题(与第一页显示的任何标题无关)、用于创建PDF的程序等等。
这是相同的方法,可以用来检查 * 任何 * 两个文件(PDF或不)是逐位相同。
要做到这一点,你所要做的就是计算和比较两个文件的校验和。我还包括一个脚本,称为AreIdentical.sh。它列在这个问题的最后。下面是如何使用它。
假设这两个文件分别命名为“my_first_PDF_file.pdf”和“another_PDF_file.pdf”。那么,在命令行上执行以下命令后,输出文本将显示“same”或“different”,具体取决于这两个文件是相同还是不同。

AreIdentical.sh my_first_PDF_file.pdf another_PDF_file.pdf

请注意,在计算校验和时,不会考虑文件的 name 等信息。原因是文件名不是存储在文件本身中,而是存储在文件的目录项中。因此,即使两个文件的文件名不同,也可能会发现它们是相同的;类似地,由于同样的原因,在计算校验和时也不考虑ls -l返回的创建日期(与PDF嵌入元数据中的日期相反)。

如何使用脚本ComparePdfs.shComparePdfs2.sh

我们假设要比较的两个pdf文件file1.pdf和file2.pdf位于工作目录中。
作为示例,假设它们都具有4页,并且除了页3之外所有页都相同。

完全按照行动计划行事

在命令行中,我们执行

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
v7pvogib

v7pvogib5#

下面是一个完成的脚本“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

@语言学转:请联系我在脚本中给出的电子邮件,这样我就可以给你适当的信贷!

相关问题