% 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}
\def\@anim@version{2020/08/29}
\ProvidesPackage{animate}
[\@anim@version\space PDF & SVG animations from files and inline graphics]
\RequirePackage{xkeyval}
\RequirePackage{ifthen}
\RequirePackage{iftex}
\RequirePackage{ifdraft}
\RequirePackage{calc}
%driver options (the only package options we process immediately)
\newboolean{@anim@dvips}
\setboolean{@anim@dvips}{false}
\newboolean{@anim@dvipdfmx}
\setboolean{@anim@dvipdfmx}{false}
\newboolean{@anim@dvisvgm}
\setboolean{@anim@dvisvgm}{false}
\ifpdf\else
\setboolean{@anim@dvips}{true}% default dvi mode
\setboolean{@anim@dvipdfmx}{false}
\DeclareOptionX{dvips}{%
\setboolean{@anim@dvips}{true}
\setboolean{@anim@dvipdfmx}{false}
}
\DeclareOptionX{dvipdfmx}{%
\setboolean{@anim@dvipdfmx}{true}
\setboolean{@anim@dvips}{false}
\PassOptionsToPackage{dvipdfmx}{pdfbase}
\PassOptionsToPackage{dvipdfmx}{graphics}
}
\DeclareOptionX{xetex}{%
\setboolean{@anim@dvipdfmx}{true}
\setboolean{@anim@dvips}{false}
\PassOptionsToPackage{xetex}{pdfbase}
}
\DeclareOptionX{dvisvgm}{%
\setboolean{@anim@dvisvgm}{true}
\setboolean{@anim@dvips}{false}
\PassOptionsToPackage{dvisvgm}{pdfbase}
\PassOptionsToPackage{dvisvgm}{graphics}
}
\fi
\newboolean{@anim@xetex}
\setboolean{@anim@xetex}{false}
\ifxetex
\setboolean{@anim@xetex}{true}
\setboolean{@anim@dvipdfmx}{true}
\setboolean{@anim@dvips}{false}
\fi
%exporting animation frames
\newboolean{@anim@export}
\setboolean{@anim@export}{false}
\newboolean{@anim@insideexport}
\setboolean{@anim@insideexport}{false}
\newenvironment{anim@export}{%
\global\@anim@insideexporttrue%
}{%
\global\@anim@insideexportfalse%
}
\DeclareOptionX{export}{\setboolean{@anim@export}{true}}
\DeclareOptionX*{}\ProcessOptionsX*\relax %allow anything as an option
%(remaining package options will be processed near end of this file)
\RequirePackage{graphics}%\scalebox, \resizebox, \rotatebox
\RequirePackage{zref-abspage}
% 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 `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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{pdfbase}
\@ifpackagelater{pdfbase}{2017/09/29}{}{
\PackageError{animate}{%
Support package `pdfbase.sty' too old.%
}{%
Please install an up to date version of `pdfbase.sty'.\MessageBreak%
Aborting.%
}%
}
\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
\ExplSyntaxOff
\if@anim@dvisvgm
\setboolean{@anim@export}{false}
\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 {?nl}}}
\def\ocgbase@oc@emc{\special{dvisvgm:raw {?nl}}}
\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:}
}
\let\@anim@pdfcatalog\pbs_pdfcatalog:n
\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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\pdfmdfivesum is used for hashing object references of embedded files based
%on their MD5 digest (in order to avoid multiple inclusion); if it is not
%available, hashing will be based on the file name
\ifluatex
\RequirePackage{pdftexcmds}
\let\@anim@pdfmdfivesum\pdf@filemdfivesum
\else
\ifcsname pdfmdfivesum\endcsname
\def\@anim@pdfmdfivesum#1{\pdfmdfivesum file {#1}}
\else
\ifcsname mdfivesum\endcsname
\def\@anim@pdfmdfivesum#1{\mdfivesum file {#1}}
\else
\def\@anim@pdfmdfivesum#1{#1}
\fi
\fi
\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{% dvips: no multi-page support
\edef\@anim@curfile{[\@anim@gropts]{#1}}%
\global\setbox\@anim@box=\hbox{%
\expandafter\includegraphics\@anim@curfile}%
}
\else
%pdfTeX, LuaTeX, dvipdfmx, xetex, dvisvgm
\def\@anim@filebox#1#2{%
\edef\@anim@curfile{[\@anim@gropts,page=#2]{#1}}%
\global\setbox\@anim@box=\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{%#1:@anim@num, #2:@anim@curframe@zb, #3:filename,
% #4: page number of multipage file
\if@anim@dvisvgm%
% with dvisvgm, final animation dims must be passed to includegraphics;
% otherwise, final bbox of the document may be wrong, in particular in the
% case of standalone animations with downscaled graphics
\ifnum#2=\z@\relax%
\@anim@filebox{#3}{#4}% store file in a box
\@anim@scale\@anim@box% get final dimensions of animation widget
%prevent later re-scaling
\gdef\@anim@widtharg{\width}%
\gdef\@anim@heightarg{\height}%
\gdef\@anim@totheightarg{\totalheight}%
\gdef\@anim@boxscale{\@ne}%
%append final dims to inclusion opts, also used for the remaining files
%of the current animation
\xdef\@anim@gropts{\@anim@gropts%
\ifx\@anim@gropts\@empty\else,\fi width=\@anim@animwidth%
,height=\@anim@animheight,totalheight=\@anim@animtotalheight}%
\fi%
\fi%
% fingerprint "..."
% of external graphics to prevent re-embedding
\edef\@anim@fingerprint{%
\@anim@pdfmdfivesum{#3}.#4.\@anim@gropts%
\if@anim@dvisvgm.\@anim@abspage\fi%
}%
\edef\@anim@curxform{\@anim@getkeyval{xform:\@anim@fingerprint}}%
\ifthenelse{\equal{\@anim@curxform}{}}{%
% new ".."
\@anim@filebox{#3}{#4}% store file in a box
\@anim@newkey{natdims:\@anim@fingerprint}{%
{\the\wd\@anim@box}{\the\ht\@anim@box}{\the\dp\@anim@box}%
}%
\@anim@xinline{#1}{#2}{\@anim@box}{newfile}% delegate Form XObject creation
\@anim@newkey{xform:\@anim@fingerprint}{\@anim@@lastxform}%
}{% file known, re-using existing form xobject
\edef\@anim@curndims{\@anim@getkeyval{natdims:\@anim@fingerprint}}%
\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%
}%
\global\let\@anim@@lastxform\@anim@curxform%
\@anim@xinline{#1}{#2}{\@anim@box}{knownfile}%
}%
}
%creates Form XObject from box contents
\def\@anim@xinline#1#2#3#4{%
\def\@anim@status{#4}% "newfile", "knownfile" or "inline" (inline graphics)
\edef\@anim@curwd{\the\wd#3}%
\edef\@anim@curht{\the\ht#3}%
\edef\@anim@curdp{\the\dp#3}%
\ifnum#2=\z@\relax%
%measure 0th frame
\setbox\@anim@measbox=\hbox to \wd#3{%
\vrule width \z@ height \ht#3 depth \dp#3\hss}%
%determine final dims of animation widget
\@anim@scale{\@anim@measbox}%
\fi%
%test if natural dimensions of the current frame differ from
%final widget size
\def\@anim@needresize{0}%
\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%
%if it's a new file, make xobject from it at its natural size
\ifthenelse{\equal{\@anim@status}{newfile}}{%
\@anim@xform{1}{0}{}{}{#3}% `{1}'-->with additional resources (opacity etc.)
\global\let\@anim@@lastxform\@anim@lastxform%
\def\@anim@status{knownfile}%
\ifnum\@anim@needresize>\z@\relax%
\global\setbox#3=\hbox to \@anim@curwd{%
\vrule width \z@ height \@anim@curht depth \@anim@curdp%
\@anim@refxform{\@anim@lastxform}%
\hss%
}%
\fi%
}{%
\ifthenelse{\equal{\@anim@status}{knownfile}}{%
\global\let\@anim@lastxform\@anim@@lastxform%
}{}%
}%
%adjust size of current frame to final animation dims, if necessary
\ifnum\@anim@needresize>\z@\relax%
\global\setbox#3=\hbox{%
\raisebox{-\@anim@animdepth}{%
\resizebox*{\@anim@animwidth}{%
\@anim@animtotalheight}{\raisebox{\depth}{\box#3}}%
}%
}%
\ifthenelse{\equal{\@anim@status}{knownfile}}{%
\@anim@xform{0}{0}{}{}{#3}% without additional Resources
}{}%
\fi%
%distill box with inline graphics to xobject
\ifthenelse{\equal{\@anim@status}{inline}}{%
\@anim@xform{1}{0}{}{}{#3}% with additional Resources
}{}%
%keep a record of XObject number
\@anim@newkey{img@#2}{\@anim@lastxform}%
\if@anim@timeline\else%
\@anim@newkey{frmcontent@#2}{\@anim@getkeyval{img@#2},}%
\@anim@makeframe{#1}{#2}%
\fi%
\message{}%
}
\def\@anim@insertfrmcontent#1,#2\@nil{%
\ifthenelse{\equal{#1}{}}{}{%
\if@anim@dvips%
\@anim@refxform{{#1}}%
\else%
\@anim@refxform{#1}%
\fi%
}%
\ifthenelse{\equal{#2}{}}{}{\@anim@insertfrmcontent#2\@nil}%
}
%inserts one animation frame into the output acc. to
% \ifcase\@anim@method as
% 0 & 1: non-interactive Widget annotation
% 2: Form XObject referenced in the page content, tagged as OC
% or dvisvgm
\def\@anim@makeframe#1#2{%
%container box
\edef\@anim@tmpvar{\@anim@getkeyval{frmcontent@#2},}%
\global\setbox\@anim@box=\hbox to \@anim@animwidth{%
\vrule width \z@ height \@anim@animheight depth \@anim@animdepth%
\expandafter\@anim@insertfrmcontent\@anim@tmpvar\@nil%
\hss%
}%
%inside a `landscape' environment together with the icon and widget methods,
%the frame content needs to be rotated counter-clockwise by 90 deg
\ifnum\@anim@method>\@ne\else%
\ifx\@anim@lscape\@anim@@lscape%
\global\setbox\@anim@box=\hbox{\rotatebox{90}{\box\@anim@box}}%
\fi%
\fi%
\ifcase\@anim@method% icon based
\@anim@xform{0}{1}{}{}{\@anim@box}%
%initial visibility
\ifnum\@anim@poster>\@anim@mtwo\relax% insert poster frame
\ifnum#2=\@anim@poster\relax%
\let\@anim@posterap\@anim@lastxform%
\else%
\ifnum\@anim@poster=\@anim@mone\relax% use last frame as poster
\let\@anim@posterap\@anim@lastxform%
\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
\@anim@xform{0}{1}{}{}{\@anim@box}%
\@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%
\box\@anim@box%
\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%
% `marked content' method for dvisvgm
\@anim@xform{0}{0}{}{}{\@anim@box}%
\ocgbase@oc@bdc{\@anim@curocg}%
\@anim@refxform{\@anim@lastxform}%
\ocgbase@oc@emc%
\else%
% /OC method for PDF output
\@anim@xform{0}{0}{}{/OC \@anim@curocg}{\@anim@box}%
\@anim@refxform{\@anim@lastxform}%
%% `marked content' method (slower, perhaps)
%\@anim@xform{0}{0}{}{}{\@anim@box}%
%\ocgbase@oc@bdc{\@anim@curocg}%
%\@anim@refxform{\@anim@lastxform}%
%\ocgbase@oc@emc%
\fi%
\fi%
\fi%
}
%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}{%
[-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
\@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}{%
[-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
\@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}{%
[-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
\@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%
\global\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}{%
[-1 0 0 1 15 0] concat
\if@anim@dvisvgm\else\ifx\@anim@lscape\@anim@@lscape
[0 1 -1 0 15 0] concat
\fi\fi%
\@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
\global\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%
\global\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%
}%
%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{?nl}%
%
}%
\fi%
\begingroup%
%store current abs. page num in macro \@anim@abspage
\zref@labelbyprops{anim@abspage\the\@anim@num}{abspage}%
\zref@def@extractdefault{\@anim@abspage}{%
anim@abspage\the\@anim@num}{abspage}{-1}%
\@anim@beginLTR%
\ifcsname Ginput@path\endcsname% make use of graphic[xs] search path
\let\input@path\Ginput@path%
\fi%
\setkeys{anim@user}{#1}%
\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@clip\xdef\@anim@gropts{\@anim@gropts%
\ifx\@anim@gropts\@empty\else,\fi clip}\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
\setboolean{@anim@doscaling}{false}%
\fi%
\if@anim@draft%
\if@anim@multipage%
%store file in a box
\@anim@filebox{\@anim@pathtofile}{\@anim@first}%
\else%
%get file name extension
\@anim@getpath{\@anim@base\@anim@first}{\@anim@ftype}%
\@anim@filebox{\@anim@pathtofile}{1}%
\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\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\if@anim@timeline%
\anim@export%
\fi\fi%
%read all frames of the sequence
\loop\ifnum\@anim@curframe\@anim@relop\@anim@last\relax\else%
\if@anim@export\if@anim@timeline\else%
\anim@export%
\fi\fi%
\if@anim@multipage%
%embed graphics
\@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{%
\@anim@pathtofile}{\the\@anim@curframe}%
\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}%
\fi%
\if@anim@export\if@anim@timeline\else%
\endanim@export%
\fi\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
%build timeline from optional timeline file
\if@anim@timeline\@anim@buildtmln{\the\@anim@num}\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