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).

  • 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}. – Marco Daniel 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. – Ashley Montanaro 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}
  • 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? – Ashley Montanaro Sep 22 '13 at 15:11
  • @AshleyMontanaro see update, now uses \only<2|handout:2> to force multiple slides in handout mode. – David Carlisle 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! – Ashley Montanaro 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}
  • 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) – David Carlisle Sep 23 '13 at 13:28
  • @David : Didn't know \@ifclasswith. Thanks, @David. – AlexG Sep 23 '13 at 13:52

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.