9

I have written a beamer presentation and I would like all the frames to have corresponding PDF bookmarks, much like as in this other question on here: Beamer: how to make each frame appear in the PDF toc? . However, it seems that the answer given to that question makes every slide get a bookmark, so frames with \pauses which have multiple corresponding slides get duplicate bookmarks.

(My understanding is that in beamer, a frame is the logical concept defined as everything between the \begin{frame} and \end{frame} and may be represented in the output as one or more slides.)

I include a minimum illustrative example, based on the previously referenced answer, which I compile with pdflatex (and my \beamer@version=3.20):

\documentclass{beamer}

\usepackage{bookmark}
\usepackage{etoolbox}

\makeatletter
\apptocmd{\beamer@@frametitle}{\bookmark[page=\the\c@page,level=3]{#1}}%
{\message{** patching of \string\beamer@@frametitle succeeded **}}%
{\message{** patching of \string\beamer@@frametitle failed **}}%
\makeatother


\begin{document}

\begin{frame}{Title}
Hello \pause world
\end{frame}
\end{document}

Result: a PDF with one frame but two slides, and two bookmarks, one for each slide. Wanted: a PDF with one frame but two slides, and one bookmark, one for each frame.

I am surprised that the example doesn't work, as I would have thought that \frametitle (or rather its \@dblarg helper \beamer@@frametitle) would get called once per frame instead of (as it appears given the result) once per slide. (Is there any implementation documentation for beamer that might help me with this, as so far I've failed to find it?)

Also, as my presentation is already written, I would like to avoid having to replace \begin{frame} with \begin{myframe} everywhere if possible (especially as some of my frames use the \frametitle{Title} syntax and others the \begin{frame}{Title} syntax of setting the frame title), and I'm aware that there will be a few difficulties in this approach.

3 Answers3

12
\makeatletter
\apptocmd{\beamer@@frametitle}{\only<1>{\bookmark[page=\the\c@page,level=3]{#1}}}%
{\message{** patching of \string\beamer@@frametitle succeeded **}}%
{\message{** patching of \string\beamer@@frametitle failed **}}%
\makeatother

adds the bookmark just for the first slide in each frame (or at least it seems to work on your MWE)

David Carlisle
  • 757,742
  • 1
    That does indeed work, thanks, and is (embarrassingly) much simpler than anything I was going to think of. This has also led me to the idea of having one bookmark per slide, but with the 'slide in frame' number part of the bookmark caption: replacing the \apptocmd line with \apptocmd{\beamer@@frametitle}{\bookmark[page=\the\c@page,level=3]{#1 (\the\beamer@slideinframe)}}% achieves that. Hope this helps someone else too. (And it seems I can put off learning more about beamer's implementation a little longer...) – cyberSingularity Aug 10 '12 at 07:51
  • why if I put these lines of code into a .sty file it does not work? – Aurelius Mar 21 '14 at 17:39
  • This solution doesn't work for me; I get the following error message: Undefined control sequence. \beamer@doifinframe ->\bookmark [page=\the \c@page ,level=3] – xFioraMstr18 Jul 13 '23 at 02:11
  • 1
    @xFioraMstr18 the code here still works, you show \bookmark undefined which indicates you have not loaded bookmark package – David Carlisle Jul 14 '23 at 04:16
  • Okay, your answer works now when I \usepackage{bookmark} – xFioraMstr18 Jul 14 '23 at 08:41
  • Incidentally, why do you put empty comments % after each of your middle three lines? – xFioraMstr18 Jul 14 '23 at 08:42
  • 1
    @xFioraMstr18 I copied the style in the question, not needed here but https://tex.stackexchange.com/questions/7453/what-is-the-use-of-percent-signs-at-the-end-of-lines-why-is-my-macro-creat – David Carlisle Jul 14 '23 at 09:17
1

I am so happy to find this and the related thread. This is my final working solution. And I take no credit for this. I am just posting hear for some rookie Latex user like me to figure out easier:

  \AtBeginSection{\frame{\tableofcontents[currentsection]}}

  \usepackage{bookmark}
  \usepackage{etoolbox}
  \makeatletter
  % save the current definition of \beamer@@frametitle
  \let\nobookmarkbeamer@@frametitle\beamer@@frametitle
  % then patch it to do the bookmarks and/or TOC entries
  % \apptocmd{\beamer@@frametitle}{%
  \apptocmd{\beamer@@frametitle}{%
  \only<1>{\bookmark[page=\the\c@page,level=3]{#1}}
  }%
  {\message{** patching of \string\beamer@@frametitle succeeded **}}%
  {\message{** patching of \string\beamer@@frametitle failed **}}%

  \pretocmd{\beamer@checknoslide}{%
    % ensure the bookmark is not created if the slide is filtered out
    \let\beamer@@frametitle\nobookmarkbeamer@@frametitle
    }%
    {\message{** patching of \string\beamer@checknoslide succeeded **}}%
    {\errmessage{** patching of \string\beamer@checknoslide failed **}}%

  \makeatother

And for those who use markdown pandoc:

header-includes: |
  ```{=latex}
  % add bookmark level 2 for PDF
  % from https://tex.stackexchange.com/questions/17230/beamer-how-to-make-each-frame-appear-in-the-pdf-toc

  \AtBeginSection{\frame{\tableofcontents[currentsection]}}

  \usepackage{bookmark}
  \usepackage{etoolbox}
  \makeatletter
  % save the current definition of \beamer@@frametitle
  \let\nobookmarkbeamer@@frametitle\beamer@@frametitle
  % then patch it to do the bookmarks and/or TOC entries
  % \apptocmd{\beamer@@frametitle}{%
  \apptocmd{\beamer@@frametitle}{%
  \only<1>{\bookmark[page=\the\c@page,level=3]{#1}}
  }%
  {\message{** patching of \string\beamer@@frametitle succeeded **}}%
  {\message{** patching of \string\beamer@@frametitle failed **}}%

  \pretocmd{\beamer@checknoslide}{%
    % ensure the bookmark is not created if the slide is filtered out
    \let\beamer@@frametitle\nobookmarkbeamer@@frametitle
    }%
    {\message{** patching of \string\beamer@checknoslide succeeded **}}%
    {\errmessage{** patching of \string\beamer@checknoslide failed **}}%

  \makeatother
  ```
1

Here is a variant of David Carlisle's answer obtained by using \pdfbookmark in place of \bookmark. The advantage here is that we do not need to \usepackage{bookmark}.

\makeatletter
\apptocmd{\beamer@@frametitle}{\only<1>{\pdfbookmark[3]{#1}{#1}}}
{\message{** patching of \string\beamer@@frametitle succeeded **}}
{\message{** patching of \string\beamer@@frametitle failed **}}
\makeatother