使用 pdflatex 在 PDF 中隐藏标记

使用 pdflatex 在 PDF 中隐藏标记

我用它latexdiff来显示我在大型文本(超过 200 页)中所做的更改。不过,我的大部分更改只影响几页,因此我不希望读者仔细阅读 200 页以寻找少数几个进行了单独拼写更正的页面:200 页中只有大约 30 页包含更改。

我想:

  1. 在发生更改的页面上插入隐藏的 PDF 标记
  2. 使用 pdflatex 编译
  3. 运行脚本,过滤掉不包含隐藏 PDF 标记的页面

    book.tex -latexdiff-> book_diff.tex -pdftex-> 200pp.pdf -script-> 30pp.pdf

有人可以推荐:

  • 用于在 PDF 文件中插入某种“标记”的 tex 包
  • 一个用于读取 PDF(并查找所述标记)的 Python 包

答案1

我的第一个想法是使用 I/O 文件操作,例如\write\immediate\write,但它面临着浮动对象及其行为的已知问题。当没有\global前缀时,我也遇到了带有自己计数器的浮动对象的问题。

我宁愿直接使用交叉引用来确保受保护的写入。我可以借助 LuaTeX 为您提供此解决方案。处理步骤如下:

  • 我们排版一份常规文档并标记一个位置。就本文而言,这是一个可见的标记,也是一个页码。定义使用带有\label特定前缀的常规命令,例如malipivo。我将文件filter.tex和命令命名为\writeme。该命令使用自己的计数器,这确保了命令中标记的唯一性\label
  • 根据实际排版材料,文件filter.tex会被处理多次,本例中是两次。第一次运行后,我们得到一个带有两个红色问号的文档(预览中的第 1 行),第二次运行后,我们得到正确排版的交叉引用(预览中的第 2 行)。

这是代码:

%! *latex filter.tex
%! Run me twice or even more times to get references right.
\def\myprefixis{malipivo}

\documentclass[a4paper]{article}
\usepackage{tikz}
\usepackage[numbers]{kantlipsum}
\newcount\mycounter 
\mycounter=0
% Our own marker...
% Save the reference and mark it...
\def\writeme{%
\global\advance\mycounter by 1%
\label{\myprefixis\the\mycounter}%
\begin{tikzpicture}%
\begin{pgfinterruptboundingbox}%
\node[red,font=\bfseries\Huge,scale=4]{\pageref{\myprefixis\the\mycounter}};%
\end{pgfinterruptboundingbox}%
\end{tikzpicture}%
  }% End of \writeme...

\begin{document}
\section{My experiment}
\kant[1-2]\writeme
\kant[14]\writeme
\kant[15-16]\writeme
\kant[25]\writeme\ There is a typo and\writeme\ one more\writeme
\kant[26-32]\writeme
\kant[46]\writeme
\begin{figure}[p]
\kant[51] I am floating.\writeme
\end{figure}
\kant[52-61]\writeme
\end{document}

第一次运行后的 filter.pdf 第二次运行后的 filter.pdf

该文件的内容filter.aux如下:

\relax 
\@writefile{toc}{\contentsline {section}{\numberline {1}My experiment}{1}}
\newlabel{malipivo1}{{1}{1}}
\newlabel{malipivo2}{{1}{1}}
\newlabel{malipivo3}{{1}{2}}
\newlabel{malipivo4}{{1}{2}}
\newlabel{malipivo5}{{1}{2}}
\newlabel{malipivo6}{{1}{2}}
\newlabel{malipivo7}{{1}{4}}
\newlabel{malipivo8}{{1}{4}}
\newlabel{malipivo10}{{1}{7}}
\newlabel{malipivo9}{{1}{8}}

实际上,您可以看到,当数字与其页码对应项交换时,存在一些浮动对象(malipivo10<-> malipivo97<-> 8)。我们需要以某种方式处理此辅助文件并从​​中提取页面filter.pdf。我使用了 LuaTeX 和pdfpages包。

  • 起初我以为我需要对行进行排序,但似乎没有必要,它已经按页码排序,而不是按标记排序。

  • 但是,我需要提取malipivo包含前缀的行并跳过其他行。我使用的string.find是 LuaTeX。此步骤的终端中有一个注释,上面写着Testing note on page 1...

  • 然后我需要提取页码来获得1 1 2 2 2 2 4 4 7 8,我使用了该string.gsub函数。

  • 我必须保证每个页面只被包含一次,所以我们应该1 2 4 7 8在删除重复项后得到这个数字序列。

  • 我的下一步是添加逗号,我在连接临时字符串时这样做了。我们开始吧1,2,4,7,8

  • 剩下的就比较简单了。我制作了一个 LaTeX 命令来获取\includepdf[pages={1,2,4,7,8},fitpaper]{filter.pdf}它并将其发送到文档主体。

我在 LuaTeX 中创建了一个简单的函数,它testme有两个参数,第一个参数要求输入测试文件(filter),代码使用它的auxpdf文件,第二个参数要求输入我们使用的前缀(理论上可以有更多前缀),我使用了malipivo。实际的排版由完成\directlua{testme("filter","malipivo")}

filtered.tex我附上了一次运行的代码( )以及最后在原始代码()中标记的lualatex选定页面的预览( ) 。filtered.pdffilter.tex

%! lualatex filtered.tex
%! run me only once
\documentclass{article}
\usepackage{pdfpages}
\usepackage{luacode}

\begin{document}

\begin{luacode*}
function testme (filtering, thekey)
-- Initializing variables...
local myinput=filtering..".aux" -- Where are the reference?
local myinputpdf=filtering..".pdf" -- Where are the real PDF pages?
local mylines="" -- List of pages to get is?
local mycount=0 -- How many tested reference do we have?
local lastcount="" -- What is the previous reference?
-- The core of the function...
for mylinetemp in io.lines(myinput) do -- Read input file line by line
  test=string.find(mylinetemp,thekey) -- Is a unique key involved? 
  if test~=nil then -- Yes, the key is present there...
    myline=string.gsub(mylinetemp,"\\newlabel{"..thekey..".-}{{.-}{(.-)}}", "%1", 1) -- Find a group with page reference.
    print("Testing note on page "..myline.."...") -- Print information to the terminal
    mycount=mycount+1 -- Increase a number of tested references
    if mycount==1 then -- Save the first value as the starting value
      mylines=myline -- Start the resulting string
      lastcount=myline -- Remember the last occurance
    else -- Add value to the list if not already stored in the list
      if lastcount~=myline then -- But only if last two values differ (aka uniq)
        mylines=mylines..","..myline -- Add comma and value to the string (aka join)
        lastcount=myline -- Remember this occurance as the last one for next testing
      end -- of if not lastcount
    end -- of if mycount
  end -- of if thekey is involved
end -- of myline
-- Print the results and generate PDF via regular typesetting...
local keyresult="\\includepdf[pages={"..mylines.."},fitpaper]{"..myinputpdf.."}"
print(keyresult)
tex.print(keyresult)
end -- of function testme
\end{luacode*}

% The tested file, e.g. filter.{aux,pdf}, and its reference label prefix.
\directlua{testme("filter","malipivo")}

\end{document}

已过滤.pdf

答案2

好的,我写了一个工作管道的初稿。

  • 根据@ChristianH的建议,我使用了pdf评论
  • 对于脚本,我使用了:

代码在这里: https://gist.github.com/ivanistheone/219dad11a30efef82b7e

相关内容