Preservar enlaces de referencias cruzadas en un PDF extraído

Preservar enlaces de referencias cruzadas en un PDF extraído

Cuando escribo mis conferencias, las escribo en un documento como este mwe

% document name : main.tex
\documentclass{scrbook}
\usepackage{etoc}
\newcommand{\chaptertoc}[1][Contenu du chapitre]{%
    %\etocsettocstyle{\addsec*{#1}}{}%
    \etocsettocstyle{\addsec*{#1\\\rule{\textwidth}{0.4pt}} \small }{}
    \localtableofcontents%
}

\usepackage{hyperref}

\usepackage[]{blindtext}

\begin{document}
\tableofcontents
\chapter{Chapter One}
\chaptertoc{}
\section{section one of chapter one}
\Blindtext
\section{section two of chapter one}
\Blindtext
\chapter{Chapter Two}
\chaptertoc{}
\section{section one of chapter two}
\Blindtext
\section{section two of chapter two}
\Blindtext
\section{section three of chapter two}
\Blindtext
\end{document}

Continúo modificando y ampliando este documento main.tex y comparto el contenido con mis alumnos según el progreso de la conferencia, generalmente capítulo por capítulo. Así que creo un nuevo documento que contiene algo parecido a este mwe:

% document name: pdf_chapter1.tex
\documentclass{article}
\usepackage[]{pdfpages}
\usepackage{hyperref}
\begin{document}
    \includepdf[pages={3-5}]{main}
\end{document}

Y comparte el resultado compilado. El flujo de trabajo (es) fue conveniente porque lo he estado haciendo así durante muchos años, pero el problema es que pierdo todos los enlaces de referencias cruzadas de los capítulos, índice y ecuaciones del documento. ¿Podría ayudarme a resolver este problema o, si no es posible, sugerirme otro flujo de trabajo?

Respuesta1

Sugeriría usarlo \includeonlypara compilar partes más pequeñas del documento. Asegúrese de compilar todo el documento primero, para que los números de página y las referencias cruzadas en las partes más pequeñas sean correctos.

\documentclass{scrbook}
\usepackage{etoc}
\newcommand{\chaptertoc}[1][Contenu du chapitre]{%
    %\etocsettocstyle{\addsec*{#1}}{}%
    \etocsettocstyle{\addsec*{#1\\\rule{\textwidth}{0.4pt}} \small }{}
    \localtableofcontents%
}

\usepackage{hyperref}

\usepackage[]{blindtext}

\begin{filecontents*}[overwrite]{cap1.tex}
\chapter{Chapter One}
\chaptertoc{}
\section{section one of chapter one}
\Blindtext
\[
  E = mc^{2}\label{eq}
\]
\section{section two of chapter one}
\Blindtext
\end{filecontents*}

\begin{filecontents*}[overwrite]{cap2.tex}
\chapter{Chapter Two}
\chaptertoc{} 
\section{section one of chapter two}
\Blindtext
\section{section two of chapter two}
\Blindtext
\section{section three of chapter two}
\Blindtext
\ref{eq}
\end{filecontents*}

\includeonly{cap2}

\begin{document}
\tableofcontents

\include{cap1}
\include{cap2}

\end{document}

Respuesta2

Probablemente un mecanismo similar al mecanismo \include/ \includeonlypodría ser bueno.

Un mecanismo que también escribe los llamados puntos de control con valores de contador en archivos auxiliares en caso de que las cosas (partes de archivos en lugar de archivos) no se procesen para la composición tipográfica.

Pero con las siguientes diferencias con el mecanismo \include/ \includeonly:

  1. En lugar de leer archivos con nombres específicos, se leerían partes de un archivo LaTeX, a las que se les dan nombres y que en el archivo .tex-input-file están anidadas entre una secuencia \Filepart{⟨name of filepart⟩}y una secuencia \EndOfFilepart.

  2. De manera análoga al comando \includeonly{⟨comma list with the names of the files that are to be read in⟩}, debería haber un comando \OnlyFileparts{⟨comma list with the names of those fileparts that are to be read in for typesetting⟩}.

  3. Si una parte de un archivo no debe leerse para componerla, LaTeX tendría que cambiar al modo palabra por palabra y leer el archivo y crear tokens de caracteres y desecharlos hasta que se
    \EndOfFilepart
    encuentre la secuencia de tokens de caracteres.

  4. En el caso de que el contenido de una parte de archivo no esté tipografiado en la ejecución actual de LaTeX, pero el archivo auxiliar asociado que contiene los datos de las etiquetas de referencia cruzada y similares definidos en esta parte de archivo aún se lea, tendría que haber una argumento opcional, donde, en el caso de que se cargue el paquete hyperref, se puede especificar la URL de otro archivo PDF que contenga esta parte del archivo, de modo que cuando se hagan referencias cruzadas a etiquetas que se definieron en la parte del archivo no tipográfica, se Aparece un enlace externo a este otro archivo PDF en lugar de un enlace interno sin destino (y por lo tanto con el destino de pdfTeX-engines corregido automáticamente en la página 1).

Con el siguiente ejemplo de funcionamiento mínimo se manipula un mecanismo con los dos componentes siguientes:

\OnlyFilepart{⟨comma list with the names of those fileparts that are to be read in for typesetting⟩}

y

\Filepart[⟨URL of pdf-file containing this part⟩]{⟨name of filepart⟩}...\EndOfFilepart
  • \OnlyFilepartssolo puede aparecer en el preámbulo del archivo .tex principal.
  • Con el mecanismo \include/ \includeonly, los puntos de control tienen nombres que corresponden a los nombres de los archivos. Con el mecanismo \Filepart... \EndOfFilepart/ \OnlyFileparts, los puntos de control se numeran consecutivamente comenzando con el número 1 y ellos y los archivos auxiliares/.aux asociados tienen nombres según el esquema Filepart⟨number of the checkpoint belonging to the filepart⟩. De este modo, varias partes del archivo que en cualquier caso deben leerse juntas pueden tener el mismo nombre.
  • La parte del mecanismo que, en el caso de no componer una parte del archivo, lee esa parte del archivo palabra por palabra y crea tokens de caracteres y los desecha hasta que \EndOfFilepartse encuentra la secuencia, no lee línea por línea, sino carácter por carácter. Por un lado, de este modo no se pierden caracteres en una línea. Por otro lado, el mecanismo es lento en ordenadores lentos.
  • No anide partes de archivos dentro de partes de archivos.
  • \Fileparty la coincidencia \EndOfFilepartdebe estar en el mismo ámbito/grupo.
  • \Fileparty la coincidencia \EndOfFilepartdebe estar en el mismo archivo de entrada .tex.
  • \Filepart[⟨URL of pdf-file containing this part⟩]{⟨name of filepart⟩}...\EndOfFilepartno debe aparecer en argumentos de macro ni en textos de reemplazo de macros ni ser componente de valores de registros de tokens y similares.
  • El código del siguiente ejemplo de trabajo mínimo se escribió en un teléfono inteligente, donde estaba instalado TeX Live 2020. Utiliza las funciones proporcionadas por el entorno de programación expl3. Para las pruebas, se compiló con pdflatex [pdfTeX, versión 3.14159265-2.6-1.40.21 (TeX Live 2020) (formato precargado = pdflatex), LaTeX2e <2020-10-01> nivel de parche 4, capa de programación L3 <2021-02- 18>].
  • Con lanzamientos más recientes de LaTeX 2ε donde está disponible el nuevo sistema de gancho, el mecanismo \include/ \includeonlyviene junto con algunos ganchos para ejecutar algunos tokens cada vez que se incluye un archivo. Con el mecanismo \Filepart... \EndOfFilepart/ \OnlyFilepartsno se implementan ganchos/no se utiliza el nuevo sistema de ganchos de LaTeX 2ε. Esto se debe a que el autor de la publicación inicial de esta respuesta aún no está lo suficientemente acostumbrado al nuevo sistema de enlace de LaTeX 2ε.
  • El mecanismo \include/ \includeonlysolo funciona cuando, antes de activarlo \includeonly, se compiló todo el documento con todos los archivos incluidos tantas veces como sea necesario para obtener el documento con todas las referencias cruzadas, etc., coincidentes. De manera análoga, el mecanismo \Filepart... \EndOfFilepart/ \OnlyFilepartssolo funciona cuando, antes de activarlo \OnlyFileparts, el documento completo se compiló con todas las partes del archivo incluidas tantas veces como sea necesario para obtener el documento con todas las referencias cruzadas, etc., coincidentes.
  • El código no ha sido probado intensivamente. Úselo bajo su propio riesgo.
\makeatletter
%----------------------------------------------------------------------------------------------------
% Infrastructure for switching to verbatim-mode and gobbling things until encountering 
% \EndDocumentPart
%----------------------------------------------------------------------------------------------------
\ExplSyntaxOn
\cs_new_eq:NN \UD@StringCase \str_case:nnTF 
\cs_new_eq:NN \UD@StringTail \str_tail:n
\cs_new_eq:NN \UD@IfEmpty \tl_if_empty:nTF
%\cs_new_eq:NN \UseName \use:c
%\cs_new:Npn \ExpandArgs #1
% {
% \cs_if_exist_use:cF { exp_args:N #1 }
% { \msg_expandable_error:nnn { kernel } { unknown-arg-expansion } {#1} }
% }
%\msg_new:nnn { kernel } { unknown-arg-expansion }
% { Unknown~arg~expansion~"#1" }
\ExplSyntaxOff
\newcommand\UD@SwitchToVerbatimAndGgobbleToEndOfFilepart[1]{%
  \begingroup
  \endlinechar=-1\relax
  \let\do\@makeother\dospecials\do\^^I\do\^^M% 
  \UD@GgobbleToEndOfFilepartLoop{#1}{}%
}%
\begingroup
\newcommand\UD@GgobbleToEndOfFilepartLoop[4]{%
  \if#4Z\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \endgroup
    \newcommand\UD@GgobbleToEndOfFilepartLoop[3]{%
      \UD@StringCase{##2##3}{#1{#3}{\endgroup##1}}{}{%
        \UD@IfEmpty{##2}%
          {\UD@GgobbleToEndOfFilepartLoop{##1}{##3}}%
          {\ExpandArgs{ne}\UD@GgobbleToEndOfFilepartLoop{##1}{\UD@StringTail{##2}}{##3}}%
      }%
    }%
  }{%
    \UD@GgobbleToEndOfFilepartLoop
    {#1#2}%
    {{#3#4}{\UD@GgobbleToEndOfFilepartLoop{##1}{##2##3}}}%
    {#3#4}%
  }%
}%
\@firstofone{%
  \let\do\@makeother\dospecials\do\^^I\do\^^M%
  \UD@GgobbleToEndOfFilepartLoop{}{}{}%
}\EndOfFilepartZ%
%----------------------------------------------------------------------------------------------------
% Infrastructure for patching/restoring \newlabel and \new@label@record:
%----------------------------------------------------------------------------------------------------
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\UD@Savednewlabel{}%
\@ifdefinable\UD@Savednew@label@record{}%
\newcommand*\UD@ResetNewlabelAndNew@label@record[1]{%
  \AtIfFilepartIncluded{#1}{}{%
    \csname @\ifx\csname ver@hyperref.\@pkgextension\endcsname\relax gobble\else firstofone\fi\endcsname
    {\let\newlabel\UD@Savednewlabel}%
    \let\new@label@record\UD@Savednew@label@record
  }%
}%
\newcommand\UD@SwitchNewlabelAndNew@label@record[2]{%
  \AtIfFilepartIncluded{#2}{}{%
    \csname @\ifx\csname ver@hyperref.\@pkgextension\endcsname\relax gobble\else firstofone\fi\endcsname
    {%
      \let\UD@Savednewlabel\newlabel
      \def\newlabel{\UD@Patchednewlabel{#1}}%
    }%
    \let\UD@Savednew@label@record\new@label@record
    \def\new@label@record{\UD@Patchednew@label@record{#1}}%
  }%
}%
\@ifdefinable\UD@Patchednewlabel@AddURL{%
  \long\def\UD@Patchednewlabel@AddURL#1#2#3#4#5#6\\{{#2}{#3}{#4}{#5}{#1}}%
}%
\newcommand\UD@Patchednewlabel[3]{%
  \expandafter\UD@PassFirstToSecond
  \expandafter{%
    \UD@Patchednewlabel@AddURL{#1}#3{}{}{}{}\\%
  }%
  {\UD@Savednewlabel{#2}}%
}%
\newcommand\UD@Patchednew@label@record[3]{%
  \UD@Savednew@label@record{#2}{#3{xr-url}{#1}}%
}%
%----------------------------------------------------------------------------------------------------
% Infrastructure for \Filepart and \EndOfFilepart
%----------------------------------------------------------------------------------------------------
\newwrite\UD@Filepartaux
\newcommand\UD@previous@auxout{}%
\newif\ifUD@FilepartSW\UD@FilepartSWfalse
\newcommand\UD@FilepartNesting{0}%
\newcommand\UD@FilepartList{}%
\newcounter{UD@FilepartCheckpoints}%
%----------------------------------------------------------------------------------------------------
\newcommand\OnlyFileparts[1]{%
  \UD@FilepartSWtrue
  \let\UD@FilepartList\@empty
  \@for\reserved@a:=#1\do
  {%
    \ifx\UD@FilepartList\@empty
      \expandafter\def\expandafter\UD@FilepartList\expandafter{\reserved@a}%
    \else
      \expandafter\expandafter\expandafter\def
      \expandafter\expandafter\expandafter\UD@FilepartList
      \expandafter\expandafter\expandafter{\expandafter\UD@FilepartList\expandafter,\reserved@a}%
    \fi
  }%
}%
\@onlypreamble\OnlyFileparts
%----------------------------------------------------------------------------------------------------
\NewDocumentCommand\Filepart{om}{%
  \relax
  \xdef\UD@FilepartNesting{\the\numexpr((\UD@FilepartNesting)+1)\relax}%
  \ifnum\UD@FilepartNesting>1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \@latex@error{\string\Filepart\space cannot be nested}\@eha
    \UD@SwitchToVerbatimAndGgobbleToEndOfFilepart{\EndOfFilepart}%
  }%
  {%
    \clearpage
    \addtocounter{UD@FilepartCheckpoints}\@ne
    \if@filesw
      \IfNoValueF{#1}{%
        \immediate\write\@auxout{\string\UD@SwitchNewlabelAndNew@label@record{#1}{#2}}%
      }%
      \immediate\write\@auxout{\string\@input{Filepart\arabic{UD@FilepartCheckpoints}.aux}}%
      \IfNoValueF{#1}{%
        \immediate\write\@auxout{\string\UD@ResetNewlabelAndNew@label@record{#2}}%
      }%
    \fi
    \let\UD@previous@auxout\@auxout
    \@tempswatrue
    \AtIfFilepartIncluded{#2}%
    {%
      \let\@auxout\UD@Filepartaux
      \if@filesw
        \immediate\openout\UD@Filepartaux "Filepart\arabic{UD@FilepartCheckpoints}.aux"
        \immediate\write\UD@Filepartaux{\relax}%
      \fi
    }{%
      \UD@SwitchToVerbatimAndGgobbleToEndOfFilepart{%
        \deadcycles\z@
        \@nameuse{cp@Filepart\arabic{UD@FilepartCheckpoints}}%
        \let\@auxout\UD@previous@auxout
        \xdef\UD@FilepartNesting{\the\numexpr((\UD@FilepartNesting)-1)\relax}%
      }%
    }%
  }%
}%
%----------------------------------------------------------------------------------------------------
\newcommand\AtIfFilepartIncluded[1]{%
  \begingroup
  \@tempswatrue
  \ifUD@FilepartSW
    \@tempswafalse
    \def\reserved@b{#1}%
    \@for\reserved@a:=\UD@FilepartList\do{%
      \ifx\reserved@a\reserved@b\@tempswatrue\fi
    }%
  \fi
  \expandafter\endgroup
  \if@tempswa\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%----------------------------------------------------------------------------------------------------
\newcommand*\EndOfFilepart{%
  \ifnum\UD@FilepartNesting=1 \expandafter\@firstofone\else\expandafter\@gobble\fi
  {%
    \clearpage
    \if@filesw
      \immediate\write\UD@Filepartaux{\string\@setckpt{Filepart\arabic{UD@FilepartCheckpoints}}\@charlb}%
      {\let\@elt\@wckdocumentptelt \cl@@ckpt}%
      \immediate\write\UD@Filepartaux{\@charrb}%
      \immediate\closeout\UD@Filepartaux
    \fi
    \let\@auxout\UD@previous@auxout
  }%
  \ifnum\UD@FilepartNesting<1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\@latex@error{Unmatched \string\EndOfFilepart}\@eha}%
  {\xdef\UD@FilepartNesting{\the\numexpr((\UD@FilepartNesting)-1)\relax}}%
}%
\newcommand*\@wckdocumentptelt[1]{%
  \immediate\write\UD@Filepartaux{\string\setcounter{#1}{\the\@nameuse{c@#1}}}%
}%
%----------------------------------------------------------------------------------------------------
\makeatother

\documentclass{scrbook}
\usepackage{etoc}
\newcommand{\chaptertoc}[1][Contenu du chapitre]{%
    %\etocsettocstyle{\addsec*{#1}}{}%
    \etocsettocstyle{\addsec*{#1\\\rule{\textwidth}{0.4pt}}\small}{}%
    \localtableofcontents
}


%\OnlyFileparts{Lecture2}
%\OnlyFileparts{Lecture1}
%\OnlyFileparts{Lecture3,Lecture4}

\usepackage[pdfnewwindow=true]{hyperref}
\usepackage[]{blindtext}

\begin{document}
\Filepart{ToC}%
\tableofcontents
\EndOfFilepart
\Filepart[file:./Lecture1.pdf]{Lecture1}%
\chapter{Chapter One}
\chaptertoc{}
\section{section one of chapter one}
\Blindtext
\section{section two of chapter one}
\label{A label}%
\Blindtext
\EndOfFilepart
\Filepart{Lecture2}%
\chapter{Chapter Two}
\chaptertoc{}
\section{section one of chapter two}
\Blindtext
\section{section two of chapter two}
\Blindtext
\section{section three of chapter two}
\Blindtext
\EndOfFilepart
\Filepart{Lecture3}%
\chapter{Chapter Three}
\chaptertoc{}
\section{section one of chapter three}
\Blindtext
\ref{A label}%
%\expandafter\show\csname r@A label\endcsname
\section{section two of chapter three}
\Blindtext
\section{section three of chapter three}
\Blindtext
\EndOfFilepart
\Filepart{Lecture4}%
\chapter{Chapter Four}
\chaptertoc{}
\section{section one of chapter four}
\Blindtext
\section{section two of chapter four}
\Blindtext
\section{section three of chapter four}
\Blindtext
\EndOfFilepart
\Filepart{Lecture2}%
\chapter{Chapter Five - should always go together with Chapter Two}
\chaptertoc{}
Chapter Five should always go together with Chapter Two, 
thus\verb|\Filepart|-commands get the same name.
\section{section one of chapter five}
\Blindtext
\section{section two of chapter five}
\Blindtext
\section{section three of chapter five}
\Blindtext
\EndOfFilepart
\end{document}

información relacionada