12

I am writing a Beamer presentation which includes an animation, created via the animateinline environment within the animate package. When I create a handout of my slides (by setting the handout option), I would like to have each frame of the animation displayed as a separate slide, preferably with no animation controls shown. Is there an easy way to do this that does not involve duplicating the code for the animation?

A minimal example showing what I want to achieve is:

\documentclass{beamer}
\usepackage{animate}
\usepackage{boolexpr}

\begin{document}

\begin{frame}
    \begin{center}
        \begin{animateinline}[controls]{1}
            \multiframe{2}{iStep=1+1}
            {
            \ifthenelse{\iStep=1}{Frame 1}{Frame 2}
            }
        \end{animateinline}
    \end{center}
\end{frame}

\end{document}

This gives an animation with two frames. What I would like is that, when I change the source to include the handout option to the beamer document class, each frame of the animation corresponds to a new slide in the handout (so the handout would have two slides).

3
  • 1
    Welcome to TeX.SX! Please add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}. Sep 17 '13 at 10:01
  • This will be a difficult task to accomplish. What about frame content around the animateinline environment? It would need to be repeated on each handout page. What if there is another animateinline in the same frame with a different number of animation frames?
    – AlexG
    Sep 19 '13 at 13:26
  • 1
    Thanks. This is a shame as I feel this would be a fairly standard task for people producing slides with animations. Sep 19 '13 at 15:46
6
+50

enter image description here

This disables the animateinline environment, and modifies the \multiframe loop so that it does

\only<2|handout:2>{.....}

