summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/media4svg/media4svg.sty
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2020-04-10 03:06:35 +0000
committerNorbert Preining <norbert@preining.info>2020-04-10 03:06:35 +0000
commit25111608e6aa05042b0c6f83009262e1973d7a45 (patch)
tree4e47675c9f816298a780508cf0b31db2f84bd5fd /macros/latex/contrib/media4svg/media4svg.sty
parent122d129e46fd990f791aeb4ff07eaa1b35b9af0d (diff)
CTAN sync 202004100306
Diffstat (limited to 'macros/latex/contrib/media4svg/media4svg.sty')
-rw-r--r--macros/latex/contrib/media4svg/media4svg.sty736
1 files changed, 736 insertions, 0 deletions
diff --git a/macros/latex/contrib/media4svg/media4svg.sty b/macros/latex/contrib/media4svg/media4svg.sty
new file mode 100644
index 0000000000..a14c4cd00f
--- /dev/null
+++ b/macros/latex/contrib/media4svg/media4svg.sty
@@ -0,0 +1,736 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% media4svg.sty
+%
+% multimedia inclusion package for the `dvisvgm' backend
+%
+% Supported workflows:
+%
+% [dvilua | p | up]latex + dvisvgm
+% xelatex --no-pdf + dvisvgm
+%
+% Copyright 2020--\today, Alexander Grahn
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License.
+%
+% The latest version of this license is in
+% http://mirrors.ctan.org/macros/latex/base/lppl.txt
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is A. Grahn.
+
+\RequirePackage{iftex}
+\ifpdf
+ \PackageError{media4svg}{%
+ Wrong output format (PDF).\MessageBreak
+ This package only works with the `dvisvgm' backend.\MessageBreak
+ A TeX engine must be used that produces\MessageBreak
+ DVI or XDV output%
+ }{}%
+\fi
+
+\RequirePackage{expl3}
+\RequirePackage{l3keys2e}
+\RequirePackage{xparse}
+\RequirePackage{atbegshi}
+
+\def\g@msvg@date@tl{2020/04/09}
+\def\g@msvg@version@tl{0.1}
+
+\ProvidesExplPackage{media4svg}{\g@msvg@date@tl}{\g@msvg@version@tl}
+{acrobat-9/X compatible media}
+
+\tl_gset_eq:NN\g_msvg_date_tl\g@msvg@date@tl
+\tl_gset_eq:NN\g_msvg_version_tl\g@msvg@version@tl
+
+%package options
+\msg_set:nnnn{media4svg}{unknown~package~option}{Unknown~package~option~`#1'.}{
+ Package option~`#1'~is~unknown;\\
+ perhaps~it~is~spelled~incorrectly.
+}
+
+\bool_new:N\g_msvg_dvisvgm_bool
+\bool_new:N\g_msvg_pkgdraft_bool
+\bool_new:N\g_msvg_pkgembed_bool
+\bool_gset_true:N\g_msvg_pkgembed_bool
+\int_new:N\g_msvg_pkgresizeflag_int% resizing flag according to options given
+\tl_gset:Nn\g_msvg_pkgwdarg_tl{\width}
+\tl_gset:Nn\g_msvg_pkghtarg_tl{\height}
+\tl_gset:Nn\g_msvg_pkgttarg_tl{\totalheight}
+\bool_new:N\g_msvg_pkgiso_bool
+\tl_gset:Nn\g_msvg_pkgscalearg_tl{1.0}
+\tl_new:N\g_msvg_pkgcontrols_tl
+\tl_new:N\g_msvg_pkgautoplay_tl
+\tl_new:N\g_msvg_pkgloop_tl
+\tl_new:N\g_msvg_pkgtime_tl
+\tl_new:N\g_msvg_pkgmuted_tl
+\tl_gset:Nn\g_msvg_pkgmtype_tl{audio/mpeg}
+
+\keys_define:nn{media4svg}{
+ dvisvgm .choice:,
+ dvisvgm / true .code:n = {
+ \bool_gset_true:N\g_msvg_dvisvgm_bool
+% \PassOptionsToPackage{dvisvgm}{pdfbase}
+ },
+ dvisvgm / false .code:n = {\bool_gset_false:N\g_msvg_dvisvgm_bool},
+ dvisvgm .default:n = {true},
+
+ draft .bool_gset:N = \g_msvg_pkgdraft_bool,
+
+ final .bool_gset_inverse:N = \g_msvg_pkgdraft_bool,
+
+ autoplay .choice:,
+ autoplay / true .code:n = {\tl_gset:Nn\g_msvg_pkgautoplay_tl{autoplay=''~}},
+ autoplay / false .code:n = {\tl_gclear:N\g_msvg_pkgautoplay_tl},
+ autoplay .default:n = {true},
+
+ loop .choice:,
+ loop / true .code:n = {\tl_gset:Nn\g_msvg_pkgloop_tl{loop=''~}},
+ loop / false .code:n = {\tl_gclear:N\g_msvg_pkgloop_tl},
+ loop .default:n = {true},
+
+ controls .choice:,
+ controls / true .code:n = {\tl_gset:Nn\g_msvg_pkgcontrols_tl{controls=''~}},
+ controls / false .code:n = {\tl_gclear:N\g_msvg_pkgcontrols_tl},
+ controls .default:n = {true},
+
+ muted .choice:,
+ muted / true .code:n = {\tl_gset:Nn\g_msvg_pkgmuted_tl{muted=''~}},
+ muted / false .code:n = {\tl_gclear:N\g_msvg_pkgmuted_tl},
+ muted .default:n = {true},
+
+ time .code:n = {\tl_gset:Nn\g_msvg_pkgtime_tl{currentTime='#1'~}},
+ time .value_required:n = {true},
+
+ mimetype .tl_gset:N = \g_msvg_pkgmtype_tl,
+
+ url .bool_gset_inverse:N = \g_msvg_pkgembed_bool,
+
+ embed .bool_gset:N = \g_msvg_pkgembed_bool,
+
+ width .code:n = {
+ \tl_gset:Nn\g_msvg_pkgwdarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_pkgwd_tl{
+ \int_gadd:Nn\g_msvg_pkgresizeflag_int{4}
+ \tl_set:Nn\l_msvg_pkgwd_tl{}
+ }
+ },
+ width .value_required:n = {true},
+
+ height .code:n = {
+ \tl_gset:Nn\g_msvg_pkghtarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_pkght_tl{
+ \int_gadd:Nn\g_msvg_pkgresizeflag_int{2}
+ \tl_set:Nn\l_msvg_pkght_tl{}
+ }
+ },
+ height .value_required:n = {true},
+
+ totalheight .code:n = {
+ \tl_gset:Nn\g_msvg_pkgttarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_pkgtt_tl{
+ \int_gadd:Nn\g_msvg_pkgresizeflag_int{\c_one_int}
+ \tl_set:Nn\l_msvg_pkgtt_tl{}
+ }
+ },
+ totalheight .value_required:n = {true},
+
+ keepaspectratio .bool_gset:N = \g_msvg_pkgiso_bool,
+
+ scale .code:n = {\tl_gset:Nx\g_msvg_pkgscalearg_tl{#1}},
+ scale .value_required:n = {true},
+
+ unknown .code:n = {
+ \msg_error:nnx{media4svg}{unknown~package~option}{\l_keys_key_tl}
+ }
+}
+\ProcessKeysOptions{media4svg}
+
+\msg_set:nnnn{media4svg}{missing~driver~option}{Global~option~`dvisvgm'~no~set.}{
+ This~package~only~works~with~the~`dvisvgm'~backend.\\
+ Set~`dvisvgm'~as~documentclass~option.
+}
+\bool_if:NF\g_msvg_dvisvgm_bool{
+ \msg_error:nn{media4svg}{missing~driver~option}
+}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\group_begin:
+\char_set_catcode_other:N\%
+\cs_new_nopar:Nn\msvg_percent:{%}
+\group_end:
+
+\NewDocumentCommand\includemedia{O{}mm}{% #1 options, #2 text/image,
+ \tl_gset:Nx\g_msvg_media_arg_tl{#3} % #3 media file or url
+ \msvg_uriend:
+ \group_begin:
+ \msvg_beginLTR:
+ \leavevmode
+ \msvg_reset:
+ \keys_set:nn{media4svg/user}{#1}
+ \sbox\l_msvg_poster_box{#2}
+ \msvg_scale:n{\l_msvg_poster_box}
+ \special{dvisvgm:bbox~\g_msvg_wd_tl~\g_msvg_ht_tl~\g_msvg_dp_tl~transform}
+ \bool_if:NTF\g_msvg_draft_bool{
+ \tl_if_blank:oTF{#2}{
+ \msvg_draftbox:n{\g_msvg_media_arg_tl}
+ }{
+ \hbox_to_wd:nn{\g_msvg_wd_tl}{
+ \vrule~width~\c_zero_dim~height~\g_msvg_ht_tl~depth~\g_msvg_dp_tl
+ \box_use:N\l_msvg_poster_box\hss
+ }
+ }
+ }{
+ \hbox_overlap_right:n{\box_use:N\l_msvg_poster_box}
+ \tl_gclear_new:N\g_msvg_media_blob_tl
+ \bool_if:NT\g_msvg_embed_bool{
+ \file_get_full_name:VNTF\g_msvg_media_arg_tl\l_msvg_full_name_tl{
+ \sys_if_engine_luatex:T{\message{<\l_msvg_full_name_tl}}
+ }{
+ \msg_error:nnx{media4svg}{file~not~found}{\g_msvg_media_arg_tl}
+ }
+ % base64-encode (non-Lua way) the media file
+ \sys_if_engine_luatex:F{
+ \msvg_convert_file_to_blob:nN{
+ \l_msvg_full_name_tl}\g_msvg_media_blob_tl
+ }
+ }
+ \special{dvisvgm:raw {?nl}
+ \tl_if_blank:VT\g_msvg_controls_tl{
+ <svg~
+ id='msvg@kbdCtrl@\g_msvg_id_tl'~
+ width='0'~
+ height='0'~
+ onfocus=''~
+ onkeydown='
+ if($("\g_msvg_id_tl").controls){return;}
+ switch(event.key){
+ case "~":
+ if($("\g_msvg_id_tl").paused){
+ $("\g_msvg_id_tl").play();
+ }else{
+ $("\g_msvg_id_tl").pause();
+ }
+ break;
+ case "ArrowUp":
+ if(event.ctrlKey){$("\g_msvg_id_tl").muted=false;}else{
+ try{$("\g_msvg_id_tl").volume+=0.02;}catch(e){}}
+ break;
+ case "ArrowDown":
+ if(event.ctrlKey){$("\g_msvg_id_tl").muted=true;}else{
+ try{$("\g_msvg_id_tl").volume-=0.02;}catch(e){}}
+ break;
+ case "ArrowLeft":
+ if(event.ctrlKey){
+ $("\g_msvg_id_tl").currentTime-=$("\g_msvg_id_tl").duration/10;
+ }else{
+ $("\g_msvg_id_tl").currentTime-=$("\g_msvg_id_tl").duration/100;
+ }
+ break;
+ case "ArrowRight":
+ if(event.ctrlKey){
+ $("\g_msvg_id_tl").currentTime+=$("\g_msvg_id_tl").duration/10;
+ }else{
+ $("\g_msvg_id_tl").currentTime+=$("\g_msvg_id_tl").duration/100;
+ }
+ break;
+ case "Home":
+ $("\g_msvg_id_tl").currentTime=0;
+ break;
+ case "End":
+ $("\g_msvg_id_tl").currentTime=$("\g_msvg_id_tl").duration;
+ break;
+ }
+ '
+ ></svg>{?nl}
+ }
+ <foreignObject~
+ transform='translate({?x},{?(y-(\dim_to_decimal_in_bp:n{\g_msvg_ht_tl}))})'
+ width='\dim_to_decimal_in_bp:n{\g_msvg_wd_tl}'~
+ height='\dim_to_decimal_in_bp:n{\g_msvg_tt_tl}'~
+ cursor='pointer'~
+ >{?nl}
+ <video~
+ x="0"~y="0"~
+ id='msvg@\g_msvg_id_tl'~
+ width='100\msvg_percent:'~height='100\msvg_percent:'~
+ \g_msvg_controls_tl \g_msvg_autoplay_tl \g_msvg_loop_tl \g_msvg_muted_tl
+ \tl_if_blank:VT\g_msvg_controls_tl{
+ onplaying='$("kbdCtrl@\g_msvg_id_tl").focus();'~
+ onmouseup='event.preventDefault();event.stopPropagation();
+ event.target.play();'~
+ onmousedown='event.preventDefault();event.stopPropagation();
+ event.target.pause();'~
+ ontouchend='event.preventDefault();event.stopPropagation();
+ if(event.targetTouches.length!=0){
+ permPause@msvg@\g_msvg_id_tl=true;
+ }else{
+ if(permPause@msvg@\g_msvg_id_tl){
+ permPause@msvg@\g_msvg_id_tl=false;
+ }
+ else{event.target.play();}
+ }
+ '~
+ ontouchstart='event.preventDefault();event.stopPropagation();
+ var~permPause@msvg@\g_msvg_id_tl=false;
+ event.target.pause();'~
+ ontouchmove='event.preventDefault();event.stopPropagation();'~
+ }
+ \tl_if_blank:VF\g_msvg_time_tl{
+ onloadstart='event.target.currentTime=\g_msvg_time_tl;'~
+ }
+ xmlns='http://www.w3.org/1999/xhtml'
+ >{?nl}
+ \bool_if:NTF\g_msvg_embed_bool{
+ \sys_if_engine_luatex:TF{
+ <source~src='data:\g_msvg_mtype_tl;base64,{?nl}
+ \directlua{media4svg.base64("\l_msvg_full_name_tl",72,"{?nl}")}'~
+ type='\g_msvg_mtype_tl'/>{?nl}
+ }{
+ <source~src='data:\g_msvg_mtype_tl;base64,{?nl}
+ \g_msvg_media_blob_tl'~type='\g_msvg_mtype_tl'/>{?nl}
+ }
+ }{
+ <source~src='\g_msvg_media_arg_tl'~type='\g_msvg_mtype_tl'/>{?nl}
+ }
+ </video>{?nl}
+ </foreignObject>
+ }
+ \bool_if:NT\g_msvg_embed_bool{
+ \sys_if_engine_luatex:T{\message{>}}}
+ \hbox_to_wd:nn{\g_msvg_wd_tl}{
+ \vrule~width~\c_zero_dim~height~\g_msvg_ht_tl~depth~\g_msvg_dp_tl\hss
+ }
+ \int_gincr:N\g_msvg_mmcnt_int
+ }
+ \msvg_endLTR:
+ \group_end:
+}
+\tl_set_eq:NN\l_msvg_includemedia_tl\includemedia
+\tl_set:Nn\includemedia{\msvg_uribegin:\l_msvg_includemedia_tl}
+
+%environment \msvg_uribegin: ... \msvg_uriend: to sanitize possibly
+%active chars in URLs (RFC 2396), path specifications and JavaScript
+\group_begin:
+\char_set_catcode_other:n{`\~}
+\cs_new_protected_nopar:Npn\msvg_uribegin:{
+ \group_begin:
+ %code contributed by J. Wright
+ \tl_map_inline:nn{.:;?!/''*+,->=<$@([])^_`|~}{
+ \cs_set_nopar:Npx\__msvg_tmp:w{\token_to_str:N##1}
+ \char_set_active_eq:NN##1\__msvg_tmp:w
+ }
+ \tl_map_inline:nn{\#\&\%\\\{\}}{
+ \cs_set_nopar:Npx##1{\token_to_str:N##1}
+ }
+}
+\group_end:
+\cs_set_eq:NN\msvg_uriend:\group_end:
+
+%calculates widget dimensions from natural ones, taking resizing options
+%into account
+\int_new:N\g_msvg_resizeflag_int% resizing flags according to options given
+\cs_new:Nn\msvg_scale:n{% #1 box number
+ %totalheight overrides height if both height & totalheight options were given
+ \bool_if:nT{
+ \int_compare_p:n{\g_msvg_resizeflag_int=3} ||
+ \int_compare_p:n{\g_msvg_resizeflag_int=7}
+ }{\int_gsub:Nn\g_msvg_resizeflag_int{2}}
+ \group_begin:
+ %natural dimensions \width, \height, \depth, \totalheight
+ \tl_set:Nn\width {\box_wd:N#1}
+ \tl_set:Nn\height{\box_ht:N#1}
+ \tl_set:Nn\depth {\box_dp:N#1}
+ \tl_set:Nn\totalheight{\dimexpr\height+\depth\relax}
+ \tl_gset:Nx\g_tmpa_tl{\dim_eval:n{\width}}
+ \tl_gset:Nx\g_tmpb_tl{\dim_eval:n{\totalheight}}
+ %evaluate width/height/totalheight options
+ \tl_gset:Nx\g_msvg_wd_tl{\dim_abs:n{\g_msvg_wdarg_tl}}
+ \tl_gset:Nx\g_msvg_ht_tl{\dim_abs:n{\g_msvg_htarg_tl}}
+ \tl_gset:Nx\g_msvg_tt_tl{\dim_abs:n{\g_msvg_ttarg_tl}}
+ \dim_compare:nT{\width=\c_zero_dim}{\box_gset_wd:Nn#1{\g_msvg_wd_tl}}
+ \dim_compare:nT{\totalheight=\c_zero_dim}{
+ \bool_if:nT{ %height option given
+ \int_compare_p:n{\g_msvg_resizeflag_int=6}||
+ \int_compare_p:n{\g_msvg_resizeflag_int=2}
+ }{\box_gset_ht:Nn#1{\g_msvg_ht_tl}}
+ \bool_if:nT{ %totalheight option given
+ \int_compare_p:n{\g_msvg_resizeflag_int=5}||
+ \int_compare_p:n{\g_msvg_resizeflag_int=\c_one_int}
+ }{\box_gset_ht:Nn#1{\g_msvg_tt_tl}}
+ }
+ \group_end:
+ \tl_gset:Nn\g_msvg_dp_tl{\c_zero_dim} %to be initialised here
+ %now resize (originally non-zero size) poster box according to the
+ %options given
+ \bool_if:nF{
+ \dim_compare_p:n{\g_tmpa_tl=\c_zero_dim}||
+ \dim_compare_p:n{\g_tmpb_tl=\c_zero_dim}
+ }{
+ %bit 2^2=width, 2^1=height, 2^0=totalhight given
+ \int_case:nn{\g_msvg_resizeflag_int}{
+ {\c_one_int}{
+ \box_resize_to_ht_plus_dp:Nn#1{\g_msvg_tt_tl}
+ }
+ {2}{
+ \box_resize_to_ht:Nn#1{\g_msvg_ht_tl}
+ }
+ {4}{
+ \box_resize_to_wd:Nn#1{\g_msvg_wd_tl}
+ }
+ {5}{
+ \bool_if:NTF\g_msvg_iso_bool{
+ \dim_set:Nn\l_tmpa_dim{
+ (\box_ht:N#1+\box_dp:N#1)*\dim_ratio:nn{\g_msvg_wd_tl}{\box_wd:N#1}
+ }
+ \dim_set:Nn\l_tmpa_dim{\dim_abs:n{\l_tmpa_dim}}
+ \dim_set:Nn\l_tmpb_dim{\dim_abs:n{\g_msvg_tt_tl}}
+ \dim_compare:nTF{\l_tmpa_dim<\l_tmpb_dim}{
+ \box_resize_to_wd:Nn#1{\g_msvg_wd_tl}
+ }{
+ \box_resize_to_ht_plus_dp:Nn#1{\g_msvg_tt_tl}
+ }
+ }{
+ \box_resize_to_wd_and_ht_plus_dp:Nnn#1{\g_msvg_wd_tl}{\g_msvg_tt_tl}
+ }
+ }
+ {6}{
+ \bool_if:NTF\g_msvg_iso_bool{
+ \dim_set:Nn\l_tmpa_dim{
+ \box_ht:N#1*\dim_ratio:nn{\g_msvg_wd_tl}{\box_wd:N#1}
+ }
+ \dim_set:Nn\l_tmpa_dim{\dim_abs:n{\l_tmpa_dim}}
+ \dim_set:Nn\l_tmpb_dim{\dim_abs:n{\g_msvg_ht_tl}}
+ \dim_compare:nTF{\l_tmpa_dim<\l_tmpb_dim}{
+ \box_resize_to_wd:Nn#1{\g_msvg_wd_tl}
+ }{
+ \box_resize_to_ht:Nn#1{\g_msvg_ht_tl}
+ }
+ }{
+ \box_resize_to_wd_and_ht:Nnn#1{\g_msvg_wd_tl}{\g_msvg_ht_tl}
+ }
+ }
+ }
+ }
+ %apply scaling factor
+ \box_scale:Nnn#1{\g_msvg_scalearg_tl}{\g_msvg_scalearg_tl}
+ %dimensions after resizing
+ \tl_gset:Nx\g_msvg_wd_tl{\dim_use:N\box_wd:N#1}
+ \tl_gset:Nx\g_msvg_ht_tl{\dim_use:N\box_ht:N#1}
+ \tl_gset:Nx\g_msvg_dp_tl{\dim_use:N\box_dp:N#1}
+ \tl_gset:Nx\g_msvg_tt_tl{\dim_eval:n{\box_ht:N#1+\box_dp:N#1}}
+ \dim_compare:nT{\g_msvg_wd_tl=\c_zero_dim}{\msg_warning:nn{media4svg}{zero~width}}
+ \dim_compare:nT{\g_msvg_tt_tl=\c_zero_dim}{
+ \msg_warning:nn{media4svg}{zero~height}}
+}
+
+%environment for setting LTR typesetting direction with e-TeX based engines
+\cs_new:Nn\msvg_beginLTR:{
+ \cs_if_exist:NT\TeXXeTstate{
+ \int_compare:nT{\TeXXeTstate>\c_zero_int}{\beginL}
+ }
+}
+\cs_new:Nn\msvg_endLTR:{
+ \cs_if_exist:NT\TeXXeTstate{
+ \int_compare:nT{\TeXXeTstate>\c_zero_int}{\endL}
+ }
+}
+
+\cs_new:Nn\msvg_draftbox:n{ %#1 text string to be shown
+ \hbox_overlap_right:n{
+ \hbox_to_wd:nn{\g_msvg_wd_tl}{
+ \vrule~height~\g_msvg_ht_tl~depth~\g_msvg_dp_tl\hss
+ \vrule
+ }
+ }
+ \box_move_down:nn{\g_msvg_dp_tl}{
+ \hbox_to_wd:nn{\g_msvg_wd_tl}{
+ \vbox_to_ht:nn{\g_msvg_tt_tl}{
+ \hrule~width~\g_msvg_wd_tl\vss
+ \hbox_to_wd:nn{\g_msvg_wd_tl}{\hss\ttfamily{\tiny#1}\hss}\vss
+ \hrule
+ }
+ }
+ }
+}
+
+\box_new:N\l_msvg_poster_box
+\dim_new:N\g_msvg_wd_dim
+\dim_new:N\g_msvg_ht_dim
+\dim_new:N\g_msvg_dp_dim
+
+\int_new:N\g_msvg_mmcnt_int
+
+\msg_set:nnn{media4svg}{zero~width}{
+ Media~widget~\msg_line_context:\ has~zero~width.
+}
+
+\msg_set:nnn{media4svg}{zero~height}{
+ Media~widget~\msg_line_context:\ has~zero~height.
+}
+
+%missing package error message
+\msg_set:nnn{media4svg}{missing~package}{
+ Package~`#1'~has~not~been~loaded~yet.\\
+ Put~the~line\\
+ ~~\string\usepackage#2{#1}\\
+ to~the~preamble~of~your~document.
+}
+
+\msg_set:nnn{media4svg}{incompatible~package}{
+ Packages~`media4svg'~and~`#1'~are~incompatible.\\
+ Remove~`#1'~from~the~document~preamble.
+}
+
+%creating global definitions
+\cs_new:Npn\msvg@newkey#1#2{\tl_gset:cx{#1}{#2}}
+
+\AtBeginDocument{
+ \iow_now:Nx\@mainaux{
+ \token_to_str:N\providecommand\token_to_str:N\msvg@newkey[2]{}}
+ \@ifpackageloaded{media9}{
+ \msg_error:nnn{media4svg}{incompatible~package}{media9}}{}%
+}
+
+%macros for writing global defs to \jobname.aux
+\msg_set:nnn{media4svg}{rerun}{Rerun~to~get~internal~references~right!}
+\msg_set:nnn{media4svg}{undefined~reference}{
+ Line~\msg_line_number: :~Media~reference~`#1'~not~defined.
+}
+\msg_set:nnn{media4svg}{undefined~references}{
+ There~were~undefined~media~references!}
+\msg_set:nnn{media4svg}{same~id}{
+ Line~\msg_line_number: :~Label~`#1'~multiply~defined.
+}
+\msg_set:nnn{media4svg}{multiple~ids}{There~were~multiply-defined~ids!}
+
+\cs_new_nopar:Nn\msvg_keytoaux_now:nn{
+ \iow_now:Nx\@mainaux{\token_to_str:N\msvg@newkey{#1}{#2}}
+ \bool_if:nT{
+ !\cs_if_exist:cTF{#1}{
+ \str_if_eq_p:ee{\tl_use:c{#1}}{#2}
+ }{
+ \c_false_bool
+ }
+ }{
+ \cs_if_exist:NF\g_msvg_rerunwarned_tl{
+ \tl_new:N\g_msvg_rerunwarned_tl
+ \AtEndDocument{\msg_warning:nn{media4svg}{rerun}}
+ }
+ }
+}
+\cs_new_nopar:Nn\msvg_keytoaux_shipout:nn{
+ \iow_shipout_x:Nx\@mainaux{\token_to_str:N\msvg@newkey{#1}{#2}}
+ \cs_if_exist:cF{#1}{
+ \cs_if_exist:NF\g_msvg_rerunwarned_tl{
+ \tl_new:N\g_msvg_rerunwarned_tl
+ \AtEndDocument{\msg_warning:nn{media4svg}{rerun}}
+ }
+ }
+}
+
+%reset various variables for every new media inclusion
+\cs_new:Nn\msvg_reset:{
+ \tl_gset:Nx\g_msvg_id_tl{\int_use:N\g_msvg_mmcnt_int}
+ \bool_gset_eq:NN\g_msvg_draft_bool\g_msvg_pkgdraft_bool
+ \tl_gset_eq:NN\g_msvg_autoplay_tl\g_msvg_pkgautoplay_tl
+ \tl_gset_eq:NN\g_msvg_loop_tl\g_msvg_pkgloop_tl
+ \tl_gset_eq:NN\g_msvg_controls_tl\g_msvg_pkgcontrols_tl
+ \tl_gset_eq:NN\g_msvg_mtype_tl\g_msvg_pkgmtype_tl
+ \bool_gset_eq:NN\g_msvg_embed_bool\g_msvg_pkgembed_bool
+ \tl_gset_eq:NN\g_msvg_time_tl\g_msvg_pkgtime_tl
+ \tl_gset_eq:NN\g_msvg_muted_tl\g_msvg_pkgmuted_tl
+ \tl_set_eq:NN\l_msvg_wd_tl\l_msvg_pkgwd_tl
+ \tl_set_eq:NN\l_msvg_ht_tl\l_msvg_pkght_tl
+ \tl_set_eq:NN\l_msvg_tt_tl\l_msvg_pkgtt_tl
+ \tl_gset_eq:NN\g_msvg_wdarg_tl\g_msvg_pkgwdarg_tl
+ \tl_gset_eq:NN\g_msvg_htarg_tl\g_msvg_pkghtarg_tl
+ \tl_gset_eq:NN\g_msvg_ttarg_tl\g_msvg_pkgttarg_tl
+ \bool_gset_eq:NN\g_msvg_iso_bool\g_msvg_pkgiso_bool
+ \tl_gset_eq:NN\g_msvg_scalearg_tl\g_msvg_pkgscalearg_tl
+ \int_gset_eq:NN\g_msvg_resizeflag_int\g_msvg_pkgresizeflag_int
+ \box_clear:N\l_msvg_poster_box
+}
+
+%document command options
+
+\msg_set:nnnn{media4svg}{unknown~option}{
+ Line~\msg_line_number: :~Unknown~option~`#1'.
+}{
+ Option~`#1'~is~not~known~by~media4svg:\\
+ perhaps~it~is~spelled~incorrectly.
+}
+
+\bool_new:N\g_msvg_draft_bool
+\bool_new:N\g_msvg_iso_bool
+\bool_new:N\g_msvg_embed_bool
+
+\keys_define:nn{media4svg/user}{
+ %user override automatic id
+ id .code:n = {
+ \tl_gset:Nx\g_msvg_id_tl{#1}
+ \tl_gtrim_spaces:N\g_msvg_id_tl
+ \cs_if_exist:cTF{msvg@\g_msvg_id_tl}{
+ \msg_warning:nnx{media4svg}{same~id}{#1}
+ \cs_if_exist:NF\g_msvg_sameid_tl{
+ \tl_new:N\g_msvg_sameid_tl
+ \AtEndDocument{\msg_warning:nn{media4svg}{multiple~ids}}
+ }
+ }{
+ \tl_new:c{msvg@\g_msvg_id_tl}
+ }
+ },
+ id .value_required:n = {true},
+
+ draft .bool_gset:N = \g_msvg_draft_bool,
+
+ final .bool_gset_inverse:N = \g_msvg_draft_bool,
+
+ autoplay .choice:,
+ autoplay / true .code:n = {\tl_gset:Nn\g_msvg_autoplay_tl{autoplay=''~}},
+ autoplay / false .code:n = {\tl_gclear:N\g_msvg_autoplay_tl},
+ autoplay .default:n = {true},
+
+ loop .choice:,
+ loop / true .code:n = {\tl_gset:Nn\g_msvg_loop_tl{loop=''~}},
+ loop / false .code:n = {\tl_gclear:N\g_msvg_loop_tl},
+ loop .default:n = {true},
+
+ controls .choice:,
+ controls / true .code:n = {\tl_gset:Nn\g_msvg_controls_tl{controls=''~}},
+ controls / false .code:n = {\tl_gclear:N\g_msvg_controls_tl},
+ controls .default:n = {true},
+
+ muted .choice:,
+ muted / true .code:n = {\tl_gset:Nn\g_msvg_muted_tl{muted=''~}},
+ muted / false .code:n = {\tl_gclear:N\g_msvg_muted_tl},
+ muted .default:n = {true},
+
+ time .code:n = {\tl_gset:Nn\g_msvg_time_tl{#1}},
+ time .value_required:n = {true},
+
+ mimetype .tl_gset:N = \g_msvg_mtype_tl,
+
+ url .bool_gset_inverse:N = \g_msvg_embed_bool,
+
+ embed .bool_gset:N = \g_msvg_embed_bool,
+
+ width .code:n = {
+ \tl_gset:Nn\g_msvg_wdarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_wd_tl{
+ \int_gadd:Nn\g_msvg_resizeflag_int{4}
+ \tl_set:Nn\l_msvg_wd_tl{}
+ }
+ },
+ width .value_required:n = {true},
+
+ height .code:n = {
+ \tl_gset:Nn\g_msvg_htarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_ht_tl{
+ \int_gadd:Nn\g_msvg_resizeflag_int{2}
+ \tl_set:Nn\l_msvg_ht_tl{}
+ }
+ },
+ height .value_required:n = {true},
+
+ totalheight .code:n = {
+ \tl_gset:Nn\g_msvg_ttarg_tl{#1}
+ \tl_if_exist:NF\l_msvg_tt_tl{
+ \int_gadd:Nn\g_msvg_resizeflag_int{\c_one_int}
+ \tl_set:Nn\l_msvg_tt_tl{}
+ }
+ },
+ totalheight .value_required:n = {true},
+
+ keepaspectratio .bool_gset:N = \g_msvg_iso_bool,
+
+ scale .code:n = {\tl_gset:Nx\g_msvg_scalearg_tl{#1}},
+ scale .value_required:n = {true},
+
+ unknown .code:n = {
+ \msg_error:nnx{media4svg}{unknown~option}{\l_keys_key_tl}
+ }
+}
+
+\NewDocumentCommand\addmediapath{m}{
+ \str_set:Nn\l_tmpa_str{#1}
+ \seq_put_right:NV\l_file_search_path_seq\l_tmpa_str
+}
+
+% external Lua script `media4svg.lua' defines
+% media4svg.base64("<file name>", <chunk size>, "<end-of-line string>")
+\sys_if_engine_luatex:T{\directlua{require('media4svg')}}
+
+% base64-encodes external binary file into tl variable;
+% non-LuaTeX version, running media4svg.lua via shell-escape
+% (very slow!)
+\newread\g_msvg_stream_ior
+\cs_new_protected_nopar:Nn\msvg_convert_file_to_blob:nN{% #1 filename, #2 tlvar
+ \sys_if_shell_unrestricted:F{
+ \msg_error:nnx{media4svg}{unrestricted~shell~required}{#1}
+ }
+ % get path to media4svg.lua
+ \immediate\openin\g_msvg_stream_ior="|kpsewhich~media4svg.lua"\relax
+ \ior_str_get:NN\g_msvg_stream_ior\l_tmpa_tl
+ \tl_if_blank:VT\l_tmpa_tl{
+ \msg_error:nnxx{media4svg}{missing~script}{media4svg.lua}{#1}
+ }
+ \closein\g_msvg_stream_ior
+ % encode
+ \immediate\openin\g_msvg_stream_ior="|texlua~\l_tmpa_tl\space #1"\relax
+ \message{<#1}
+ \tl_gclear_new:N#2
+ \ior_str_map_inline:Nn\g_msvg_stream_ior{
+ \tl_gput_right:Nn#2{##1{?nl}}\message{.}}\message{>}
+ \closein\g_msvg_stream_ior
+}
+
+\msg_set:nnnn{media4svg}{file~not~found}{
+ Line~\msg_line_number:\\
+ File\\
+ `#1'\\
+ not~found.
+}{
+ Make~sure~file\\
+ `#1'\\
+ exists~and~is~readable,~or~set~command~option~`url'~if~it~is~a~remote~file!
+}
+
+\msg_set:nnnn{media4svg}{unrestricted~shell~required}{
+ Line~\msg_line_number: :~In~order~to~embed~file~`#1',\\
+ LaTeX~must~be~invoked~with~the~--shell-escape~option.
+}{
+ Alternatively,~use~one~of~the~package/command~options\\
+ `url'~or~`embed=false'~to~prevent~embedding.
+}
+
+\msg_set:nnnn{media4svg}{missing~script}{
+ Line~\msg_line_number: :~Script~`#1'~couldn't~be~found.\\
+ In~order~to~embed~file~`#2',~it~must~be~present~on~the~system.
+}{
+ File~`#2'~is~part~of~the~`media4svg'~package.\\
+ Make~sure~the~package~was~correctly~installed.
+}
+
+\int_new:N\g@msvg@page@int %abs. page counter (zero based)
+\int_gset:Nn\g@msvg@page@int{-1}
+
+\AtBeginShipout{
+ \int_gincr:N\g@msvg@page@int
+ \AtBeginShipoutUpperLeft{
+ \special{dvisvgm:rawdef {?nl}
+ <script~type="text/javascript">{?nl}
+ <![CDATA[{?nl}
+ function~$(id)~{
+ return~document.getElementById("msvg@"+id.toString().trim());
+ };{?nl}
+ ]]>{?nl}
+ </script>
+ }
+ }
+}