% Copyright 2007--today Alexander Grahn % This material is subject to the LaTeX Project Public License. See % http://mirrors.ctan.org/macros/latex/base/lppl.txt % for the details of that license. % Package for creating portable, JavaScript driven animations from sets of % graphics files or inline graphics (e. g. LaTeX-picture, PSTricks, % pgf/TikZ, ...) % Supports LaTeX->dvips->ps2pdf, (Xe)LaTeX->(x)dvipdfmx, LuaLaTeX, % pdfLaTeX and LaTeX->dvisvgm workflows. \NeedsTeXFormat{LaTeX2e}[2022-06-01] \def\@anim@version{2023/06/18} \ProvidesPackage{animate} [\@anim@version\space PDF & SVG animations from files and inline graphics] \RequirePackage{ifthen} \RequirePackage{iftex} \RequirePackage{ifdraft} \RequirePackage{calc} %driver options (the only package options we process immediately) \newboolean{@anim@dvips} \newboolean{@anim@dvipdfmx} \newboolean{@anim@dvisvgm} \newboolean{@anim@xetex} \newboolean{@anim@export}%exporting animation frames \ExplSyntaxOn \DeclareKeys[anim@pkg]{ pdftex.code:n = {}, pdftex.value_forbidden:n = true, luatex.code:n = {}, luatex.value_forbidden:n = true, xetex.code:n = {}, xetex.value_forbidden:n = true, dvips.code:n = {}, dvips.value_forbidden:n = true, dvipdfmx.code:n = { \PassOptionsToPackage{dvipdfmx}{pdfbase} \PassOptionsToPackage{dvipdfmx}{ocgbase} \PassOptionsToPackage{dvipdfmx}{graphics} }, dvipdfmx.value_forbidden:n = true, dvisvgm.code:n = { \PassOptionsToPackage{dvisvgm}{pdfbase} \PassOptionsToPackage{dvisvgm}{graphics} }, dvisvgm.value_forbidden:n = true, export.legacy_if_gset:n = @anim@export, export.default:n = true, } \ExplSyntaxOff \DeclareUnknownKeyHandler[anim@pkg]{} \ProcessKeyOptions[anim@pkg] % remaining package options to be processed near end of this file \RequirePackage{pdfbase} \@ifpackagelater{pdfbase}{2022/08/04}{}{ \PackageError{animate}{% Support package `pdfbase.sty' too old.% }{% Please install an up to date version of `pdfbase.sty'.\MessageBreak% Aborting.% }% } \ifpdf\else \setboolean{@anim@dvips}{true}% default dvi mode \fi \ExplSyntaxOn \bool_if:NT\g_pbs_dvipdfmx_bool{ \setboolean{@anim@dvipdfmx}{true} \setboolean{@anim@dvips}{false} } \bool_if:NT\g_pbs_dvisvgm_bool{ \setboolean{@anim@dvisvgm}{true} \setboolean{@anim@dvips}{false} } \sys_if_engine_xetex:T{ \bool_if:NT\g_pbs_dvipdfmx_bool{\setboolean{@anim@xetex}{true}} \setboolean{@anim@dvips}{false} } \ExplSyntaxOff \RequirePackage{graphics}%\scalebox, \resizebox, \rotatebox \RequirePackage{zref-abspage} \newboolean{@anim@insideexport} \newenvironment{anim@export}{% \global\@anim@insideexporttrue% }{% \global\@anim@insideexportfalse% } % get number of pages in file given as #1 (file basename); #2 extension; % store result into macro given as #3 \ifpdf %pdflatex/lualatex \def\@anim@getpagecount#1#2#3{% \pdfximage page 1 {#1.#2}\xdef#3{\the\pdflastximagepages}% } \else \if@anim@xetex \def\@anim@getpagecount#1#2#3{% \xdef#3{\the\numexpr\XeTeXpdfpagecount "#1.#2"\relax}% } \else \if@anim@dvips \def\@anim@getpagecount#1#2#3{\gdef#3{1}}% \else %dvipdfmx, dvisvgm \def\@anim@getpagecount#1#2#3{{% \global\let#3\@undefined% \def\%##1: ##2:{% \expandafter\edef\csname ##1\endcsname{##2}% \global\let#3\Pages% }% \endlinechar`\:% `:' appended to every line read \IfFileExists{#1.xbb}{% %read from xbb file {\catcode`\:=12\catcode`\%=0\sbox0{\input{#1.xbb}}}% \ifdefined#3\else% \PackageError{animate}{% Cannot read number of pages from file\MessageBreak% -------------------------------------\MessageBreak% #1.xbb\MessageBreak% -------------------------------------\MessageBreak% This file seems to be invalid and should be deleted% }{}% \fi% }{% %read from command pipe (`extractbb') %firstly, check whether reading from pipe is allowed \immediate\closein\@inputcheck% \immediate\openin\@inputcheck="|extractbb -h"\relax% \ifeof\@inputcheck% \immediate\closein\@inputcheck% \PackageError{animate}{% Cannot determine number of pages in file\MessageBreak% ----------------------------------------\MessageBreak% #1.#2\MessageBreak% ----------------------------------------\MessageBreak% Try --shell-escape option (--enable-pipes in MiKTeX),% \MessageBreak or run\MessageBreak% \space\space extractbb #1.#2\MessageBreak% on the command line to provide a valid `xbb' file% }{}% \else% \immediate\closein\@inputcheck% {\catcode`\:=12\catcode`\%=0\sbox0{\@@input "|extractbb -O #1.#2"}}% \fi% }% }} \fi \fi \fi \if@anim@dvisvgm \setboolean{@anim@export}{false} \fi \if@anim@export \@ifclassloaded{standalone}{}{ \PackageError{animate}{% Option `export' requires the `standalone' document class.\MessageBreak% Replace current document class with `standalone'% }{% Put the line\MessageBreak% `\protect\documentclass{standalone}'\MessageBreak% at the beginning of the document preamble.% }% }% \standaloneenv{anim@export} \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % low level PDF/SVG operations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ExplSyntaxOn \let\@anim@literal\pbs_literal:nn \def\@anim@xform#1#2#3#4#5{ \pbs_pdfxform:nnnnn{#1}{#2}{#3}{#4}{#5} \xdef\@anim@lastxform{\pbs_pdflastxform:} } \let\@anim@refxform\pbs_pdfrefxform:n \def\@anim@annot#1#2#3#4{ \pbs_pdfannot:nnnn{#1}{#2}{#3}{#4} } \let\@anim@fpeval\fp_eval:n %hashing object references of embedded files to avoid multiple inclusion \let\@anim@pdfmdfivesum\file_mdfive_hash:n \ExplSyntaxOff \if@anim@dvisvgm \def\@anim@updatebbox#1#2#3{\special{dvisvgm:bbox #1 #2 #3 transform}} %approach similar to OCGs, that is, putting the frame content in an svg group, % ..., whose visibility is then manipulated by JavaScript \def\@anim@newocg#1#2{\xdef\@anim@curocg{id='_#1.#2' class='ocg'}} \def\ocgbase@add@to@off@list#1{% \xdef\@anim@curocg{\@anim@curocg\space visibility='hidden'}% } \def\ocgbase@oc@bdc#1{\special{dvisvgm:raw }} \def\ocgbase@oc@emc{\special{dvisvgm:raw }} \else \ExplSyntaxOn \def\@anim@dictobj#1{ \pbs_pdfobj:nnn{}{dict}{#1} \xdef\@anim@lastobj{\pbs_pdflastobj:} } \def\@anim@arrayobj#1{ \pbs_pdfobj:nnn{}{array}{#1} \xdef\@anim@lastobj{\pbs_pdflastobj:} } \def\@anim@streamobj#1#2{ \pbs_pdfobj:nnn{}{stream}{{#1}{#2}} \xdef\@anim@lastobj{\pbs_pdflastobj:} } \def\@anim@widget#1#2#3#4{ \pbs_pdfannot:nnnn{#1}{#2}{#3}{#4} \pbs_appendtofields:n{\pbs_pdflastann:} } \ExplSyntaxOff \RequirePackage{ocgbase} %OCG generating and configuration macros \def\@anim@newocg#1#2{%#1:@anim@num, #2:@anim@curframe@zb \ocgbase@new@ocg{#1.#2}{}{1}% \xdef\@anim@curocg{\ocgbase@last@ocg}% } \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %creating and using global definitions \def\@anim@newkey#1#2{{\expandafter\xdef\csname#1\endcsname{#2}}} \def\@anim@getkeyval#1{\ifcsname#1\endcsname\csname#1\endcsname\fi} \def\@animate@rerunwarn{% \ifcsname @anim@rerunwarned\endcsname\else% \gdef\@anim@rerunwarned{}% \PackageWarningNoLine{animate}{% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak @ Rerun to get internal references right! @\MessageBreak @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}% \fi% } %macro for writing global defs to external *.aux file \def\@anim@keytoaux#1#2{% \immediate\write\@mainaux{\string\@anim@newkey{#1}{#2}}% \ifthenelse{\equal{\@anim@getkeyval{#1}}{#2}}{}{% \AtEndDocument{\@animate@rerunwarn}}% } \AtBeginDocument{% \immediate\write\@mainaux{\string\providecommand\string\@anim@newkey[2]{}}% } %missing package error message \newcommand{\@anim@missing}[2][]{% \ifthenelse{\equal{#1}{}}{% \def\@anim@pkgopt{}% }{% \def\@anim@pkgopt{[#1]}% }% \PackageError{animate}{% Package `#2' required. Put the line\MessageBreak% `\protect\usepackage\@anim@pkgopt{#2}'\MessageBreak% to the preamble of your document% }{}% } \newboolean{@anim@grxloaded} \setboolean{@anim@grxloaded}{false} \AtBeginDocument{% \@ifpackageloaded{graphicx}{\setboolean{@anim@grxloaded}{true}}{}% \gdef\@anim@lscape{}% \gdef\@anim@@lscape{:ls}% \ifdefined\landscape% \g@addto@macro{\landscape}{\gdef\@anim@lscape{:ls}}% \g@addto@macro{\endlandscape}{\gdef\@anim@lscape{}}% \fi% } % true if any of `autoplay' or `autoresume' options is set \newboolean{@anim@autoplayorresume} % true if any of `controls' or `palindrome' or `label' options is set \newboolean{@anim@timeline} %true if `timeline' option is set \newboolean{@anim@multipage} % multipage document? \newboolean{@anim@nomouse} % animation widget to react on mouse events? \newbox\@anim@box %stores animation frames \newbox\@anim@measbox % for measuring purposes \newdimen\@anim@tmpdima %length registers for occasional use \newdimen\@anim@tmpdimb \def\@anim@firstofthree#1#2#3{#1} \def\@anim@secndofthree#1#2#3{#2} \def\@anim@thirdofthree#1#2#3{#3} %macros for recalling saved nat. dimensions \def\@anim@xformnatwd#1{\expandafter\@anim@firstofthree#1} \def\@anim@xformnatht#1{\expandafter\@anim@secndofthree#1} \def\@anim@xformnatdp#1{\expandafter\@anim@thirdofthree#1} %helper macro that typesets graphics file into savebox \if@anim@dvips \def\@anim@filebox#1#2#3#4{% dvips: no multi-page support \edef\@anim@curfile{[#3]{#1}}% \setbox#4=\hbox{% \expandafter\includegraphics\@anim@curfile}% } \else %pdfTeX, LuaTeX, dvipdfmx, xetex, dvisvgm \def\@anim@filebox#1#2#3#4{% \edef\@anim@curfile{[#3,page=#2]{#1}}% \setbox#4=\hbox{% \expandafter\includegraphics\@anim@curfile}% } \fi \def\@anim@checkboxsize#1#2{% #1: box number, #2: file \ifdim\wd#1=\z@% \PackageError{animate}{% Graphics to be used for first frame% \MessageBreak must not have zero width% }{% Check content of file #2% }% \fi% \ifdim\ht#1=\z@\ifdim\dp#1=\z@% \PackageError{animate}{% Graphics to be used for first frame% \MessageBreak must not have zero height% }{% Check content of file #2% }% \fi\fi% } %create Form XObject from graphics file \def\@anim@ximage#1#2#3#4#5{%#1:@anim@num, #2:@anim@curframe@zb, #3:filename, % #4: page number of multipage file, #5 graphicx inclusion options % fingerprint "..." % of external graphics to prevent re-embedding \edef\@anim@fingerprint{% \@anim@pdfmdfivesum{#3}.#4.#5% \if@anim@dvisvgm.\@anim@abspage\fi% }% \edef\@anim@curxform{\@anim@getkeyval{xform:\@anim@fingerprint}}% \ifthenelse{\equal{\@anim@curxform}{}}{% % new file \@anim@filebox{#3}{#4}{#5}{\@anim@box}% store file in a box \edef\@anim@natdims{{\the\wd\@anim@box}{\the\ht\@anim@box}{\the\dp\@anim@box}}% \@anim@xinline{#1}{#2}{\@anim@box}{newfile}% Form XObject creation \@anim@newkey{natdims:\@anim@lastxform}{\@anim@natdims}% \@anim@newkey{scaleddims:\@anim@lastxform}{% scaled dimensions {\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}% }% \@anim@newkey{xform:\@anim@fingerprint}{\@anim@lastxform}% }{% file known, re-using existing xform \edef\@anim@curndims{\@anim@getkeyval{scaleddims:\@anim@curxform}}% \setbox\@anim@box=\hbox to \@anim@xformnatwd{\@anim@curndims}{% \vrule width \z@ height \@anim@xformnatht{\@anim@curndims} depth \@anim@xformnatdp{\@anim@curndims}% \@anim@refxform{\@anim@curxform}% \hss% }% \@anim@xinline{#1}{#2}{\@anim@box}{\@anim@curxform}% }% } %creates Form XObject from box contents \def\@anim@xinline#1#2#3#4{% #1 anim num, #2 frame num, #3 box num, #4 status ( \edef\@anim@curwd{\the\wd#3}% `newfile', xform ref of known file or `inline') \edef\@anim@curht{\the\ht#3}% \edef\@anim@curdp{\the\dp#3}% % measure 0th frame, to determine final animation widget dims \ifnum#2=\z@\relax% \ifthenelse{\equal{#4}{newfile}\OR\equal{#4}{inline}}{% \setbox\@anim@measbox=\hbox to \wd#3{% \vrule width \z@ height \ht#3 depth \dp#3\hss}% }{% known file \edef\@anim@curndims{\@anim@getkeyval{natdims:#4}}% \setbox\@anim@measbox=\hbox to \@anim@xformnatwd{\@anim@curndims}{% \vrule width \z@ height \@anim@xformnatht{\@anim@curndims} depth \@anim@xformnatdp{\@anim@curndims}% \hss% }% }% \@anim@scale{\@anim@measbox}% \if@anim@dvisvgm% for clipping purposes \@anim@keytoaux{a#1.wdbp}{\strip@pt\dimexpr0.996264\dimexpr\@anim@animwidth}% \@anim@keytoaux{a#1.htbp}{\strip@pt\dimexpr0.996264\dimexpr\@anim@animheight}% \@anim@keytoaux{a#1.thtbp}{\strip@pt\dimexpr0.996264\dimexpr\@anim@animtotalheight}% \fi% \fi% \def\@anim@needresize{0}% % test if content dimensions differ from those of the final widget \ifdim\@anim@curwd=\@anim@animwidth\else\def\@anim@needresize{1}\fi% \ifdim\@anim@curht=\@anim@animheight\else\def\@anim@needresize{1}\fi% \ifdim\@anim@curdp=\@anim@animdepth\else\def\@anim@needresize{1}\fi% % resize content to final dimensions, if necessary \ifnum\@anim@needresize>\z@\relax% \setbox#3=\hbox{\resizebox{\@anim@animwidth}{\@anim@animheight}{\box#3}}% \fi% \ifthenelse{\equal{#4}{newfile}\OR\equal{#4}{inline}}{% \@anim@xform{1}{1}{}{}{#3}% %keep a record of XObject number \@anim@newkey{img@#2}{\@anim@lastxform}% }{% %known file \ifnum\@anim@needresize>\z@% \@anim@xform{0}{1}{}{}{#3}% \@anim@newkey{img@#2}{\@anim@lastxform}% \else% \@anim@newkey{img@#2}{#4}% \fi% }% \message{}% } \def\@anim@refxformlist#1,#2\@nil{% \ifthenelse{\equal{#1}{}}{}{% \if@anim@dvips% \@anim@refxform{{#1}}% \else% \@anim@refxform{#1}% \fi% }% \ifthenelse{\equal{#2}{}}{}{\@anim@refxformlist#2\@nil}% } % this counts the length of a clist ,,,..., (note the % trailing comma) \def\@anim@countxformlist#1{% \expandafter\@anim@@countxformlist\expandafter0\expandafter:#1,\@nil% } \def\@anim@@countxformlist#1:#2,#3\@nil{% \ifx\relax#2\relax% \the\numexpr#1% \else% \ifx\relax#3\relax% \the\numexpr#1% \else% \expandafter\@anim@@countxformlist\the\numexpr #1+1:#3\@nil% \fi% \fi% } \def\@anim@zaptrailingcommafromxref#1,\@nil{\if@anim@dvips{#1}\else#1\fi}% % inserts one animation frame into the output acc. to \ifcase\@anim@method % as a non-interactive Widget annotation (0 or 1) or as an xform (2) that is % referenced in the page content (and tagged as OCG or for multipage PDF export) % args: #1 animation num, #2 frame number, #3 comma-separated list of xform % refs (transparencies) \def\@anim@makeframe#1#2#3{% \edef\@anim@arg{#3}% \setboolean{@anim@singleref}{false}\def\@anim@framexform{}% % count number of xforms in the frame content; a single xform can be referenced % at once, while a transparency list (multiple, overlayed xforms) must be boxed % and nested in an additional xform \ifnum\@anim@countxformlist{\@anim@arg}=\@ne% \setboolean{@anim@singleref}{true}% \edef\@anim@framexform{\expandafter\@anim@zaptrailingcommafromxref\@anim@arg\@nil}% \fi% % however, this isn't possible on landscape pages with \@anim@method==0|1 % because frame content needs to be rotated by 90 deg counterclockwise \ifnum\@anim@method>\@ne\else\ifx\@anim@lscape\@anim@@lscape% \setboolean{@anim@singleref}{false}\def\@anim@framexform{}% \fi\fi% % ... nor if the animation is to be exported to multipage PDF \if@anim@export% \setboolean{@anim@singleref}{false}\def\@anim@framexform{}% \fi% % ... also, for method=ocg, we prefer packing content in an xform, as it allows % higher frame rates \ifnum\@anim@method=\tw@\if@anim@dvisvgm\else% \setboolean{@anim@singleref}{false}\def\@anim@framexform{}% \fi\fi% \if@anim@singleref\else% % put frame content in a box if necessary \setbox\@anim@box=\hbox to \@anim@animwidth{% \vrule width \z@ height \@anim@animheight depth \@anim@animdepth% \expandafter\@anim@refxformlist\@anim@arg,\@nil% \hss% }% % rotate content on lscape pages \ifnum\@anim@method>\@ne\else\ifx\@anim@lscape\@anim@@lscape% \setbox\@anim@box=\hbox{\rotatebox{90}{\box\@anim@box}}% \fi\fi% \fi% \ifcase\@anim@method% icon based \if@anim@singleref\else% \@anim@xform{0}{1}{}{}{\@anim@box}% \let\@anim@framexform\@anim@lastxform% \fi% %initial visibility \ifnum\@anim@poster>\@anim@mtwo\relax% insert poster frame \ifnum#2=\@anim@poster\relax% \let\@anim@posterap\@anim@framexform% \else% \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster \let\@anim@posterap\@anim@framexform% \fi% \fi% \fi% %insert (invisible) widget with current frame as appearance \@anim@widget{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{% /Subtype/Widget% /F 2% /FT/Btn/Ff 65537% /BS <>% /AP <>% /MK <>>>% /T (#1.#2)% }% \or% widget based %initial visibility \def\@anim@annotflag{/F 2}% default: hidden \ifnum\@anim@poster>\@anim@mtwo\relax% insert poster frame \ifnum#2=\@anim@poster\relax% \def\@anim@annotflag{/F 4}% not hidden + print (4) \else% \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster \ifthenelse{% \NOT\equal{\@anim@getkeyval{a#1.poster}}{}\AND% #2=\@anim@getkeyval{a#1.poster}% }{% \def\@anim@annotflag{/F 4}% }{}% \fi% \fi% \fi% %frame insertion \if@anim@singleref\else% \@anim@xform{0}{1}{}{}{\@anim@box}% \let\@anim@framexform\@anim@lastxform% \fi% \@anim@widget{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{% /Subtype/Widget% \@anim@annotflag% /FT/Btn/Ff 65537% /BS <>% /AP <>% /MK <>>>% /T (#1.#2)% }% \or% ocg-based (abused for dvisvgm backend as well as for % multipage PDF export) \if@anim@export% \if@anim@insideexport\else\anim@export\fi% \box\@anim@box% \endanim@export% \else% \@anim@newocg{#1}{#2}% %initial visibility \ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster \ifthenelse{% \NOT\equal{\@anim@getkeyval{a#1.poster}}{}\AND% #2=\@anim@getkeyval{a#1.poster}% }{}{% \ocgbase@add@to@off@list{\@anim@curocg}% }% \else% \ifnum#2=\@anim@poster\relax\else% \ocgbase@add@to@off@list{\@anim@curocg}% \fi% \fi% %frame insertion \if@anim@dvisvgm% \if@anim@singleref\else% \@anim@xform{0}{1}{}{}{\@anim@box}% \let\@anim@framexform\@anim@lastxform% \fi% % `marked content' method for dvisvgm \ocgbase@oc@bdc{\@anim@curocg}% \@anim@refxform{\@anim@framexform}% \ocgbase@oc@emc% \else% % /OC method for PDF output, higher frame rates than % with marked content (BDC/EMC) \@anim@xform{0}{1}{}{/OC \@anim@curocg}{\@anim@box}% \@anim@refxform{\@anim@lastxform}% \fi% \fi% \fi% } \newboolean{@anim@singleref} %create XObjects of all button faces \ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1 %dvips .OR. dvisvgm %stroking commands \def\@anim@btnend{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \ifx\empty\@anim@bg\empty\else gsave \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke % 1 setlinewidth 4.5 4.7 moveto 8.6 7.5 lineto 4.5 10.3 lineto stroke 0 setlinejoin 10.0 4.7 moveto 10.0 10.3 lineto stroke } \def\@anim@btnstep{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \ifx\empty\@anim@bg\empty\else gsave \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke % 1 setlinewidth 5.5 4.7 moveto 9.6 7.5 lineto 5.5 10.3 lineto stroke } \def\@anim@btnplay{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 0 1 moveto 14 1 14 6.5 2 arct 14 6.5 lineto 14 14 1 14 2 arct 0 14 lineto \ifx\empty\@anim@bg\empty\else gsave closepath \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke 0.1 setlinewidth 0 14 moveto 0 1 lineto stroke % 1 setlinewidth 5 4 moveto 5 11 lineto 10 7.5 lineto closepath stroke } \def\@anim@btnpause{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 0 1 moveto 14 1 14 6.5 2 arct 14 6.5 lineto 14 14 1 14 2 arct 0 14 lineto \ifx\empty\@anim@bg\empty\else gsave closepath \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke % 0 setlinecap 2 setlinewidth 2.2 4 moveto 2.2 11 lineto stroke } \def\@anim@btnminus{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \ifx\empty\@anim@bg\empty\else gsave \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke % 1.0 setlinewidth 0 setlinecap 4.7 7.5 moveto 10.3 7.5 lineto stroke } \def\@anim@btnplus{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \ifx\empty\@anim@bg\empty\else gsave \@anim@bg\space bgfill grestore \fi \@anim@fg\space stroke % 1.0 setlinewidth 0 setlinecap 4.7 7.5 moveto 10.3 7.5 lineto 7.5 4.7 moveto 7.5 10.3 lineto stroke } \def\@anim@btnresetbg{% Reset-button background for dvisvgm 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \@anim@bg\space fill } \def\@anim@btnreset{% 0.5 setlinewidth 1 setlinecap 1 setlinejoin 6.5 1 moveto 1 1 1 6.5 2 arct 1 6.5 lineto 1 14 6.5 14 2 arct 6.5 14 lineto 14 14 14 6.5 2 arct 14 6.5 lineto 14 1 6.5 1 2 arct closepath \ifx\empty\@anim@bg\empty\else\if@anim@dvisvgm\else gsave \@anim@bg\space bgfill grestore \fi\fi \@anim@fg\space stroke % 1 setlinewidth 7.5 4.7 moveto 7.5 10.3 lineto stroke 0 setlinejoin 3.5 5 moveto 7 7.5 lineto 3.5 10 lineto closepath fill 11.5 5 moveto 8 7.5 lineto 11.5 10 lineto closepath fill 1 setlinewidth 2 setlinecap 3 7.5 moveto 3.5 7.5 lineto 12 7.5 moveto 11.5 7.5 lineto stroke } \def\@anim@makebutton#1#2{% #1: name ; #2:current colour, alpha, ... \edef\@anim@arg{#1}% \ifx\@anim@EndLeft\@anim@arg% \@anim@xbutton{EndLeft}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% [-1 0 0 1 15 0] concat \@anim@btnend}{#2}% \fi% \ifx\@anim@EndRight\@anim@arg% \@anim@xbutton{EndRight}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% \@anim@btnend}{#2}% \fi% \ifx\@anim@Minus\@anim@arg% \@anim@xbutton{Minus}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% \@anim@btnminus}{#2}% \fi% \ifx\@anim@PauseLeft\@anim@arg% \@anim@xbutton{PauseLeft}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% [-1 0 0 1 15 0] concat \@anim@btnpause}{#2}% \fi% \ifx\@anim@PauseRight\@anim@arg% \@anim@xbutton{PauseRight}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% \@anim@btnpause}{#2}% \fi% \ifx\@anim@PlayLeft\@anim@arg% \@anim@xbutton{PlayLeft}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% [-1 0 0 1 15 0] concat \@anim@btnplay}{#2}% \fi% \ifx\@anim@PlayRight\@anim@arg% \@anim@xbutton{PlayRight}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% \@anim@btnplay}{#2}% \fi% \ifx\@anim@Plus\@anim@arg% \@anim@xbutton{Plus}{\@anim@btnplus}{#2}% \fi% \ifx\@anim@Reset\@anim@arg% \if@anim@dvisvgm% Reset btn has filled foreground parts. In dvisvgm, for % filling and setting transparency correctly, BG and FG are treated % separately. \ifcsname btn#1:#2\endcsname\else% \ifx\empty\@anim@bg\empty\else% \@anim@xbutton{ResetBG}{\@anim@btnresetbg}{#2}% \fi% \begingroup% \def\@anim@alpha{}% \@anim@xbutton{ResetFG}{\@anim@btnreset}{#2}% \endgroup% \ifx\empty\@anim@bg\empty\else% \setbox\@anim@box=\hbox to \@anim@btnsize {% \vbox to \@anim@btnsize {\vss% \@anim@refxform{\@anim@getkeyval{btnResetBG:#2}}% \@anim@refxform{\@anim@lastxform}% }\hss% }% \@anim@xform{0}{1}{}{}{\@anim@box}% \fi% \@anim@newkey{btn#1:#2}{\@anim@lastxform}% \fi% \else% \@anim@xbutton{Reset}{% \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% \@anim@btnreset}{#2}% \fi% \fi% \ifx\@anim@StepLeft\@anim@arg% \@anim@xbutton{StepLeft}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% [-1 0 0 1 15 0] concat \@anim@btnstep}{#2}% \fi% \ifx\@anim@StepRight\@anim@arg% \@anim@xbutton{StepRight}{% \if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi\fi% \@anim@btnstep}{#2}% \fi% } \def\@anim@xbutton#1#2#3{% #1: name; #2: stroking commands, % only create if button face doesn't exist yet \ifcsname btn#1:#3\endcsname\else% #3: current colour+alpha+ ... combination \setbox\@anim@box=\hbox to 15bp {\vbox to 15bp {\vss% \@anim@literal{}{% save \ifx\empty\@anim@alpha\empty% /bgfill {fill} bind def \else\if@anim@dvisvgm /bgfill {fill} bind def \else% /bgfill {% /.setfillconstantalpha where {% pop gsave \@anim@alpha\space .setfillconstantalpha fill 1 .setfillconstantalpha newpath fill grestore newpath% }{% /.setopacityalpha where {% pop gsave \@anim@alpha\space .setopacityalpha fill 1 .setopacityalpha newpath fill grestore newpath% }{% %Distiller gsave mark /ca \@anim@alpha\space/SetTransparency pdfmark fill mark /ca 1.0 /SetTransparency pdfmark newpath fill grestore newpath% } ifelse% } ifelse% } bind def \fi\fi% #2 restore% }% }\hss}% \if@anim@dvisvgm% \setbox\@anim@box=\hbox{% \resizebox*{!}{\@anim@btnsize}{\box\@anim@box}}% \fi% %distill box into XObject \@anim@xform{0}{1}{}{% \ifx\empty\@anim@alpha\empty\else\if@anim@dvisvgm% fill-opacity='\@anim@alpha'% \fi\fi% }{\@anim@box}% \@anim@newkey{btn#1:#3}{\@anim@lastxform}% \fi% } \else %pdftex/dvipdfmx/xetex %stroking commands \def\@anim@btnend{% 5 w 1 J 1 j \@anim@fg\space 65 10 m 30 10 l 18.957 10 10 18.957 10 30 c 10 120 l 10 131.043 18.957 140 30 140 c 120 140 l 131.043 140 140 131.043 140 120 c 140 30 l 140 18.957 131.043 10 120 10 c \ifx\empty\@anim@bg\empty s \else\@anim@bg\space b \fi % 10 w 45 47 m 86 75 l 45 103 l S 0 j 100 47 m 100 103 l S% } \def\@anim@btnstep{% 5 w 1 J 1 j \@anim@fg\space 65 10 m 30 10 l 18.957 10 10 18.957 10 30 c 10 120 l 10 131.043 18.957 140 30 140 c 120 140 l 131.043 140 140 131.043 140 120 c 140 30 l 140 18.957 131.043 10 120 10 c \ifx\empty\@anim@bg\empty s \else\@anim@bg\space b \fi % 10 w 55 47 m 96 75 l 55 103 l S% } \def\@anim@btnplay{% 5 w 1 J 1 j \@anim@fg\space 0 10 m 120 10 l 131.043 10 140 18.957 140 30 c 140 120 l 140 131.043 131.043 140 120 140 c 0 140 l \ifx\empty\@anim@bg\empty S \else\@anim@bg\space B \fi 1 w 0 140 m 0 10 l S % 10 w 50 40 m 50 110 l 100 75 l s% } \def\@anim@btnpause{% 5 w 1 J 1 j \@anim@fg\space 0 10 m 120 10 l 131.043 10 140 18.957 140 30 c 140 120 l 140 131.043 131.043 140 120 140 c 0 140 l \ifx\empty\@anim@bg\empty S \else\@anim@bg\space B \fi % 0 J 20 w 22 40 m 22 110 l S% } \def\@anim@btnminus{% 5 w 1 J 1 j \@anim@fg\space 65 10 m 30 10 l 18.957 10 10 18.957 10 30 c 10 120 l 10 131.043 18.957 140 30 140 c 120 140 l 131.043 140 140 131.043 140 120 c 140 30 l 140 18.957 131.043 10 120 10 c \ifx\empty\@anim@bg\empty s \else\@anim@bg\space b \fi % 10 w 0 J 47 75 m 103 75 l S% } \def\@anim@btnplus{% 5 w 1 J 1 j \@anim@fg\space 65 10 m 30 10 l 18.957 10 10 18.957 10 30 c 10 120 l 10 131.043 18.957 140 30 140 c 120 140 l 131.043 140 140 131.043 140 120 c 140 30 l 140 18.957 131.043 10 120 10 c \ifx\empty\@anim@bg\empty s \else\@anim@bg\space b \fi % 10 w 0 J 47 75 m 103 75 l 75 47 m 75 103 l S% } \def\@anim@btnreset{% 5 w 1 J 1 j \@anim@fg\space 65 10 m 30 10 l 18.957 10 10 18.957 10 30 c 10 120 l 10 131.043 18.957 140 30 140 c 120 140 l 131.043 140 140 131.043 140 120 c 140 30 l 140 18.957 131.043 10 120 10 c \ifx\empty\@anim@bg\empty s \else\@anim@bg\space b \fi % 10 w 75 47 m 75 103 l S \@anim@@@fg\space \ifx\empty\@anim@alpha\empty\else/R2 gs \fi 35 50 m 70 75 l 35 100 l f 115 50 m 80 75 l 115 100 l f 2 J 0 j 30 75 m 35 75 l 120 75 m 115 75 l S% } \def\@anim@makebutton#1#2{% #1: name ; #2: current colour, alpha, ... \edef\@anim@arg{#1}% \ifx\@anim@EndLeft\@anim@arg% \@anim@xbutton{EndLeft}{% q -0.1 0 0 0.1 15 0 cm \ifx\@anim@lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi% \@anim@btnend\space Q% }{#2}% \fi% \ifx\@anim@EndRight\@anim@arg% \@anim@xbutton{EndRight}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnend\space Q% }{#2}% \fi% \ifx\@anim@Minus\@anim@arg% \@anim@xbutton{Minus}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnminus\space Q% }{#2}% \fi% \ifx\@anim@PauseLeft\@anim@arg% \@anim@xbutton{PauseLeft}{% q -0.1 0 0 0.1 15 0 cm \ifx\@anim@lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi% \@anim@btnpause\space Q% }{#2}% \fi% \ifx\@anim@PauseRight\@anim@arg% \@anim@xbutton{PauseRight}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnpause\space Q% }{#2}% \fi% \ifx\@anim@PlayLeft\@anim@arg% \@anim@xbutton{PlayLeft}{% q -0.1 0 0 0.1 15 0 cm \ifx\@anim@lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi% \@anim@btnplay\space Q% }{#2}% \fi% \ifx\@anim@PlayRight\@anim@arg% \@anim@xbutton{PlayRight}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnplay\space Q% }{#2}% \fi% \ifx\@anim@Plus\@anim@arg% \@anim@xbutton{Plus}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnplus\space Q% }{#2}% \fi% \ifx\@anim@Reset\@anim@arg% \@anim@xbutton{Reset}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnreset\space Q% }{#2}% \fi% \ifx\@anim@StepLeft\@anim@arg% \@anim@xbutton{StepLeft}{% q -0.1 0 0 0.1 15 0 cm \ifx\@anim@lscape\@anim@@lscape 0 -1 -1 0 150 150 cm \fi% \@anim@btnstep\space Q% }{#2}% \fi% \ifx\@anim@StepRight\@anim@arg% \@anim@xbutton{StepRight}{% q 0.1 0 0 0.1 0 0 cm \ifx\@anim@lscape\@anim@@lscape 0 1 -1 0 150 0 cm \fi% \@anim@btnstep\space Q% }{#2}% \fi% } %XObject creation \def\@anim@xbutton#1#2#3{% #1 name, #2 stroking commands, #3 @anim@num \ifcsname btn#1:#3\endcsname\else% only create if button face doesn't% exist yet \edef\@anim@arg{#1}% \@anim@streamobj{% /Type/XObject/Subtype/Form/BBox [0 0 15 15]% \ifx\empty\@anim@alpha\empty\else% /Resources <<% /ExtGState <<% /R1 <>% \ifx\@anim@Reset\@anim@arg% /R2 <>% \fi% >>% >>% \fi% }{\ifx\empty\@anim@alpha\empty\else/R1 gs\fi\space #2}% \@anim@newkey{btn#1:#3}{\@anim@lastobj}% \fi% } \fi %determines file type of the sequence \def\zap@finalspace#1 \@nil{\unquote@name{#1}} \ifpdf \def\@anim@getpath#1#2{% #2: empty | user provided file extension \ifx\@empty#2\@empty% \gdef\@anim@ext{.pdf}% we start with `pdf' \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.mps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.png}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpeg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jp2}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.j2k}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpx}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% None of the files\MessageBreak% `#1.pdf',\MessageBreak% `#1.mps',\MessageBreak% `#1.png',\MessageBreak% `#1.jpg',\MessageBreak% `#1.jpeg',\MessageBreak% `#1.jp2',\MessageBreak% `#1.j2k' or\MessageBreak% `#1.jpx',\MessageBreak% could be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }}}}}}}}% \else% \gdef\@anim@ext{.#2}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% File `#1.#2' could not be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }% \fi% \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}% } \else \if@anim@dvipdfmx %XeLaTeX, dvipdfmx \def\@anim@getpath#1#2{% \ifx\@empty#2\@empty% \gdef\@anim@ext{.pdf}% we start with `pdf' \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.mps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.eps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.ps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.png}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpeg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.bmp}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% None of the files\MessageBreak% `#1.pdf',\MessageBreak% `#1.mps',\MessageBreak% `#1.eps',\MessageBreak% `#1.ps',\MessageBreak% `#1.png',\MessageBreak% `#1.jpg',\MessageBreak% `#1.jpeg' or\MessageBreak% `#1.bmp'\MessageBreak% could be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }}}}}}}}% \else% \gdef\@anim@ext{.#2}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% File `#1.#2' could not be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }% \fi% \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}% } \else \if@anim@dvisvgm \def\@anim@getpath#1#2{% \ifx\@empty#2\@empty% \gdef\@anim@ext{.pdf}% we start with `pdf' \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.eps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.ps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.mps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.svg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.png}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpg}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jpeg}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% None of the files\MessageBreak% `#1.pdf',\MessageBreak% `#1.eps',\MessageBreak% `#1.ps',\MessageBreak% `#1.mps',\MessageBreak% `#1.svg',\MessageBreak% `#1.png',\MessageBreak% `#1.jpg',\MessageBreak% `#1.jpeg' or\MessageBreak% could be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }}}}}}}}% \else% \gdef\@anim@ext{.#2}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% File `#1.#2' could not be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }% \fi% \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}% } \else %dvips \def\@anim@getpath#1#2{% \ifx\@empty#2\@empty% \gdef\@anim@ext{.eps}% we start with `eps' \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.mps}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.ps}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% None of the files\MessageBreak% `#1.eps',\MessageBreak% `#1.mps' or\MessageBreak% `#1.ps'\MessageBreak% could be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }}}% \else% \gdef\@anim@ext{.#2}% \IfFileExists{#1\@anim@ext}{}{% \PackageError{animate}{% File `#1.#2' could not be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }% \fi% \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}% } \fi \fi \fi %counts embedded animations \newcount\@anim@num\@anim@num=\z@% %current frame \newcount\@anim@curframe \newcount\@anim@curframe@zb %zero based %draftbox \def\@anim@draftbox{% \begingroup% \vtop{% draw boxes \offinterlineskip% \hbox{\raisebox{-\@anim@animdepth}{% \frame{% \rule{\z@}{\@anim@animtotalheight}\hskip\@anim@animwidth% }% }}% \if@anim@controls% \setlength{\@anim@tmpdima}{\@anim@btnsize}% \setlength{\@anim@tmpdimb}{\z@}% \vskip 0.1\@anim@tmpdima% \hbox to \@anim@animwidth {% \if@anim@ctrlleft\hspace{\@anim@ctrlsindent}\fi% \ifnum\if@anim@ctrlright\@ne\else% \if@anim@ctrlcentre\@ne\else\z@\fi\fi=\@ne\hss\fi% \setboolean{@anim@controls@firstgrp}{false}% \if@anim@controls@stop% \setboolean{@anim@controls@firstgrp}{true}% \addtolength{\@anim@tmpdimb}{2\@anim@tmpdima}% \fi% \if@anim@controls@step% \setboolean{@anim@controls@firstgrp}{true}% \addtolength{\@anim@tmpdimb}{2\@anim@tmpdima}% \fi% \if@anim@controls@play% \setboolean{@anim@controls@firstgrp}{true}% \addtolength{\@anim@tmpdimb}{2\@anim@tmpdima}% \fi% \if@anim@controls@firstgrp% \frame{\phantom{\rule{\@anim@tmpdimb}{\@anim@tmpdima}}}% \fi% \if@anim@controls@speed% \if@anim@controls@firstgrp\hskip 0.3\@anim@tmpdima\fi% \frame{\phantom{\rule{3\@anim@tmpdima}{\@anim@tmpdima}}}% \fi% \ifnum\if@anim@ctrlleft\@ne\else% \if@anim@ctrlcentre\@ne\else\z@\fi\fi=\@ne\hss\fi% \if@anim@ctrlright\hspace{\@anim@ctrlsindent}\fi% }% \fi% }% \endgroup% } %detects multipage PDF and corrects user supplied page range \def\@anim@checkmultipage#1#2{% no multi-page support in dvips \setboolean{@anim@multipage}{false}}% \if@anim@dvips\else \def\@anim@checkmultipage#1#2{% #1: file base name, #2 user provided file ext \ifx\@empty#2\@empty% \IfFileExists{#1.pdf}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.pdf}% }{}% \else% \IfFileExists{#1.#2}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.#2}% }{}% \fi% \if@anim@multipage% \xdef\@anim@pathtofile{\expandafter\zap@finalspace\@filef@und\@nil}% \filename@parse{\@anim@pathtofile}% \@anim@getpagecount{\filename@area\filename@base}{\filename@ext}{% \@anim@lastpage% }% \ifdefined\@anim@lastpage\else% double check multipage support \setboolean{@anim@multipage}{false}% \fi% \fi% \if@anim@multipage% %we need it zero-based \edef\@anim@lastpage{\the\numexpr\@anim@lastpage-\@ne\relax}% \ifx\@anim@first\@empty% \gdef\@anim@first{0}% \else% \ifnum\@anim@first<\z@\relax\gdef\@anim@first{0}\fi% \ifnum\@anim@first>\@anim@lastpage\relax% \global\let\@anim@first\@anim@lastpage% \fi% \fi% \ifx\@anim@last\@empty% \global\let\@anim@last\@anim@lastpage% \else% \ifnum\@anim@last<\z@\relax\gdef\@anim@last{0}\fi% \ifnum\@anim@last>\@anim@lastpage\relax% \global\let\@anim@last\@anim@lastpage% \fi% \fi% \@anim@curframe=\@anim@first% \advance\@anim@curframe by \@ne% \xdef\@anim@first{\the\@anim@curframe}% \@anim@curframe=\@anim@last% \advance\@anim@curframe by \@ne% \xdef\@anim@last{\the\@anim@curframe}% \fi% }% \fi% %environment for setting LTR typesetting direction \def\@anim@beginLTR{% \ifdefined\textdir% LuaTeX \begingroup% \edef\@anim@curTxtDir{\the\textdir}% \textdir TLT\relax% \else% e-TeX based engines \ifnum\TeXXeTstate>\z@\beginL\fi% \fi% } \def\@anim@endLTR{% \ifdefined\textdir% \endgroup% \else% \ifnum\TeXXeTstate>\z@\endL\fi% \fi% } %user command for embedding animation sequence % #1: options % #2: frame rate (fps) % #3: basename of graphics file sequence (without frame number and extension) % #4: first frame (integer) % #5: last frame (integer) \newcommand{\animategraphics}[5][]{% \@anim@endsanitize% \if@anim@export\else\leavevmode\fi% \if@anim@grxloaded\else% \if@anim@dvipdfmx\if@anim@xetex% \@anim@missing{graphicx}\else% \@anim@missing[dvipdfmx]{graphicx}\fi% \else% \@anim@missing{graphicx}% \fi% \fi% \@anim@reset% to default settings \if@anim@dvisvgm% \special{dvisvgm:raw % }% \fi% \begingroup% \@anim@beginLTR% \ifcsname Ginput@path\endcsname% make use of graphic[xs] search path \let\input@path\Ginput@path% \fi% \SetKeys[anim@user]{#1}% %store current abs. page num in macro \@anim@abspage \if@anim@dvisvgm\if@anim@draft\else% \zref@labelbyprops{anim@abspage\the\@anim@num}{abspage}% \zref@def@extractdefault{\@anim@abspage}{% anim@abspage\the\@anim@num}{abspage}{-1}% \fi\fi% \ifx\empty\@anim@bg\empty\xdef\@anim@alpha{}\fi% \xdef\@anim@btnsize{\the\dimexpr\@anim@btnsize\relax}% %correct wrong option combination; totalheight overrides height \ifnum\@anim@resizeflags=3\relax% height+totalheight->totalheight \global\@anim@resizeflags=\@ne% \fi% \ifnum\@anim@resizeflags=7\relax% height+totalheight+width->totalheight+width \global\@anim@resizeflags=5% \fi% \ifx\@anim@bb\@empty\else\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi\@anim@bb}\fi% \ifx\@anim@viewport\@empty\else\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi\@anim@viewport}\fi% \ifx\@anim@trim\@empty\else\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi\@anim@trim}\fi% \ifx\@anim@angle\@empty\else\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi\@anim@angle}\fi% \if@anim@hiresbb\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi hiresbb}\fi% \if@anim@interpolate\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi interpolate}\fi% \ifx\@anim@pagebox\@empty\else\xdef\@anim@gropts{\@anim@gropts% \ifx\@anim@gropts\@empty\else,\fi\@anim@pagebox}\fi% \ifthenelse{\boolean{@anim@autoplay}\OR\boolean{@anim@autoresume}}{% \setboolean{@anim@autoplayorresume}{true}% }{}% \ifthenelse{\NOT\boolean{@anim@controls}\AND\boolean{@anim@step}}{% \setboolean{@anim@loop}{true}% }{}% \if@anim@step% %for stepping animations, ignore any `controls' settings except \setboolean{@anim@controls@play}{false}% `step' and `stop' \setboolean{@anim@controls@speed}{false}% \setboolean{@anim@controls}{false}% \if@anim@controls@stop\setboolean{@anim@controls}{true}\fi% \if@anim@controls@step\setboolean{@anim@controls}{true}\fi% \fi% \edef\@anim@base{#3}% \edef\@anim@first{#4}% \edef\@anim@last{#5}% \@anim@checkmultipage{\@anim@base}{\@anim@ftype}%test for multipage file \if@anim@multipage\else% cope with wrong user input \ifthenelse{\equal{#4}{}\OR\equal{#5}{}}{% \PackageError{animate}{% Missing frame number in \protect\animategraphics\space command% }{}% }{}% \ifthenelse{\@anim@first<\z@\OR\@anim@last<\z@}{% \PackageError{animate}{% Negative frame numbers not allowed% }{}% }{}% \fi% \def\@anim@relop{>}% \let\@anim@numtemplate\@anim@first% \ifnum\@anim@first>\@anim@last\relax% \edef\@anim@every{-\@anim@every}% \def\@anim@relop{<}% \let\@anim@numtemplate\@anim@last% \fi% \global\@anim@curframe=\@anim@first% \global\@anim@curframe@zb=\z@% \if@anim@export% \def\@anim@method{\tw@}% \setboolean{@anim@controls}{false}% \setboolean{@anim@draft}{false}% \fi% \if@anim@dvisvgm% \def\@anim@method{\tw@}% using ocg-like method for dvisvgm \fi% \if@anim@draft% \if@anim@multipage% %store file in a box \@anim@filebox{\@anim@pathtofile}{\@anim@first}{\@anim@gropts}{\@anim@box}% \else% %get file name extension \@anim@getpath{\@anim@base\@anim@first}{\@anim@ftype}% \@anim@filebox{\@anim@pathtofile}{1}{\@anim@gropts}{\@anim@box}% \fi% \@anim@scale{\@anim@box}% %draw draftbox according to dimensions of the first frame \@anim@draftbox% \else% \xdef\@anim@nfps{#2\space}% current frame rate \xdef\@anim@nfps{\expandafter\@anim@zap@space\@anim@nfps\@empty}% \ifdim\@anim@nfps pt<\z@% \PackageError{animate}{% Negative frame rate `\@anim@nfps' is not allowed% }{}% \fi% \global\let\@anim@fps\@anim@nfps% % \if@anim@export% \anim@export% \fi% %embed content (graphics sequence) \loop\ifnum\@anim@curframe\@anim@relop\@anim@last\relax\else% \if@anim@multipage% %embed graphics \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{% \@anim@pathtofile}{\the\@anim@curframe}{\@anim@gropts}% \else% %get path to current file end its extension \@anim@getpath{% \@anim@base\@anim@pad{\@anim@numtemplate}{\the\@anim@curframe}% }{\@anim@ftype}% %embed graphics \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{% \@anim@pathtofile}{1}{\@anim@gropts}% \fi% \global\advance\@anim@curframe by \@anim@every% \global\advance\@anim@curframe@zb by \@ne% \repeat% \xdef\@anim@frames{\the\@anim@curframe@zb}% total number \global\@anim@tmpcnt=\@anim@frames% \global\advance\@anim@tmpcnt by -\@ne% \xdef\@anim@maxframe{\the\@anim@tmpcnt}% highest frame index %make animation frames from embedded content ... \if@anim@dvisvgm\ifcsname a\the\@anim@num.htbp\endcsname% \@anim@beginsvgclip{\the\@anim@num}% \fi\fi% \if@anim@timeline% ... by building timeline (optional timeline file) \@anim@buildtmln{\the\@anim@num}% \else% ... or by direct insertion \global\@anim@curframe@zb=\z@% \whiledo{\@anim@curframe@zb<\@anim@frames}{% \@anim@makeframe{\the\@anim@num}{\the\@anim@curframe@zb}{% \@anim@getkeyval{img@\the\@anim@curframe@zb},% }% \global\advance\@anim@curframe@zb by \@ne% }% \fi% \if@anim@dvisvgm\ifcsname a\the\@anim@num.htbp\endcsname% \@anim@endsvgclip% \fi\fi% % if last frame used as poster, write frame num to aux file \ifnum\@anim@poster=\@anim@mone\relax% \@anim@keytoaux{a\the\@anim@num.poster}{\@anim@maxframe}% \fi% %insert animation widget & controls \if@anim@export\else% % insert $% % }% } \fi \endgroup \endinput