Preservando links de referências cruzadas em um PDF extraído

Preservando links de referências cruzadas em um PDF extraído

Quando escrevo minhas palestras, escrevo-as em um 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}

Continuo modificando e expandindo este documento main.tex e compartilhando o conteúdo com meus alunos com base no andamento da aula, normalmente capítulo por capítulo. Então eu crio um novo documento que contém algo como este mwe :

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

E compartilhe o resultado compilado. O fluxo de trabalho (é) foi conveniente porque já faço assim há muitos anos, mas o problema é que perco todos os links de referências cruzadas dos capítulos, índice e equações do documento. Você poderia me ajudar a resolver esse problema ou, se não for possível, sugerir outro fluxo de trabalho?

Responder1

Eu sugeriria usar \includeonlypara compilar partes menores do documento. Certifique-se de compilar o documento inteiro primeiro, para que os números das páginas e as referências cruzadas nas partes menores estejam corretas.

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

Responder2

Provavelmente, um mecanismo semelhante ao mecanismo \include/ \includeonlypode ser bom.

Um mecanismo que também grava os chamados pontos de verificação com valores de contador em arquivos auxiliares, caso coisas (partes de arquivos em vez de arquivos) não sejam processadas para composição tipográfica.

Mas com as seguintes diferenças em relação ao mecanismo \include/ \includeonly:

  1. Em vez de ler arquivos com nomes específicos, seriam lidas partes de um arquivo LaTeX, que recebem nomes e que no arquivo .tex-input estão aninhadas entre uma sequência \Filepart{⟨name of filepart⟩}e uma sequência \EndOfFilepart.

  2. Análogo ao comando \includeonly{⟨comma list with the names of the files that are to be read in⟩}, deve haver um comando \OnlyFileparts{⟨comma list with the names of those fileparts that are to be read in for typesetting⟩}.

  3. Se uma parte do arquivo não devesse ser lida para composição tipográfica, o LaTeX teria que mudar para o modo literal e ler o arquivo e criar tokens de caracteres e jogá-los fora até que a sequência de tokens de caracteres
    \EndOfFilepart
    fosse encontrada.

  4. No caso de o conteúdo de uma parte do arquivo não ser digitado na execução atual do LaTeX, mas o arquivo auxiliar associado que contém os dados dos rótulos de referência cruzada e similares definidos nesta parte do arquivo ainda for lido, teria que haver um argumento opcional, onde, no caso de o pacote hyperref ser carregado, pode-se especificar a URL para outro arquivo PDF que contém esta parte do arquivo, de modo que, ao fazer referência cruzada de rótulos de referência cruzada que foram definidos na parte do arquivo não-typeset, um um link externo para este outro arquivo PDF aparece em vez de um link interno sem destino (e, portanto, com o destino dos motores pdfTeX corrigido automaticamente para a página 1).

Com o seguinte exemplo de trabalho mínimo, um mecanismo é manipulado com os dois componentes a seguir:

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

e

\Filepart[⟨URL of pdf-file containing this part⟩]{⟨name of filepart⟩}...\EndOfFilepart
  • \OnlyFilepartssó pode aparecer no preâmbulo do arquivo .tex principal.
  • Com o mecanismo \include/ \includeonly, os pontos de verificação possuem nomes que correspondem aos nomes dos arquivos. Com o mecanismo \Filepart... \EndOfFilepart/ \OnlyFileparts, os pontos de verificação são numerados consecutivamente começando com o número 1 e eles e os arquivos auxiliares/arquivos .aux associados têm nomes de acordo com o esquema Filepart⟨number of the checkpoint belonging to the filepart⟩. Desta forma, várias partes do arquivo que em qualquer caso devem ser lidas juntas podem ter o mesmo nome.
  • A parte do mecanismo que no caso de não compor um filepart lê esse filepart literalmente e cria tokens de caracteres e os joga fora até que a sequência \EndOfFilepartseja encontrada, não lê linha por linha, mas caractere por caractere. Por um lado, nenhum caractere se perde em uma linha dessa maneira. Por outro lado, o mecanismo é lento em computadores lentos.
  • Não aninhe fileparts dentro de fileparts.
  • \Fileparte a correspondência \EndOfFilepartdeve estar no mesmo escopo/grupo.
  • \Fileparte a correspondência \EndOfFilepartdeve estar no mesmo arquivo de entrada .tex.
  • \Filepart[⟨URL of pdf-file containing this part⟩]{⟨name of filepart⟩}...\EndOfFilepartnão deve ocorrer nem em argumentos de macro nem em textos de substituição de macros, nem ser componente de valores de registradores de token e similares.
  • O código do exemplo mínimo de trabalho a seguir foi escrito em um smartphone, onde o TeX Live 2020 foi instalado. Ele usa recursos fornecidos pelo ambiente de programação expl3. Para teste foi compilado com pdflatex [pdfTeX, Versão 3.14159265-2.6-1.40.21 (TeX Live 2020) (formato pré-carregado = pdflatex), LaTeX2e <2020-10-01> patch nível 4, camada de programação L3 <2021-02- 18>].
  • Com versões mais recentes do LaTeX 2ε onde o novo sistema de ganchos está disponível, o mecanismo \include/ \includeonlyvem junto com alguns ganchos para executar alguns tokens cada vez que ocorre a inclusão de um arquivo. Com o mecanismo \Filepart... \EndOfFilepart/ \OnlyFileparts- nenhum gancho é implementado/o novo sistema de gancho do LaTeX 2ε não é usado. Isso ocorre porque o autor do lançamento inicial desta resposta ainda não está suficientemente acostumado com o novo sistema de ganchos do LaTeX 2ε.
  • O mecanismo \include/ \includeonlysó funciona quando - antes da ativação \includeonly- todo o documento foi compilado com todos os arquivos incluídos quantas vezes forem necessárias para obter o documento com todas as referências cruzadas, etc. Analogamente, o mecanismo \Filepart... \EndOfFilepart/ \OnlyFilepartssó funciona quando - antes da ativação \OnlyFileparts- todo o documento foi compilado com todas as partes do arquivo incluídas quantas vezes forem necessárias para obter o documento com todas as referências cruzadas, etc., correspondentes.
  • O código não foi testado intensivamente. Use por sua conta e risco.
\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}

informação relacionada