% Copyright 2007--2008 Alexander Grahn % This material is subject to the LaTeX Project Public License. See % http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html % 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 and pdfLaTeX workflows. \NeedsTeXFormat{LaTeX2e} \def\@anim@version{2010/02/17} \ProvidesPackage{animate} [\@anim@version\space PDF animations from files and inline graphics] %test for e-TeX \expandafter\ifx\csname eTeXversion\endcsname\relax \PackageError{animate}{% Missing support for e-TeX; aborting...% }{% Use a TeX compiler that supports e-TeX and enable e-TeX % in the format.% } \fi \RequirePackage{keyval} \RequirePackage{ifthen} \RequirePackage{ifpdf} \RequirePackage{ifdraft} \RequirePackage{calc} \RequirePackage{animfp} %driver options (the only package options we process immediately) \newboolean{@anim@@dvips} \setboolean{@anim@@dvips}{false} \newboolean{@anim@@dvipdfmx} \setboolean{@anim@@dvipdfmx}{false} \ifpdf\else \setboolean{@anim@@dvips}{true}% default dvi mode \setboolean{@anim@@dvipdfmx}{false} \DeclareOption{dvips}{% \setboolean{@anim@@dvips}{true} \setboolean{@anim@@dvipdfmx}{false} } \DeclareOption{dvipdfmx}{% \setboolean{@anim@@dvipdfmx}{true} \setboolean{@anim@@dvips}{false} } \DeclareOption{xetex}{% \setboolean{@anim@@dvipdfmx}{true} \setboolean{@anim@@dvips}{false} } \fi \newboolean{@anim@xetex} \setboolean{@anim@xetex}{false} \expandafter\ifx\csname XeTeXrevision\endcsname\relax\else \setboolean{@anim@xetex}{true} \setboolean{@anim@@dvipdfmx}{true} \setboolean{@anim@@dvips}{false} \fi \DeclareOption*{}\ProcessOptions*\relax %allow anything as an option %(remaining package options will be processed near end of this file) \ifpdf %test for correct pdfTeX version \ifnum\pdftexversion<120\relax% \PackageError{animate}{% pdfTeX, version >= 1.20, required% }{% Install a newer version!% }% \fi %load MP to PDF converter \InputIfFileExists{supp-pdf.mkii}{}{% \InputIfFileExists{supp-pdf}{}{% \PackageWarningNoLine{animate}{% Neither of the files `supp-pdf.mkii' and `supp-pdf.tex',% \MessageBreak% which are part of ConTeXt, could be found.% \MessageBreak% Therefore, MetaPost generated PS files cannot% \MessageBreak% be embedded using pdfTeX% } }} \else \if@anim@@dvipdfmx\else % dvips %if geometry package is loaded, execute `\geometry{dvips}' right before % `\begin{document}' \let\@anim@document\document \def\document{% \endgroup% \@ifpackageloaded{geometry}{\geometry{dvips}}{}% \begingroup% \@anim@document% } %define `?pdfmark' operator as in file hdvips.def from package `hyperref' \AtBeginDvi{% \expandafter\ifx\csname pdfmark\endcsname\relax% \special{! systemdict /pdfmark known% {% userdict /?pdfmark systemdict /exec get put% }{% userdict /?pdfmark systemdict /pop get put userdict /pdfmark systemdict /cleartomark get put% }% ifelse% }% \fi% } %determine DVI resolution and output warning message if too big \AtBeginDocument{% \special{ps:\@anim@dpiwarning}% } \fi \fi \catcode`\%=11\catcode`\#=14 \edef\@anim@catcode{\the\catcode`\_}\catcode`\_=13 \begingroup\let_\space \xdef\@anim@dpiwarning{# {Resolution 1200 gt VResolution 1200 gt or product (Ghostscript) search {pop pop pop true}{pop false}ifelse and {# (@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n# @@____Warning:_DVI_resolution_greater_than_1200_dpi!_____@@\string\n# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n# @@_______________________________________________________@@\string\n# @@_Animations_may_be_distorted_or_invisible._____________@@\string\n# @@_Dvips_should_be_called_either_without_option_`-Ppdf':_@@\string\n# @@_______________________________________________________@@\string\n# @@___dvips_\jobname\string\n @@_______________________________________________________@@\string\n# @@_or_with_a_different_resolution_setting:_______________@@\string\n# @@_______________________________________________________@@\string\n# @@___dvips_-Ppdf_-D1200_\jobname\string\n @@_______________________________________________________@@\string\n# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\string\n) (%stderr) (w) file exch writestring} if} ?pdfmark } \endgroup \catcode`\%=14\catcode`\#=6\catcode`\_=\@anim@catcode %\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 \expandafter\ifx\csname pdfmdfivesum\endcsname\relax \def\pdfmdfivesum file #1{#1} \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} %macro for writing global defs to external *.aux file \def\@anim@keytoaux#1#2{% \@bsphack\protected@write\@auxout{}{% \string\@anim@newkey{#1}{#2}% }\@esphack% \ifcsname#1\endcsname\else% \ifcsname @anim@rerunwarned\endcsname\else% \gdef\@anim@rerunwarned{}% \AtEndDocument{% \PackageWarningNoLine{animate}{% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak @@ Rerun to get internal references right! @@\MessageBreak @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}% }% \fi% \fi% } %missing package error message \newcommand{\@anim@missing}[2][]{% \ifthenelse{\equal{#1}{}}{% \def\@anim@pkgopt{}% }{% \def\@anim@pkgopt{[#1]}% }% \PackageError{animate}{% Package `#2' has not been loaded yet.\MessageBreak% 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}% }{}% } %alternative animation method using OCGs (option `useocg') \newboolean{@anim@useocg} % true if any of `autoplay' or `autoresume' options is set \newboolean{@anim@autoplayorresume} % true if any of `controls' or `palindrome' options is set \newboolean{@anim@ctrlorplndrm} \newboolean{@anim@timeline} %true if `timeline' option is set \newboolean{@anim@multipage} % multipage document? %add AcroForm and OCProperties entries to Catalog \ifpdf \newcount\@anim@@fields \pdfobj reserveobjnum \@anim@@fields=\pdflastobj \newcount\@anim@@ocgs \pdfobj reserveobjnum \@anim@@ocgs=\pdflastobj \newcount\@anim@@posterocgs \pdfobj reserveobjnum \@anim@@posterocgs=\pdflastobj \pdfcatalog{ /AcroForm <> /OCProperties << /OCGs \the\@anim@@ocgs\space 0 R /D << /BaseState/OFF /ON \the\@anim@@posterocgs\space 0 R >> >> } \def\@anim@fields{} \def\@anim@ocgs{} \def\@anim@posterocgs{} \AtEndDocument{% \immediate\pdfobj useobjnum \@anim@@fields {% [\@anim@fields]% }% \immediate\pdfobj useobjnum \@anim@@ocgs {% [\@anim@ocgs]% }% \immediate\pdfobj useobjnum \@anim@@posterocgs {% [\@anim@posterocgs]% }% }% \else %counts inserted widget annots \newcount\@anim@fieldnum\@anim@fieldnum=\z@% \if@anim@@dvipdfmx %array which takes refs to all widget annotations \special{pdf:obj @anim@fields [ ]} %array which takes all ocgs (one per animation frame) \special{pdf:obj @anim@ocgs [ ]} %array which takes ocgs shown by default (the poster frames) \special{pdf:obj @anim@posterocgs [ ]} \special{pdf:put @catalog << /AcroForm <> /OCProperties << /OCGs @anim@ocgs /D <> >> >>} \else \special{ps: mark /_objdef {@anim@fields} /type/array /OBJ pdfmark mark /_objdef {@anim@ocgs} /type/array /OBJ pdfmark mark /_objdef {@anim@posterocgs} /type/array /OBJ pdfmark mark {Catalog} << /AcroForm <> /OCProperties << /OCGs {@anim@ocgs} /D <> >> >> /PUT pdfmark } \fi \fi \newbox\@anim@box %stores animation frames \newdimen\@anim@tmpdima %length registers for occasional use \newdimen\@anim@tmpdimb %tests whether file is already known (and embedded), if so it returns identifier %of xobj, otherwise returns `!' \def\@anim@fileknown#1#2{% #1 file name, pdf: #2 page No. ps: #2 @anim@num %identify file by md5sum \ifcsname file:\pdfmdfivesum file {#1}.#2\endcsname% \@anim@getkeyval{file:\pdfmdfivesum file {#1}.#2}\else!\fi% } \def\@anim@makefileknown#1#2#3{%#1 file name, pdf: #2 page No. ps: #2 @anim@num, \@anim@newkey{file:\pdfmdfivesum file {#1}.#2}{#3}% #3 Form XObj ID } %helper macro that typesets graphics file into savebox \ifpdf \def\@anim@filebox#1#2{% #1 filename, #2 page No. for multipage files \ifx\@anim@gropts\@empty% \def\@anim@mps{.mps}% \ifx\@anim@ext\@anim@mps% \global\setbox\@anim@box=\hbox{\convertMPtoPDF{#1}{1}{1}}% \else% \pdfximage page #2 {#1}% \global\setbox\@anim@box=\hbox{\pdfrefximage\pdflastximage}% \fi% \else% \edef\@anim@curfile{[clip\@anim@gropts,page=#2]{#1}}% \global\setbox\@anim@box=\hbox{% \expandafter\includegraphics\@anim@curfile}% \fi% } \else \if@anim@xetex \def\@anim@filebox#1#2{% \edef\@anim@curfile{[clip\@anim@gropts,page=#2]{#1}}% \global\setbox\@anim@box=\hbox{% \expandafter\includegraphics\@anim@curfile}% } \else \def\@anim@filebox#1#2{% #2 ignored \edef\@anim@curfile{[clip\@anim@gropts]{#1}}% \global\setbox\@anim@box=\hbox{% \expandafter\includegraphics\@anim@curfile}% } \fi \fi %create Form XObject from graphics file \ifthenelse{\boolean{pdf}\OR\boolean{@anim@xetex}}{ \def\@anim@ximage#1#2#3#4{%#1:@anim@num, #2:@anim@curframe@zb, #3:filename, %#4: page number of multipage file \ifthenelse{\equal{\@anim@fileknown{#3}{#4}}{!}}{% new file to be embedded \@anim@filebox{#3}{#4}% store file in a box \@anim@getsize{\@anim@box}% \ifnum#2=\z@% \@anim@scale{\@anim@box}% scale animation widget \fi% \@anim@xinline{#1}{#2}{\@anim@box}{!}% delegate Form XObject creation \ifx\@anim@gropts\@empty\if@anim@multipage\message{<#4>}\fi\fi% \@anim@makefileknown{#3}{#4}{\@anim@lastxform}% keep form xobject number }{% file known, re-use existing form xobject \ifnum#2=\z@% \@anim@filebox{#3}{#4}% for size determination of first frame \@anim@getsize{\@anim@box}% \@anim@scale{\@anim@box}% \fi% \@anim@xinline{#1}{#2}{}{\@anim@fileknown{#3}{#4}}% }% } }{ \if@anim@@dvipdfmx \def\@anim@ximage#1#2#3#4{% #4: not used \ifthenelse{\equal{\@anim@fileknown{#3}{1}}{!}}{%new file to be embedded \@anim@filebox{#3}{}% \@anim@getsize{\@anim@box}% \ifnum#2=\z@% \@anim@scale{\@anim@box}% \fi% \@anim@xinline{#1}{#2}{\@anim@box}{!}% \@anim@makefileknown{#3}{1}{\@anim@lastxform}% }{% \ifnum#2=\z@% \@anim@filebox{#3}{}% \@anim@getsize{\@anim@box}% \@anim@scale{\@anim@box}% \fi% \@anim@xinline{#1}{#2}{}{\@anim@fileknown{#3}{1}}% }% } \else \def\@anim@ximage#1#2#3#4{% #4: not used \ifthenelse{\equal{\@anim@fileknown{#3}{#1}}{!}}{%file is new to current \@anim@filebox{#3}{}% animation \@anim@getsize{\@anim@box}% \ifnum#2=\z@% \@anim@scale{\@anim@box}% \fi% \@anim@xinline{#1}{#2}{\@anim@box}{!}% \@anim@makefileknown{#3}{#1}{\@anim@lastxform}% }{%file already used in the current animation, re-use existing xobject \ifnum#2=\z@% \@anim@filebox{#3}{}% \@anim@getsize{\@anim@box}% \@anim@scale{\@anim@box}% \fi% \@anim@xinline{#1}{#2}{}{\@anim@fileknown{#3}{#1}}% }% } \fi } %creates Form XObject from box contents \ifpdf% %#1: @anim@num, #2:@anim@curframe@zb, #3: empty (`') or box number, %#4: `!' or form xobj identifier \def\@anim@xinline#1#2#3#4{% \ifthenelse{\equal{#4}{!}}{% %put graphics into XObject \global\setbox\@anim@box=\hbox{% \raisebox{-\dp#3}[\@anim@frameheight\p@][\@anim@framedepth\p@]{\box#3}% }% \immediate\pdfxform resources {\the\pdfpageresources}\@anim@box% \xdef\@anim@lastxform{\the\pdflastxform}% %keep a record of XObject number \@anim@newkey{img@#2}{\@anim@lastxform\space 0 R}% }{% \@anim@newkey{img@#2}{#4\space 0 R}% }% \if@anim@timeline\else% \@anim@newkey{frmxobject@#2}{/im#2\space\@anim@getkeyval{img@#2}}% \@anim@newkey{frmcontent@#2}{ q /im#2\space Do Q}% \@anim@makeframe{#1}{#2}% \fi% } \else \if@anim@@dvipdfmx \def\@anim@xinline#1#2#3#4{% \ifthenelse{\equal{#4}{!}}{% %put graphics into XObject \special{pdf:bxobj @anim@frm@#1@#2 width \@anim@framewidth pt height \@anim@frameheight pt depth \@anim@framedepth pt}% \begin{picture}(0,0)\put(0,0){\box#3}\end{picture}% \special{pdf:exobj}% \xdef\@anim@lastxform{@anim@frm@#1@#2}% \@anim@newkey{img@#2}{\@anim@lastxform}% }{% \@anim@newkey{img@#2}{#4}% }% \if@anim@timeline\else% \@anim@newkey{frmxobject@#2}{/im#2\space\@anim@getkeyval{img@#2}}% \@anim@newkey{frmcontent@#2}{ q /im#2\space Do Q}% \@anim@makeframe{#1}{#2}% \fi% } \else \def\@anim@xinline#1#2#3#4{% \ifthenelse{\equal{#4}{!}}{% \begingroup% \setlength{\unitlength}{1pt}% \begin{picture}(0,0)% %mark BBox of the graphics \put(0,-\@anim@framedepth){% \special{ps: currentpoint /frame@lly exch def /frame@llx exch def }% }% \put(\@anim@framewidth,\@anim@frameheight){% \special{ps: currentpoint /frame@ury exch def /frame@urx exch def }% }% %define some length values in current PS coordinate units \put(0,0){% \special{ps: currentpoint /origin@y exch def /origin@x exch def }% }% \put(72.27,72.27){% \special{ps: currentpoint origin@y exch sub /one@inch@y exch def origin@x sub /one@inch@x exch def }% }% \end{picture}% \endgroup% \special{ps: gsave %translate graphics to upper left page corner {% frame@llx neg frame@ury neg translate one@inch@x DVImag div neg one@inch@y DVImag div neg translate% }?pdfmark %distill graphics into XObject mark /_objdef {@anim@frm@#1@#2} /BBox [frame@llx frame@lly frame@urx frame@ury] /BP pdfmark {% isls{%landscape mode (powerdot, geometry /w landscape option) /frame@dxdy {% frame@urx frame@llx sub abs frame@ury frame@lly sub abs div% } bind def /frame@dydx {1 frame@dxdy div} bind def /frame@cx {frame@urx frame@llx add 2 div} bind def /frame@cy {frame@ury frame@lly add 2 div} bind def % graphics needs to be rescaled for some reason ... [frame@dxdy 0 0 frame@dydx 1 frame@dxdy sub frame@cx mul 1 frame@dydx sub frame@cy mul] concat %... rotated by 270 degrees ... [0 -1 1 0 frame@cx frame@cy sub frame@cx frame@cy add] concat %... and flipped around vertical axis [-1 0 0 1 frame@llx frame@urx add 0] concat% }{% flip around horizontal axis in portrait mode [1 0 0 -1 0 frame@lly frame@ury add] concat% }ifelse }?pdfmark }% \begin{picture}(0,0)\put(0,0){\box#3}\end{picture}% \special{ps: mark /EP pdfmark grestore }% \xdef\@anim@lastxform{@anim@frm@#1@#2}% \@anim@newkey{img@#2}{{@anim@frm@#1@#2}}% }{% \@anim@newkey{img@#2}{{#4}}% }% \if@anim@timeline\else% \@anim@newkey{frmxobject@#2}{/im#2\space\@anim@getkeyval{img@#2}}% \@anim@newkey{frmcontent@#2}{ q /im#2\space Do Q}% \@anim@makeframe{#1}{#2}% \fi% } \fi \fi \def\@anim@posterlast{last}% helper macros \def\@anim@posterfirst{first}% \def\@anim@posternone{none}% %creates OCG \ifpdf \def\@anim@newocg#1#2{%#1:@anim@num, #2:@anim@curframe@zb \immediate\pdfobj{<>}% new ocg \xdef\@anim@curocg{\the\pdflastobj\space 0 R}% %append to ocg array \xdef\@anim@ocgs{\@anim@ocgs\space\@anim@curocg}% %store ref to ocg if it's a poster \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \xdef\@anim@posterocg{\@anim@curocg}% \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \xdef\@anim@posterocg{\@anim@curocg}% \fi% \fi% } \else \if@anim@@dvipdfmx \def\@anim@newocg#1#2{% \special{pdf:obj @anim@ocg@#1@#2 <>}% \special{pdf:put @anim@ocgs @anim@ocg@#1@#2}% \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \xdef\@anim@posterocg{@anim@ocg@#1@#2}% \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \xdef\@anim@posterocg{@anim@ocg@#1@#2}% \fi% \fi% } \else \def\@anim@newocg#1#2{% \special{ps: mark /_objdef {@anim@ocg@#1@#2} /type/dict /OBJ pdfmark mark {@anim@ocg@#1@#2} <> /PUT pdfmark mark {@anim@ocgs} {@anim@ocg@#1@#2} /APPEND pdfmark }% \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \xdef\@anim@posterocg{@anim@ocg@#1@#2}% \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \xdef\@anim@posterocg{@anim@ocg@#1@#2}% \fi% \fi% } \fi \fi %non-interactive Widget annotation, representing one frame of the animation \ifpdf \def\@anim@makeframe#1#2{% #1:@anim@num, #2:@anim@curframe@zb %container XObject for all transparencies that compose the frame \begingroup% \setlength{\unitlength}{1pt}% \global\setbox\@anim@box=\hbox{% \pdfliteral{q}% \begin{picture}(\@anim@framewidth,\@anim@frametotalheight)% \end{picture}% \pdfliteral{Q\@anim@getkeyval{frmcontent@#2}}% }% \endgroup% \immediate\pdfxform resources {% /XObject <<\@anim@getkeyval{frmxobject@#2}>>}\@anim@box% \if@anim@useocg% \@anim@newocg{#1}{#2}% \def\@anim@annotflag{/F 4}%, print, visibility set by OCG \else% %widget visibility state \def\@anim@annotflag{/F 2}%default: hidden (no view, no print) \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \def\@anim@annotflag{/F 4}% visible, print \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \@anim@keytoaux{a#1.poster}{#2}% \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{% \def\@anim@annotflag{/F 4}% }{}% \fi% \fi% \fi% %frame widget, using the container XObject as its Appearance \pdfannot width \@anim@animwidth\p@ height \@anim@animheight\p@ depth \@anim@animdepth\p@ {% /Subtype/Widget% \@anim@annotflag \if@anim@useocg% /OC \@anim@curocg %associate widget with the just created OCG \fi% /FT/Btn/Ff 65537% non-interactive push button /BS <>% /AP <>% /T (#1.#2)% }% \xdef\@anim@fields{\@anim@fields\space\the\pdflastannot\space 0 R}% } \else \if@anim@@dvipdfmx \def\@anim@makeframe#1#2{% %container XObject \global\setbox\@anim@box=\hbox{% \special{pdf:content \@anim@getkeyval{frmcontent@#2}}% }% \special{pdf:bxobj @anim@anmfrm@#1@#2 width \@anim@framewidth pt height \@anim@frameheight pt depth \@anim@framedepth pt}% \begin{picture}(0,0)\put(0,0){\box\@anim@box}\end{picture}% \special{pdf:put @resources << /XObject <<\@anim@getkeyval{frmxobject@#2}>>% >>}% \special{pdf:exobj}% \if@anim@useocg% \@anim@newocg{#1}{#2}% \def\@anim@annotflag{/F 4}% \else% \def\@anim@annotflag{/F 2}% \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \def\@anim@annotflag{/F 4}% \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \@anim@keytoaux{a#1.poster}{#2}% \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{% \def\@anim@annotflag{/F 4}% }{}% \fi% \fi% \fi% %frame widget \special{pdf:annot @annot@\the\@anim@fieldnum\space width \@anim@animwidth pt height \@anim@animheight pt depth \@anim@animdepth pt <<% /Subtype/Widget% \@anim@annotflag \if@anim@useocg/OC @anim@ocg@#1@#2\fi% /FT/Btn/Ff 65537% /BS <>% /AP <>% /T (#1.#2)% >>% }% \special{pdf:put @anim@fields @annot@\the\@anim@fieldnum}% \global\advance\@anim@fieldnum by \@ne% } \else \def\@anim@makeframe#1#2{% %container XObject \special{ps: mark /_objdef {@anim@anmfrm@#1@#2} /type/stream /OBJ pdfmark mark {@anim@anmfrm@#1@#2} (\@anim@getkeyval{frmcontent@#2}) /PUT pdfmark mark {@anim@anmfrm@#1@#2} << /Type/XObject/Subtype/Form/FormType 1 /BBox [frame@llx frame@lly frame@urx frame@ury] /Resources <>>> >> /PUT pdfmark }% \if@anim@useocg% \@anim@newocg{#1}{#2}% \def\@anim@annotflag{/F 4}% \else% \def\@anim@annotflag{/F 2}% \ifx\@anim@poster\@anim@posternone\else% \ifnum#2=\z@% \ifx\@anim@poster\@anim@posterfirst% \def\@anim@annotflag{/F 4}% \fi% \fi% \ifx\@anim@poster\@anim@posterlast% \@anim@keytoaux{a#1.poster}{#2}% \ifthenelse{\equal{\@anim@getkeyval{a#1.poster}}{#2}}{% \def\@anim@annotflag{/F 4}% }{}% \fi% \fi% \fi% %frame widget \begingroup% \setlength{\unitlength}{1pt}% \begin{picture}(0,0)% mark annotation rectangle \put(0,-\@anim@animdepth){% \special{ps: currentpoint /wid@lly exch def /wid@llx exch def }% }% \put(\@anim@animwidth,\@anim@animheight){% \special{ps: currentpoint /wid@ury exch def /wid@urx exch def }% }% \end{picture}% \endgroup% \special{ps: mark /_objdef {annot@\the\@anim@fieldnum}% /Rect [wid@llx wid@lly wid@urx wid@ury]% /Subtype/Widget% \@anim@annotflag \if@anim@useocg/OC {@anim@ocg@#1@#2}\fi% /FT/Btn/Ff 65537 /BS <>% /AP <>% /T (#1.#2)% /ANN pdfmark mark {@anim@fields} {annot@\the\@anim@fieldnum} /APPEND pdfmark }% \global\advance\@anim@fieldnum by \@ne% } \fi \fi %create container XObjects for play & pause button faces \ifpdf \def\@anim@makeppcontainer#1#2#3{% #1: @anim@num, #2: Right or Left, % #3: index of existing button face colour combination \immediate\pdfobj{<>}% \edef\@anim@playocg{\the\pdflastobj\space 0 R}% \immediate\pdfobj{<>}% \edef\@anim@pauseocg{\the\pdflastobj\space 0 R}% %append to ocg array \xdef\@anim@ocgs{\@anim@ocgs\space\@anim@playocg\space\@anim@pauseocg}% %although not really necessary, append play button ocg to posterocg array \xdef\@anim@posterocgs{\@anim@posterocgs\space\@anim@playocg}% %new container XObject \immediate\pdfobj stream attr{% /Type/XObject/Subtype/Form/BBox [0 0 15 15]% /Resources <<% /Properties <>% /XObject <<% /im0 \@anim@getkeyval{btnPlay#2:#3} /im1 \@anim@getkeyval{btnPause#2:#3}% >>% >>% }{% /OC/oc0 BDC q /im0 Do Q EMC /OC/oc1 BDC q /im1 Do Q EMC% }% \@anim@newkey{btn#1.PlayPause#2}{\the\pdflastobj\space 0 R}% } \else \if@anim@@dvipdfmx \def\@anim@makeppcontainer#1#2#3{% \special{pdf:obj @#1.Play#2 <>}% \special{pdf:obj @#1.Pause#2 <>}% \special{pdf:put @anim@ocgs @#1.Play#2 @#1.Pause#2}% \special{pdf:put @anim@posterocgs @#1.Play#2}% \special{pdf:stream @btn#1.PlayPause#2\space (/OC/oc0 BDC q /im0 Do Q EMC /OC/oc1 BDC q /im1 Do Q EMC) <<% /Type/XObject/Subtype/Form/BBox [0 0 15 15]% /Resources <<% /Properties <>% /XObject <>% >>% >>% }% \@anim@newkey{btn#1.PlayPause#2}{@btn#1.PlayPause#2}% } \else \def\@anim@makeppcontainer#1#2#3{% \special{ps: %OCGs mark /_objdef {#1.Play#2} /type/dict /OBJ pdfmark mark {#1.Play#2} <> /PUT pdfmark mark /_objdef {#1.Pause#2} /type/dict /OBJ pdfmark mark {#1.Pause#2} <> /PUT pdfmark mark {@anim@ocgs} {#1.Play#2} /APPEND pdfmark mark {@anim@ocgs} {#1.Pause#2} /APPEND pdfmark mark {@anim@posterocgs} {#1.Play#2} /APPEND pdfmark mark /_objdef {btn#1.PlayPause#2} /type/stream /OBJ pdfmark mark {btn#1.PlayPause#2} (% /OC/oc0 BDC q /im0 Do Q EMC /OC/oc1 BDC q /im1 Do Q EMC% ) /PUT pdfmark mark {btn#1.PlayPause#2} << /Type/XObject/Subtype/Form/FormType 1 /BBox [0 0 15 15] /Resources <<% /Properties <>% /XObject <>% >>% >> /PUT pdfmark }% } \fi \fi %create XObjects of all button faces \if@anim@@dvips \def\@anim@btnend{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1 setlinewidth 4.5 4 moveto 9.5 7.5 lineto 4.5 11 lineto stroke 0 setlinejoin 10.5 4.4 moveto 10.5 10.6 lineto stroke } \def\@anim@btnstep{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1 setlinewidth 5 4 moveto 10 7.5 lineto 5 11 lineto stroke } \def\@anim@btnplay{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1 setlinewidth 5 4 moveto 5 11 lineto 10 7.5 lineto closepath stroke } \def\@anim@btnpause{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 0 setlinecap 1 setlinejoin 0 1 moveto 14 1 lineto 14 14 lineto 0 14 lineto stroke 2 setlinewidth 2.2 4 moveto 2.2 11 lineto stroke } \def\@anim@btnminus{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1.0 setlinewidth 0 setlinecap 4 7.5 moveto 11 7.5 lineto stroke } \def\@anim@btnplus{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1.0 setlinewidth 0 setlinecap 4 7.5 moveto 11 7.5 lineto 7.5 4 moveto 7.5 11 lineto stroke } \def\@anim@btnreset{% \@anim@bg\space \@anim@fg\space 0.25 setlinewidth 1 setlinecap 1 setlinejoin 1 1 moveto 14 1 lineto 14 14 lineto 1 14 lineto closepath stroke 1 setlinewidth 7.5 4 moveto 7.5 11 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@makebuttons#1{% #1: @anim@num \@anim@xbutton{EndLeft}{[-1 0 0 1 15 0] concat \@anim@btnend}{#1}% \@anim@xbutton{EndRight}{\@anim@btnend}{#1}% \@anim@xbutton{Minus}{\@anim@btnminus}{#1}% \@anim@xbutton{PauseLeft}{[-1 0 0 1 15 0] concat \@anim@btnpause}{#1}% \@anim@xbutton{PauseRight}{\@anim@btnpause}{#1}% \@anim@xbutton{PlayLeft}{[-1 0 0 1 15 0] concat \@anim@btnplay}{#1}% \@anim@xbutton{PlayRight}{\@anim@btnplay}{#1}% \@anim@xbutton{Plus}{\@anim@btnplus}{#1}% \@anim@xbutton{Reset}{\@anim@btnreset}{#1}% \@anim@xbutton{StepLeft}{[-1 0 0 1 15 0] concat \@anim@btnstep}{#1}% \@anim@xbutton{StepRight}{\@anim@btnstep}{#1}% } \def\@anim@xbutton#1#2#3{% #1: name; #2: stroking commands, #3 @anim@num \special{ps: gsave [1 0 0 1 0 0] setmatrix mark /_objdef {btn#1:#3} /BBox [0 0 15 15] /BP pdfmark {% %landscape mode (powerdot, geometry /w landscape option) isls{% [0 -1 1 0 0 15] concat % rotate by 270 degrees [-1 0 0 1 15 0] concat% flip around vertical axis }if #2 }?pdfmark mark /EP pdfmark grestore }% } \else %stroking commands \def\@anim@btnend{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 45 40 m 95 75 l 45 110 l S 0 j 105 44 m 105 106 l S } \def\@anim@btnstep{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 50 40 m 100 75 l 50 110 l S } \def\@anim@btnplay{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 50 40 m 50 110 l 100 75 l h S } \def\@anim@btnpause{% \@anim@bg\space 2.5 w 1 j \@anim@fg\space 0 10 m 140 10 l 140 140 l 0 140 l S 20 w 22 40 m 22 110 l S } \def\@anim@btnminus{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 0 J 40 75 m 110 75 l S } \def\@anim@btnplus{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 0 J 40 75 m 110 75 l 75 40 m 75 110 l S } \def\@anim@btnreset{% \@anim@bg\space 2.5 w 1 J 1 j \@anim@fg\space 10 10 130 130 re S 10 w 75 40 m 75 110 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@makebuttons#1{% \@anim@xbutton{EndLeft}{% q -0.1 0 0 0.1 15 0 cm \@anim@btnend\space Q% }{#1}% \@anim@xbutton{EndRight}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnend\space Q% }{#1}% \@anim@xbutton{Minus}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnminus\space Q% }{#1}% \@anim@xbutton{PauseLeft}{% q -0.1 0 0 0.1 15 0 cm \@anim@btnpause\space Q% }{#1}% \@anim@xbutton{PauseRight}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnpause\space Q% }{#1}% \@anim@xbutton{PlayLeft}{% q -0.1 0 0 0.1 15 0 cm \@anim@btnplay\space Q% }{#1}% \@anim@xbutton{PlayRight}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnplay\space Q% }{#1}% \@anim@xbutton{Plus}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnplus\space Q% }{#1}% \@anim@xbutton{Reset}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnreset\space Q% }{#1}% \@anim@xbutton{StepLeft}{% q -0.1 0 0 0.1 15 0 cm \@anim@btnstep\space Q% }{#1}% \@anim@xbutton{StepRight}{% q 0.1 0 0 0.1 0 0 cm \@anim@btnstep\space Q% }{#1}% } %XObject creation \ifpdf \def\@anim@xbutton#1#2#3{% #1 name, #2 stroking commands, #3 @anim@num \immediate\pdfobj stream attr{% /Type/XObject/Subtype/Form/BBox [0 0 15 15]% }{#2}% \@anim@newkey{btn#1:#3}{\the\pdflastobj\space 0 R}% } \else% dvipdfmx \def\@anim@xbutton#1#2#3{% \special{pdf:stream @btn#1:#3\space (#2) <<% /Type/XObject/Subtype/Form/BBox [0 0 15 15] >>% }% } \fi \fi %determines file type of the sequence \ifpdf \def\@anim@getext#1{% \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{.jbig2}% \IfFileExists{#1\@anim@ext}{}{% \gdef\@anim@ext{.jb2}% \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}{% Neither of the files\MessageBreak% `#1.pdf',\MessageBreak% `#1.mps',\MessageBreak% `#1.png',\MessageBreak% `#1.jpg',\MessageBreak% `#1.jpeg',\MessageBreak% `#1.jbig2',\MessageBreak% `#1.jb2',\MessageBreak% `#1.jp2',\MessageBreak% `#1.j2k' or\MessageBreak% `#1.jpx',\MessageBreak% could be found.\MessageBreak% Wrong file type? Mis-spelled file name?% }{}% }}}}}}}}}}% }% \else \if@anim@@dvipdfmx %XeLaTeX, dvipdfmx \def\@anim@getext#1{% \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}{% Neither 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 %dvips \def\@anim@getext#1{% \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}{% Neither 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?% }{}% }}}% }% \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% \setlength{\unitlength}{1pt}% \vtop{% draw boxes \offinterlineskip% \hbox{% \raisebox{-\@anim@animdepth\p@}{% \begin{picture}(\@anim@animwidth,\@anim@animtotalheight)% \put(0,0){\framebox(\@anim@animwidth,\@anim@animtotalheight){}}% \end{picture}% }% }% \if@anim@controls% \setlength{\@anim@tmpdima}{\@anim@btnsize}% \vskip 0.1\@anim@tmpdima% \hbox to \@anim@animwidth\p@ {% \hss% \setlength{\@anim@tmpdimb}{2\@anim@tmpdima}% \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)% \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}% \put(0,\strip@pt\@anim@tmpdima){% \line(1,0){\strip@pt\@anim@tmpdimb}% }% \put(0,0){\line(0,1){\strip@pt\@anim@tmpdima}}% \end{picture}% \if@anim@step\else% \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)% \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}% \put(0,\strip@pt\@anim@tmpdima){% \line(1,0){\strip@pt\@anim@tmpdimb}% }% \end{picture}% \fi% \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)% \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}% \put(0,\strip@pt\@anim@tmpdima){% \line(1,0){\strip@pt\@anim@tmpdimb}% }% \put(\strip@pt\@anim@tmpdimb,0){% \line(0,1){\strip@pt\@anim@tmpdima}% }% \end{picture}% \if@anim@step\else% \hskip 0.3\@anim@tmpdima% \setlength{\@anim@tmpdimb}{3\@anim@tmpdima}% \begin{picture}(\strip@pt\@anim@tmpdimb,\strip@pt\@anim@tmpdima)% \put(0,0){\line(0,1){\strip@pt\@anim@tmpdima}}% \put(0,0){\line(1,0){\strip@pt\@anim@tmpdimb}}% \put(0,\strip@pt\@anim@tmpdima){% \line(1,0){\strip@pt\@anim@tmpdimb}% }% \put(\strip@pt\@anim@tmpdimb,0){% \line(0,1){\strip@pt\@anim@tmpdima}% }% \end{picture}% \fi% \hss% }% \fi% }% \endgroup% } \ifpdf %detects multipage PDF and corrects user supplied page range \def\@anim@checkmultipage#1{% #1: file base name \IfFileExists{#1.pdf}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.pdf}% }{% \IfFileExists{#1.jbig2}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.jbig2}% }{% \IfFileExists{#1.jb2}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.jb2}% }{}% }% }% \if@anim@multipage% \@anim@filebox{#1\@anim@ext}{1}% \@anim@curframe=\pdflastximagepages% \advance\@anim@curframe by -\@ne%since \pdfximagepages is 1-based \edef\@anim@lastpage{\the\@anim@curframe}% \ifx\@anim@first\@empty% \gdef\@anim@first{0}% \else% \ifnum\@anim@first<\z@\gdef\@anim@first{0}\fi% \ifnum\@anim@first>\@anim@lastpage% \xdef\@anim@first{\@anim@lastpage}% \fi% \fi% \ifx\@anim@last\@empty% \xdef\@anim@last{\@anim@lastpage}% \else% \ifnum\@anim@last<\z@\gdef\@anim@last{0}\fi% \ifnum\@anim@last>\@anim@lastpage% \xdef\@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% }% \else \if@anim@xetex \def\@anim@checkmultipage#1{% #1: file base name \IfFileExists{#1.pdf}{% \setboolean{@anim@multipage}{true}% \gdef\@anim@ext{.pdf}% }{}% \if@anim@multipage% \@anim@curframe=\XeTeXpdfpagecount "#1.pdf"% \advance\@anim@curframe by -\@ne%since XeTeXpdfpagecount is 1-based \edef\@anim@lastpage{\the\@anim@curframe}% \ifx\@anim@first\@empty% \gdef\@anim@first{0}% \else% \ifnum\@anim@first<\z@\gdef\@anim@first{0}\fi% \ifnum\@anim@first>\@anim@lastpage% \xdef\@anim@first{\@anim@lastpage}% \fi% \fi% \ifx\@anim@last\@empty% \xdef\@anim@last{\@anim@lastpage}% \else% \ifnum\@anim@last<\z@\gdef\@anim@last{0}\fi% \ifnum\@anim@last>\@anim@lastpage% \xdef\@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% }% \else \def\@anim@checkmultipage#1{}% no-op in dvips & dvipdfmx mode \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][]{% \leavevmode% \ifpdf\else% \if@anim@grxloaded% \if@anim@xetex% \DeclareGraphicsRule{.mps}{eps}{*}{}% \fi% \else% \if@anim@xetex% \@anim@missing[xetex]{graphicx}% \else% \if@anim@@dvipdfmx% \@anim@missing[dvipdfmx]{graphicx}% \else% \@anim@missing{graphicx}% \fi% \fi% \fi% \fi% \@anim@reset% to default settings \setkeys{anim@user}{#1}% \ifthenelse{\boolean{@anim@autoplay}\OR\boolean{@anim@autoresume}}{% \setboolean{@anim@autoplayorresume}{true}% }{}% \ifthenelse{\boolean{@anim@controls}\OR\boolean{@anim@palindrome}}{% \setboolean{@anim@ctrlorplndrm}{true}% }{}% \ifthenelse{\NOT\boolean{@anim@controls}\AND\boolean{@anim@step}}{% \setboolean{@anim@loop}{true}% }{}% \def\@anim@base{#3}% \def\@anim@first{#4}% \def\@anim@last{#5}% % \@anim@checkmultipage{\@anim@base}%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{>}% \ifnum\@anim@first>\@anim@last% \edef\@anim@every{-\@anim@every}% \def\@anim@relop{<}% \fi% \global\@anim@curframe=\@anim@first% \global\@anim@curframe@zb=\z@% % \if@anim@draft% \if@anim@multipage% %store file in a box \@anim@filebox{\@anim@base\@anim@ext}{\@anim@first}% \else% %get file name extension \@anim@getext{\@anim@base\@anim@first}% \@anim@filebox{\@anim@base\@anim@first\@anim@ext}{1}% \fi% \@anim@getsize{\@anim@box}% \@anim@scale{\@anim@box}% %draw draftbox according to dimensions of the first frame \@anim@draftbox% \else% \if@anim@controls% %create button faces only once in the current colour combination \ifcsname btncol:\@anim@bgcolour:\@anim@fgcolour\endcsname\else% \@anim@makebuttons{\the\@anim@num}% \@anim@newkey{btncol:\@anim@bgcolour:\@anim@fgcolour}{\the\@anim@num}% \fi% \if@anim@step\else% %combine Pause & Play button faces into one XObject \@anim@makeppcontainer{\the\@anim@num}{Right}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \@anim@makeppcontainer{\the\@anim@num}{Left}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \fi% \fi% \xdef\@anim@fps{#2}% current frame rate \xdef\@anim@nfps{#2}% % %read all frames of the sequence \loop\ifnum\@anim@curframe\@anim@relop\@anim@last\else% \if@anim@multipage% %embed graphics \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{% \@anim@base\@anim@ext}{\the\@anim@curframe}% \else% %get file name extension of current file \@anim@getext{% \@anim@base\@anim@pad{\@anim@first}{\the\@anim@curframe}% }% %embed graphics \@anim@ximage{\the\@anim@num}{\the\@anim@curframe@zb}{% \@anim@base\@anim@pad{\@anim@first}{\the\@anim@curframe}\@anim@ext% }{1}% \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% %insert animation widget & controls \@anim@insertwidgets{\the\@anim@num}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \fi% \global\advance\@anim@num by \@ne% \catcode`\:=\@anim@colon\catcode`\;=\@anim@semicolon% \catcode`\*=\@anim@star\catcode`\,=\@anim@comma% }% %adjust catcodes of several characters within \animategraphics \let\@anim@animategraphics\animategraphics \def\animategraphics{% \edef\@anim@colon{\the\catcode`\:}\edef\@anim@semicolon{\the\catcode`\;}% \edef\@anim@star{\the\catcode`\*}\edef\@anim@comma{\the\catcode`\,}% \catcode`\:=12\catcode`\;=12\catcode`\*=12\catcode`\,=12% \@anim@animategraphics% } %inserts animation and control button widgets \def\@anim@insertwidgets#1#2{%#1:@anim@num, #2 existing btn colour combination \vtop{% \offinterlineskip% \hbox{\@anim@animwidget{#1}}% \if@anim@controls% \setlength{\@anim@tmpdima}{\@anim@btnsize}% \vskip 0.1\@anim@tmpdima% \hbox to \@anim@animwidth\p@ {% \hss% \def\@anim@tooltip{}% \@anim@buttonwidget{#1}{EndLeft}{EndLeft:#2}% \@anim@buttonwidget{#1}{StepLeft}{StepLeft:#2}% \if@anim@step\else% \@anim@buttonwidget{#1}{PlayPauseLeft}{#1.PlayPauseLeft}% \@anim@buttonwidget{#1}{PlayPauseRight}{#1.PlayPauseRight}% \fi% \@anim@buttonwidget{#1}{StepRight}{StepRight:#2}% \@anim@buttonwidget{#1}{EndRight}{EndRight:#2}% \if@anim@step\else% \hskip 0.3\@anim@tmpdima% \def\@anim@tooltip{/TU (slower)}% \@anim@buttonwidget{#1}{Minus}{Minus:#2}% \def\@anim@tooltip{/TU (default speed)}% \@anim@buttonwidget{#1}{Reset}{Reset:#2}% \def\@anim@tooltip{/TU (faster)}% \@anim@buttonwidget{#1}{Plus}{Plus:#2}% \fi% \hss% }% \fi% }% } %measures natural dimensions of its box argument \def\@anim@getsize#1{% \xdef\@anim@framewidth{\strip@pt\wd#1}% \xdef\@anim@frameheight{\strip@pt\ht#1}% \xdef\@anim@framedepth{\strip@pt\dp#1}% \setlength{\@anim@tmpdima}{\ht#1}% \addtolength{\@anim@tmpdima}{\dp#1}% \xdef\@anim@frametotalheight{\strip@pt\@anim@tmpdima}% } %calculates widget dimensions from natural ones, taking resizing options %into account \newcount\@anim@resize% resizing flags according to options given \def\@anim@scale#1{% \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}{\height}% \addtolength{\totalheight}{\depth}% %evaluate resizing options \setlength{\@anim@tmpdima}{\@anim@widtharg}% \xdef\@anim@animwidth{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@heightarg}% \xdef\@anim@animheight{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@deptharg}% \xdef\@anim@animdepth{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@heightarg}% \addtolength{\@anim@tmpdima}{\@anim@deptharg}% \xdef\@anim@animtotalheight{\strip@pt\@anim@tmpdima}% %resize unspecified dimensions to keep aspect ratio \ifcase\@anim@resize% bit 2^2=width, 2^1=height, 2^0=depth option given \or% 1 \setlength{\@anim@tmpdima}{% \width*\ratio{\@anim@animtotalheight\p@}{\height+\depth}% }\xdef\@anim@animwidth{\strip@pt\@anim@tmpdima}% \or% 2 \setlength{\@anim@tmpdima}{% \width*\ratio{\@anim@animtotalheight\p@}{\height+\depth}% }\xdef\@anim@animwidth{\strip@pt\@anim@tmpdima}% \or% 3 \setlength{\@anim@tmpdima}{% \width*\ratio{\@anim@animtotalheight\p@}{\height+\depth}% }\xdef\@anim@animwidth{\strip@pt\@anim@tmpdima}% \or% 4 \setlength{\@anim@tmpdima}{% \height*\ratio{\@anim@animwidth\p@}{\width}% }\xdef\@anim@animheight{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{% \depth*\ratio{\@anim@animwidth\p@}{\width}% }\xdef\@anim@animdepth{\strip@pt\@anim@tmpdima}% \or% 5 \ifdim\height=\z@\else% resize height only if original height .ne. zero \setlength{\@anim@tmpdima}{% \totalheight*\ratio{\@anim@animwidth\p@}{\width}-\@anim@animdepth\p@}% \xdef\@anim@animheight{\strip@pt\@anim@tmpdima}% \fi% \or% 6 \ifdim\depth=\z@\else% resize depth only if original depth .ne. zero \setlength{\@anim@tmpdima}{% \totalheight*\ratio{\@anim@animwidth\p@}{\width}-\@anim@animheight\p@}% \xdef\@anim@animdepth{\strip@pt\@anim@tmpdima}% \fi% \fi% %apply scaling factor, totalheight \setlength{\@anim@tmpdima}{\@anim@animwidth\p@}% \setlength{\@anim@tmpdima}{\@anim@boxscale\@anim@tmpdima}% \xdef\@anim@animwidth{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@animheight\p@}% \setlength{\@anim@tmpdima}{\@anim@boxscale\@anim@tmpdima}% \xdef\@anim@animheight{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@animdepth\p@}% \setlength{\@anim@tmpdima}{\@anim@boxscale\@anim@tmpdima}% \xdef\@anim@animdepth{\strip@pt\@anim@tmpdima}% \setlength{\@anim@tmpdima}{\@anim@animheight\p@}% \addtolength{\@anim@tmpdima}{\@anim@animdepth\p@}% \xdef\@anim@animtotalheight{\strip@pt\@anim@tmpdima}% \endgroup% } %interactive Widget annotation that is overlayed on the non-interactive %frame Widgets \ifpdf \def\@anim@animwidget#1{% %create JavaScript objects \@anim@pojscript{#1}% to be executed on PO event \@anim@otherjscript{#1}% on other events in the AA dict \if@anim@useocg% %add poster to posterocg array \ifx\@anim@poster\@anim@posternone\else% \xdef\@anim@posterocgs{\@anim@posterocgs\space\@anim@posterocg}% \fi% \fi% \pdfannot width \@anim@animwidth\p@ height \@anim@animheight\p@ depth \@anim@animdepth\p@ {% /Subtype/Widget% /FT/Btn/Ff 65536% interactive push button /BS <>% /H/N% /T (anm#1)% /Contents (animation by animate[\@anim@version])% /AA <<% bind actions to trigger events /PO <<% /S/JavaScript/JS \@anim@pojscriptobj% >>% \@anim@otherjscriptkey% >>% }% %append widget reference to Fields array of the AcroForm dict \xdef\@anim@fields{\@anim@fields\space\the\pdflastannot\space 0 R}% \hbox to \@anim@animwidth\p@ {% \vrule width 0pt height \@anim@animheight\p@ depth \@anim@animdepth\p@% \hss% }% }% \else \if@anim@@dvipdfmx \def\@anim@animwidget#1{% \@anim@pojscript{#1}% \@anim@otherjscript{#1}% \if@anim@useocg% \ifx\@anim@poster\@anim@posternone\else% \special{pdf:put @anim@posterocgs \@anim@posterocg}% \fi% \fi% \special{pdf:annot @annot@\the\@anim@fieldnum\space width \@anim@animwidth pt height \@anim@animheight pt depth \@anim@animdepth pt <<% /Subtype/Widget% /FT/Btn/Ff 65536% /BS <>% /H/N% /T (anm#1)% /Contents (animation by animate[\@anim@version])% /AA <<% /PO <<% /S/JavaScript/JS @a#1@pojscript% >>% \@anim@otherjscriptkey% >> >>% }% \special{pdf:put @anim@fields @annot@\the\@anim@fieldnum}% \global\advance\@anim@fieldnum by \@ne% \hbox to \@anim@animwidth\p@ {% \vrule width 0pt height \@anim@animheight\p@ depth \@anim@animdepth\p@% \hss% }% }% \else \def\@anim@animwidget#1{% \begingroup% \setlength{\unitlength}{1pt}% %mark annotation rectangle \begin{picture}(0,0)% \put(0,-\@anim@animdepth){% \special{ps: currentpoint /wid@lly exch def /wid@llx exch def }% }% \put(\@anim@animwidth,\@anim@animheight){% \special{ps: currentpoint /wid@ury exch def /wid@urx exch def }% }% \end{picture}% \endgroup% \@anim@pojscript{#1}% \@anim@otherjscript{#1}% \if@anim@useocg% \ifx\@anim@poster\@anim@posternone\else% \special{ps: mark {@anim@posterocgs} {\@anim@posterocg} /APPEND pdfmark }% \fi% \fi% \special{ps: mark /_objdef {annot@\the\@anim@fieldnum}% /Rect [wid@llx wid@lly wid@urx wid@ury]% /Subtype/Widget% /FT/Btn/Ff 65536% /BS <>% /H/N% /T (anm#1)% /Contents (animation by animate[\@anim@version])% /AA <<% /PO <<% /S/JavaScript/JS {a#1@pojscript}% >>% \@anim@otherjscriptkey% >>% /ANN pdfmark mark {@anim@fields} {annot@\the\@anim@fieldnum} /APPEND pdfmark }% \global\advance\@anim@fieldnum by \@ne% \hbox to \@anim@animwidth\p@ {% \vrule width 0pt height \@anim@animheight\p@ depth \@anim@animdepth\p@% \hss% }% } \fi \fi %creates control button widget \ifpdf \def\@anim@buttonwidget#1#2#3{%#1:@anim@num, #2:action, #3:button face XObject \@anim@upjscript{#1}{#2}% JavaScript actions for ButtonUp events \setlength{\@anim@tmpdima}{\@anim@btnsize}% \hbox to \@anim@tmpdima {% \pdfannot width \@anim@tmpdima height \@anim@tmpdima depth 0pt {% /Subtype/Widget% /FT/Btn/Ff 65536% push button /BS <>% /H/I% /AP <>% /T (#1.#2)% \@anim@tooltip% /A <>% }% \xdef\@anim@fields{\@anim@fields\space\the\pdflastannot\space 0 R}% \vrule width 0pt height \@anim@tmpdima depth 0pt% \hss% }% }% \else \if@anim@@dvipdfmx \def\@anim@buttonwidget#1#2#3{% \@anim@upjscript{#1}{#2}% \setlength{\@anim@tmpdima}{\@anim@btnsize}% \hbox to \@anim@tmpdima {% \special{pdf:annot @annot@\the\@anim@fieldnum\space width \the\@anim@tmpdima\space height \the\@anim@tmpdima\space depth 0pt <<% /Subtype/Widget% /FT/Btn/Ff 65536% /BS <>% /H/I% /AP <>% /T (#1.#2)% \@anim@tooltip% /A <>% >>% }% \special{pdf:put @anim@fields @annot@\the\@anim@fieldnum}% \global\advance\@anim@fieldnum by \@ne% \vrule width 0pt height \@anim@tmpdima depth 0pt% \hss% }% }% \else \def\@anim@buttonwidget#1#2#3{% \@anim@upjscript{#1}{#2}% \setlength{\@anim@tmpdima}{\@anim@btnsize}% \begingroup% \setlength{\unitlength}{1pt}% \begin{picture}(0,0)% \put(0,0){% \special{ps: currentpoint /wid@lly exch def /wid@llx exch def }% }% \put(\strip@pt\@anim@tmpdima,\strip@pt\@anim@tmpdima){% \special{ps: currentpoint /wid@ury exch def /wid@urx exch def }% }% \end{picture}% \endgroup% \special{ps: mark /_objdef {annot@\the\@anim@fieldnum} /Rect [wid@llx wid@lly wid@urx wid@ury] /Subtype/Widget /FT/Btn/Ff 65536 /BS <> /H/I /AP <>% /T (#1.#2)% \@anim@tooltip% /A <>% /ANN pdfmark mark {@anim@fields} {annot@\the\@anim@fieldnum} /APPEND pdfmark }% \global\advance\@anim@fieldnum by \@ne% \hbox to \the\@anim@tmpdima {% \vrule width 0pt height \the\@anim@tmpdima\space depth 0pt% \hss% }% } \fi \fi \newboolean{@anim@inside} % for checking whether we are inside the \setboolean{@anim@inside}{false} % `animateinline' environment \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 \newcount\@anim@skipfram % counter for skipped frames %user environment for animating inline graphics % #1: options % #2: frame rate (fps) \newenvironment{animateinline}[2][]{% \leavevmode% \setboolean{@anim@inside}{true}% \@anim@reset% to default settings \setkeys{anim@user}{#1}% \ifthenelse{\boolean{@anim@autoplay}\OR\boolean{@anim@autoresume}}{% \setboolean{@anim@autoplayorresume}{true}% }{}% \ifthenelse{\boolean{@anim@controls}\OR\boolean{@anim@palindrome}}{% \setboolean{@anim@ctrlorplndrm}{true}% }{}% \ifthenelse{\NOT\boolean{@anim@controls}\AND\boolean{@anim@step}}{% \setboolean{@anim@loop}{true}% }{}% \if@anim@draft\else% %create button faces if necessary \if@anim@controls% \ifcsname btncol:\@anim@bgcolour:\@anim@fgcolour\endcsname\else% \@anim@makebuttons{\the\@anim@num}% \@anim@newkey{btncol:\@anim@bgcolour:\@anim@fgcolour}{\the\@anim@num}% \fi% \if@anim@step\else% \@anim@makeppcontainer{\the\@anim@num}{Right}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \@anim@makeppcontainer{\the\@anim@num}{Left}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \fi% \fi% \xdef\@anim@fps{#2}% \xdef\@anim@nfps{#2}% current frame rate (for use in \newframe) \fi% \global\@anim@curframe@zb=\z@% \global\@anim@skipfram=\z@% \catcode`\:=\@anim@colon\catcode`\;=\@anim@semicolon% \catcode`\*=\@anim@star\catcode`\,=\@anim@comma% \@anim@beginframe% \ignorespaces% }{% \unskip% \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}% \catcode`\:=12\catcode`\;=12\catcode`\*=12\catcode`\,=12% \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 \@anim@insertwidgets{\the\@anim@num}{% \@anim@getkeyval{btncol:\@anim@bgcolour:\@anim@fgcolour}}% \fi% \global\advance\@anim@num by \@ne% \catcode`\:=\@anim@colon\catcode`\;=\@anim@semicolon% \catcode`\*=\@anim@star\catcode`\,=\@anim@comma% \setboolean{@anim@inside}{false}% } \let\@anim@animateinline\animateinline \def\animateinline{% \edef\@anim@colon{\the\catcode`\:}\edef\@anim@semicolon{\the\catcode`\;}% \edef\@anim@star{\the\catcode`\*}\edef\@anim@comma{\the\catcode`\,}% \catcode`\:=12\catcode`\;=12\catcode`\*=12\catcode`\,=12% \@anim@animateinline% } %usercommand for use within `animateinline' environment; %terminates the current frame and starts a new one \def\newframe{% \unskip% \if@anim@inside\else% \PackageError{animate}{% \protect\newframe\space cannot be used outside `animateinline'% \MessageBreak environment% }{}% \fi% \@anim@endframe{\the\@anim@num}{\the\@anim@curframe@zb}% \@ifstar\@anim@newframestar\@anim@newframe% } \newcommand{\@anim@newframe}[1][]{% #1: new frame rate \ifnum\@anim@skipfram=\z@% \if@anim@draft\else% \if@anim@step\else% \if@anim@timeline\else% \edef\@anim@pfps{\@anim@nfps}% \edef\@anim@nfps{#1}% \ifx\@anim@nfps\@empty% \edef\@anim@nfps{\@anim@pfps}% \else% \ifdim\@anim@nfps\p@=\@anim@pfps\p@\else% \ifnum\@anim@curframe@zb=\z@% \xdef\@anim@fps{#1}% \fi% %build JavaScript commands to fill the `nFpsAt' & `pFpsAt' arrays \xdef\@anim@nfpsat{% \@anim@nfpsat% a\the\@anim@num.nFpsAt[\the\@anim@curframe@zb]=Math.abs(#1);% }% \xdef\@anim@pfpsat{% \@anim@pfpsat% a\the\@anim@num.pFpsAt[\the\@anim@curframe@zb]=% Math.abs(\@anim@pfps);% }% \setboolean{@anim@chfps}{true}% change fps \fi% \fi% \fi% \fi% \fi% \global\advance\@anim@curframe@zb by \@ne% \fi% \@anim@beginframe% \ignorespaces% } \newcommand{\@anim@newframestar}[1][]{% starred variant for pausing animation \ifnum\@anim@skipfram=\z@% #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}% \xdef\@anim@pfps{\@anim@nfps}% \xdef\@anim@nfps{#1}% \ifx\@anim@nfps\@empty% \xdef\@anim@nfps{\@anim@pfps}% \else% \ifdim\@anim@nfps\p@=\@anim@pfps\p@\else% \ifnum\@anim@curframe@zb=\z@% \xdef\@anim@fps{#1}% \fi% %build JavaScript commands to fill the `nFpsAt' & `pFpsAt' arrays \xdef\@anim@nfpsat{% \@anim@nfpsat% a\the\@anim@num.nFpsAt[\the\@anim@curframe@zb]=Math.abs(#1);% }% \xdef\@anim@pfpsat{% \@anim@pfpsat% a\the\@anim@num.pFpsAt[\the\@anim@curframe@zb]=% Math.abs(\@anim@pfps);% }% \setboolean{@anim@chfps}{true}% change fps \fi% \fi% \fi% \fi% \fi% \global\advance\@anim@curframe@zb by \@ne% \fi% \@anim@beginframe% \ignorespaces% } %starts new frame \def\@anim@beginframe{% \begin{lrbox}{\@anim@box}% store graphics in a box \the\@anim@begin% } %terminates current frame \def\@anim@endframe#1#2{% \the\@anim@end% \end{lrbox}% \ifnum\@anim@skipfram=\z@% \@anim@getsize{\@anim@box}%determine size of graphics \ifnum#2=\z@% \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% \@anim@scale{\@anim@box}% %draw draftbox according to dimensions of the first frame \if@anim@draft\@anim@draftbox\fi% \fi% %now create Form XObject of box contents \if@anim@draft\else% \@anim@xinline{#1}{#2}{\@anim@box}{!}\message{}% \fi% \fi% \global\advance\@anim@skipfram by \@ne% \ifnum\@anim@skipfram=\@anim@every% \global\@anim@skipfram=\z@% \fi% } %user command for building loops around parameterized frame content, just 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{\multiframe}[3]{% #1: #repetitions, #2: vars, #3: frame content \unskip% \if@anim@inside\else% \PackageError{animate}{% \protect\multiframe\space cannot be used outside `animateinline'% \MessageBreak environment% }{}% \fi% \if@anim@insidemulti% \PackageError{animate}{\protect\multiframe\space cannot be nested}{}% \fi% \setboolean{@anim@insidemulti}{true}% %reset macro for updating variables \gdef\@anim@updatevars{}% %reset loop counter \global\@anim@mulframecnt=\z@% %remove spaces from variable declaration list (2nd arg) \xdef\@anim@vardecls{#2\space}% \xdef\@anim@vardecls{\expandafter\zap@space\@anim@vardecls\@empty}% \ifnum#1<\z@% \PackageError{animate}{% \protect\multiframe: first argument must be greater than zero% }{}% \fi% %parse list of variable declarations and build macro for updating them \expandafter\@anim@parsevars\@anim@vardecls,\@nil% \whiledo{\@anim@mulframecnt<#1}{% \ifnum\@anim@mulframecnt>\z@% \newframe% \@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}% %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}{#3}% \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\@anim@add\csname#1\endcsname{#2}{0.0}% %global copy that saves current variable value between loops \expandafter\gdef\csname#1@old\endcsname{#2}% %append script for updating variable to \@anim@updatevars macro \g@addto@macro\@anim@updatevars{% %new value \expandafter\@anim@add\csname#1\endcsname{\csname#1@old\endcsname}{#3}% %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 \expandafter\edef\csname#1\endcsname{#2}% %global copy that saves current variable value between loops \expandafter\gdef\csname#1@old\endcsname{#2}% %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 #3% \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 (stringed zeros) from given num \ifnum10#1<1#2 \@anim@template{0#1}{#2}% \else% \ifnum10#1=1#2 \@anim@template{0#1}{#2}% \else% #1% \fi% \fi% }% \edef\@anim@catcode{\the\catcode`\_}\catcode`\_=13 \begingroup\let_\space \xdef\@anim@nusewarning{% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak% @_There_were_unused_animation_transparencies._______@\MessageBreak% @_See_the_transcript_file___________________________@\MessageBreak% @___``\jobname.log''\MessageBreak% @_for_additional_information!_______________________@\MessageBreak% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% } \endgroup \catcode`\_=\@anim@catcode %building timeline from timeline file \newread\@anim@@tmlnfile \newboolean{@anim@eof} \newcount\@anim@tmpcnt %scratch counter for different uses \newcount\@anim@curlayer %takes the number of the current layer being processed \newcount\@anim@lineno %current input line No. \def\@anim@buildtmln#1{% #1:@anim@num \endlinechar=-1% suppress trailing space at input line end \global\@anim@curframe@zb=\z@% %read timeline file a first time to get number of lines (= number of frames) \openin\@anim@@tmlnfile=\@anim@tmlnfile% \read\@anim@@tmlnfile to \@anim@inputline% \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, resource & transparency lists for each frame \@anim@newkey{trlst@\the\@anim@curframe@zb}{}% \@anim@newkey{frmxobject@\the\@anim@curframe@zb}{}% \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}% \global\advance\@anim@curframe@zb by \@ne% }% \read\@anim@@tmlnfile to \@anim@inputline% \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% \xdef\@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@% \read\@anim@@tmlnfile to \@anim@inputline% \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% \message{\@anim@maxlayer\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{frmxobject@\the\@anim@curframe@zb}{% \@anim@getkeyval{frmxobject@\the\@anim@curframe@zb}% \@anim@getkeyval{% layerxobject@\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{% layerxobject@\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 \edef\@anim@trlst{% \the\@anim@curframe@zb.\@anim@getkeyval{trlst@\the\@anim@curframe@zb}}% \expandafter\@anim@findmult\@anim@trlst,\@nil% %insert frame Widget \@anim@makeframe{#1}{\the\@anim@curframe@zb}% %clean-up \expandafter\@anim@resetmult\@anim@trlst,\@nil% \@anim@newkey{trlst@\the\@anim@curframe@zb}{}% \@anim@newkey{frmxobject@\the\@anim@curframe@zb}{}% \@anim@newkey{frmcontent@\the\@anim@curframe@zb}{}% \message{.}% \global\advance\@anim@curframe@zb by \@ne% }% \read\@anim@@tmlnfile to \@anim@inputline% \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% }% \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% \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:#3\@nil{% \if@anim@step\else% \ifthenelse{\equal{#1}{*}}{%first field is a star (pause frame) \xdef\@anim@pauseat{% \@anim@pauseat% a\the\@anim@num.pauseAt[\the\@anim@curframe@zb]=1;% }% \setboolean{@anim@pauseframes}{true}% }{}% \xdef\@anim@pfps{\@anim@nfps}% \xdef\@anim@nfps{#2}% %treat the second field (new frame rate) \ifx\@anim@nfps\@empty% no change of frame rate \xdef\@anim@nfps{\@anim@pfps}% \else% \ifdim\@anim@nfps\p@=\@anim@pfps\p@\else% \ifnum\@anim@curframe@zb=\z@% \xdef\@anim@fps{#2}% \fi% %build JavaScript commands to fill the `nFpsAt' & `pFpsAt' arrays \xdef\@anim@nfpsat{% \@anim@nfpsat% a\the\@anim@num.nFpsAt[\the\@anim@curframe@zb]=Math.abs(#2);% }% \xdef\@anim@pfpsat{% \@anim@pfpsat% a\the\@anim@num.pFpsAt[\the\@anim@curframe@zb]=Math.abs(\@anim@pfps);% }% \setboolean{@anim@chfps}{true}% change fps \fi% \fi% \fi% %parse the third field (list of layer specifications) \global\@anim@curlayer=\z@% \@anim@parsethird#3;\@nil% } %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% \xdef\@anim@maxlayer{\the\@anim@curlayer}% \fi% \@anim@parsethird#2\@nil% }% } %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@% =0 means: repeat until end of timeline \edef\@anim@repeatuntil{\@anim@frames}% \else% \global\@anim@tmpcnt=\@anim@curframe@zb% \global\advance\@anim@tmpcnt by \@anim@repeats% \ifnum\@anim@frames<\@anim@tmpcnt% \edef\@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% %clear ressource list \@anim@newkey{layerxobject@\the\@anim@tmpcnt.\the\@anim@curlayer}{}% %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 and update layer xobject resource %list according to transparency specifications \ifnum\@anim@transp<#1\else% ignore non-existing \ifnum\@anim@transp=#1\else% transparencies \global\@anim@tmpcnt=\@anim@curframe@zb% \loop\ifnum\@anim@repeatuntil>\@anim@tmpcnt% %ressource list \edef\@anim@tmpvar{\@anim@getkeyval{% layerxobject@\the\@anim@tmpcnt.\the\@anim@curlayer}}% \@anim@newkey{layerxobject@\the\@anim@tmpcnt.\the\@anim@curlayer}{% \@anim@tmpvar\space/im#1\space\@anim@getkeyval{img@#1}% }% %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\space q /im#1\space Do Q% }% %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% }% } \edef\@anim@catcode{\the\catcode`\_}\catcode`\_=13 \begingroup\let_\space \xdef\@anim@multwarning{% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\MessageBreak% @_In_certain_animation_frames,_transparencies_were__@\MessageBreak% @_multiply_included._This_may_considerably_slow_____@\MessageBreak% @_down_animation_speed._Revise_the_timeline_file_of_@\MessageBreak% @_the_corresponding_animation!_See_the_transcript___@\MessageBreak% @_file______________________________________________@\MessageBreak% @___``\jobname.log''\MessageBreak% @_for_additional_information!_______________________@\MessageBreak% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% }% \endgroup \catcode`\_=\@anim@catcode %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 multiply 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% }% } %get number of repetitions of frame \def\@anim@getrepetitions#1x\@nil{% \gdef\@anim@repeats{#1}% } %command options %setting the widget size \define@key{anim@user}{width}{% \gdef\@anim@widtharg{#1}% \global\advance\@anim@resize by 4% } \define@key{anim@user}{height}{% \gdef\@anim@heightarg{#1}% \global\advance\@anim@resize by 2% } \define@key{anim@user}{depth}{% \gdef\@anim@deptharg{#1}% \global\advance\@anim@resize by \@ne% } \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% }% } \if@anim@@dvips %background frame of buttons \def\@anim@@@bg{% 0 setlinejoin 0 0 moveto 15 0 lineto 15 15 lineto 0 15 lineto closepath fill% } \else% pdftex and dvipdfmx \def\@anim@@@bg{% 0 j 0 0 150 150 re f% } \fi \define@key{anim@user}{buttonbg}{%background colour of buttons \global\@anim@tmpcnt=\@ne% \gdef\@anim@colour{}% \@anim@colours#1:\@nil% \xdef\@anim@bgcolour{\@anim@colour}% \if@anim@@dvips \ifnum\@anim@tmpcnt=\@ne% \xdef\@anim@bg{\@anim@colour\space setgray\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=3\relax% \xdef\@anim@bg{\@anim@colour\space setrgbcolor\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=4\relax% \xdef\@anim@bg{\@anim@colour\space setcmykcolor\space\@anim@@@bg}% \fi% \fi% \fi% \else% pdftex and dvipdfmx \ifnum\@anim@tmpcnt=\@ne% \xdef\@anim@bg{\@anim@colour\space g\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=3\relax% \xdef\@anim@bg{\@anim@colour\space rg\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=4\relax% \xdef\@anim@bg{\@anim@colour\space k\space\@anim@@@bg}% \fi% \fi% \fi% \fi% } \define@key{anim@user}{buttonfg}{%stroking colour of buttons \global\@anim@tmpcnt=\@ne% \gdef\@anim@colour{}% \@anim@colours#1:\@nil% \xdef\@anim@fgcolour{\@anim@colour}% \if@anim@@dvips \ifnum\@anim@tmpcnt=\@ne% \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% \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% } \newboolean{@anim@controls} \define@key{anim@user}{controls}[true]{% \setboolean{@anim@controls}{#1}% } \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}% } \define@key{anim@user}{poster}[first]{% | none | last \ifthenelse{% correct wrong input to `none' \equal{#1}{first}\OR\equal{#1}{last}% }{% \gdef\@anim@poster{#1}% }{% \gdef\@anim@poster{none}% }% } \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}% }% } \define@key{anim@user}{timeline}{% \IfFileExists{#1}{% \gdef\@anim@tmlnfile{#1}% \setboolean{@anim@timeline}{true}% }{% \PackageError{animate}{timeline file `#1' cannot be opened for reading% }{% Make sure file `#1' exists and is readable!% }% }% } \newtoks\@anim@begin \define@key{anim@user}{begin}{% \@anim@begin{#1}% } \newtoks\@anim@end \define@key{anim@user}{end}{% \@anim@end{#1}% } \define@key{anim@user}{every}{% embed every #1th frame \ifnum#1<\@ne\gdef\@anim@every{1}\else\gdef\@anim@every{#1}\fi% } \define@key{anim@user}{bb}{% \if@anim@grxloaded\g@addto@macro\@anim@gropts{, bb=#1}% \else\@anim@missing{graphicx}\fi% } \define@key{anim@user}{viewport}{% \if@anim@grxloaded\g@addto@macro\@anim@gropts{, viewport=#1}% \else\@anim@missing{graphicx}\fi% } \define@key{anim@user}{trim}{% \if@anim@grxloaded\g@addto@macro\@anim@gropts{, trim=#1}% \else\@anim@missing{graphicx}\fi% } \newboolean{@anim@meas} \define@key{anim@user}{measure}[true]{% \setboolean{@anim@meas}{#1}% } \define@key{anim@user}{useocg}[true]{% \setboolean{@anim@useocg}{#1}% } %macro to reset macros and booleans \def\@anim@reset{% \gdef\@anim@boxscale{1.0}% \global\@anim@resize\z@% \gdef\@anim@widtharg{\width}% \gdef\@anim@heightarg{\height}% \gdef\@anim@deptharg{\depth}% \xdef\@anim@bg{\@anim@@bg}% \xdef\@anim@fg{\@anim@@fg}% \if@anim@@dvips\else\xdef\@anim@@@fg{\@anim@@@@fg}\fi% \xdef\@anim@bgcolour{\@anim@@bgcolour}% default button colours \xdef\@anim@fgcolour{\@anim@@fgcolour}% \xdef\@anim@btnsize{\@anim@@btnsize}% \xdef\@anim@poster{\@anim@@poster}% \global\let\if@anim@controls=\if@anim@@controls% \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\if@anim@useocg=\if@anim@@useocg% \gdef\@anim@posterocg{}% \gdef\@anim@properties{}% \setboolean{@anim@pauseframes}{false}% \gdef\@anim@pauseat{}% \setboolean{@anim@chfps}{false}% \gdef\@anim@nfpsat{}% \gdef\@anim@pfpsat{}% \gdef\@anim@tmlnfile{}% \setboolean{@anim@timeline}{false}% \global\@anim@begin={}% \global\@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}% \setboolean{@anim@ctrlorplndrm}{false}% } %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}{xetex}[]{ \ifthenelse{\equal{#1}{}}{}{% \PackageError{animate}{% Package option `xetex' 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% \xdef\@anim@@bgcolour{\@anim@colour}% \if@anim@@dvips \ifnum\@anim@tmpcnt=\@ne% \xdef\@anim@@bg{\@anim@colour\space setgray\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=3\relax% \xdef\@anim@@bg{\@anim@colour\space setrgbcolor\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=4\relax% \xdef\@anim@@bg{\@anim@colour\space setcmykcolor\space\@anim@@@bg}% \fi% \fi% \fi% \else% pdftex and dvipdfmx \ifnum\@anim@tmpcnt=\@ne% \xdef\@anim@@bg{\@anim@colour\space g\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=3\relax% \xdef\@anim@@bg{\@anim@colour\space rg\space\@anim@@@bg}% \else% \ifnum\@anim@tmpcnt=4\relax% \xdef\@anim@@bg{\@anim@colour\space k\space\@anim@@@bg}% \fi% \fi% \fi% \fi% } \if@anim@@dvips \def\@anim@@fg{0 setgray}% \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% \xdef\@anim@@fgcolour{\@anim@colour}% \if@anim@@dvips% \ifnum\@anim@tmpcnt=\@ne% \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% \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@@btnsize{1.44em}% \define@key{anim@pkg}{buttonsize}{% \gdef\@anim@@btnsize{#1}% } \newboolean{@anim@@controls} \setboolean{@anim@@controls}{false}% \define@key{anim@pkg}{controls}[true]{% \setboolean{@anim@@controls}{#1}% } \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{first}% \define@key{anim@pkg}{poster}[first]{% \ifthenelse{% \equal{#1}{first}\OR\equal{#1}{last}% }{% \gdef\@anim@@poster{#1}% }{% \gdef\@anim@@poster{none}% }% } \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}% } \define@key{anim@pkg}{final}[true]{% \ifthenelse{\equal{#1}{true}}{% \setboolean{@anim@@draft}{false}% }{% \setboolean{@anim@@draft}{true}% }% } \newboolean{@anim@@useocg} \setboolean{@anim@@useocg}{false} \define@key{anim@pkg}{useocg}[true]{% \setboolean{@anim@@useocg}{#1}% } %process package options \def\@anim@setpkgkeys#1{\setkeys{anim@pkg}{#1}} \edef\@anim@pkgopts{{\@ptionlist{\@currname.\@currext}}} \expandafter\@anim@setpkgkeys\@anim@pkgopts %JavaScript objects %animation widget's PageOpen event \ifpdf \def\@anim@pojscript#1{% \immediate\pdfobj stream {\@anim@@pojscript{#1}}% \xdef\@anim@pojscriptobj{\the\pdflastobj\space 0 R}% } \else \if@anim@@dvipdfmx \def\@anim@pojscript#1{% \special{pdf:stream @a#1@pojscript (\@anim@@pojscript{#1})}% } \else \def\@anim@pojscript#1{% \special{ps: mark /_objdef {a#1@pojscript} /type/stream /OBJ pdfmark mark {a#1@pojscript} (\@anim@@pojscript{#1}) /PUT pdfmark }% } \fi \fi \def\@anim@@pojscript#1{% #1: @anim@num % console.show();% % console.clear();% \if@anim@useocg\else var curdoc=this;% var a#1_intd;% \fi var a#1,a#1_int;% if(typeof(a#1)=='undefined'){% initialize animation a#1=new Object();% %takes references to frame ocgs/Field objects belonging to the current %animation a#1.fr=new Array();% \if@anim@controls a#1.btn=new Array();%takes references to control button face ocgs a#1.sm=1;% speed multiplier \fi% %initialize fr & btn properties \if@anim@useocg %get array of ocgs of current page var ocg=this.getOCGs(this.pageNum);% for(var i in ocg){% var ocgName=ocg[i].name.split('.');% if(ocgName[0]==#1){% \if@anim@controls\if@anim@step\else if(ocgName[1].charAt(0)=='P'){% PlayLeft, PauseLeft, ... a#1.btn[ocgName[1]]=ocg[i];% %set basic button state a#1.btn[ocgName[1]].state=ocg[i].initState;% }else{% frame ocg \fi\fi %get array of animation frames a#1.fr[ocgName[1]]=ocg[i];% %set basic frame state a#1.fr[ocgName[1]].state=ocg[i].initState;% \if@anim@controls\if@anim@step\else% }% \fi\fi% }% }% \else %get array of animation frames for(i=0;i<=\@anim@maxframe;i++){% a#1.fr[i]=this.getField('#1.'+i);% }% \if@anim@controls\if@anim@step\else var ocg=this.getOCGs(this.pageNum);% for(var i in ocg){% var ocgName=ocg[i].name.split('.');% if(ocgName[0]==#1){% a#1.btn[ocgName[1]]=ocg[i];% a#1.btn[ocgName[1]].state=ocg[i].initState;% }% }% \fi\fi% \fi% \ifx\@anim@poster\@anim@posterlast % set default frame %holds index of the frame to be displayed a#1.idx=\@anim@maxframe;% \else % first & none a#1.idx=0;% \fi% %playing state and direction \if@anim@step% \if@anim@palindrome a#1.playsRight=true;% \fi% \else a#1.isPlaying=false;% a#1.playsRight=true;% a#1.isPaused=false;% \if@anim@pauseframes %this array takes the frame numbers at which to pause playback a#1.pauseAt=new Array();% \@anim@pauseat% \fi% \if@anim@chfps %arrays that take frame numbers (array index) and fps values a#1.nFpsAt=new Array();% \@anim@nfpsat% a#1.pFpsAt=new Array();% \@anim@pfpsat% a#1.fps=Math.abs(\@anim@fps);% \fi a#1.dt=1000/(1e-6+Math.abs(\@anim@fps));% \fi% %actions a#1.actnEndLeft=function(){% \if@anim@step\else a#1.actnPause();% a#1.isPaused=false;% because it has been explicitly stopped \fi% \if@anim@useocg a#1.fr[a#1.idx].state=false;% a#1.idx=0;% a#1.fr[0].state=true;% \else a#1.fr[a#1.idx].display=display.hidden;% a#1.idx=0;% a#1.fr[0].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@chfps a#1.fps=Math.abs(\@anim@fps);% a#1.dt=1000/(1e-6+a#1.fps);% \fi% };% a#1.actnEndRight=function(){% \if@anim@step\else a#1.actnPause();% a#1.isPaused=false;% \fi% \if@anim@useocg a#1.fr[a#1.idx].state=false;% a#1.idx=\@anim@maxframe;% a#1.fr[a#1.idx].state=true;% \else a#1.fr[a#1.idx].display=display.hidden;% a#1.idx=\@anim@maxframe;% a#1.fr[a#1.idx].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@chfps %frame rate from the last fps change (\@anim@nfps) a#1.fps=Math.abs(\@anim@nfps);% a#1.dt=1000/(1e-6+a#1.fps);% \fi% };% a#1.actnNext=function(){% \if@anim@useocg a#1.fr[a#1.idx].state=false;% \else a#1.fr[a#1.idx].display=display.hidden;% \fi try{% \if@anim@useocg a#1.fr[++a#1.idx].state=true;% \else a#1.fr[++a#1.idx].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@step\else\if@anim@meas a#1.frcnt++;\fi\fi% }catch(e){% --a#1.idx;% \if@anim@palindrome% \if@anim@step a#1.actnEndRight();% a#1.playsRight=false;% \else% \if@anim@useocg a#1.fr[a#1.idx].state=true;% \else a#1.fr[a#1.idx].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@meas if(a#1.isPlaying){a#1.stopMeas();}\fi if(a#1.isPlaying){a#1.isPaused=true;a#1.actnPlayLeft();}% \fi% \else% \if@anim@step a#1.actnEndRight();% \else% \if@anim@loop if(a#1.isPlaying){% \if@anim@chfps a#1.fps=Math.abs(\@anim@fps);% a#1.dt=1000/(1e-6+a#1.fps);% \fi a#1.actnPlayRight();% }else{a#1.actnEndRight();}% \else a#1.actnEndRight();% \fi% \fi% \fi% }% \if@anim@step\else% \if@anim@chfps if(% a#1.nFpsAt[a#1.idx]>=0&&% a#1.nFpsAt[a#1.idx]!=a#1.fps% ){% a#1.fps=a#1.nFpsAt[a#1.idx];% a#1.dt=1000/(1e-6+a#1.fps);% if(a#1.isPlaying){a#1.isPaused=true;a#1.actnPlayRight();}% }% \fi% \if@anim@pauseframes if(a#1.isPlaying&&a#1.pauseAt[a#1.idx]){a#1.actnPause();}% \fi% \fi% };% \if@anim@ctrlorplndrm a#1.actnPrev=function(){% \if@anim@useocg a#1.fr[a#1.idx].state=false;% \else a#1.fr[a#1.idx].display=display.hidden;% \fi try{% \if@anim@useocg a#1.fr[--a#1.idx].state=true;% \else a#1.fr[--a#1.idx].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@step\else\if@anim@meas a#1.frcnt++;\fi\fi% }catch(e){% ++a#1.idx;% \if@anim@palindrome% \if@anim@step a#1.actnEndLeft();% a#1.playsRight=true;% \else% \if@anim@useocg a#1.fr[a#1.idx].state=true;% \else a#1.fr[a#1.idx].display=display.visible;% curdoc.dirty=false;% \fi% \if@anim@meas if(a#1.isPlaying){a#1.stopMeas();}\fi if(a#1.isPlaying){a#1.isPaused=true;a#1.actnPlayRight();}% \fi% \else% \if@anim@step a#1.actnEndLeft();% \else% \if@anim@loop if(a#1.isPlaying){% \if@anim@chfps a#1.fps=Math.abs(\@anim@nfps);% a#1.dt=1000/(1e-6+a#1.fps);% \fi a#1.actnPlayLeft();% }else{a#1.actnEndLeft();}% \else a#1.actnEndLeft();% \fi% \fi% \fi% }% \if@anim@step\else% \if@anim@chfps if(% a#1.pFpsAt[a#1.idx]>=0&&% a#1.pFpsAt[a#1.idx]!=a#1.fps% ){% a#1.fps=a#1.pFpsAt[a#1.idx];% a#1.dt=1000/(1e-6+a#1.fps);% if(a#1.isPlaying){a#1.isPaused=true;a#1.actnPlayLeft();}% }% \fi% \if@anim@pauseframes if(a#1.isPlaying&&a#1.pauseAt[a#1.idx]){a#1.actnPause();}% \fi% \fi% };% \fi% \if@anim@step\else a#1.actnPause=function(){% \if@anim@meas if(a#1.isPlaying){a#1.stopMeas();}\fi try{app.clearInterval(a#1_int);}catch(e){}% a#1.isPlaying=false;% a#1.isPaused=true;% \if@anim@controls a#1.btn['PauseLeft'].state=false;% a#1.btn['PlayLeft'].state=true;% a#1.btn['PauseRight'].state=false;% a#1.btn['PlayRight'].state=true;% \fi% };% a#1.actnPlayRight=function(){% try{app.clearInterval(a#1_int);}catch(e){}% if(!a#1.isPaused){a#1.actnEndLeft();}% a#1.playsRight=true;% a#1.isPlaying=true;% a#1.isPaused=false;% \if@anim@controls a#1.btn['PauseLeft'].state=true;% a#1.btn['PlayLeft'].state=false;% a#1.btn['PauseRight'].state=true;% a#1.btn['PlayRight'].state=false;% \fi% \if@anim@meas a#1.startMeas();\fi a#1_int=app.setInterval(% 'a#1.actnNext()',a#1.dt\if@anim@controls/a#1.sm\fi% );% };% \if@anim@ctrlorplndrm a#1.actnPlayLeft=function(){% try{app.clearInterval(a#1_int);}catch(e){}% if(!a#1.isPaused){a#1.actnEndRight();}% a#1.playsRight=false;% a#1.isPlaying=true;% a#1.isPaused=false;% \if@anim@controls a#1.btn['PauseLeft'].state=true;% a#1.btn['PlayLeft'].state=false;% a#1.btn['PauseRight'].state=true;% a#1.btn['PlayRight'].state=false;% \fi% \if@anim@meas a#1.startMeas();\fi a#1_int=app.setInterval(% 'a#1.actnPrev()',a#1.dt\if@anim@controls/a#1.sm\fi% );% };% \fi% \if@anim@controls a#1.actnIncr=function(){% speed up animation try{app.clearInterval(a#1_int);}catch(e){}% a#1.sm*=1.2;% if(a#1.isPlaying){% if(a#1.playsRight){% a#1_int=app.setInterval('a#1.actnNext()',a#1.dt/a#1.sm);% }else{% a#1_int=app.setInterval('a#1.actnPrev()',a#1.dt/a#1.sm);% }% }% };% a#1.actnDecr=function(){% slow down animation try{app.clearInterval(a#1_int);}catch(e){}% a#1.sm/=1.2;% if(a#1.isPlaying){% if(a#1.playsRight){% a#1_int=app.setInterval('a#1.actnNext()',a#1.dt/a#1.sm);% }else{% a#1_int=app.setInterval('a#1.actnPrev()',a#1.dt/a#1.sm);% }% }% };% a#1.actnReset=function(){% reset to default speed a#1.sm=1;% try{app.clearInterval(a#1_int);}catch(e){}% if(a#1.isPlaying){% if(a#1.playsRight){% a#1_int=app.setInterval('a#1.actnNext()',a#1.dt/a#1.sm);% }else{% a#1_int=app.setInterval('a#1.actnPrev()',a#1.dt/a#1.sm);% }% }% };% \fi% \fi% \if@anim@step\else% \if@anim@meas var spc=String.fromCharCode(32);% a#1.frcnt=0;% frame counter for speed measurements a#1.msStart=0;% takes start time (in millisecs) a#1.msEnd=0;% takes end time (in millisecs) a#1.startMeas=function(){% a#1.frcnt=0;% reset frame counter a#1.msStart=(new Date()).getTime();% };% a#1.stopMeas=function(){% a#1.msEnd=(new Date()).getTime();% app.alert({% cMsg:'av.'+spc+'frame'+spc+'rate:'+spc+% 1e3*a#1.frcnt/(a#1.msEnd-a#1.msStart)+spc+'fps',% nIcon:3% }); };% \fi% \fi% }% \if@anim@step\else% \if@anim@autoplay% \if@anim@useocg% \if@anim@ctrlorplndrm if(a#1.playsRight){a#1.actnPlayRight();}else{a#1.actnPlayLeft();}% \else% a#1.actnPlayRight();% \fi% \else \if@anim@ctrlorplndrm if(a#1.playsRight){% a#1_intd=app.setTimeOut('a#1.actnPlayRight()',1);% }else{% a#1_intd=app.setTimeOut('a#1.actnPlayLeft()',1);% }% \else% a#1_intd=app.setTimeOut('a#1.actnPlayRight()',1);% \fi% \fi% \fi% \if@anim@autoresume if(a#1.isPaused){% \if@anim@useocg% \if@anim@ctrlorplndrm if(a#1.playsRight){a#1.actnPlayRight();}else{a#1.actnPlayLeft();}% \else a#1.actnPlayRight();% \fi% \else% \if@anim@ctrlorplndrm if(a#1.playsRight){% a#1_intd=app.setTimeOut('a#1.actnPlayRight()',1);% }else{% a#1_intd=app.setTimeOut('a#1.actnPlayLeft()',1);% }% \else a#1_intd=app.setTimeOut('a#1.actnPlayRight()',1);% \fi% \fi% }% \fi% \fi% } %other trigger events in the anim widget's AA dictionary \def\@anim@otherjscript#1{% \xdef\@anim@otherjscriptkey{% /PC <>% \if@anim@step\else% /D <>% \fi% /U <>% }% } %actions for control buttons \def\@anim@upjscript#1#2{% \def\@anim@action{#2}% \def\@anim@EndLeft{EndLeft}% \def\@anim@StepLeft{StepLeft}% \def\@anim@PlayPauseLeft{PlayPauseLeft}% \def\@anim@PlayPauseRight{PlayPauseRight}% \def\@anim@StepRight{StepRight}% \def\@anim@EndRight{EndRight}% \def\@anim@Minus{Minus}% \def\@anim@Reset{Reset}% \def\@anim@Plus{Plus}% \xdef\@anim@upjscriptstring{% app.focusRect=false;% \ifx\@anim@action\@anim@EndLeft a#1.actnEndLeft();% \else% \ifx\@anim@action\@anim@StepLeft% \if@anim@step a#1.actnPrev();% \else if(!a#1.isPlaying){a#1.isPaused=true;a#1.actnPrev();}% \fi% \else% \ifx\@anim@action\@anim@PlayPauseLeft if(a#1.isPlaying){a#1.actnPause();}else{a#1.actnPlayLeft();}% \else% \ifx\@anim@action\@anim@PlayPauseRight if(a#1.isPlaying){a#1.actnPause();}else{a#1.actnPlayRight();}% \else% \ifx\@anim@action\@anim@StepRight% \if@anim@step a#1.actnNext();% \else if(!a#1.isPlaying){a#1.isPaused=true;a#1.actnNext();}% \fi% \else% \ifx\@anim@action\@anim@EndRight a#1.actnEndRight();% \else% \ifx\@anim@action\@anim@Minus a#1.actnDecr();% \else% \ifx\@anim@action\@anim@Reset a#1.actnReset();% \else% \ifx\@anim@action\@anim@Plus a#1.actnIncr();% \fi\fi\fi\fi\fi\fi\fi\fi\fi% }% }