with the loop counter being used in <...> so beamer does its normal stuff and makes a slide corresponding to each frame of the iteration. (only the two lines marked XXX are modified.

The handout specification is needed to force it to use multiple slides in handout mode.

\documentclass
%[handout]
{beamer}


\usepackage{animate}
\usepackage{boolexpr}

\makeatletter
\def\animateinline[#1]#2{%
\@anim@insidetrue
}
\def\endanimateinline{}


\renewcommand{\multiframe}[3]{% #1: #repetitions, #2: vars, #3: frame content
  \unskip%
  \if@anim@inside\else%
    \PackageError{animate}{%
      \protect\multiframe\space cannot be used outside `animateinline'%
      \MessageBreak environment%
    }{}%
  \fi%
  \if@anim@insidemulti%
    \PackageError{animate}{\protect\multiframe\space cannot be nested}{}%
  \fi%
  \setboolean{@anim@insidemulti}{true}%
  %reset macro for updating variables
  \gdef\@anim@updatevars{}%
  %reset loop counter
  \global\@anim@mulframecnt=\z@%
  %remove spaces from variable declaration list (2nd arg)
  \xdef\@anim@vardecls{#2\space}%
  \xdef\@anim@vardecls{\expandafter\zap@space\@anim@vardecls\@empty}%
  \ifnum#1<\z@%
    \PackageError{animate}{%
      \protect\multiframe: first argument must be greater than zero%
    }{}%
  \fi%
  %parse list of variable declarations and build macro for updating them
  \expandafter\@anim@parsevars\@anim@vardecls,\@nil%
  \whiledo{\@anim@mulframecnt<#1}{%
    \ifnum\@anim@mulframecnt>\z@%
    % \newframe% don't do this XXX
      \@anim@updatevars% update variables
    \fi%
    \global\advance\@anim@mulframecnt by \@ne%
    \ignorespaces%
    \only<\the\@anim@mulframecnt|handout:\the\@anim@mulframecnt>{#3}% execute loop body( using \only<>) XXX
    \unskip%
  }%
  \setboolean{@anim@insidemulti}{false}%
  \ignorespaces%
}


\makeatother
\begin{document}


\begin{frame}
    \begin{center}
        \begin{animateinline}[controls]{1}
            \multiframe{2}{iStep=1+1}
            {
            \ifthenelse{\iStep=1}{Frame 1}{Frame 2}
            }
        \end{animateinline}
    \end{center}
\end{frame}

\end{document}
4
  • Thanks very much! This seems to very nearly do what I want. However, it doesn't seem to work as expected when I pass the [handout] option to Beamer, i.e. begin with \documentclass[handout]{beamer}. In this setting, I see both animation frames displayed on one slide, i.e. "Frame 1 Frame 2". Any ideas? Sep 22 '13 at 15:11
  • @AshleyMontanaro see update, now uses \only<2|handout:2> to force multiple slides in handout mode. Sep 22 '13 at 15:35
  • Great, this now works perfectly for me and I'm sure it'll be useful for others too. Thanks! Sep 22 '13 at 17:03
  • @AshleyMontanaro: Well, before being generally useable, ordinary \newframes should as well work correctly in handout mode, that is to create overlays. Try \begin{animateinline}[controls]{1}Frame 1\newframe Frame 2\end{animateinline}.
    – AlexG
    Sep 23 '13 at 12:51
3

Here is a more generally usable solution (from an insider), because it works with embedded \newframes, scaling options, \animategraphics, timelines, ...

animate internal macros are only patched, if the class option handout option is actually set (making use of \@ifclasswith{beamer}{handout}{.... }{} thanks to David Carlisle):

\documentclass
[handout]
{beamer}

\usepackage{animate}

\makeatletter
\newcount\@currentframe

\@ifclasswith{beamer}{handout}{
  %non-interactive Widget annotation, representing one frame of the animation
  \ifpdf
    \def\@anim@makeframe#1#2{% #1:@anim@num, #2:@anim@curframe@zb
      %container XObject for all transparencies that compose the frame
      \begingroup%
      \setlength{\unitlength}{1pt}%
        \global\setbox\@anim@box=\hbox{%
          \pdfliteral{q}%
          \begin{picture}(\@anim@framewidth,\@anim@frametotalheight)%
          \end{picture}%
          \pdfliteral{Q\@anim@getkeyval{frmcontent@#2}}%
        }%
      \endgroup%
      \immediate\pdfxform resources {%
        /XObject <<\@anim@getkeyval{frmxobject@#2}>>}\@anim@box%
      \if@anim@useocg%
        \@anim@newocg{#1}{#2}%
        \ifx\@anim@poster\@anim@posterlast%
          \@anim@keytoaux{a#1.poster}{#2}%
          \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{}{%
            \xdef\@anim@offocgs{\@anim@offocgs\space\@anim@curocg}%
          }%
        \else%
          \ifnum#2=\z@%
            \ifx\@anim@poster\@anim@posternone%
              \xdef\@anim@offocgs{\@anim@offocgs\space\@anim@curocg}%
            \fi%
          \else%
            \xdef\@anim@offocgs{\@anim@offocgs\space\@anim@curocg}%
          \fi%
        \fi%
        \def\@anim@annotflag{/F 4}%, print, visibility set by OCG
      \else%
        %widget visibility state
        \def\@anim@annotflag{/F 4}%, print, visibility set by OCG
        \ifx\@anim@poster\@anim@posternone\else%
          \ifnum#2=\z@%
            \ifx\@anim@poster\@anim@posterfirst%
              \def\@anim@annotflag{/F 4}% visible, print
            \fi%
          \fi%
          \ifx\@anim@poster\@anim@posterlast%
            \@anim@keytoaux{a#1.poster}{#2}%
            \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{%
              \def\@anim@annotflag{/F 4}%
            }{}%
          \fi%
        \fi%
      \fi%
      %frame widget, using the container XObject as its Appearance
      \pdfannot
        width \@anim@animwidth\p@ height \@anim@animheight\p@
        depth \@anim@animdepth\p@
      {%
        /Subtype/Widget%
        \@anim@annotflag
        \if@anim@useocg%
          /OC \@anim@curocg %associate widget with the just created OCG
        \fi%
        /FT/Btn/Ff 65537% non-interactive push button
        /BS <</W 0>>%
        /AP <</N \the\pdflastxform\space 0 R>>%
        /T (#1.#2)%
      }%
      %\xdef\@anim@fields{\@anim@fields\space\the\pdflastannot\space 0 R}%
    }
  \else
    \if@anim@@dvipdfmx
      \def\@anim@makeframe#1#2{%
        %container XObject
        \global\setbox\@anim@box=\hbox{%
          \special{pdf:content \@anim@getkeyval{frmcontent@#2}}%
        }%
        \special{pdf:bxobj @anim@anmfrm@#1@#2 width \@anim@framewidth pt
          height \@anim@frameheight pt depth \@anim@framedepth pt}%
        \begin{picture}(0,0)\put(0,0){\box\@anim@box}\end{picture}%
        \special{pdf:put @resources <<
          /XObject <<\@anim@getkeyval{frmxobject@#2}>>%
        >>}%
        \special{pdf:exobj}%
        \if@anim@useocg%
          \@anim@newocg{#1}{#2}%
          \ifx\@anim@poster\@anim@posterlast%
            \@anim@keytoaux{a#1.poster}{#2}%
            \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{}{%
              \special{pdf:put @anim@offocgs @anim@ocg@#1@#2}%
            }%
          \else%
            \ifnum#2=\z@%
              \ifx\@anim@poster\@anim@posternone%
                \special{pdf:put @anim@offocgs @anim@ocg@#1@#2}%
              \fi%
            \else%
              \special{pdf:put @anim@offocgs @anim@ocg@#1@#2}%
            \fi%
          \fi%
          \def\@anim@annotflag{/F 4}%
        \else%
          \def\@anim@annotflag{/F 4}%
          \ifx\@anim@poster\@anim@posternone\else%
            \ifnum#2=\z@%
              \ifx\@anim@poster\@anim@posterfirst%
                \def\@anim@annotflag{/F 4}%
              \fi%
            \fi%
            \ifx\@anim@poster\@anim@posterlast%
              \@anim@keytoaux{a#1.poster}{#2}%
              \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{%
                \def\@anim@annotflag{/F 4}%
              }{}%
            \fi%
          \fi%
        \fi%
        %frame widget
        \special{pdf:annot @annot@\the\@anim@fieldnum\space
          width \@anim@animwidth pt height \@anim@animheight pt
          depth \@anim@animdepth pt <<%
            /Subtype/Widget%
            \@anim@annotflag
            \if@anim@useocg/OC @anim@ocg@#1@#2\fi%
            /FT/Btn/Ff 65537%
            /BS <</W 0>>%
            /AP <</N @anim@anmfrm@#1@#2>>%
            /T (#1.#2)%
          >>%
        }%
        %\special{pdf:put @anim@fields @annot@\the\@anim@fieldnum}%
        \global\advance\@anim@fieldnum by \@ne%
      }
    \else
      \def\@anim@makeframe#1#2{%
        %container XObject
        \special{ps:
          mark  /_objdef {@anim@anmfrm@#1@#2} /type/stream /OBJ pdfmark
          mark {@anim@anmfrm@#1@#2} (\@anim@getkeyval{frmcontent@#2}) /PUT
            pdfmark
          mark {@anim@anmfrm@#1@#2} <<
            /Type/XObject/Subtype/Form/FormType 1
            /BBox [frame@llx frame@lly frame@urx frame@ury]
            /Resources <</XObject <<\@anim@getkeyval{frmxobject@#2}>>>>
          >> /PUT pdfmark
        }%
        \if@anim@useocg%
          \@anim@newocg{#1}{#2}%
          \ifx\@anim@poster\@anim@posterlast%
            \@anim@keytoaux{a#1.poster}{#2}%
            \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{}{%
              \special{ps: mark {@anim@offocgs} {@anim@ocg@#1@#2} /APPEND pdfmark}%
            }%
          \else%
            \ifnum#2=\z@%
              \ifx\@anim@poster\@anim@posternone%
                \special{ps: mark {@anim@offocgs} {@anim@ocg@#1@#2} /APPEND pdfmark}%
              \fi%
            \else%
              \special{ps: mark {@anim@offocgs} {@anim@ocg@#1@#2} /APPEND pdfmark}%
            \fi%
          \fi%
          \def\@anim@annotflag{/F 4}%
        \else%
          \def\@anim@annotflag{/F 4}%
          \ifx\@anim@poster\@anim@posternone\else%
            \ifnum#2=\z@%
              \ifx\@anim@poster\@anim@posterfirst%
                \def\@anim@annotflag{/F 4}%
              \fi%
            \fi%
            \ifx\@anim@poster\@anim@posterlast%
              \@anim@keytoaux{a#1.poster}{#2}%
              \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{%
                \def\@anim@annotflag{/F 4}%
              }{}%
            \fi%
          \fi%
        \fi%
        %frame widget
        \begingroup%
          \setlength{\unitlength}{1pt}%
          \begin{picture}(0,0)% mark annotation rectangle
            \put(0,-\@anim@animdepth){%
            \special{ps:
              currentpoint /wid@lly exch def /wid@llx exch def
            }%
          }%
          \put(\@anim@animwidth,\@anim@animheight){%
            \special{ps:
              currentpoint /wid@ury exch def /wid@urx exch def
            }%
          }%
          \end{picture}%
        \endgroup%
        \special{ps:
          mark
            /_objdef {annot@\the\@anim@fieldnum}%
            /Rect [wid@llx wid@lly wid@urx wid@ury]%
            /Subtype/Widget%
            \@anim@annotflag
            \if@anim@useocg/OC {@anim@ocg@#1@#2}\fi%
            /FT/Btn/Ff 65537
            /BS <</W 0>>%
            /AP <</N {@anim@anmfrm@#1@#2}>>%
            /T (#1.#2)%
          /ANN pdfmark
          %mark {\@anim@fields} {annot@\the\@anim@fieldnum} /APPEND pdfmark
        }%
        \global\advance\@anim@fieldnum by \@ne%
      }
    \fi
  \fi
  \let\@anim@makeframe@orig\@anim@makeframe
  \def\@anim@makeframe#1#2{% #1:@anim@num, #2:@anim@curframe@zb
    \@currentframe=#2\relax%
    \advance\@currentframe by \@ne%
    \only<\@currentframe|handout:\@currentframe>{\@anim@makeframe@orig{#1}{#2}}%
  }
  \def\@anim@animwidget#1{%
    \hbox to \@anim@animwidth\p@ {%
      \vrule width 0pt height \@anim@animheight\p@ depth \@anim@animdepth\p@%
      \hss%
    }%
  }%
  \def\@anim@insertwidgets#1#2{%#1:@anim@num, #2 existing btn colour combination
    \vtop{%
      \offinterlineskip%
      \hbox{\@anim@animwidget{#1}}%
      \if@anim@controls%
        \setlength{\@anim@tmpdima}{\@anim@btnsize}%
        \vskip 0.1\@anim@tmpdima%
        \hbox to \@anim@animwidth\p@ {%
          \hss\vrule width 0pt height \@anim@tmpdima depth 0pt\hss%
        }%
      \fi%
    }%
  }
}{}
\makeatother

\begin{document}

\begin{frame}
  \begin{center}
      \begin{animateinline}[controls,scale=2]{1}
          Frame 1
      \newframe
          Frame 2
      \newframe
      \multiframe{2}{iStep=3+1}{Frame \iStep}
      \newframe
          Frame 5
      \end{animateinline}
  \end{center}
\end{frame}
\end{document}
3
  • 1
    Ah thanks +1 I was just half looking at \newframe but this will save me bothering:-) I was going to suggest the code should be guarded with \@ifclasswith{beamer}{handout}{.... }{} which might be a bit clearer and saves running the options again) Sep 23 '13 at 13:28
  • @David : Didn't know \@ifclasswith. Thanks, @David.
    – AlexG
    Sep 23 '13 at 13:52
  • Is there any update that should be applied to this code? I tried it in Overleaf, with pdfLaTeX with many different Tex Live versions. I always got at least 30 errors (undefined control sequences, can't use blank space, etc) and my animation disappeared. Thanks in advance.
    – B. Dors
    Jun 2 '21 at 12:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.