diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/animate/animate.sty |
Initial commit
Diffstat (limited to 'macros/latex/contrib/animate/animate.sty')
-rw-r--r-- | macros/latex/contrib/animate/animate.sty | 4413 |
1 files changed, 4413 insertions, 0 deletions
diff --git a/macros/latex/contrib/animate/animate.sty b/macros/latex/contrib/animate/animate.sty new file mode 100644 index 0000000000..8fa51fbe19 --- /dev/null +++ b/macros/latex/contrib/animate/animate.sty @@ -0,0 +1,4413 @@ +% 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{2019/08/20} +\ProvidesPackage{animate} +[\@anim@version\space PDF & SVG animations from files and inline graphics] + +\RequirePackage{xkeyval} +\RequirePackage{ifthen} +\RequirePackage{ifpdf} +\RequirePackage{ifluatex} +\RequirePackage{ifxetex} +\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`\%=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"% + \let\@anim@foo\@anim@bar% <-- needed for some reason to make + \ifeof\@inputcheck% <-- this test work correctly + \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`\%=0\sbox0{\@@input "|extractbb -O #1.#2"}}% + \fi% + }% + }} + \fi + \fi +\fi + +\if@anim@dvisvgm + \setboolean{@anim@export}{false} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \AtBeginDocument{% + % Add PS and PDF file inclusion (PDF files as of dvisvgm-2.6.3) and + % fix some scaling issues in the dvisvgm.def graphics driver + \def\GPT@space{ } + \def\Gin@extensions{.svg,.eps,.png,.jpg,.jpeg} + \def\Ginclude@pdf#1{\Ginclude@psorpdf{#1}{pdffile}} + \def\Ginclude@eps#1{\let\Gin@page\@empty\Ginclude@psorpdf{#1}{PSfile}} + \def\Ginclude@psorpdf#1#2{% + \message{<#1>}% + \bgroup + \def\@tempa{!}% + \dimen@\Gin@req@width + \dimen@ii.1bp% + \divide\dimen@\dimen@ii + \@tempdima\Gin@req@height + \divide\@tempdima\dimen@ii + \Gin@req@width0.99626\Gin@req@width% + \Gin@req@height0.99626\Gin@req@height% + \ifGin@clip\special{dvisvgm:raw + <g><clipPath id="GinClip\Gin@clip@id">% + <path d="M{?x},{?y}l\strip@pt\Gin@req@width,0l0,-\strip@pt\Gin@req@height + l-\strip@pt\Gin@req@width,0Z"/>% + </clipPath>% + <g clip-path="url(\Gin@hash@tag GinClip\Gin@clip@id)">}% + \fi% + \special{#2="#1"\GPT@space + \ifx\Gin@page\@empty\else page=\Gin@page\GPT@space\fi + llx=\Gin@llx\GPT@space + lly=\Gin@lly\GPT@space + urx=\Gin@urx\GPT@space + ury=\Gin@ury\GPT@space + \ifx\Gin@scalex\@tempa\else rwi=\number\dimen@\GPT@space\fi + \ifx\Gin@scaley\@tempa\else rhi=\number\@tempdima\GPT@space\fi + }% + \ifGin@clip% + \special{dvisvgm:raw </g></g>}% + \begingroup% + \count@\Gin@clip@id\advance\count@ by\@ne\xdef\Gin@clip@id{\the\count@}% + \endgroup% + \fi% + \egroup} + \@namedef{Gin@rule@.ps}#1{{eps}{.ps}{#1}} + \@namedef{Gin@rule@.eps}#1{{eps}{.eps}{#1}} + \@namedef{Gin@rule@.mps}#1{{eps}{.mps}{#1}} + \@namedef{Gin@rule@.pdf}#1{{pdf}{.xbb}{#1}} + \def\Gread@pdf#1{% + \Gread@generic{#1}\Gread@extractbb@aux% + }% + \def\Gread@extractbb@aux#1{% + \ifeof\@inputcheck% + \immediate\openin\@inputcheck=% + "|extractbb % + \ifx\Gin@page\@empty\else -p \Gin@page\GPT@space\fi + \ifx\Gin@pagebox\@empty\else -B \Gin@pagebox\GPT@space\fi + -O \Gin@base\Gin@ext"% + \fi% + \Gread@true% + \let\@tempb\Gread@false% + \ifeof\@inputcheck% + \@latex@error% + {Cannot run pipe command. Try --shell-escape\MessageBreak% + (--enable-pipes in MikTeX) option}% + {Alternatively, execute\MessageBreak\space\space + extractbb + \ifx\Gin@page\@empty\else -p \Gin@page\GPT@space\fi + \ifx\Gin@pagebox\@empty\else -B \Gin@pagebox\GPT@space\fi + \Gin@base\Gin@ext\MessageBreak in a terminal.}% + \else% + \loop% + \read\@inputcheck to\@tempa% + \ifeof\@inputcheck% + \Gread@false% + \else% + \expandafter\Gread@find@bb\@tempa:.\\% + \fi% + \ifGread@% + \repeat% + \immediate\closein\@inputcheck% + \fi% + } + \def\Ginclude@bitmap#1{% + \dimen@\Gin@urx pt% + \advance\dimen@ by-\Gin@llx pt% + \edef\Gin@svg@view@width{\strip@pt\dimen@}% + \dimen@\Gin@ury pt% + \advance\dimen@ by-\Gin@lly pt% + \edef\Gin@svg@view@height{\strip@pt\dimen@}% + \dimen@\Gin@svg@real@height@bp pt% + \advance\dimen@ by-\Gin@ury pt% + \edef\Gin@svg@view@base{\strip@pt\dimen@}% + \Gin@req@width0.99626\Gin@req@width% + \Gin@req@height0.99626\Gin@req@height% + \raise\strip@pt\Gin@req@height bp\hbox{% + \special{dvisvgm: raw + <g transform="translate({?x},{?y})"> + <svg overflow="\ifGin@clip hidden\else visible\fi" width="\strip@pt\Gin@req@width" height="\strip@pt\Gin@req@height" + viewBox="\Gin@llx\GPT@space\Gin@svg@view@base\GPT@space\Gin@svg@view@width\GPT@space\Gin@svg@view@height"> + <image width="\Gin@svg@real@width@bp" height="\Gin@svg@real@height@bp" + xlink:href="#1"/> + </svg> + </g>}% + }% + } + \@namedef{Gin@rule@.svg}#1{{svg}{.svg}{#1}} + \let\Ginclude@svg\Ginclude@bitmap + \def\Gread@svg#1{% + \begingroup + \catcode`\"12\relax% + \immediate\openin\@inputcheck#1 % + \ifeof\@inputcheck + \@latex@error{File `#1' not found}\@ehc + \else + \let\Gin@urx\relax + \let\Gin@ury\relax + \Gread@true + \let\@tempb\Gread@false + \loop + \read\@inputcheck to\@tempa + \ifeof\@inputcheck + \Gread@false + \else + \ifx\@tempa\Gin@partext\else + \ifx\Gin@ury\relax\expandafter\Gread@svg@height\@tempa height=\relax\fi% + \ifx\Gin@urx\relax\expandafter\Gread@svg@width\@tempa width=\relax\fi% + \fi% + \fi + \ifx\Gin@urx\relax\else\ifx\Gin@ury\relax\else\Gread@false\fi\fi% + \ifGread@ + \repeat + \immediate\closein\@inputcheck + \ifx\Gin@urx\relax + \@latex@error{Cannot determine width of graphic in #1 (no BoundingBox)}\@ehc + \def\Gin@urx{72}% + \fi + \ifx\Gin@ury\relax + \@latex@error{Cannot determine height of graphic in #1 (no BoundingBox)}\@ehc + \def\Gin@ury{72}% + \fi + \fi + \edef\Gin@setter{\def\noexpand\Gin@urx{\Gin@urx}\def\noexpand\Gin@ury{\Gin@ury}}% + \expandafter\endgroup\Gin@setter% + \def\Gin@llx{0}% + \def\Gin@lly{0}% + \edef\Gin@svg@real@width@bp{\Gin@urx}% + \edef\Gin@svg@real@height@bp{\Gin@ury}% + } + \def\Gin@partext{\par} + \def\Gread@svg@height#1height={\@ifnextchar\relax{}{\@ifnextchar'\Gread@svg@height@apo\Gread@svg@height@double}} + \def\Gread@svg@height@apo'#1'#2\relax{\afterassignment\Gin@gobble@till@relax\dimen@#1pt\relax\edef\Gin@ury{\strip@pt\dimen@}} + \def\Gread@svg@height@double"#1"#2\relax{\afterassignment\Gin@gobble@till@relax\dimen@#1pt\relax\edef\Gin@ury{\strip@pt\dimen@}} + \def\Gread@svg@width#1width={\@ifnextchar\relax{}{\@ifnextchar'\Gread@svg@width@apo\Gread@svg@width@double}} + \def\Gread@svg@width@apo'#1'#2\relax{\afterassignment\Gin@gobble@till@relax\dimen@#1pt\relax\edef\Gin@urx{\strip@pt\dimen@}} + \def\Gread@svg@width@double"#1"#2\relax{\afterassignment\Gin@gobble@till@relax\dimen@#1pt\relax\edef\Gin@urx{\strip@pt\dimen@}} + \def\Gin@gobble@till@relax#1\relax{} + \edef\Gin@hash@tag{\string#} + \def\Gin@clip@id{0} + \@namedef{Gin@rule@.jpg}#1{{bitmap}{.xbb}{#1}} + \@namedef{Gin@rule@.jpeg}#1{{bitmap}{.xbb}{#1}} + \@namedef{Gin@rule@.png}#1{{bitmap}{.xbb}{#1}} + \def\Gread@bitmap#1{% + \Gread@generic{#1}\Gread@extractbb@aux% + \dimen@\Gin@urx pt% + \advance\dimen@ by-\Gin@llx pt% + \edef\Gin@svg@real@width@bp{\strip@pt\dimen@}% + \dimen@\Gin@ury pt% + \advance\dimen@ by-\Gin@lly pt% + \edef\Gin@svg@real@height@bp{\strip@pt\dimen@}% + } + } + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\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}} + + %approach similar to OCGs, that is, putting the frame content in an svg group, + % <g id='...'>...</g>, 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}<g #1>}} + \def\ocgbase@oc@emc{\special{dvisvgm:raw {?nl}</g>}} +\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 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\ifpdf\else + \if@anim@dvipdfmx\else + \if@anim@dvisvgm\else % dvips + %if geometry package is loaded, execute `\geometry{dvips}' right before + % `\begin{document}'; not sure whether still needed at all + \let\@anim@document\document + \def\document{% + \endgroup% + \@ifpackageloaded{geometry}{\geometry{dvips}}{}% + \begingroup% + \@anim@document% + } + \fi + \fi +\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% +% \if@anim@dvisvgm% disable `landscape' environment +% \renewenvironment{landscape}{}{}% +% \else% + \g@addto@macro{\landscape}{\gdef\@anim@lscape{:ls}}% + \g@addto@macro{\endlandscape}{\gdef\@anim@lscape{}}% +% \fi% + \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{[clip\@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{[clip\@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,width=\@anim@animwidth% + ,height=\@anim@animheight,totalheight=\@anim@animtotalheight}% + \fi% + \fi% + % fingerprint "<file chksum>.<page>.<graphicx opts>.<current document page>" + % 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 "<file chksum>.<page>.<graphicx opts>" + \@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{<a#1,fr#2>}% +} + +\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 <</W 0>>% + /AP <</N \@anim@lastxform>>% + /MK <</TP 1/I \@anim@lastxform/IF<</S/A/FB true>>>>% + /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 <</W 0>>% + /AP <</N \@anim@lastxform>>% + /MK <</TP 1/I \@anim@lastxform/IF<</S/A/FB true>>>>% + /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{% + \@anim@fg\space + 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 fill grestore + \fi + 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{% + \@anim@fg\space + 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 fill grestore + \fi + stroke + % + 1 setlinewidth + 5.5 4.7 moveto + 9.6 7.5 lineto + 5.5 10.3 lineto + stroke + } + \def\@anim@btnplay{% + \@anim@fg\space + 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 fill grestore + \fi + 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{% + \@anim@fg\space + 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 fill grestore + \fi + stroke + % + 0 setlinecap + 2 setlinewidth + 2.2 4 moveto + 2.2 11 lineto + stroke + } + \def\@anim@btnminus{% + \@anim@fg\space + 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 fill grestore + \fi + stroke + % + 1.0 setlinewidth + 0 setlinecap + 4.7 7.5 moveto + 10.3 7.5 lineto + stroke + } + \def\@anim@btnplus{% + \@anim@fg\space + 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 fill grestore + \fi + 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@btnreset{% + \@anim@fg\space + 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 fill grestore + \fi + 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 + \ifx\@anim@lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi% + \@anim@btnend}{#2}% + \fi% + \ifx\@anim@EndRight\@anim@arg% + \@anim@xbutton{EndRight}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnend}{#2}% + \fi% + \ifx\@anim@Minus\@anim@arg% + \@anim@xbutton{Minus}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnminus}{#2}% + \fi% + \ifx\@anim@PauseLeft\@anim@arg% + \@anim@xbutton{PauseLeft}{% + [-1 0 0 1 15 0] concat + \ifx\@anim@lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi% + \@anim@btnpause}{#2}% + \fi% + \ifx\@anim@PauseRight\@anim@arg% + \@anim@xbutton{PauseRight}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnpause}{#2}% + \fi% + \ifx\@anim@PlayLeft\@anim@arg% + \@anim@xbutton{PlayLeft}{% + [-1 0 0 1 15 0] concat + \ifx\@anim@lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi% + \@anim@btnplay}{#2}% + \fi% + \ifx\@anim@PlayRight\@anim@arg% + \@anim@xbutton{PlayRight}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnplay}{#2}% + \fi% + \ifx\@anim@Plus\@anim@arg% + \@anim@xbutton{Plus}{\@anim@btnplus}{#2}% + \fi% + \ifx\@anim@Reset\@anim@arg% + \@anim@xbutton{Reset}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnreset}{#2}% + \fi% + \ifx\@anim@StepLeft\@anim@arg% + \@anim@xbutton{StepLeft}{% + [-1 0 0 1 15 0] concat + \ifx\@anim@lscape\@anim@@lscape [0 -1 -1 0 15 15] concat \fi% + \@anim@btnstep}{#2}% + \fi% + \ifx\@anim@StepRight\@anim@arg% + \@anim@xbutton{StepRight}{% + \ifx\@anim@lscape\@anim@@lscape [0 1 -1 0 15 0] concat \fi% + \@anim@btnstep}{#2}% + \fi% + } + \def\@anim@xbutton#1#2#3{% #1: name; #2: stroking commands, + \ifcsname btn#1:#3\endcsname\else% #3: current colour+alpha+ ... combination + % only create if button face doesn't exist yet + \global\setbox\@anim@box=\hbox to 15bp {\vbox to 15bp {\vss% + \@anim@literal{}{#2}% + }\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% + opacity='\@anim@alpha'% + \else% + /Group <</S/Transparency>>% + \fi% + \fi% + }{\@anim@box}% + %nested XObject if transparency is to be added + \if@anim@dvisvgm\else% + \ifx\empty\@anim@alpha\empty\else% + \global\setbox\@anim@box=\hbox to 15bp {\vbox to 15bp {\vss% + \@anim@literal{direct}{% + /.setopacityalpha where {% + %Ghostscript + pop \@anim@alpha\space .setopacityalpha% + }{% + %Distiller + mark /CA \@anim@alpha /ca \@anim@alpha /SetTransparency pdfmark% + } ifelse% + }% + \@anim@refxform{\@anim@lastxform}% + }\hss}% + \@anim@xform{0}{0}{}{}{\@anim@box}% + \fi% + \fi% + \@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 + 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 + \@anim@streamobj{% % exist yet + /Type/XObject/Subtype/Form/BBox [0 0 15 15] + \ifx\empty\@anim@alpha\empty\else% + /Group <</S/Transparency>>% + \fi% + }{#2}% + \ifx\empty\@anim@alpha\empty\else% + \@anim@streamobj{% + /Type/XObject/Subtype/Form/BBox [0 0 15 15]% + /Resources <<% + /ExtGState <<% + /R1 <<% + /Type/ExtGState/ca \@anim@alpha/CA \@anim@alpha/AIS false% + >>% + >>% + /XObject <</R2 \@anim@lastobj>>% + >>% + }{/R1 gs /R2 Do}% + \fi% + \@anim@newkey{btn#1:#3}{\@anim@lastobj}% + \fi% + } +\fi + +%determines file type of the sequence +\def\zap@finalspace#1 \@nil{#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 {% + \hss% + \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% + \hss% + }% + \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}% + <!-- animation by LaTeX-package `animate', + https://ctan.org/tex-archive/macros/latex/contrib/animate, + v. \@anim@version\space-->% + }% + \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}% + \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% + \if@anim@hiresbb\xdef\@anim@gropts{\@anim@gropts,hiresbb}\fi% + \if@anim@interpolate\xdef\@anim@gropts{\@anim@gropts,interpolate}\fi% + \ifx\@anim@pagebox\@empty\else% + \xdef\@anim@gropts{\@anim@gropts,pagebox=\@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 <script> part + \if@anim@dvisvgm\@anim@script{\the\@anim@num}\fi% + \@anim@insertwidgets{\the\@anim@num}{% + \@anim@bgcolour:\@anim@fgcolour:\@anim@alpha% + \if@anim@dvisvgm:\@anim@btnsize:\@anim@abspage\fi% + \@anim@lscape% + }% + \fi% + \fi% + \@anim@endLTR% + \endgroup% + \global\advance\@anim@num by \@ne% +}% +%adjust catcode of `:' character within \animategraphics +\let\@anim@animategraphics\animategraphics +\def\animategraphics{\@anim@sanitizeColon\@anim@animategraphics} + +%inserts animation and control button widgets +\newboolean{@anim@controls@firstgrp} +\def\@anim@insertwidgets#1#2{%#1:@anim@num, #2 btn colour, alpha, ... + \vtop{% + \offinterlineskip% + \hbox{\@anim@animwidget{#1}}% + \if@anim@controls% + \setlength{\@anim@tmpdima}{\@anim@btnsize}% + \vskip 0.1\@anim@tmpdima% + \hbox to \@anim@animwidth {% + \hss% + \def\@anim@tooltip{}% + \setboolean{@anim@controls@firstgrp}{false}% + \if@anim@controls@stop% + \setboolean{@anim@controls@firstgrp}{true}% + \@anim@makebutton{EndLeft}{#2}% + \@anim@buttonwidget{#1}{EndLeft}{EndLeft:#2}% + \fi% + \if@anim@controls@step% + \setboolean{@anim@controls@firstgrp}{true}% + \@anim@makebutton{StepLeft}{#2}% + \@anim@buttonwidget{#1}{StepLeft}{StepLeft:#2}% + \fi% + \if@anim@controls@play% + \setboolean{@anim@controls@firstgrp}{true}% + \@anim@makebutton{PauseLeft}{#2}% + \@anim@buttonwidget{#1}{PauseLeft}{PauseLeft:#2}% + \@anim@makebutton{PlayLeft}{#2}% + \@anim@buttonwidget{#1}{PlayLeft}{PlayLeft:#2}% + \@anim@buttonwidget{#1}{PlayPauseLeft}{}% + \@anim@makebutton{PauseRight}{#2}% + \@anim@buttonwidget{#1}{PauseRight}{PauseRight:#2}% + \@anim@makebutton{PlayRight}{#2}% + \@anim@buttonwidget{#1}{PlayRight}{PlayRight:#2}% + \@anim@buttonwidget{#1}{PlayPauseRight}{}% + \fi% + \if@anim@controls@step% + \setboolean{@anim@controls@firstgrp}{true}% + \@anim@makebutton{StepRight}{#2}% + \@anim@buttonwidget{#1}{StepRight}{StepRight:#2}% + \fi% + \if@anim@controls@stop% + \setboolean{@anim@controls@firstgrp}{true}% + \@anim@makebutton{EndRight}{#2}% + \@anim@buttonwidget{#1}{EndRight}{EndRight:#2}% + \fi% + \if@anim@controls@speed% + \if@anim@controls@firstgrp\hskip 0.3\@anim@tmpdima\fi% + \def\@anim@tooltip{/TU (slower)}% + \@anim@makebutton{Minus}{#2}% + \@anim@buttonwidget{#1}{Minus}{Minus:#2}% + \def\@anim@tooltip{/TU (default speed)}% + \@anim@makebutton{Reset}{#2}% + \@anim@buttonwidget{#1}{Reset}{Reset:#2}% + \def\@anim@tooltip{/TU (faster)}% + \@anim@makebutton{Plus}{#2}% + \@anim@buttonwidget{#1}{Plus}{Plus:#2}% + \fi% + \hss% + }% + \fi% + }% +} + +\newcount\@anim@resizeflags% resizing flags according to options given. + +%post-scaling, not possible for embedded files with dvisvgm +\newboolean{@anim@doscaling} + +%set animation widget dimensions +\def\@anim@scale#1{% #1: box number + \begingroup% + %natural dimensions \width, \height, \depth, \totalheight + \def\width{\wd#1}% + \def\height{\ht#1}% + \def\depth{\dp#1}% + \let\totalheight\@anim@tmpdimb% + \setlength{\totalheight}{\dimexpr\height+\depth\relax}% + %evaluate resizing options + \xdef\@anim@animwidth{\the\dimexpr\@anim@widtharg\relax}% + \xdef\@anim@animheight{\the\dimexpr\@anim@heightarg\relax}% + \xdef\@anim@animtotalheight{\the\dimexpr\@anim@totheightarg\relax}% + \endgroup% + %now resize + \ifcase\@anim@resizeflags% bit 2^2=width, 2^1=height, 2^0=totalhight given + \or% 1 + \global\setbox#1=\hbox{\resizebox*{!}{\@anim@animtotalheight}{\box#1}}% + \or% 2 + \global\setbox#1=\hbox{\resizebox{!}{\@anim@animheight}{\box#1}}% + \or\or% 4 + \global\setbox#1=\hbox{\resizebox{\@anim@animwidth}{!}{\box#1}}% + \or% 5 + \if@anim@iso% + \setlength{\@anim@tmpdima}{% + \totalheightof{\usebox#1}*\ratio{\@anim@animwidth}{\wd#1}}% + \ifdim\@anim@tmpdima<\z@\@anim@tmpdima=-\@anim@tmpdima\fi% + \setlength{\@anim@tmpdimb}{\@anim@animtotalheight}% + \ifdim\@anim@tmpdimb<\z@\@anim@tmpdimb=-\@anim@tmpdimb\fi% + \ifdim\@anim@tmpdima<\@anim@tmpdimb% + \global\setbox#1=\hbox{\resizebox*{\@anim@animwidth}{!}{\box#1}}% + \else% + \global\setbox#1=\hbox{% + \resizebox*{!}{\@anim@animtotalheight}{\box#1}}% + \fi% + \else% + \global\setbox#1=\hbox{% + \resizebox*{\@anim@animwidth}{\@anim@totheightarg}{\box#1}}% + \fi% + \or% 6 + \if@anim@iso% + \setlength{\@anim@tmpdima}{\ht#1*\ratio{\@anim@animwidth}{\wd#1}}% + \ifdim\@anim@tmpdima<\z@\@anim@tmpdima=-\@anim@tmpdima\fi% + \setlength{\@anim@tmpdimb}{\@anim@animheight}% + \ifdim\@anim@tmpdimb<\z@\@anim@tmpdimb=-\@anim@tmpdimb\fi% + \ifdim\@anim@tmpdima<\@anim@tmpdimb% + \global\setbox#1=\hbox{\resizebox{\@anim@animwidth}{!}{\box#1}}% + \else% + \global\setbox#1=\hbox{\resizebox{!}{\@anim@animheight}{\box#1}}% + \fi% + \else% + \global\setbox#1=\hbox{% + \resizebox{\@anim@animwidth}{\@anim@animheight}{\box#1}}% + \fi% + \fi% + %apply scale + \ifdim\@anim@boxscale pt=\p@\else% + \global\setbox#1=\hbox{\scalebox{\@anim@boxscale}{\box#1}}% + \fi% + %dimensions after resizing + \xdef\@anim@animwidth{\the\wd#1}% + \xdef\@anim@animheight{\the\ht#1}% + \xdef\@anim@animdepth{\the\dp#1}% + \xdef\@anim@animtotalheight{\the\dimexpr\ht#1+\dp#1\relax}% +} + +%interactive Widget annotation serving as animation frame container / that is +%overlayed on the non-interactive frame Widgets or on the page content with +%frame OCGs +\if@anim@dvisvgm + \def\@anim@animwidget#1{% + \ifnum\@anim@poster>\@anim@maxframe\relax% + \PackageError{animate}{% + Poster frame `\@anim@poster' is out-of-bounds\MessageBreak% + on input line \the\inputlineno.\MessageBreak% + Try option `poster=last'% + }{}% + \fi% + \@anim@annot{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{% + id='anm#1' + \if@anim@nomouse\else + cursor='pointer' + \fi% + }% + \@anim@updatebbox{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}% + \hbox to \@anim@animwidth {% + \vrule width \z@ height \@anim@animheight depth \@anim@animdepth% + \hss% + }% + } +\else + \def\@anim@animwidget#1{% + \@anim@pojscript{#1}% + \@anim@pcjscript{#1}% + \def\@anim@annotflag{}% + \ifnum\@anim@poster>\@anim@maxframe\relax% + \PackageError{animate}{% + Poster frame `\@anim@poster' is out-of-bounds\MessageBreak% + on input line \the\inputlineno.\MessageBreak% + Try option `poster=last'% + }{}% + \fi% + \ifnum\@anim@method=\z@\relax% + \def\@anim@annotflag{/F 4}% 4=allow printing + \ifnum\@anim@poster=\@anim@mtwo\relax% + \ifdefined\@anim@apdummy\else% empty appearance widget + \setbox\@anim@box=\hbox{\phantom{x}}% + \@anim@xform{0}{0}{}{}{\@anim@box}% + \global\let\@anim@apdummy\@anim@lastxform% + \@anim@widget{1ex}{1ex}{\z@}{% + /Subtype/Widget% + /F 2% + /FT/Btn/Ff 65537% + /BS <</W 0>>% + /AP <</N \@anim@lastxform>>% + /MK <</TP 1/I \@anim@lastxform/IF<</S/A/FB true>>>>% + /T (0000)% + }% + \fi% + \def\@anim@apmk{\@anim@apdummy}% + \else% + \def\@anim@apmk{\@anim@posterap}% + \fi% + \else% + \ifdefined\@anim@apdummy\else% empty appearance dummy + \setbox\@anim@box=\hbox{\phantom{x}}% + \@anim@xform{0}{0}{}{}{\@anim@box}% + \global\let\@anim@apdummy\@anim@lastxform% + \fi% + \def\@anim@apmk{\@anim@apdummy}% + \fi% + %this is for Foxit compatibility: + % Widget annots don't seem to acknowledge /P* events + % a non-interactive /Screen annotation for initializing the animation + % upon PageOpen/PageVisible events and for clean-up upon PageClose/ + % PageInvisible events + \@anim@annot{1ex}{1ex}{\z@}{% + /Subtype/Screen/F 2% + /AA <<% + /PV <</S/JavaScript/JS \@anim@pojscriptobj>>% PageVisible + /PO <</S/JavaScript/JS \@anim@pojscriptobj>>% PageOpen + /PI <</S/JavaScript/JS \@anim@pcjscriptobj>>% PageInvisible + /PC <</S/JavaScript/JS \@anim@pcjscriptobj>>% PageClose + >>% + }% + \@anim@widget{\@anim@animwidth}{\@anim@animheight}{\@anim@animdepth}{% + /Subtype/Widget% + /FT/Btn/Ff \if@anim@nomouse 65537\else 65536\fi% + \@anim@annotflag% + /BS <</W 0>>% + /H/N% + /T (anm#1)% + \@anim@alttext% %/Contents (...) + /AA <<% + /PV <</S/JavaScript/JS \@anim@pojscriptobj>>% PageVisible + /PO <</S/JavaScript/JS \@anim@pojscriptobj>>% PageOpen + /PI <</S/JavaScript/JS \@anim@pcjscriptobj>>% PageInvisible + /PC <</S/JavaScript/JS \@anim@pcjscriptobj>>% PageClose + \if@anim@nomouse\else% + /D <</S/JavaScript/JS (\@anim@wdgtDownJS{#1})>>% mouse-down + /U <</S/JavaScript/JS (\@anim@wdgtUpJS{#1})>>% mouse-up + \fi% + >>% + /AP <</N \@anim@apmk>>% + /MK <</TP 1/I \@anim@apmk/IF<</S/A/FB true>>>>% + }% + \hbox to \@anim@animwidth {% + \vrule width \z@ height \@anim@animheight depth \@anim@animdepth% + \hss% + }% + } +\fi +%creates control button widget +\newboolean{@anim@js} +\newboolean{@anim@mk} +\if@anim@dvisvgm + \def\@anim@buttonwidget#1#2#3{% #1:@anim@num, #2:action, + % #3:button face and colour combination + \def\@anim@arg{#2}\@anim@jstrue% + \ifx\@anim@PlayLeft\@anim@arg% + \@anim@jsfalse% + \@anim@newocg{#1}{PlayLeft}% + \fi% + \ifx\@anim@PauseLeft\@anim@arg% + \@anim@jsfalse% + \@anim@newocg{#1}{PauseLeft}% + \ocgbase@add@to@off@list{\@anim@curocg}% + \fi% + \ifx\@anim@PlayRight\@anim@arg% + \@anim@jsfalse% + \@anim@newocg{#1}{PlayRight}% + \fi% + \ifx\@anim@PauseRight\@anim@arg% + \@anim@jsfalse% + \@anim@newocg{#1}{PauseRight}% + \ocgbase@add@to@off@list{\@anim@curocg}% + \fi% + % insert button face + \if@anim@js% + \ifx\@empty#3\@empty\else% PlayPauseLeft/PlayPauseRight don't have btn + \@anim@refxform{\@anim@getkeyval{btn#3}}% % faces + \fi% + \else% PlayLeft, PauseLeft, PlayRight, PauseRight + \ocgbase@oc@bdc{\@anim@curocg}% + \@anim@refxform{\@anim@getkeyval{btn#3}}% + \ocgbase@oc@emc% + \fi% + % insert widget + \if@anim@js% + \@anim@annot{\@anim@btnsize}{\@anim@btnsize}{\z@}{% + cursor='pointer' onmousedown='\@anim@btnJS{#1}{\@anim@arg}'% + }% + \@anim@updatebbox{\@anim@btnsize}{\@anim@btnsize}{\z@}% + \hbox to \@anim@btnsize {% + \vrule width \z@ height \@anim@btnsize depth \z@% + \hss% + }% + \fi% + } +\else + \def\@anim@buttonwidget#1#2#3{%#1:@anim@num, #2:action, + %#3:button face and colour+alpha+... combination + \edef\@anim@arg{#2}\@anim@jstrue\@anim@mktrue% + \def\@anim@annotflag{/F 0}% visible, but don't print + \ifx\@anim@PlayLeft\@anim@arg\@anim@jsfalse\fi% %hidden, don't print | + \ifx\@anim@PauseLeft\@anim@arg\@anim@jsfalse\def\@anim@annotflag{/F 2}\fi%_| + \ifx\@anim@PlayRight\@anim@arg\@anim@jsfalse\fi% + \ifx\@anim@PauseRight\@anim@arg\@anim@jsfalse\def\@anim@annotflag{/F 2}\fi% + \ifx\@anim@PlayPauseLeft\@anim@arg\@anim@mkfalse\fi% + \ifx\@anim@PlayPauseRight\@anim@arg\@anim@mkfalse\fi% + \if@anim@mk\else% + \ifdefined\@anim@apdummy\else% empty appearance dummy + \setbox\@anim@box=\hbox{\phantom{x}}% + \@anim@xform{0}{0}{}{}{\@anim@box}% + \global\let\@anim@apdummy\@anim@lastxform% + \fi% + \fi% + \@anim@widget{\@anim@btnsize}{\@anim@btnsize}{\z@}{% + /Subtype/Widget% + \@anim@annotflag% + /FT/Btn/Ff \if@anim@js 65536\else 65537\fi% + /H\if@anim@js/I\else/N\fi% + /BS <</W 0>>% + \if@anim@mk% + /AP <</N \@anim@getkeyval{btn#3}>>% + /MK <</TP 1/I \@anim@getkeyval{btn#3}/IF<</S/A/FB true>>>>% + \else% + /AP <</N \@anim@apdummy>>% + /MK <</TP 1/I \@anim@apdummy/IF<</S/A/FB true>>>>% + \fi% + /T (#1.#2)% + \@anim@tooltip% + \if@anim@js% + %/A <</S/JavaScript/JS (\@anim@btnJS{#1}{\@anim@arg})>>% + /AA <</D <</S/JavaScript/JS (\@anim@btnJS{#1}{\@anim@arg})>>>>% + \fi% + }% + \if@anim@js% + \hbox to \@anim@btnsize {% + \vrule width \z@ height \@anim@btnsize depth \z@% + \hss% + }% + \fi% + } +\fi + +\newboolean{@anim@pauseframes} % true if \newframe* is being used +\newboolean{@anim@chfps} % true if \newframe or \newframe* is being used + % with optional `new frame rate' argument +\newboolean{@anim@usrjs} % true if user JavaScript provided by user + +\newcount\@anim@skipfram % counter for skipped frames + +%user environment for animating inline graphics +% #1: options +% #2: frame rate (fps) +\newenvironment{animateinline}[2][]{% + \@anim@endsanitize% + \if@anim@export\else\leavevmode\fi% + \@anim@reset% to default settings + \if@anim@dvisvgm% + \special{dvisvgm:raw{?nl}% + <!-- animation by LaTeX-package `animate', + https://ctan.org/tex-archive/macros/latex/contrib/animate, + v. \@anim@version\space-->% + }% + \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% + \ifdefined\NoHyper\NoHyper\fi% silently suppress any hyperref specials + \ifcsname Ginput@path\endcsname% make use of graphic[xs] search path + \let\input@path\Ginput@path% + \fi% + \setkeys{anim@user}{#1}% + \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% + \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% + \global\@anim@curframe@zb=\z@% + \global\@anim@skipfram=\z@% + \if@anim@export% + \def\@anim@method{\tw@}% + \setboolean{@anim@controls}{false}% + \setboolean{@anim@draft}{false}% + \fi% + \if@anim@dvisvgm% + \def\@anim@method{\tw@}% + \fi% + \if@anim@draft\else% + \if@anim@step\else% + \xdef\@anim@nfps{-1}% + \@anim@processfpsarg{#2}% + \fi% + \if@anim@export\if@anim@timeline% + \anim@export% + \fi\fi% + \fi% + \let\newframe\@anim@@newframe% + \let\multiframe\@anim@multiframe% + \@anim@beginframe% + \ignorespaces% +}{% + \unskip% + \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}% + \global\advance\@anim@curframe@zb by \@ne% + \if@anim@draft\else% + \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% + %insert animation widget & controls + \if@anim@export\else% + % insert <script> part + \if@anim@dvisvgm\@anim@script{\the\@anim@num}\fi% + \@anim@insertwidgets{\the\@anim@num}{% + \@anim@bgcolour:\@anim@fgcolour:\@anim@alpha% + \if@anim@dvisvgm:\@anim@btnsize:\@anim@abspage\fi% + \@anim@lscape% + }% + \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% + \fi% + \ifdefined\endNoHyper\endNoHyper\fi% + \@anim@endLTR% + \endgroup% + \global\advance\@anim@num by \@ne% +} +\let\@anim@animateinline\animateinline +\def\animateinline{\@anim@sanitizeColon\@anim@animateinline} + +%usercommand for use within `animateinline' environment; +%terminates the current frame and starts a new one +\def\@anim@@newframe{% aliased to \newframe inside `animateinline' + \unskip% + \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}% + \@ifstar\@anim@newframestar\@anim@newframe% +} +\def\@anim@processfpsarg#1{% + %process frame rate argument + \global\let\@anim@pfps\@anim@nfps% + \xdef\@anim@nfps{#1\space}% + \xdef\@anim@nfps{\expandafter\zap@space\@anim@nfps\@empty}% + \ifx\@anim@nfps\@empty% no change of frame rate + \global\let\@anim@nfps\@anim@pfps% + \fi% + \ifnum\@anim@curframe@zb=\z@\relax% + \global\let\@anim@fps\@anim@nfps% default fps + \global\let\@anim@nfpsat\@anim@nfps% + \else% + \xdef\@anim@nfpsat{\@anim@nfpsat,\@anim@nfps}% + \fi% + \ifdim\@anim@nfps pt=\@anim@pfps pt\else% + \ifnum\@anim@curframe@zb=\z@\relax\else% + \setboolean{@anim@chfps}{true}% change fps + \fi% + \fi% + \ifdim\@anim@nfps pt<\z@% + \PackageError{animate}{% + Negative frame rate `\@anim@nfps' is not allowed% + }{}% + \fi% +}% +\newcommand{\@anim@newframe}[1][]{% #1: new frame rate + \ifnum\@anim@skipfram=\z@\relax% + \global\advance\@anim@curframe@zb by \@ne% + \if@anim@draft\else% + \if@anim@step\else% + \if@anim@timeline\else% + %process frame rate argument + \@anim@processfpsarg{#1}% + \fi% + \fi% + \fi% + \fi% + \@anim@beginframe% + \ignorespaces% +} +\newcommand{\@anim@newframestar}[1][]{% starred variant for pausing animation + \ifnum\@anim@skipfram=\z@\relax% #1: new frame rate + \if@anim@draft\else% + \if@anim@step\else% + \if@anim@timeline\else% + %build JavaScript commands to fill the `pauseAt' array + \xdef\@anim@pauseat{% + \@anim@pauseat% + a\the\@anim@num_pauseAt[\the\@anim@curframe@zb]=1;% + }% + \setboolean{@anim@pauseframes}{true}% + \fi% + \fi% + \fi% + \global\advance\@anim@curframe@zb by \@ne% + \if@anim@draft\else% + \if@anim@step\else% + \if@anim@timeline\else% + %process frame rate argument + \@anim@processfpsarg{#1}% + \fi% + \fi% + \fi% + \fi% + \@anim@beginframe% + \ignorespaces% +} + +%starts new frame +\def\@anim@beginframe{% + \if@anim@export\if@anim@timeline\else\ifnum\@anim@skipfram=\z@\relax% + \anim@export% + \fi\fi\fi% + \begingroup% + \lrbox{\@anim@box}% store graphics in a box + \ifdefined\@anim@curTxtDir\textdir\@anim@curTxtDir\fi% + \@anim@begin% +} + +%terminates current frame +\def\@anim@endframe#1#2{% + \@anim@end% + \endlrbox% + \endgroup% + \ifnum\@anim@skipfram=\z@\relax% + \ifnum#2=\z@\relax% + \ifdim\wd\@anim@box=\z@% + \PackageError{animate}{% + Contents of first frame must not have zero width% + }{% + Possible reason: \protect\begin{animateinline}{...} + immediately followed by \protect\newframe% + }% + \fi% + \ifdim\ht\@anim@box=\z@\ifdim\dp\@anim@box=\z@% + \PackageError{animate}{% + Contents of first frame must not have zero height% + }{}% + \fi\fi% + %draw draftbox according to dimensions of the first frame + \if@anim@draft% + \@anim@scale{\@anim@box}% + \@anim@draftbox% + \fi% + \else% remaining frames + %deal with zero width or totalheight boxes + \ifdim\wd\@anim@box=\z@\global\setbox\@anim@box=\hbox{\phantom{X}}\fi% + \ifdim\ht\@anim@box=\z@\ifdim\dp\@anim@box=\z@% + \global\setbox\@anim@box=\hbox{\phantom{X}}% + \fi\fi% + \fi% + %now create Form XObject of box contents + \if@anim@draft\else% + \@anim@xinline{#1}{#2}{\@anim@box}{inline}% + \fi% + \if@anim@export\if@anim@timeline\else% + \endanim@export% + \fi\fi% + \fi% + \global\advance\@anim@skipfram by \@ne% + \ifnum\@anim@skipfram=\@anim@every\relax% + \global\@anim@skipfram=\z@% + \fi% +} + +%user command for building loops around parameterized frame content, somewhat +%like \multido (package multido) with embedded \newframe +\newcount\@anim@mulframecnt %takes current loop No. of \multiframe +\newboolean{@anim@insidemulti} % for checking whether we are inside \multiframe +\setboolean{@anim@insidemulti}{false} +\newcommand{\@anim@multiframe}[3]{% + % aliased to \multiframe inside `animateinline' + % #1: #repetitions, #2: vars, #3: frame content + \unskip% + \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@\relax% + \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@\relax% + \@anim@@newframe% + \@anim@updatevars% update variables + \fi% + \global\advance\@anim@mulframecnt by \@ne% + \ignorespaces% + #3% execute loop body + \unskip% + }% + \setboolean{@anim@insidemulti}{false}% + \ignorespaces% +} + +%splits list of variable declarations +\def\@anim@parsevars#1,#2\@nil{% + \ifthenelse{\equal{#1}{}}{}{\@anim@parsedecl#1\@nil=+\@nil\relax}% + \ifthenelse{\equal{#2}{}}{}{\@anim@parsevars#2\@nil}% +} +%parser for single variable declaration +\def\@anim@parsedecl#1=#2+#3\@nil#4\relax{% + \ifx\@empty#4\@empty% + \PackageError{animate}{\protect\multiframe: bad variable declaration}{}% + \fi% + \ifthenelse{\equal{#1}{}\OR\equal{#2}{}\OR\equal{#3}{}}{% + \PackageError{animate}{\protect\multiframe: bad variable declaration}{}% + }{}% + \edef\@anim@vartype{\@anim@getvartype#1\@nil}% + \ifthenelse{\equal{\@anim@vartype}{d}\OR\equal{\@anim@vartype}{D}}{% + % dimensions, prefix d, D + %initialize variable + \setlength{\@anim@tmpdima}{#2}% + \expandafter\edef\csname#1\endcsname{\number\@anim@tmpdima sp}% + %global copy that saves current variable value between loops + \expandafter\xdef\csname#1@old\endcsname{\number\@anim@tmpdima sp}% + \setlength{\@anim@tmpdimb}{#3}% + %global copy of increment + \expandafter\xdef\csname#1@inc\endcsname{\number\@anim@tmpdimb sp}% + %append script for updating variable to \@anim@updatevars macro + \g@addto@macro\@anim@updatevars{% + %new value + \setlength{\@anim@tmpdima}{\csname#1@old\endcsname}% + \addtolength{\@anim@tmpdima}{\csname#1@inc\endcsname}% + \expandafter\edef\csname#1\endcsname{\number\@anim@tmpdima sp}% + %global copy + \expandafter\xdef\csname#1@old\endcsname{\number\@anim@tmpdima sp}% + }% + }{% + \ifthenelse{% + \equal{\@anim@vartype}{n}\OR\equal{\@anim@vartype}{N}% + \OR\equal{\@anim@vartype}{r}\OR\equal{\@anim@vartype}{R}% + }{% real numbers, prefix n, N, r, R + %initialize variable + \expandafter\edef\csname#1\endcsname{\@anim@fpeval{#2}}% + %global copy that saves current variable value between loops + \expandafter\xdef\csname#1@old\endcsname{\@anim@fpeval{#2}}% + %append script for updating variable to \@anim@updatevars macro + \g@addto@macro\@anim@updatevars{% + %new value + \expandafter\edef\csname#1\endcsname{% + \@anim@fpeval{#3+\csname#1@old\endcsname}% + }% + %global copy + \expandafter\xdef\csname#1@old\endcsname{\csname#1\endcsname}% + }% + }{% + \ifthenelse{\equal{\@anim@vartype}{i}\OR\equal{\@anim@vartype}{I}}{% + % integers, prefix i, I + %initialize variable + \setcounter{@anim@ltxcnt}{#2}% + \expandafter\edef\csname#1\endcsname{\the@anim@ltxcnt}% + %global copy that saves current variable value between loops + \expandafter\xdef\csname#1@old\endcsname{\the@anim@ltxcnt}% + \setcounter{@anim@ltxcnt}{#3}% + %global copy of increment + \expandafter\xdef\csname#1@inc\endcsname{\the@anim@ltxcnt}% + %append script for updating variable to \@anim@updatevars macro + \g@addto@macro\@anim@updatevars{% + %new value + \expandafter\global\expandafter\@anim@tmpcnt\csname#1@old\endcsname% + \global\advance\@anim@tmpcnt by \csname#1@inc\endcsname% + \expandafter\edef\csname#1\endcsname{\the\@anim@tmpcnt}% + %global copy + \expandafter\xdef\csname#1@old\endcsname{\the\@anim@tmpcnt}% + }% + }{% + \PackageError{animate}{% + \protect\multiframe: wrong name prefix `\@anim@vartype' in% + \MessageBreak variable `#1'.\MessageBreak% + Use any of d, D (dimensions), i, I (integer numbers)\MessageBreak% + or n, N, r, R (real numbers) as the first letter to\MessageBreak% + specify the variable type% + }{}% + }% + }% + }% +} +%get initial letter from variable name (the variable type, as with \multido) +\def\@anim@getvartype#1#2\@nil{#1}% + +%prints zero padded integers +% #1: arbitrary integer number as template specifying the +% width, e. g. `987654' for a width of 6 digits +% #2: the number to be formatted +\def\@anim@pad#1#2{% + \@anim@@pad{\@anim@template{0}{#1}}{#2}% +} +%low level macros used by \@anim@pad +\def\@anim@@pad#1#2{% #1: string of zeros specifying width, #2 number + \ifnum1#2<1#1 + \@anim@@pad{#1}{0#2}% + \else% + #2% + \fi% +}% +\def\@anim@template#1#2{% create template (string of zeros) from given num + \ifnum10#1>1#2 + #1% + \else% + \@anim@template{0#1}{#2}% + \fi% +}% + +\begingroup\catcode`\_=13\let_\space +\xdef\@anim@nusewarning{% + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak% + @_There_are_unused_animation_transparencies._@\MessageBreak% + @_See_the_transcript_file____________________@\MessageBreak% + @___``\jobname.log''\MessageBreak% + @_for_additional_information!________________@\MessageBreak% + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% +} +\endgroup + +%macros for sanitizing characters +\def\@anim@sanitize#1#2\@nil{% + \catcode`#1=12% + \ifx\@empty#2\@empty\else% + \@anim@sanitize#2\@nil% + \fi% +} +\def\@anim@sanitizeJS{% sanitize JS code while being read from timeline file + \begingroup% + \@anim@sanitize.:;?!/"'*+,->=<$\&@][)(^_`|~\#\@nil% + \def\\{\string\\}% + \def\{{\string\{}% + \def\}{\string\}}% + \def\%{\string\%}% +} +\def\@anim@sanitizeColon{% sanitize colon (`:') while reading the option list, + \begingroup% in particular the `buttonfg' and `buttonbg' options + \@anim@sanitize:\@nil% arguments +} +\let\@anim@endsanitize\endgroup + +%building timeline from timeline file +\newread\@anim@@tmlnfile +\newboolean{@anim@eof} +\newcount\@anim@tmpcnt %scratch counter for different uses +\newcounter{@anim@ltxcnt} %scratch LaTeX counter for different uses +\newcount\@anim@curlayer %takes the number of the current layer being processed +\newcount\@anim@lineno %current input line No. +\newcount\@anim@curfield %current field of input line processed + +\def\@anim@buildtmln#1{% #1:@anim@num + \global\@anim@curframe@zb=\z@% + %read timeline file a first time to get number of lines (= number of frames) + \openin\@anim@@tmlnfile=\@anim@tmlnfile% + \@anim@sanitizeJS% + \endlinechar=-1% suppress trailing space at input line end + \global\read\@anim@@tmlnfile to \@anim@inputline% + \@anim@endsanitize% + \edef\@anim@inputline{\@anim@inputline\space}% + %remove all spaces from input line + \edef\@anim@inputline{\expandafter\zap@space\@anim@inputline\@empty}% + \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else% + \setboolean{@anim@eof}{false}\fi% + \whiledo{\NOT\boolean{@anim@eof}}{% + \ifthenelse{\equal{\@anim@inputline}{}}{}{% + %initialise contents & transparency lists for each frame + \@anim@newkey{trlst@\the\@anim@curframe@zb}{}% + \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}% + \global\advance\@anim@curframe@zb by \@ne% + }% + \@anim@sanitizeJS% + \endlinechar=-1% suppress trailing space at input line end + \global\read\@anim@@tmlnfile to \@anim@inputline% + \@anim@endsanitize% + \edef\@anim@inputline{\@anim@inputline\space}% + \edef\@anim@inputline{\expandafter\zap@space\@anim@inputline\@empty}% + \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else% + \setboolean{@anim@eof}{false}\fi% + }% + \closein\@anim@@tmlnfile% + \global\let\@anim@transp\@anim@frames% total number of transparencies + \xdef\@anim@frames{\the\@anim@curframe@zb}%total number of actual frames + \global\@anim@tmpcnt=\@anim@frames% + \global\advance\@anim@tmpcnt by -\@ne% + \xdef\@anim@maxframe{\the\@anim@tmpcnt}% highest frame index + \global\@anim@curframe@zb=\z@% + \gdef\@anim@maxlayer{0}% highest layer index + %reopen timeline file and build timeline + \openin\@anim@@tmlnfile=\@anim@tmlnfile% + \global\@anim@lineno=\z@% + \@anim@sanitizeJS% + \endlinechar=-1% suppress trailing space at input line end + \global\read\@anim@@tmlnfile to \@anim@inputline% + \@anim@endsanitize% + \edef\@anim@inputlinenospc{\@anim@inputline\space}% + \edef\@anim@inputlinenospc{% + \expandafter\zap@space\@anim@inputlinenospc\@empty}% + \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else% + \setboolean{@anim@eof}{false}\fi% + \message{<building timeline a#1 from file `\@anim@tmlnfile':}% + \whiledo{\NOT\boolean{@anim@eof}}{% + \global\advance\@anim@lineno by \@ne% + \ifthenelse{\equal{\@anim@inputlinenospc}{}}{}{% + %process input line + \global\@anim@curfield=\z@% + \expandafter\@anim@parseline\@anim@inputline:\@nil% + %combine the layers of the current frame + \global\@anim@curlayer=\z@% + \loop\ifnum\@anim@curlayer>\@anim@maxlayer\relax\else% + \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{% + \@anim@getkeyval{frmcontent@\the\@anim@curframe@zb}% + \@anim@getkeyval{% + layercontent@\the\@anim@curframe@zb.\the\@anim@curlayer}% + }% + \@anim@newkey{trlst@\the\@anim@curframe@zb}{% + \@anim@getkeyval{trlst@\the\@anim@curframe@zb}% + \@anim@getkeyval{% + layertrlst@\the\@anim@curframe@zb.\the\@anim@curlayer}% + }% + \@anim@newkey{% + layercontent@\the\@anim@curframe@zb.\the\@anim@curlayer}{}% + \@anim@newkey{% + layertrlst@\the\@anim@curframe@zb.\the\@anim@curlayer}{}% + \global\advance\@anim@curlayer by \@ne% + \repeat% + %detect multiple inclusion of the same transp. in the current frame + \xdef\@anim@trlst{% + \the\@anim@curframe@zb.\@anim@getkeyval{trlst@\the\@anim@curframe@zb}}% + \expandafter\@anim@findmult\@anim@trlst,\@nil% + \if@anim@export\if@anim@insideexport\else\anim@export\fi\fi% + %insert frame Widget + \@anim@makeframe{#1}{\the\@anim@curframe@zb}% + \if@anim@export\endanim@export\fi% + %clean-up + \expandafter\@anim@resetmult\@anim@trlst,\@nil% + \@anim@newkey{trlst@\the\@anim@curframe@zb}{}% + \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}% + \message{.}% + \global\advance\@anim@curframe@zb by \@ne% + }% + \@anim@sanitizeJS% + \endlinechar=-1% suppress trailing space at input line end + \global\read\@anim@@tmlnfile to \@anim@inputline% + \@anim@endsanitize% + \edef\@anim@inputlinenospc{\@anim@inputline\space}% + \edef\@anim@inputlinenospc{% + \expandafter\zap@space\@anim@inputlinenospc\@empty}% + \ifeof\@anim@@tmlnfile\setboolean{@anim@eof}{true}\else% + \setboolean{@anim@eof}{false}% + \fi% + }% + \message{\the\@anim@curframe@zb\space frames built}% + \closein\@anim@@tmlnfile% + %check for unused transparencies + \global\@anim@tmpcnt=\z@% + \loop\ifnum\@anim@transp>\@anim@tmpcnt\relax% + \ifcsname u@tr\the\@anim@tmpcnt\endcsname% + {\expandafter\global\expandafter\let\csname + u@tr\the\@anim@tmpcnt\endcsname\@undefined}% + \else% + \PackageWarning{animate}{% + Transparency \the\@anim@tmpcnt\space has never been used\MessageBreak% + in the current animation.\MessageBreak% + Timeline ``\@anim@tmlnfile'',\MessageBreak\jobname.tex% + }% + \ifcsname @anim@nusewarned\endcsname\else% + \AtEndDocument{% + \PackageWarningNoLine{animate}{\@anim@nusewarning}% + }% + \gdef\@anim@nusewarned{}% + \fi% + \fi% + \global\advance\@anim@tmpcnt by \@ne% + \repeat% + \message{>}% +} + +%reads one line of timeline file and splits into its colon separated parts +\def\@anim@parseline#1:#2\@nil{% + \ifcase\@anim@curfield\relax% + %first field: a star (pause frame) + \if@anim@step\else% + \edef\@anim@tmp{#1\space}% + \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}% + \ifthenelse{\equal{\@anim@tmp}{*}}{% + \xdef\@anim@pauseat{% + \@anim@pauseat% + a\the\@anim@num_pauseAt[\the\@anim@curframe@zb]=1;% + }% + \setboolean{@anim@pauseframes}{true}% + }{}% + \fi% + \global\advance\@anim@curfield by \@ne% + \@anim@parseline#2\@nil% + \or% + \if@anim@step\else% + %second field: new frame rate + \@anim@processfpsarg{#1}% + \fi% + \global\advance\@anim@curfield by \@ne% + \@anim@parseline#2\@nil% + \or% + %parse the third field (list of layer specifications) + \global\@anim@curlayer=\z@% + \edef\@anim@tmp{#1\space}% + \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}% + \expandafter\@anim@parsethird\@anim@tmp;\@nil% + \edef\@anim@tmp{#2\space}% + \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}% + %fourth field: JavaScript provided by the user + \ifx\@anim@tmp\empty\else\@anim@parseforth#2\@nil\fi% + \fi% +} + +%parses frame contents specification (semicolon separated list of layer +%specifications) +\def\@anim@parsethird#1;#2\@nil{% + \ifthenelse{\equal{#1}{}}{}{\@anim@parselayer#1,\@nil}%process one layer spec + \ifthenelse{\equal{#2}{}}{}{% + \global\advance\@anim@curlayer by \@ne% + \ifnum\@anim@curlayer>\@anim@maxlayer\relax% + \xdef\@anim@maxlayer{\the\@anim@curlayer}% + \fi% + \@anim@parsethird#2\@nil% + }% +} + +%process JavaScript field +\def\@anim@parseforth#1:\@nil{% + \edef\@anim@tmp{#1\space}% + \edef\@anim@tmp{\expandafter\zap@space\@anim@tmp\@empty}% + \ifx\@anim@tmp\@empty\else% + \xdef\@anim@usrjsat{% + \@anim@usrjsat% + a\the\@anim@num_usrJS[\the\@anim@curframe@zb]=function(){#1};% + }% + \setboolean{@anim@usrjs}{true}% + \fi% +} + +%parses contents of one layer specification (comma separated list of transp. +%specs) +\def\@anim@parselayer#1,#2\@nil{% + \ifthenelse{\equal{#1}{}}{}{\@anim@process#1x\@nil}%process one transp spec + \ifthenelse{\equal{#2}{}}{}{\@anim@parselayer#2\@nil}% +} + +%process transparency spec, such as `123' or `456x78' or `9x0' or `c' (clear +%transparency stack) +\def\@anim@process#1x#2\@nil{% + %determine number of repetitions of current transparency + \ifthenelse{\equal{#2}{}}{% + \gdef\@anim@repeats{1}% + }{% + \@anim@getrepetitions#2\@nil% + }% + \ifnum\@anim@repeats=\z@\relax% =0 means: repeat until end of timeline + \let\@anim@repeatuntil\@anim@frames% + \else% + \global\@anim@tmpcnt=\@anim@curframe@zb% + \global\advance\@anim@tmpcnt by \@anim@repeats% + \ifnum\@anim@frames<\@anim@tmpcnt\relax% + \let\@anim@repeatuntil\@anim@frames% + \else% + \edef\@anim@repeatuntil{\the\@anim@tmpcnt}% + \fi% + \fi% + %test whether transparency stack of the current layer is to be cleared + \ifthenelse{\equal{#1}{c}\OR\equal{#1}{C}}{% + \global\@anim@tmpcnt=\@anim@curframe@zb% + \loop\ifnum\@anim@frames>\@anim@tmpcnt\relax% + %clear layer content + \@anim@newkey{layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}{}% + %clear list of transparencies used in the current layer + \@anim@newkey{layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}{}% + \global\advance\@anim@tmpcnt by \@ne% + \repeat% + }{% + %build contents of animation layer according to transparency specifications + \ifnum\@anim@transp<#1\relax\else% ignore non-existing + \ifnum\@anim@transp=#1\relax\else% transparencies + \global\@anim@tmpcnt=\@anim@curframe@zb% + \loop\ifnum\@anim@repeatuntil>\@anim@tmpcnt\relax% + %layer content + \edef\@anim@tmpvar{\@anim@getkeyval{% + layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}}% + \@anim@newkey{layercontent@\the\@anim@tmpcnt.\the\@anim@curlayer}{% + \@anim@tmpvar\@anim@getkeyval{img@#1},% + }% + %append transp. to list of transparencies used in the current layer + \edef\@anim@tmpvar{\@anim@getkeyval{% + layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}}% + \@anim@newkey{layertrlst@\the\@anim@tmpcnt.\the\@anim@curlayer}{% + \@anim@tmpvar#1,}% + \global\advance\@anim@tmpcnt by \@ne% + \repeat% + \fi% + \fi% + }% +} +%get number of repetitions of frame +\def\@anim@getrepetitions#1x\@nil{% + \gdef\@anim@repeats{#1}% +} + +\begingroup\catcode`\_=13\let_\space +\xdef\@anim@multwarning{% + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak% + @_In_certain_animation_frames,_transparencies_were_@\MessageBreak% + @_included_multiple_times._This_may_considerably___@\MessageBreak% + @_slow_down_animation_speed._Revise_the_timeline___@\MessageBreak% + @_file_of_the_corresponding_animation!_____________@\MessageBreak% + @__________________________________________________@\MessageBreak% + @_See_the_transcript_file__________________________@\MessageBreak% + @___``\jobname.log''\MessageBreak% + @_for_additional_information_about_which_anima-____@\MessageBreak% + @_tion(s)_are_affected!____________________________@\MessageBreak% + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% +}% +\endgroup + +%detects multiple inclusion of the same transparency +\def\@anim@findmult#1.#2,#3\@nil{% + \ifthenelse{\equal{#2}{}}{}{% + \@anim@newkey{u@tr#2}{}% mark current transp. as `used' + \ifcsname m@tr#2\endcsname% + \PackageWarning{animate}{% + Transparency #2 more than once included in frame #1.% + \MessageBreak% + Timeline ``\@anim@tmlnfile'' on input line \the\@anim@lineno,% + \MessageBreak\jobname.tex% + }% + \ifcsname @anim@multwarned\endcsname\else% + \AtEndDocument{% + \PackageWarningNoLine{animate}{\@anim@multwarning}% + }% + \gdef\@anim@multwarned{}% + \fi% + \else% + {\expandafter\xdef\csname m@tr#2\endcsname{}}% + \fi% + }% + \ifthenelse{\equal{#3}{}}{}{% + \@anim@findmult#1.#3\@nil% + }% +} +%reset transparency list +\def\@anim@resetmult#1.#2,#3\@nil{% + \ifthenelse{\equal{#2}{}}{}{% + {\expandafter\global\expandafter\let\csname m@tr#2\endcsname\@undefined}% + }% + \ifthenelse{\equal{#3}{}}{}{% + \@anim@resetmult#1.#3\@nil% + }% +} + +%command options +\define@key{anim@user}{label}{% + \gdef\@anim@label{#1}% + \ifcsname @anim@#1\endcsname% + \PackageWarning{animate}{Label #1 multiply defined} + \ifdefined\@anim@multlabel\else + \gdef\@anim@multlabel{}% + \AtEndDocument{% + \PackageWarningNoLine{animate}{% + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak + @ There are multiply-defined labels! @\MessageBreak + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}% + }% + \fi% + \fi% + \expandafter\gdef\csname @anim@#1\endcsname{}% +} +%setting the widget size +\define@key{anim@user}{width}{% + \gdef\@anim@widtharg{#1}% + \ifdefined\@anim@usrwd\else% + \global\advance\@anim@resizeflags by 4% + \def\@anim@usrwd{}% + \fi% +} +\define@key{anim@user}{height}{% + \gdef\@anim@heightarg{#1}% + \ifdefined\@anim@usrht\else% + \global\advance\@anim@resizeflags by 2% + \def\@anim@usrht{}% + \fi% +} +\define@key{anim@user}{totalheight}{% + \gdef\@anim@totheightarg{#1}% + \ifdefined\@anim@usrtht\else% + \global\advance\@anim@resizeflags by \@ne% + \def\@anim@usrtht{}% + \fi% +} +\define@key{anim@user}{depth}{% + \PackageWarning{animate}{Ignoring obsolete `depth' option.}% +} +\newboolean{@anim@iso} +\define@key{anim@user}{keepaspectratio}[true]{% + \setboolean{@anim@iso}{#1}% +} +\newboolean{@anim@hiresbb} +\define@key{anim@user}{hiresbb}[true]{% + \setboolean{@anim@hiresbb}{#1}% +} +\newboolean{@anim@interpolate} +\define@key{anim@user}{interpolate}[true]{% + \setboolean{@anim@interpolate}{#1}% +} +\define@key{anim@user}{pagebox}{% + \gdef\@anim@pagebox{#1}% +} +\define@key{anim@user}{scale}{% + \gdef\@anim@boxscale{#1}% +} +\define@key{anim@user}{buttonsize}{% + \gdef\@anim@btnsize{#1}% +} +\def\@anim@colours#1:#2\@nil{% helper macro to get number of colour components + \xdef\@anim@colour{\@anim@colour\space #1}% and to replace : by ` ' in the arg + \ifthenelse{\equal{#2}{}}{}{% + \global\advance\@anim@tmpcnt by \@ne% + \@anim@colours#2\@nil% + }% +} +\define@key{anim@user}{buttonbg}{%background colour of buttons + \global\@anim@tmpcnt=\@ne% + \gdef\@anim@colour{}% + \@anim@colours#1:\@nil% + \global\let\@anim@bgcolour\@anim@colour% + \ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1% + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@bg{\@anim@colour\space setgray}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@bg{\@anim@colour\space setrgbcolor}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@bg{\@anim@colour\space setcmykcolor}% + \fi% + \fi% + \fi% + \else% pdftex and dvipdfmx + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@bg{\@anim@colour\space g}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@bg{\@anim@colour\space rg}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@bg{\@anim@colour\space k}% + \fi% + \fi% + \fi% + \fi% +} +\define@key{anim@user}{buttonfg}{%stroking colour of buttons + \global\@anim@tmpcnt=\@ne% + \gdef\@anim@colour{}% + \@anim@colours#1:\@nil% + \global\let\@anim@fgcolour\@anim@colour% + \ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1% + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@fg{\@anim@colour\space setgray}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@fg{\@anim@colour\space setrgbcolor}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@fg{\@anim@colour\space setcmykcolor}% + \fi% + \fi% + \fi% + \else% pdftex and dvipdfmx + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@fg{\@anim@colour\space G}% + \xdef\@anim@@@fg{\@anim@colour\space g}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@fg{\@anim@colour\space RG}% + \xdef\@anim@@@fg{\@anim@colour\space rg}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@fg{\@anim@colour\space K}% + \xdef\@anim@@@fg{\@anim@colour\space k}% + \fi% + \fi% + \fi% + \fi% +} +\define@key{anim@user}{buttonalpha}{%button opacity + \xdef\@anim@alpha{#1}% +} +\define@key{anim@user}{alttext}{% + \ifthenelse{\equal{#1}{none}}{% + \gdef\@anim@alttext{}% + }{% + \xdef\@anim@alttext{/Contents (#1)}% + }% +} + +\newboolean{@anim@controls} +\newboolean{@anim@controls@play} +\newboolean{@anim@controls@step} +\newboolean{@anim@controls@stop} +\newboolean{@anim@controls@speed} +\def\@anim@user@controls@all{% + \setboolean{@anim@controls}{true}% + \setboolean{@anim@controls@play}{true}% + \setboolean{@anim@controls@step}{true}% + \setboolean{@anim@controls@stop}{true}% + \setboolean{@anim@controls@speed}{true}% +} +\def\@anim@user@controls@none{% + \setboolean{@anim@controls}{false}% + \setboolean{@anim@controls@play}{false}% + \setboolean{@anim@controls@step}{false}% + \setboolean{@anim@controls@stop}{false}% + \setboolean{@anim@controls@speed}{false}% +} +\define@key{anim@user}{controls}[all]{% + \@anim@user@controls@none% + \setkeys{anim@user@controls}{#1}% +} +\define@key{anim@user@controls}{all}[]{\@anim@user@controls@all} +\define@key{anim@user@controls}{true}[]{\@anim@user@controls@all} +\define@key{anim@user@controls}{on}[]{\@anim@user@controls@all} +\define@key{anim@user@controls}{none}[]{\@anim@user@controls@none} +\define@key{anim@user@controls}{false}[]{\@anim@user@controls@none} +\define@key{anim@user@controls}{off}[]{\@anim@user@controls@none} +\define@key{anim@user@controls}{play}[]{% + \setboolean{@anim@controls}{true}% + \setboolean{@anim@controls@play}{true}% +} +\define@key{anim@user@controls}{step}[]{% + \setboolean{@anim@controls}{true}% + \setboolean{@anim@controls@step}{true}% +} +\define@key{anim@user@controls}{stop}[]{% + \setboolean{@anim@controls}{true}% + \setboolean{@anim@controls@stop}{true}% +} +\define@key{anim@user@controls}{speed}[]{% + \setboolean{@anim@controls}{true}% + \setboolean{@anim@controls@speed}{true}% +} + +\newboolean{@anim@loop} +\define@key{anim@user}{loop}[true]{% + \setboolean{@anim@loop}{#1}% +} +\newboolean{@anim@autoplay} +\define@key{anim@user}{autoplay}[true]{% + \setboolean{@anim@autoplay}{#1}% + \if@anim@autoplay% + \setboolean{@anim@autoresume}{false}% + \fi% +} +\newboolean{@anim@autoresume} +\define@key{anim@user}{autoresume}[true]{% + \setboolean{@anim@autoresume}{#1}% + \if@anim@autoresume% + \setboolean{@anim@autoplay}{false}% + \fi% +} +\newboolean{@anim@autopause} +\define@key{anim@user}{autopause}[true]{% + \setboolean{@anim@autopause}{#1}% +} +\newboolean{@anim@palindrome} +\define@key{anim@user}{palindrome}[true]{% + \setboolean{@anim@palindrome}{#1}% +} +\def\@anim@mone{-1}\def\@anim@mtwo{-2} +\define@key{anim@user}{poster}[first]{% <num> | first | last | none + \ifthenelse{% + \equal{#1}{first}% + }{% + \gdef\@anim@poster{0}% + }{% + \ifthenelse{% + \equal{#1}{last}% + }{% + \gdef\@anim@poster{-1}% + }{% + \ifthenelse{% + \equal{#1}{none}% + }{% + \gdef\@anim@poster{-2}% + }{% + \ifnum#1<\z@\relax% + \PackageError{animate}{% + Poster frame `#1' is out-of-bounds on\MessageBreak% + input line \the\inputlineno.\MessageBreak% + Try one of `poster=first' or `poster=none'% + }{}% + \fi% + \gdef\@anim@poster{#1}% + }% + }% + }% +} +\newboolean{@anim@step} +\define@key{anim@user}{step}[true]{% + \setboolean{@anim@step}{#1}% +} +\newboolean{@anim@draft} +\define@key{anim@user}{draft}[true]{% + \setboolean{@anim@draft}{#1}% +} +\define@key{anim@user}{final}[true]{% + \ifthenelse{\equal{#1}{true}}{% + \setboolean{@anim@draft}{false}% + }{% + \setboolean{@anim@draft}{true}% + }% +} +\setboolean{@anim@nomouse}{false} +\define@key{anim@user}{nomouse}[true]{% + \setboolean{@anim@nomouse}{#1}% +} +\define@key{anim@user}{timeline}{% + \IfFileExists{#1}{% + \xdef\@anim@tmlnfile{\expandafter\zap@finalspace\@filef@und\@nil}% + \setboolean{@anim@timeline}{true}% + }{% + \PackageError{animate}{timeline file `#1' cannot be opened for reading% + }{% + Make sure file `#1' exists and is readable!% + }% + }% +} +\define@key{anim@user}{begin}{% + \gdef\@anim@begin{#1}% +} +\define@key{anim@user}{end}{% + \gdef\@anim@end{#1}% +} +\define@key{anim@user}{every}{% embed every #1th frame + \ifnum#1<\@ne\relax\gdef\@anim@every{1}\else\gdef\@anim@every{#1}\fi% +} +\define@key{anim@user}{bb}{% + \g@addto@macro\@anim@gropts{, bb=#1}% +} +\define@key{anim@user}{viewport}{% + \g@addto@macro\@anim@gropts{, viewport=#1}% +} +\define@key{anim@user}{trim}{% + \g@addto@macro\@anim@gropts{, trim=#1}% +} +\define@key{anim@user}{angle}{% + \g@addto@macro\@anim@gropts{, angle=#1}% +} +\newboolean{@anim@meas} +\define@key{anim@user}{measure}[true]{% + \setboolean{@anim@meas}{#1}% +} +\define@key{anim@user}{method}{% + \ifthenelse{\equal{#1}{icon}}{% + \def\@anim@method{\z@}% + }{% + \ifthenelse{\equal{#1}{widget}}{% + \def\@anim@method{\@ne}% + }{% + \ifthenelse{\equal{#1}{ocg}}{% + \def\@anim@method{\tw@}% + }{}% + }% + }% +} +\define@key{anim@user}{useocg}[]{% + \PackageError{animate}{% + Option `useocg' has been removed.\MessageBreak% + Use `method=ocg' instead% + }{}% +} + +\define@key{anim@user}{type}{\gdef\@anim@ftype{#1}}% + +%macro to reset macros and booleans +\def\@anim@reset{% + \gdef\@anim@label{}% + \setboolean{@anim@doscaling}{true}% + \global\let\@anim@boxscale\@anim@@boxscale% + \global\let\if@anim@iso=\if@anim@@iso% + \global\let\if@anim@hiresbb=\if@anim@@hiresbb% + \global\let\if@anim@interpolate=\if@anim@@interpolate% + \global\let\@anim@pagebox\@anim@@pagebox% + \global\@anim@resizeflags\@anim@@resizeflags% + \global\let\@anim@widtharg\@anim@@widtharg% + \global\let\@anim@heightarg\@anim@@heightarg% + \global\let\@anim@totheightarg\@anim@@totheightarg% + \let\@anim@usrwd\@anim@pkgwd% + \let\@anim@usrht\@anim@pkght% + \let\@anim@usrtht\@anim@pkgtht% + \let\@anim@alttext\@anim@@alttext% + \global\let\@anim@bg\@anim@@bg% + \global\let\@anim@fg\@anim@@fg% + \global\let\@anim@@@fg\@anim@@@@fg% + \global\let\@anim@bgcolour\@anim@@bgcolour% default button colours + \global\let\@anim@fgcolour\@anim@@fgcolour% + \global\let\@anim@alpha\@anim@@alpha% + \global\let\@anim@btnsize\@anim@@btnsize% + \global\let\@anim@poster\@anim@@poster% + \global\let\if@anim@controls=\if@anim@@controls% + \global\let\if@anim@controls@play=\if@anim@@controls@play% + \global\let\if@anim@controls@step=\if@anim@@controls@step% + \global\let\if@anim@controls@stop=\if@anim@@controls@stop% + \global\let\if@anim@controls@speed=\if@anim@@controls@speed% + \global\let\if@anim@loop=\if@anim@@loop% + \global\let\if@anim@autoplay=\if@anim@@autoplay% + \global\let\if@anim@autoresume=\if@anim@@autoresume% + \global\let\if@anim@autopause=\if@anim@@autopause% + \global\let\if@anim@palindrome=\if@anim@@palindrome% + \global\let\if@anim@step=\if@anim@@step% + \global\let\if@anim@draft=\if@anim@@draft% + \global\let\@anim@method\@anim@@method% + \global\let\if@anim@nomouse=\if@anim@@nomouse% + \gdef\@anim@properties{}% + \setboolean{@anim@pauseframes}{false}% + \gdef\@anim@pauseat{}% + \setboolean{@anim@chfps}{false}% + \setboolean{@anim@usrjs}{false}% + \gdef\@anim@nfpsat{}% + \gdef\@anim@pfpsat{}% + \gdef\@anim@usrjsat{}% + \gdef\@anim@tmlnfile{}% + \setboolean{@anim@timeline}{false}% + \gdef\@anim@begin{}% + \gdef\@anim@end{}% + \gdef\@anim@every{1}% frames to be included + \gdef\@anim@gropts{}% + \setboolean{@anim@multipage}{false}% + \setboolean{@anim@meas}{false}% + \setboolean{@anim@autoplayorresume}{false}% + \global\let\@anim@ftype\@anim@@ftype% +} + +%package options +\define@key{anim@pkg}{dvips}[]{% + \ifthenelse{\equal{#1}{}}{}{% + \PackageError{animate}{% + Package option `dvips' does not accept arguments% + }{}% + }% +}% +\define@key{anim@pkg}{dvipdfmx}[]{ + \ifthenelse{\equal{#1}{}}{}{% + \PackageError{animate}{% + Package option `dvipdfmx' does not accept arguments% + }{}% + }% +}% +\define@key{anim@pkg}{dvisvgm}[]{ + \ifthenelse{\equal{#1}{}}{}{% + \PackageError{animate}{% + Package option `dvisvgm' does not accept arguments% + }{}% + }% +}% +\define@key{anim@pkg}{xetex}[]{ + \ifthenelse{\equal{#1}{}}{}{% + \PackageError{animate}{% + Package option `xetex' does not accept arguments% + }{}% + }% +}% +\define@key{anim@pkg}{export}[]{ + \ifthenelse{\equal{#1}{}}{}{% + \PackageError{animate}{% + Package option `export' does not accept arguments% + }{}% + }% +}% +\def\@anim@@bg{} +\def\@anim@@bgcolour{} +\define@key{anim@pkg}{buttonbg}{%background colour of buttons + \global\@anim@tmpcnt=\@ne% + \gdef\@anim@colour{}% + \@anim@colours#1:\@nil% + \global\let\@anim@@bgcolour\@anim@colour% + \ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1% + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@@bg{\@anim@colour\space setgray}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@@bg{\@anim@colour\space setrgbcolor}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@@bg{\@anim@colour\space setcmykcolor}% + \fi% + \fi% + \fi% + \else% pdftex and dvipdfmx + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@@bg{\@anim@colour\space g}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@@bg{\@anim@colour\space rg}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@@bg{\@anim@colour\space k}% + \fi% + \fi% + \fi% + \fi% +} + +\ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1 + %dvips .OR. dvisvgm + \def\@anim@@fg{0 setgray}\def\@anim@@@@fg{} +\else% pdftex and dvipdfmx + \def\@anim@@fg{0 G}\def\@anim@@@@fg{0 g} +\fi +\def\@anim@@fgcolour{} +\define@key{anim@pkg}{buttonfg}{%stroking colour of buttons + \global\@anim@tmpcnt=\@ne% + \gdef\@anim@colour{}% + \@anim@colours#1:\@nil% + \global\let\@anim@@fgcolour\@anim@colour% + \ifnum\if@anim@dvips 1\else\if@anim@dvisvgm 1\else0\fi\fi=1% + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@@fg{\@anim@colour\space setgray}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@@fg{\@anim@colour\space setrgbcolor}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@@fg{\@anim@colour\space setcmykcolor}% + \fi% + \fi% + \fi% + \else% pdftex and dvipdfmx + \ifnum\@anim@tmpcnt=\@ne\relax% + \xdef\@anim@@fg{\@anim@colour\space G}% + \xdef\@anim@@@@fg{\@anim@colour\space g}% + \else% + \ifnum\@anim@tmpcnt=3\relax% + \xdef\@anim@@fg{\@anim@colour\space RG}% + \xdef\@anim@@@@fg{\@anim@colour\space rg}% + \else% + \ifnum\@anim@tmpcnt=4\relax% + \xdef\@anim@@fg{\@anim@colour\space K}% + \xdef\@anim@@@@fg{\@anim@colour\space k}% + \fi% + \fi% + \fi% + \fi% +} +\def\@anim@@alpha{} +\define@key{anim@pkg}{buttonalpha}{%button opacity + \xdef\@anim@@alpha{#1}% +} +\newcount\@anim@@resizeflags +\def\@anim@@widtharg{\width}% +\define@key{anim@pkg}{width}{% + \def\@anim@@widtharg{#1}% + \ifdefined\@anim@pkgwd\else% + \advance\@anim@@resizeflags by 4% + \def\@anim@pkgwd{}% + \fi% +} +\def\@anim@@heightarg{\height}% +\define@key{anim@pkg}{height}{% + \def\@anim@@heightarg{#1}% + \ifdefined\@anim@pkght\else% + \advance\@anim@@resizeflags by 2% + \def\@anim@pkght{}% + \fi% +} +\def\@anim@@totheightarg{\totalheight}% +\define@key{anim@pkg}{totalheight}{% + \def\@anim@@totheightarg{#1}% + \ifdefined\@anim@pkgtht\else% + \advance\@anim@@resizeflags by \@ne% + \def\@anim@pkgtht{}% + \fi% +} +\newboolean{@anim@@iso} +\define@key{anim@pkg}{keepaspectratio}[true]{% + \setboolean{@anim@@iso}{#1}% +} +\newboolean{@anim@@hiresbb} +\define@key{anim@pkg}{hiresbb}[true]{% + \setboolean{@anim@@hiresbb}{#1}% +} +\newboolean{@anim@@interpolate} +\define@key{anim@pkg}{interpolate}[true]{% + \setboolean{@anim@@interpolate}{#1}% +} +\def\@anim@@pagebox{} +\define@key{anim@pkg}{pagebox}{% + \def\@anim@@pagebox{#1}% +} +\def\@anim@@boxscale{1}% +\define@key{anim@pkg}{scale}{% + \def\@anim@@boxscale{#1}% +} +\def\@anim@@btnsize{1.44em}% +\define@key{anim@pkg}{buttonsize}{% + \gdef\@anim@@btnsize{#1}% +} +\edef\@anim@@alttext{/Contents(animation by animate[\@anim@version])} +\define@key{anim@pkg}{alttext}{% + \ifthenelse{\equal{#1}{none}}{% + \gdef\@anim@@alttext{}% + }{% + \xdef\@anim@@alttext{/Contents (#1)}% + }% +} + +\newboolean{@anim@@controls} +\newboolean{@anim@@controls@play} +\newboolean{@anim@@controls@step} +\newboolean{@anim@@controls@stop} +\newboolean{@anim@@controls@speed} +\def\@anim@pkg@controls@all{% + \setboolean{@anim@@controls}{true}% + \setboolean{@anim@@controls@play}{true}% + \setboolean{@anim@@controls@step}{true}% + \setboolean{@anim@@controls@stop}{true}% + \setboolean{@anim@@controls@speed}{true}% +} +\def\@anim@pkg@controls@none{% + \setboolean{@anim@@controls}{false}% + \setboolean{@anim@@controls@play}{false}% + \setboolean{@anim@@controls@step}{false}% + \setboolean{@anim@@controls@stop}{false}% + \setboolean{@anim@@controls@speed}{false}% +} +\define@key{anim@pkg}{controls}[all]{% + \@anim@pkg@controls@none% + \setkeys{anim@pkg@controls}{#1}% +} +\define@key{anim@pkg@controls}{all}[]{\@anim@pkg@controls@all} +\define@key{anim@pkg@controls}{true}[]{\@anim@pkg@controls@all} +\define@key{anim@pkg@controls}{on}[]{\@anim@pkg@controls@all} +\define@key{anim@pkg@controls}{none}[]{\@anim@pkg@controls@none} +\define@key{anim@pkg@controls}{false}[]{\@anim@pkg@controls@none} +\define@key{anim@pkg@controls}{off}[]{\@anim@pkg@controls@none} +\define@key{anim@pkg@controls}{play}[]{% + \setboolean{@anim@@controls}{true}% + \setboolean{@anim@@controls@play}{true}% +} +\define@key{anim@pkg@controls}{step}[]{% + \setboolean{@anim@@controls}{true}% + \setboolean{@anim@@controls@step}{true}% +} +\define@key{anim@pkg@controls}{stop}[]{% + \setboolean{@anim@@controls}{true}% + \setboolean{@anim@@controls@stop}{true}% +} +\define@key{anim@pkg@controls}{speed}[]{% + \setboolean{@anim@@controls}{true}% + \setboolean{@anim@@controls@speed}{true}% +} + +\newboolean{@anim@@loop} +\setboolean{@anim@@loop}{false}% +\define@key{anim@pkg}{loop}[true]{% + \setboolean{@anim@@loop}{#1}% +} +\newboolean{@anim@@autoplay} +\setboolean{@anim@@autoplay}{false} +\define@key{anim@pkg}{autoplay}[true]{% + \setboolean{@anim@@autoplay}{#1}% + \if@anim@@autoplay\setboolean{@anim@@autoresume}{false}\fi% +} +\newboolean{@anim@@autoresume} +\setboolean{@anim@@autoresume}{false} +\define@key{anim@pkg}{autoresume}[true]{% + \setboolean{@anim@@autoresume}{#1}% + \if@anim@@autoresume\setboolean{@anim@@autoplay}{false}\fi% +} +\newboolean{@anim@@autopause} +\setboolean{@anim@@autopause}{false} +\define@key{anim@pkg}{autopause}[true]{% + \setboolean{@anim@@autopause}{#1}% +} +\newboolean{@anim@@palindrome} +\setboolean{@anim@@palindrome}{false} +\define@key{anim@pkg}{palindrome}[true]{% + \setboolean{@anim@@palindrome}{#1}% +} +\gdef\@anim@@poster{0}% +\define@key{anim@pkg}{poster}[first]{% + \ifthenelse{% + \equal{#1}{first}% + }{% + \gdef\@anim@@poster{0}% + }{% + \ifthenelse{% + \equal{#1}{last}% + }{% + \gdef\@anim@@poster{-1}% + }{% + \ifthenelse{% + \equal{#1}{none}% + }{% + \gdef\@anim@@poster{-2}% + }{% + \ifnum#1<\z@\relax% + \PackageError{animate}{% + Poster frame `#1' is out-of-bounds on\MessageBreak% + input line \the\inputlineno.\MessageBreak% + Try one of `poster=first' or `poster=none'% + }{}% + \fi% + \gdef\@anim@@poster{#1}% + }% + }% + }% +} +\newboolean{@anim@@step} +\setboolean{@anim@@step}{false} +\define@key{anim@pkg}{step}[true]{% + \setboolean{@anim@@step}{#1}% +} +\newboolean{@anim@@draft} +\ifdraft{%globally set by document class + \setboolean{@anim@@draft}{true}% +}{% + \setboolean{@anim@@draft}{false}% +}% +\define@key{anim@pkg}{draft}[true]{% + \setboolean{@anim@@draft}{#1}% + \if@anim@export% + \setboolean{@anim@@draft}{false}% + \fi% +} +\define@key{anim@pkg}{final}[true]{% + \ifthenelse{\equal{#1}{true}}{% + \setboolean{@anim@@draft}{false}% + }{% + \setboolean{@anim@@draft}{true}% + }% +} +\newboolean{@anim@@nomouse} +\setboolean{@anim@@nomouse}{false} +\define@key{anim@pkg}{nomouse}[true]{% + \setboolean{@anim@@nomouse}{#1}% +} + +%file type (extension) of graphics files to be embedded +\def\@anim@@ftype{}% +\define@key{anim@pkg}{type}{\def\@anim@@ftype{#1}}% + +% animation method: icon vs. widget vs. ocg based +\define@key{anim@pkg}{method}{% + \ifthenelse{\equal{#1}{icon}}{% + \def\@anim@@method{\z@}% + }{% + \ifthenelse{\equal{#1}{widget}}{% + \def\@anim@@method{\@ne}% + }{% + \ifthenelse{\equal{#1}{ocg}}{% + \def\@anim@@method{\tw@}% + }{}% ignoring wrong input + }% + }% +} +\define@key{anim@pkg}{useocg}[]{% + \PackageError{animate}{% + Package option `useocg' has been removed.\MessageBreak% + Use `method=ocg' instead% + }{}% +} + +%default animation method is Icon based +\def\@anim@@method{\z@} + +%process package options +\def\@anim@setpkgkeys#1{\setkeys{anim@pkg}{#1}} +\edef\@anim@pkgopts{{\@ptionlist{\@currname.\@currext}}} +\expandafter\@anim@setpkgkeys\@anim@pkgopts + +%%%%%%%%%%%%%%%%%%%%%%%% +% JavaScript part +%%%%%%%%%%%%%%%%%%%%%%%% + +%some JS engine specifics +% PDF readers +\def\@anim@consoleshow{console.show();} +\def\@anim@app{app.} +\def\@anim@setTimeout{setTimeOut} +\def\@anim@log{println} +\def\@anim@shift{shift} +\if@anim@dvisvgm + % web browsers + \def\@anim@consoleshow{} + \def\@anim@app{} + \def\@anim@setTimeout{setTimeout} + \def\@anim@log{log} + \def\@anim@shift{shiftKey} +\fi + +\begingroup + +% `$' --> newline in svg output +\if@anim@dvisvgm + %insert newline special + \catcode`\$=\active\gdef${{?nl}} +\else + \catcode`$=\catcode`\% +\fi + +%JS variable declarations +\gdef\@anim@@jsvardecls#1{% #1: @anim@num + var a#1_idx;$% animation frame index + \ifnum\@anim@method>\z@% + var a#1_on;$% add. index used by Widget and OCG methods + \fi% + %takes references to frame ocgs/Field objects belonging to the current + %animation + var a#1_fr;$% + \ifnum\@anim@method=\z@ % icon based + var a#1_wid;$% reference to interactive widget + \ifnum\@anim@poster=\@anim@mtwo + var blnk;$% + \fi% + \fi% + \if@anim@controls@play% + var a#1_btnPauseLeft,a#1_btnPlayLeft,a#1_btnPauseRight,a#1_btnPlayRight;$% + \fi% + var a#1_playsRight,a#1_isPaused;$% + \if@anim@step\else + var a#1_int;$% timer id (takes return val of setIntervall()) + % function pointers + var a#1_pause,a#1_playRight,a#1_playLeft,a#1_playBwd,a#1_playFwd;$% + \if@anim@pauseframes + %this array takes the frame numbers at which to pause playback + var a#1_pauseAt;$% + \fi% + \if@anim@chfps + %arrays that take frame numbers (array index) and fps values + var a#1_nFpsAt;$% + \fi + var a#1_fps,a#1_spd;$% frames per second (FPS), speed scaling factor + var a#1_setFps;$% function pointer for setting FPS + \if@anim@meas % speed measurement + var spc=String.fromCharCode(32);$% + var a#1_frcnt,% frame counter + a#1_msStart,% takes start time (in millisecs) + a#1_msEnd;$% takes end time (in millisecs) + var a#1_startMeas,a#1_stopMeas;$% function pointers + \fi% + \fi% + \if@anim@usrjs + % array of function pointers to timeline JS actions, indexed by frame number + var a#1_usrJS,a#1_curjs;$% + \fi + var a#1_seekFrame,a#1_gotoNext,a#1_gotoPrev;$% + var a#1_stopFirst,a#1_stopLast;$% + \if@anim@controls@play + var a#1_playPauseBwd,a#1_playPauseFwd;$% + \fi% + \if@anim@controls@step + var a#1_stepBwd,a#1_stepFwd;$% + \fi% + \if@anim@controls@speed + var a#1_spdIncr,a#1_spdDecr,a#1_spdReset;$% + \fi% + \ifx\empty\@anim@label\empty\else + var anim;$% + \fi% +} + +%JS initialisation +\gdef\@anim@@jsinit#1{% #1: @anim@num + if(!a#1_fr){$% + a#1_fr=new Array();$% + \ifnum\@anim@method>\z@% + a#1_on=0;$% + \fi% + \ifcase\@anim@method %icon based + a#1_wid=this.getField('anm#1');$%reference to interactive widget + for(var i=0;i<=\@anim@maxframe;i++){$% + a#1_fr[i]=this.getField('#1.'+i).buttonGetIcon();$% + }$% + \ifnum\@anim@poster=\@anim@mtwo + if(!blnk){$% blank poster (one for all animations) + blnk=this.getField('0000').buttonGetIcon();$% + }$% + \fi% + \or %widget based + %get array of animation frames + for(var i=0;i<=\@anim@maxframe;i++){$% + a#1_fr[i]=this.getField('#1.'+i);$% + }$% + \or %ocg based + %get array of ocgs of current page + \if@anim@dvisvgm + var ocg=document.getElementsByClassName('ocg');$% + \else + var ocg=this.getOCGs(this.pageNum);$% + \fi + for(var i=0;i<ocg.length;i++){$% + \if@anim@dvisvgm + var ocgName=ocg[i].getAttribute('id').split('.');$% + \else + var ocgName=ocg[i].name.split('.');$% + \fi + if(ocgName[0]==#1){$% + %get array of animation frames + a#1_fr[ocgName[1]]=ocg[i];$% + %set basic frame state + \if@anim@dvisvgm\else + a#1_fr[ocgName[1]].state=ocg[i].initState;$% + \fi% + }$% + }$% + \fi% + \if@anim@controls@play% + \if@anim@dvisvgm + a#1_btnPauseLeft=document.getElementById('#1.PauseLeft');$% + a#1_btnPlayLeft=document.getElementById('#1.PlayLeft');$% + a#1_btnPauseRight=document.getElementById('#1.PauseRight');$% + a#1_btnPlayRight=document.getElementById('#1.PlayRight');$% + \else + a#1_btnPauseLeft=this.getField('#1.PauseLeft');$% + a#1_btnPlayLeft=this.getField('#1.PlayLeft');$% + a#1_btnPauseRight=this.getField('#1.PauseRight');$% + a#1_btnPlayRight=this.getField('#1.PlayRight');$% + \fi% + \fi% + %playing state and direction + \if@anim@step% + \if@anim@palindrome + a#1_playsRight=true;$% + \fi% + \else + a#1_playsRight=true;$% + \fi + a#1_isPaused=false;$% + \if@anim@step\else + a#1_playing=false;$% + \if@anim@pauseframes + a#1_pauseAt=new Array();$% frame numbers at which to pause playback + \@anim@pauseat% + \fi% + \if@anim@chfps + %arrays that take frame numbers (array index) and fps values + a#1_nFpsAt=new Array(\@anim@nfpsat);$% + \fi + \ifdim\@anim@fps pt=\z@% + a#1_fps=1e-6;$% + \else + a#1_fps=\@anim@fps;$% + \fi + a#1_spd=1;$% + a#1_setFps=function(f){$% + a#1_fps=(f==0?1e-6:f);$% + if(a#1_playing){$% + if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$% + }$% + };$% + \fi% + \if@anim@usrjs + %array to take frame numbers (array index) and user provided JavaScript + a#1_usrJS=new Array();$% + \@anim@usrjsat% populate array + \fi% + %actions + a#1_seekFrame=function(f){$% + \ifnum\@anim@poster=\@anim@mtwo + if(f<-1){$% + \ifcase\@anim@method %icon based + a#1_wid.buttonSetIcon(blnk);$% + this.dirty=false;$% + \or %widget based + a#1_on=0;$% + a#1_fr[0].display=display.hidden;$% + this.dirty=false;$% + \or %ocg based + a#1_on=0;$% + \if@anim@dvisvgm + a#1_fr[0].setAttribute('visibility','hidden');$% + \else + a#1_fr[0].state=false;$% + \fi% + \fi + a#1_idx=-1;$% + }$% + \fi + if(f>\@anim@maxframe||f<0){return -1;}$% + a#1_idx=f;$% + \if@anim@usrjs + if(typeof a#1_usrJS[f]!=='undefined'){$% + a#1_curjs=a#1_usrJS[f];$% + var ret=\@anim@app\@anim@setTimeout(% execute JS in "parallel" + 'try{a#1_curjs();}catch(e){console.\@anim@log(e);}',1% + );$% + }$% + \fi% + \ifcase\@anim@method %icon based + a#1_wid.buttonSetIcon(a#1_fr[f]);$% + this.dirty=false;$% + \or %widget based + a#1_fr[a#1_on].display=display.hidden;$% + a#1_fr[f].display=display.visible;$% + a#1_on=f;$% + this.dirty=false;$% + \or%ocg based + \if@anim@dvisvgm + a#1_fr[a#1_on].setAttribute('visibility','hidden');$% + a#1_fr[f].setAttribute('visibility','visible');$% + \else + a#1_fr[a#1_on].state=false;$% + a#1_fr[f].state=true;$% + \fi + a#1_on=f;$% + \fi% + \if@anim@step\else% + \if@anim@chfps + if(a#1_nFpsAt[f]!=a#1_fps){% + a#1_setFps(a#1_nFpsAt[f]);% + }$% + \fi% + \if@anim@meas + a#1_frcnt++;$% + \fi% + \fi% + return 0;$% + };$% + a#1_stopFirst=function(){% + \if@anim@step + a#1_isPaused=false;% stop + \else + a#1_pause(true);% stop + \fi + a#1_seekFrame(0);% + };$% + a#1_stopLast=function(){% + \if@anim@step + a#1_isPaused=false;% stop + \else + a#1_pause(true);% stop + \fi + a#1_seekFrame(\@anim@maxframe);% + };$% + a#1_gotoNext=function(){$% + if(a#1_seekFrame(a#1_idx+1)<0){$% + \if@anim@step\else\if@anim@meas + a#1_stopMeas();$% + \fi\fi% + \if@anim@palindrome% + \if@anim@step + a#1_stopLast();$% + a#1_playsRight=false;$% + \else + if(a#1_playing){% + a#1_seekFrame(a#1_idx-1);% + a#1_playLeft();% + }$% + \fi% + \else% + \if@anim@step + a#1_stopLast();$% + \else% + \if@anim@loop + if(a#1_playing){% + a#1_seekFrame(0);% + a#1_setFps(\@anim@fps);% + }else{a#1_stopLast();}$% + \else + a#1_stopLast();$% + \fi% + \fi% + \fi + return;$% + }$% + \if@anim@step\else% + \if@anim@pauseframes + if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}$% + \fi% + \fi% + };$% + a#1_gotoPrev=function(){$% + if(a#1_seekFrame(a#1_idx-1)<0){$% + \if@anim@step\else\if@anim@meas + a#1_stopMeas();$% + \fi\fi% + \if@anim@palindrome% + \if@anim@step + a#1_stopFirst();$% + a#1_playsRight=true;$% + \else + if(a#1_playing){% + a#1_seekFrame(a#1_idx+1);% + a#1_playRight();% + }$% + \fi% + \else% + \if@anim@step + a#1_stopFirst();$% + \else% + \if@anim@loop + if(a#1_playing){% + a#1_seekFrame(\@anim@maxframe);% + }else{a#1_stopFirst();}$% + \else + a#1_stopFirst();$% + \fi% + \fi% + \fi + return;$% + }$% + \if@anim@step\else% + \if@anim@pauseframes + if(a#1_playing&&a#1_pauseAt[a#1_idx]){a#1_pause();}$% + \fi% + \fi% + };$% + \if@anim@step\else + a#1_pause=function(stop){$% + try{\@anim@app clearInterval(a#1_int);}catch(e){}$% + a#1_playing=false;$% + a#1_isPaused=!stop;$% + \if@anim@controls@play + \if@anim@dvisvgm + a#1_btnPauseLeft.setAttribute('visibility','hidden');$% + a#1_btnPlayLeft.setAttribute('visibility','visible');$% + a#1_btnPauseRight.setAttribute('visibility','hidden');$% + a#1_btnPlayRight.setAttribute('visibility','visible');$% + \else + a#1_btnPauseLeft.display=display.hidden;$% + a#1_btnPlayLeft.display=display.visible;$% + a#1_btnPauseRight.display=display.hidden;$% + a#1_btnPlayRight.display=display.visible;$% + this.dirty=false;$% + \fi% + \fi% + };$% + a#1_playRight=function(){$% + \if@anim@meas a#1_startMeas();\fi + var tmp_int;$% + try{tmp_int=\@anim@app setInterval('a#1_gotoNext()',% + 1000/a#1_fps/a#1_spd);}catch(e){}$% + try{\@anim@app clearInterval(a#1_int);}catch(e){}$% + a#1_int=tmp_int;$% + a#1_playsRight=true;$% + a#1_playing=true;$% + a#1_isPaused=false;$% + \if@anim@controls@play% + \if@anim@dvisvgm + a#1_btnPauseLeft.setAttribute('visibility','visible');$% + a#1_btnPlayLeft.setAttribute('visibility','hidden');$% + a#1_btnPauseRight.setAttribute('visibility','visible');$% + a#1_btnPlayRight.setAttribute('visibility','hidden');$% + \else + a#1_btnPauseLeft.display=display.visible;$% + a#1_btnPlayLeft.display=display.hidden;$% + a#1_btnPauseRight.display=display.visible;$% + a#1_btnPlayRight.display=display.hidden;$% + this.dirty=false;$% + \fi% + \fi% + };$% + a#1_playLeft=function(){$% + \if@anim@meas a#1_startMeas();\fi + var tmp_int;$% + try{tmp_int=\@anim@app setInterval('a#1_gotoPrev()',% + 1000/a#1_fps/a#1_spd);}catch(e){}$% + try{\@anim@app clearInterval(a#1_int);}catch(e){}$% + a#1_int=tmp_int;$% + a#1_playsRight=false;$% + a#1_playing=true;$% + a#1_isPaused=false;$% + \if@anim@controls@play% + \if@anim@dvisvgm + a#1_btnPauseLeft.setAttribute('visibility','visible');$% + a#1_btnPlayLeft.setAttribute('visibility','hidden');$% + a#1_btnPauseRight.setAttribute('visibility','visible');$% + a#1_btnPlayRight.setAttribute('visibility','hidden');$% + \else + a#1_btnPauseLeft.display=display.visible;$% + a#1_btnPlayLeft.display=display.hidden;$% + a#1_btnPauseRight.display=display.visible;$% + a#1_btnPlayRight.display=display.hidden;$% + this.dirty=false;$% + \fi% + \fi% + };$% + \if@anim@controls@play + a#1_playPauseBwd=function(){% + if(a#1_playing){a#1_pause();}else{a#1_playBwd();}% + };$% + a#1_playPauseFwd=function(){% + if(a#1_playing){a#1_pause();}else{a#1_playFwd();}% + };$% + \fi% + \if@anim@controls@speed + a#1_spdIncr=function(){% speed up animation + a#1_spd*=1.1;% + a#1_setFps(a#1_fps);% + };$% + a#1_spdDecr=function(){% slow down animation + a#1_spd/=1.1;% + a#1_setFps(a#1_fps);% + };$% + a#1_spdReset=function(){% reset to default speed + a#1_spd=1;% + a#1_setFps(a#1_fps);% + };$% + \fi% + \if@anim@meas + a#1_startMeas=function(){% + a#1_frcnt=1;% reset frame counter + a#1_msStart=(new Date()).getTime();% + };$% + a#1_stopMeas=function(){$% + a#1_msEnd=(new Date()).getTime();$% + \@anim@consoleshow console.\@anim@log(% + 'av.'+spc+'frame'+spc+'rate:'+spc+% + 1e3*a#1_frcnt/(a#1_msEnd-a#1_msStart)+spc+'fps'% + );$% + };$% + \fi% + \fi% + \if@anim@step + a#1_stepBwd=function(){% + a#1_seekFrame(a#1_idx-1);% + a#1_isPaused=true;% + };$% + a#1_stepFwd=function(){% + a#1_seekFrame(a#1_idx+1);% + a#1_isPaused=true;% + };$% + \else + a#1_stepBwd=function(){if(!a#1_playing){% + a#1_seekFrame(a#1_idx-1);% + a#1_isPaused=true;% + }};$% + a#1_stepFwd=function(){if(!a#1_playing){% + a#1_seekFrame(a#1_idx+1);% + a#1_isPaused=true;% + }};$% + a#1_playBwd=function(){% + if(a#1_idx==0||!a#1_isPaused){a#1_stopLast();}% + a#1_playLeft();% + };$% + a#1_playFwd=function(){% + if(a#1_idx==\@anim@maxframe||!a#1_isPaused){a#1_stopFirst();}% + a#1_playRight();% + };$% + \fi% + %animation API for labelled anims + \ifx\empty\@anim@label\empty\else + if(!anim){anim=new Array();}$% + if(typeof anim['\@anim@label']==='undefined'){$% + anim['\@anim@label']={$% + \if@anim@step\else + playBwd:a#1_playBwd,$% + playFwd:a#1_playFwd,$% + pause:a#1_pause,$% + get isPlaying(){return a#1_playing;},$% + get fps(){return a#1_fps;},$% + set fps(f){$% + if(f<0||isNaN(f)){% + throw new RangeError('Frame_rate_not_in_allowed_range');% + }else{a#1_setFps(f);}% + },$% + get speed(){return a#1_spd;},$% + set speed(s){$% + if(s<=0||isNaN(s)){$% + throw new RangeError('Speed_factor_not_in_allowed_range');$% + }else{$% + a#1_spd=s;$% + a#1_setFps(a#1_fps);$% + }$% + },$% + get dt(){return 1000/a#1_fps/a#1_spd;},$% + get playsFwd(){return a#1_playsRight;},$% + \fi + get numFrames(){return \@anim@frames;},$% + get frameNum(){return a#1_idx;},$% + set frameNum(ff){$% + var f=Math.floor(ff);$% + if(f<0||f>\@anim@maxframe||isNaN(f)){% + throw new RangeError('Frame_number_not_in_allowed_range');% + }$% + \if@anim@step + if(a#1_seekFrame(f)>-1)a#1_isPaused=true;$% + \else + if(a#1_playing){$% + a#1_pause();a#1_seekFrame(f);$% + if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$% + }else{if(a#1_seekFrame(f)>-1)a#1_isPaused=true;}$% + \fi% + },$% + stopFirst:a#1_stopFirst,$% + stopLast:a#1_stopLast$% + };$% + }$% + \fi% + %poster=none + \ifnum\@anim@poster=\@anim@mtwo + a#1_seekFrame(-2);$% + \fi% + %poster=<num>|first + \ifnum\@anim@poster>\@anim@mone + a#1_seekFrame(\@anim@poster);$% + \fi% + %poster=last + \ifnum\@anim@poster=\@anim@mone + a#1_seekFrame(\@anim@maxframe);$% + \fi% + }% +} + +%page-open/visible code +\gdef\@anim@@pojscript#1{% #1: @anim@num + \if@anim@step\else% + \if@anim@autoplayorresume% + \if@anim@autoresume + if(a#1_isPaused){$% + \fi + if(a#1_playsRight){a#1_playRight();}else{a#1_playLeft();}$% + \if@anim@autoresume% + }$% + \fi% + \fi% + \fi% +} + +%animation PDF widget's PageOpen/PageVisible code as PDF stream object +\gdef\@anim@pojscript#1{% @anim@num + \@anim@streamobj{}{% +% \@anim@consoleshow% +% console.clear();% + app.focusRect=false;% + \@anim@@jsvardecls{#1}% + \@anim@@jsinit{#1}% + \@anim@@pojscript{#1}% + }% + \global\let\@anim@pojscriptobj\@anim@lastobj% +} + +%page-close/invisible code +\gdef\@anim@@pcjscript#1{% #1: @anim@num + \if@anim@step% + \if@anim@palindrome + a#1_playsRight=true;$% + \fi% + \else + if(a#1_playing){% + \if@anim@autopause + a#1_pause();% + \else + a#1_pause(true);% stop + \fi% + }$% + if(!a#1_isPaused)a#1_playsRight=true;$% + \fi + %re-display poster frame + \ifnum\@anim@poster=\@anim@mtwo %poster=none + if(!a#1_isPaused&&a#1_idx!=-2)a#1_seekFrame(-2);$% not paused == stopped + \fi% + \ifnum\@anim@poster>\@anim@mone %poster=<num>|first + if(!a#1_isPaused&&a#1_idx!=\@anim@poster)a#1_seekFrame(\@anim@poster);$% + \fi% + \ifnum\@anim@poster=\@anim@mone %poster=last + if(!a#1_isPaused&&a#1_idx!=\@anim@maxframe)a#1_seekFrame(\@anim@maxframe);$% + \fi% +} + +%animation PDF widget's PageClose and PageInvisible code as PDF stream object +\gdef\@anim@pcjscript#1{% + \@anim@streamobj{}{\@anim@@pcjscript{#1}}% + \global\let\@anim@pcjscriptobj\@anim@lastobj% +} + +%other trigger events in the anim widget's AA dictionary +\gdef\@anim@wdgtDownJS#1{% + \if@anim@step\else % pause on MouseDown + try{if(a#1_playing){a#1_pause();}}catch(e){}$% + \fi% +}% +\gdef\@anim@wdgtUpJS#1{% + try{$% + \if@anim@step% + \if@anim@palindrome + if(event.\@anim@shift)a#1_playsRight=!a#1_playsRight;$% + if(a#1_idx==\@anim@maxframe){% + a#1_playsRight=false;% + }else if(a#1_idx==0){% + a#1_playsRight=true;% + }$% + if(a#1_playsRight){% + a#1_gotoNext();% + }else{% + a#1_gotoPrev();% + }$% + \else + if(event.\@anim@shift){% + if(a#1_idx==0){% + a#1_stopLast();% + }else{% + a#1_gotoPrev();% + }$% + }else{% + if(a#1_idx==\@anim@maxframe){% + a#1_stopFirst();% + }else{% + a#1_gotoNext();% + }$% + }% + \fi + a#1_isPaused=true;$% + \else + if(!a#1_isPaused)a#1_stopFirst();$% + if(event.\@anim@shift)a#1_playsRight=!a#1_playsRight;$% + \if@anim@palindrome + if(a#1_idx==0)a#1_playsRight=true;$% + if(a#1_idx==\@anim@maxframe)a#1_playsRight=false;$% + \else + if(a#1_idx==\@anim@maxframe&&a#1_playsRight)a#1_stopFirst();$% + if(a#1_idx==0&&!a#1_playsRight)a#1_stopLast();$% + \fi + if(a#1_playsRight){% + a#1_playRight();% + }else{% + a#1_playLeft();% + }$% + \fi% + }catch(e){}$% +}% + +\gdef\@anim@EndLeft{EndLeft}% +\gdef\@anim@StepLeft{StepLeft}% +\gdef\@anim@PlayPauseLeft{PlayPauseLeft}% +\gdef\@anim@PlayLeft{PlayLeft}% +\gdef\@anim@PauseLeft{PauseLeft}% +\gdef\@anim@PlayPauseRight{PlayPauseRight}% +\gdef\@anim@PlayRight{PlayRight}% +\gdef\@anim@PauseRight{PauseRight}% +\gdef\@anim@StepRight{StepRight}% +\gdef\@anim@EndRight{EndRight}% +\gdef\@anim@Minus{Minus}% +\gdef\@anim@Reset{Reset}% +\gdef\@anim@Plus{Plus}% + +%actions for control buttons +\gdef\@anim@btnJS#1#2{% + \ifx#2\@anim@EndLeft + a#1_stopFirst();% + \else% + \ifx#2\@anim@StepLeft + a#1_stepBwd();% + \else% + \ifx#2\@anim@PlayPauseLeft + a#1_playPauseBwd();% + \else% + \ifx#2\@anim@PlayPauseRight + a#1_playPauseFwd();% + \else% + \ifx#2\@anim@StepRight + a#1_stepFwd();% + \else% + \ifx#2\@anim@EndRight + a#1_stopLast();% + \else% + \ifx#2\@anim@Minus + a#1_spdDecr();% + \else% + \ifx#2\@anim@Reset + a#1_spdReset();% + \else% + \ifx#2\@anim@Plus + a#1_spdIncr();% + \fi\fi\fi\fi\fi\fi\fi\fi\fi% +} + +\if@anim@dvisvgm + \gdef\@anim@script#1{% #1: anim num + \special{dvisvgm:raw + $<defs>$% + <script type="text/javascript">$% + <![CDATA[$% + \@anim@@jsvardecls{#1}% variables that are supposed to be global + (function(){$% IIFE (self-executing anon. function) to limit scope + function onload(){$% + \@anim@@jsinit{#1}% + \if@anim@nomouse\else + document.getElementById('anm#1').addEventListener('mouseup',% + onMouseUpWdgt);$% + document.getElementById('anm#1').addEventListener('mousedown',% + onMouseDownWdgt);$% + document.getElementById('anm#1').addEventListener('touchend',% + onTouchEndWdgt);$% + document.getElementById('anm#1').addEventListener('touchstart',% + onTouchStartWdgt);$% + document.getElementById('anm#1').addEventListener('touchmove',% + onTouchMove);$% + \fi% + onvisible();$% in case of `autoplay' option + }$% + function onvisible(){$% + \@anim@@pojscript{#1}% + }$% + function onhidden(){$% + \@anim@@pcjscript{#1}% + }$% + function onVisibilityChange(){$% + if(document.hidden){% + try{onhidden();}catch(e){}% + }else{% + try{onvisible();}catch(e){}% + }$% + }$% + document.addEventListener('visibilitychange',onVisibilityChange);$% + window.addEventListener('load',onload);$% + \if@anim@nomouse\else + var permPause#1=false; + function onWidgetUpAction(event){$% + \@anim@wdgtUpJS{#1}% + }$% + function onTouchStartWdgt(event){$% + event.preventDefault();$% + event.stopPropagation();$% + permPause#1=false; + \@anim@wdgtDownJS{#1}% + }$% + function onTouchEndWdgt(event){$% + event.preventDefault();$% + event.stopPropagation();$% + if(event.targetTouches.length>0){permPause#1=true;}$% + else{$% + if(permPause#1){permPause#1=false;}$% + else{onWidgetUpAction(event);}$% + }$% + }$% + function onTouchMove(event){$% + event.preventDefault();$% + event.stopPropagation();$% + }$% + function onMouseDownWdgt(event){$% + event.preventDefault();$% + event.stopPropagation();$% + \@anim@wdgtDownJS{#1}% + }$% + function onMouseUpWdgt(event){$% + event.preventDefault();$% + event.stopPropagation();$% + onWidgetUpAction(event);$% + }$% + \fi% + })();$% end of IIFE + ]]>$% + </script>$% + </defs>% + }% + } +\fi + +\endgroup +\endinput |