Unsichtbare Markierungen in PDFs mit pdflatex

Unsichtbare Markierungen in PDFs mit pdflatex

Ich verwende es, latexdiffum Änderungen anzuzeigen, die ich in einem großen Text (200+ Seiten) vornehme. Die meisten meiner Änderungen betreffen jedoch nur wenige Seiten, daher möchte ich nicht, dass meine Leser 200 Seiten durchforsten müssen, um die wenigen Seiten zu finden, auf denen vereinzelte Tippfehlerkorrekturen vorgenommen wurden: Nur etwa 30 der 200 Seiten enthalten Änderungen.

Ich möchte:

  1. Einfügen versteckter PDF-Marker auf Seiten, auf denen Änderungen auftreten
  2. Kompilieren mit pdflatex
  3. Führen Sie ein Skript aus, das Seiten herausfiltert, die die versteckten PDF-Marker nicht enthalten

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

Kann jemand Folgendes empfehlen:

  • ein Tex-Paket zum Einfügen von „Markierungen“ jeglicher Art in eine PDF-Datei
  • ein Python-Paket zum Lesen von PDFs (und Suchen nach den genannten Markierungen)

Antwort1

Mein erster Gedanke war, die E/A-Dateioperationen zu verwenden, z. B. \writeoder \immediate\write, aber dabei trat ein bekanntes Problem mit schwebenden Objekten und ihrem Verhalten auf. Ich hatte auch Probleme mit schwebenden Objekten mit eigenem Zähler, wenn kein \globalPräfix vorhanden war.

Ich habe lieber direkt Querverweise verwendet, bei denen ein geschütztes Schreiben gewährleistet ist. Diese Lösung kann ich Ihnen mit Hilfe von LuaTeX anbieten. Die verarbeiteten Schritte sind:

  • Wir setzen ein normales Dokument und markieren eine Position. Für die Zwecke dieses Beitrags ist es eine sichtbare Markierung und eine Seitenzahl. Die Definition verwendet einen regulären \labelBefehl mit einem bestimmten Präfix, z. B. malipivo. Ich habe die Datei filter.texund den Befehl genannt \writeme. Der Befehl verwendet einen eigenen Zähler und das stellt die Eindeutigkeit der Markierung im \labelBefehl sicher.
  • Die filter.texDatei wird je nach tatsächlichem Satzmaterial mehrmals verarbeitet, in diesem Beispiel zweimal. Nach dem ersten Durchlauf erhalten wir ein Dokument mit zwei roten Fragezeichen (Zeile 1 in der Vorschau), nach dem zweiten Durchlauf erhalten wir korrekt gesetzte Querverweise (Zeile 2 in der Vorschau).

Dies ist der Code:

%! *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 nach dem ersten Durchlauf filter.pdf nach dem zweiten Durchlauf

Der Inhalt der filter.auxDatei sieht wie folgt aus:

\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}}

Sie können tatsächlich sehen, dass es ein schwebendes Objekt gibt, da Zahlen durch ihre Seitenzahlen-Gegenstücke ersetzt werden ( malipivo10<-> malipivo9; 7<-> 8). Wir müssen diese Hilfsdatei irgendwie verarbeiten und die Seiten daraus extrahieren filter.pdf. Ich habe LuaTeX und das pdfpagesPaket verwendet.

  • Zuerst dachte ich, dass ich die Zeilen sortieren müsste, aber das scheint nicht nötig zu sein, die Sortierung erfolgt bereits nach den Seitenzahlen und nicht nach den Markierungen.

  • Ich musste jedoch Zeilen mit enthaltenem Präfix extrahieren malipivound die anderen überspringen. Ich habe string.findLuaTeX verwendet. Im Terminal erscheint zu diesem Schritt eine Notiz mit dem Inhalt Testing note on page 1....

  • Dann musste ich Seitenzahlen extrahieren 1 1 2 2 2 2 4 4 7 8, um sie zu erhalten. Ich habe die string.gsubFunktion verwendet.

  • Ich musste sicherstellen, dass jede Seite nur einmal eingefügt wird, daher sollten wir nach dem Entfernen der Duplikate diese Zahlenfolge erhalten 1 2 4 7 8.

  • Mein nächster Schritt war das Hinzufügen von Kommas. Das habe ich beim Verketten der temporären Zeichenfolge gemacht. Wir kommen zum Punkt 1,2,4,7,8.

  • Der Rest war relativ einfach. Ich habe daraus einen LaTeX-Befehl gemacht, um \includepdf[pages={1,2,4,7,8},fitpaper]{filter.pdf}es abzurufen und an den Dokumenttext zu übertragen.

Ich habe eine einfache Funktion in LuaTeX testmemit zwei Parametern erstellt. Der erste Parameter fragt nach der getesteten Datei ( filter), der Code verwendet seine auxund pdfDateien, und der zweite Parameter fragt nach einem von uns verwendeten Präfix (theoretisch könnte es mehrere Präfixe geben), ich habe verwendet malipivo. Der eigentliche Schriftsatz wird von durchgeführt \directlua{testme("filter","malipivo")}.

Anbei der Code ( filtered.tex), der einmalig ausgeführt werden soll lualatexund abschließend eine Vorschau ausgewählter Seiten ( filtered.pdf), die im Originalcode markiert wurden ( filter.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}

gefiltert.pdf

Antwort2

Okay, ich habe also einen ersten Entwurf einer funktionierenden Pipeline geschrieben.

  • Gemäß dem Vorschlag von @ChristianH habe ichpdfkommentar
  • Für das Skript habe ich Folgendes verwendet:
    • PDFMinerum die PDF-Anmerkungen zu lesen
    • pdfrwum die ausgewählten Seiten zu schreiben

Der Code ist hier: https://gist.github.com/ivanistheone/219dad11a30efef82b7e

verwandte Informationen