pdflatex を使用した PDF 内の非表示マーカー

pdflatex を使用した PDF 内の非表示マーカー

大きなテキスト (200 ページ以上) に加えた変更を示すために使用していますlatexdiff。ただし、変更のほとんどは数ページにしか影響しないため、読者が 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

\write最初に考えたのは、または などの I/O ファイル操作を使用することでした\immediate\writeが、浮動オブジェクトとその動作に関する既知の問題に直面しました。また、プレフィックスがない場合に独自のカウンターを持つ浮動オブジェクトに関しても問題がありました\global

私はむしろ、保護された書き込みが保証される相互参照を直接使用しました。LuaTeX の助けを借りてこのソリューションを提供できます。処理手順は次のとおりです。

  • 通常の文書をタイプセットし、位置をマークします。この記事の目的上、それは目に見えるマークであり、ページ番号です。定義では、\label特定のプレフィックス (例: ) が付いた通常のコマンドを使用します。malipivoファイルfilter.texとコマンドにという名前を付けました\writeme。コマンドは独自のカウンターを使用し、コマンド内のマーカーの一意性を保証します\label
  • ファイルfilter.texは、実際のタイプセット マテリアルに応じて複数回処理されます。この例では 2 回です。最初の実行後、2 つの赤い疑問符が付いたドキュメント (プレビューの行 1) が作成され、2 回目の実行後、相互参照が正しくタイプセットされます (プレビューの行 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 2回目の実行後の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実際に、数字がページ番号の対応する数字 ( <-> malipivo9; 7<-> )に交換されているため、浮動オブジェクトが存在することがわかります8。この補助ファイルを何らかの方法で処理し、ページを抽出する必要がありますfilter.pdf。私は LuaTeX とpdfpagesパッケージを使用しました。

  • 最初は行を並べ替える必要があると思いましたが、マーカーではなくページ番号ですでに並べ替えられているため、必要ないようです。

  • malipivoただし、プレフィックスを含む行を抽出し、他の行をスキップする必要がありました。LuaTeXstring.findを使用しました。この手順から、ターミナルに次のようなメモが表示されますTesting note on page 1...

  • 次に、ページ番号を抽出する必要があり1 1 2 2 2 2 4 4 7 8、 関数を使用しましたstring.gsub

  • 各ページが 1 回だけ含まれるようにする必要があったため、1 2 4 7 8重複を削除した後にこの番号のシーケンスを取得する必要があります。

  • 次のステップは、一時的な文字列を連結しながらコンマを追加することでした。 に進みます1,2,4,7,8

  • 残りは比較的簡単でした。それを LaTeX コマンドにして取得し\includepdf[pages={1,2,4,7,8},fitpaper]{filter.pdf}、ドキュメント本体に送信しました。

私は LuaTeX で 2 つのパラメータを持つ という名前の簡単な関数を作成しましたtestme。最初のパラメータはテスト対象のファイル ( filter) を要求し、コードはそのファイルauxpdfファイルを使用します。2 番目のパラメータは、使用しているプレフィックス (理論上は、プレフィックスがさらに存在する可能性があります) を要求します。私は を使用しました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

関連情報