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