diff options
Diffstat (limited to 'macros/latex/contrib/media4svg/media4svg.sty')
-rw-r--r-- | macros/latex/contrib/media4svg/media4svg.sty | 356 |
1 files changed, 231 insertions, 125 deletions
diff --git a/macros/latex/contrib/media4svg/media4svg.sty b/macros/latex/contrib/media4svg/media4svg.sty index fec450169b..1d064c818d 100644 --- a/macros/latex/contrib/media4svg/media4svg.sty +++ b/macros/latex/contrib/media4svg/media4svg.sty @@ -23,8 +23,8 @@ % % The Current Maintainer of this work is A. Grahn. -\def\g@msvg@date@tl{2022/08/12} -\def\g@msvg@version@tl{0.9} +\def\g@msvg@date@tl{2022/09/12} +\def\g@msvg@version@tl{0.10} \NeedsTeXFormat{LaTeX2e}[2022-06-01] \ProvidesExplPackage{media4svg}{\g@msvg@date@tl}{\g@msvg@version@tl} @@ -39,9 +39,17 @@ perhaps~it~is~spelled~incorrectly. } +\group_begin: +\char_set_catcode_other:N\% +\cs_new_nopar:Nn\msvg_percent:{%} +\char_set_catcode_other:N\& +\cs_new_nopar:Nn\msvg_amp:{&} +\group_end: + \bool_new:N\g_msvg_pkgdraft_bool \bool_new:N\g_msvg_pkgembed_bool \bool_gset_true:N\g_msvg_pkgembed_bool +\bool_new:N\g_msvg_pkgyt_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} @@ -49,10 +57,15 @@ \bool_new:N\g_msvg_pkgiso_bool \tl_gset:Nn\g_msvg_pkgscalearg_tl{1.0} \tl_new:N\g_msvg_pkgcontrols_tl +\tl_gset:Nx\g_msvg_pkgcontrolsyt_tl{\msvg_amp: controls=0} \tl_new:N\g_msvg_pkgautoplay_tl +\tl_new:N\g_msvg_pkgautoplayyt_tl \tl_new:N\g_msvg_pkgloop_tl +\tl_new:N\g_msvg_pkgloopyt_tl \tl_new:N\g_msvg_pkgtime_tl +\tl_new:N\g_msvg_pkgtimeyt_tl \tl_new:N\g_msvg_pkgmuted_tl +\tl_new:N\g_msvg_pkgmutedyt_tl \tl_gset:Nn\g_msvg_pkgmtype_tl{audio/mpeg} \keys_define:nn{media4svg}{ @@ -66,26 +79,53 @@ 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 / true .code:n = { + \tl_gset:Nn\g_msvg_pkgautoplay_tl{autoplay=''~} + \tl_gset:Nn\g_msvg_pkgautoplayyt_tl{\msvg_amp: autoplay=1} + }, + autoplay / false .code:n = { + \tl_gclear:N\g_msvg_pkgautoplay_tl + \tl_gclear:N\g_msvg_pkgautoplayyt_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 / true .code:n = { + \tl_gset:Nn\g_msvg_pkgloop_tl{loop=''~} + \tl_gset:Nn\g_msvg_pkgloopyt_tl{\msvg_amp: loop=1} + }, + loop / false .code:n = { + \tl_gclear:N\g_msvg_pkgloop_tl + \tl_gclear:N\g_msvg_pkgloopyt_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 / true .code:n = { + \tl_gset:Nn\g_msvg_pkgcontrols_tl{controls=''~} + \tl_gset:Nn\g_msvg_pkgcontrolsyt_tl{\msvg_amp: controls=1} + }, + controls / false .code:n = { + \tl_gclear:N\g_msvg_pkgcontrols_tl + \tl_gset:Nn\g_msvg_pkgcontrolsyt_tl{\msvg_amp: controls=0} + }, 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 / true .code:n = { + \tl_gset:Nn\g_msvg_pkgmuted_tl{muted=''~} + \tl_gset:Nn\g_msvg_pkgmutedyt_tl{\msvg_amp: mute=1} + }, + muted / false .code:n = { + \tl_gclear:N\g_msvg_pkgmuted_tl + \tl_gclear:N\g_msvg_pkgmutedyt_tl + }, muted .default:n = {true}, - time .code:n = {\tl_gset:Nn\g_msvg_pkgtime_tl{currentTime='#1'~}}, + time .code:n = { + \tl_gset:Nn\g_msvg_pkgtime_tl{currentTime='#1'~} + \tl_gset:Nn\g_msvg_pkgtimeyt_tl{\msvg_amp: start=#1} + }, time .value_required:n = {true}, mimetype .tl_gset:N = \g_msvg_pkgmtype_tl, @@ -94,6 +134,8 @@ embed .bool_gset:N = \g_msvg_pkgembed_bool, + youtube .bool_gset:N = \g_msvg_pkgyt_bool, + width .code:n = { \tl_gset:Nn\g_msvg_pkgwdarg_tl{#1} \tl_if_exist:NF\l_msvg_pkgwd_tl{ @@ -140,7 +182,7 @@ This~package~only~works~with~the~`dvisvgm'~backend.\MessageBreak A~TeX~engine~must~be~used~that~produces\MessageBreak DVI~or~XDV~output - }{}% + }{} } \msg_set:nnnn{media4svg}{missing~driver~option}{Global~option~`dvisvgm'~no~set.}{ @@ -154,25 +196,29 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\group_begin: -\char_set_catcode_other:N\% -\cs_new_nopar:Nn\msvg_percent:{%} -\group_end: +\seq_new:N\l_msvg_ytids_seq % takes list of yt video ids + +%\tl_const:Nn\g_msvg_minwd_px_tl{640} % foreignObject with at least this width +\tl_const:Nn\g_msvg_minwd_px_tl{480} % foreignObject with at least this width \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: + \msvg_uriend: % #3 media file/url or (comma-sep'd list of) yt ids \group_begin: \msvg_beginLTR: \leavevmode \msvg_reset: \keys_set:nn{media4svg/user}{#1} + \tl_set:Nx\l_msvg_media_arg_tl{#3} + \bool_if:NT\g_msvg_yt_bool{ + \bool_gset_false:N\g_msvg_embed_bool + \seq_set_split:NnV\l_msvg_ytids_seq{,}\l_msvg_media_arg_tl + } \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} + \msvg_draftbox:n{\l_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 @@ -183,10 +229,10 @@ \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{ + \file_get_full_name:VNTF\l_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} + \msg_error:nnx{media4svg}{file~not~found}{\l_msvg_media_arg_tl} } % base64-encode (non-Lua way) the media file \sys_if_engine_luatex:F{ @@ -194,18 +240,22 @@ \l_msvg_full_name_tl}{72}{{?nl}}\g_msvg_media_blob_tl } } - \special{dvisvgm:raw {?nl} - \tl_if_blank:VT\g_msvg_controls_tl{ + \tl_set:Nx\l_msvg_foreign_scale_tl{ + \fp_eval:n{\g_msvg_minwd_px_tl/\dim_to_decimal_in_bp:n{\g_msvg_wd_tl}} + } + \special{dvisvgm:raw + \bool_if:nT{ + \tl_if_blank_p:V\g_msvg_controls_tl&& + !\bool_if_p:N\g_msvg_yt_bool + }{ <svg~ id='msvg_kbdCtrl_\g_msvg_id_tl'~ - width='0'~ - height='0'~ - onfocus=''~ + width='0'~height='0'~onfocus=''~ onkeydown=' event.preventDefault(); if(!(event.key==="PageDown"||event.key==="PageUp")){ event.stopPropagation(); - } + } switch(event.key){ case "~": if($("\g_msvg_id_tl").paused){ @@ -254,12 +304,16 @@ ' ></svg>{?nl} } + <g~transform='translate({?x},{?(y-(\dim_to_decimal_in_bp:n{\g_msvg_ht_tl}))}) + scale(\fp_eval:n{1/\l_msvg_foreign_scale_tl})'> <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}'~ + width='\fp_eval:n{\l_msvg_foreign_scale_tl*\dim_to_decimal_in_bp:n{\g_msvg_wd_tl}}'~ + height='\fp_eval:n{\l_msvg_foreign_scale_tl*\dim_to_decimal_in_bp:n{\g_msvg_tt_tl}}'~ style='cursor:~pointer;'~ - \tl_if_blank:VT\g_msvg_controls_tl{ + \bool_if:nT{ + \tl_if_blank_p:V\g_msvg_controls_tl&& + !\bool_if_p:N\g_msvg_yt_bool + }{ ontouchstart=' event.preventDefault();event.stopPropagation(); if($("\g_msvg_id_tl").paused){ @@ -271,96 +325,113 @@ ' } >{?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=' % in Chrome, keyboard control - $("kbdCtrl_\g_msvg_id_tl").focus();% via separate <svg> element - event.target.focus(); % Firefox - '~ - onkeydown=' - event.preventDefault(); - if(!(event.key==="PageDown"||event.key==="PageUp")){ - event.stopPropagation(); - } - switch(event.key){ - case "~": - if(event.target.paused){ - event.target.play(); - }else{ - event.target.pause(); - } - break; - case "ArrowUp": - if(event.ctrlKey){event.target.muted=false;}else{ - try{event.target.volume+=0.02;}catch(e){}} - break; - case "ArrowDown": - if(event.ctrlKey){event.target.muted=true;}else{ - try{event.target.volume-=0.02;}catch(e){}} - break; - case "ArrowLeft": - if(event.ctrlKey){ - event.target.currentTime-=event.target.duration/10; - }else{ - event.target.currentTime-=event.target.duration/100; - } - break; - case "ArrowRight": - if(event.ctrlKey){ - event.target.currentTime+=event.target.duration/10; - }else{ - event.target.currentTime+=event.target.duration/100; - } - break; - case "Home": - event.target.currentTime=0; - break; - case "End": - event.target.currentTime=event.target.duration; - break; - case "F11": - if (event.target.requestFullscreen){ - event.target.requestFullscreen(); - } - break; - case "Tab": - event.target.blur(); - break; + \bool_if:NTF\g_msvg_yt_bool{ + <g~xmlns='http://www.w3.org/1999/xhtml'> + <iframe~ + title='YouTube~video~player'~ + width='100\msvg_percent:'~height='100\msvg_percent:'~ + allow='fullscreen;autoplay;clipboard-write;encrypted-media;gyroscope;accelerometer'~ + frameborder='0'~ + src='https://www.youtube-nocookie.com/embed/\seq_item:Nn\l_msvg_ytids_seq{1}? + modestbranding=1\msvg_amp: rel=0 + \int_compare:nNnT{\seq_count:N\l_msvg_ytids_seq}>{1}{ + \msvg_amp: playlist=\seq_use:Nn\l_msvg_ytids_seq{,} + } + \g_msvg_controlsyt_tl\g_msvg_autoplayyt_tl\g_msvg_loopyt_tl + \g_msvg_mutedyt_tl\g_msvg_timeyt_tl + '/>{?nl} + </g> + }{ + <video~ + width='100\msvg_percent:'~height='100\msvg_percent:'~ + id='msvg_\g_msvg_id_tl'~ + \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=' % in Chrome, keyboard control + $("kbdCtrl_\g_msvg_id_tl").focus();% via separate <svg> element + event.target.focus(); % Firefox + '~ + onkeydown=' + event.preventDefault(); + if(!(event.key==="PageDown"||event.key==="PageUp")){ + event.stopPropagation(); } - '~ - onclick='event.stopPropagation();'~ - oncontextmenu='event.stopPropagation();'~ - onmouseup='event.preventDefault();event.stopPropagation(); - if(event.button==0) event.target.play();'~ - onmousedown='event.preventDefault();event.stopPropagation(); - if(event.button==0) event.target.pause();'~ - } - \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} + switch(event.key){ + case "~": + if(event.target.paused){ + event.target.play(); + }else{ + event.target.pause(); + } + break; + case "ArrowUp": + if(event.ctrlKey){event.target.muted=false;}else{ + try{event.target.volume+=0.02;}catch(e){}} + break; + case "ArrowDown": + if(event.ctrlKey){event.target.muted=true;}else{ + try{event.target.volume-=0.02;}catch(e){}} + break; + case "ArrowLeft": + if(event.ctrlKey){ + event.target.currentTime-=event.target.duration/10; + }else{ + event.target.currentTime-=event.target.duration/100; + } + break; + case "ArrowRight": + if(event.ctrlKey){ + event.target.currentTime+=event.target.duration/10; + }else{ + event.target.currentTime+=event.target.duration/100; + } + break; + case "Home": + event.target.currentTime=0; + break; + case "End": + event.target.currentTime=event.target.duration; + break; + case "F11": + if (event.target.requestFullscreen){ + event.target.requestFullscreen(); + } + break; + case "Tab": + event.target.blur(); + break; + } + '~ + onclick='event.stopPropagation();'~ + oncontextmenu='event.stopPropagation();'~ + onmouseup='event.preventDefault();event.stopPropagation(); + if(event.button==0) event.target.play();'~ + onmousedown='event.preventDefault();event.stopPropagation(); + if(event.button==0) event.target.pause();'~ + } + \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='data:\g_msvg_mtype_tl;base64,{?nl} - \g_msvg_media_blob_tl'~type='\g_msvg_mtype_tl'/>{?nl} + <source~src='\l_msvg_media_arg_tl'~type='\g_msvg_mtype_tl'/>{?nl} } - }{ - <source~src='\g_msvg_media_arg_tl'~type='\g_msvg_mtype_tl'/>{?nl} + </video>{?nl} } - </video>{?nl} </foreignObject> + </g> } - \bool_if:NT\g_msvg_embed_bool{ - \sys_if_engine_luatex:T{\message{>}}} + \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 } @@ -552,7 +623,7 @@ \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}}{}% + \msg_error:nnn{media4svg}{incompatible~package}{media9}}{} } %macros for writing global defs to \jobname.aux @@ -597,12 +668,17 @@ \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_autoplayyt_tl\g_msvg_pkgautoplayyt_tl \tl_gset_eq:NN\g_msvg_loop_tl\g_msvg_pkgloop_tl + \tl_gset_eq:NN\g_msvg_loopyt_tl\g_msvg_pkgloopyt_tl \tl_gset_eq:NN\g_msvg_controls_tl\g_msvg_pkgcontrols_tl + \tl_gset_eq:NN\g_msvg_controlsyt_tl\g_msvg_pkgcontrolsyt_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_timeyt_tl\g_msvg_pkgtimeyt_tl \tl_gset_eq:NN\g_msvg_muted_tl\g_msvg_pkgmuted_tl + \tl_gset_eq:NN\g_msvg_mutedyt_tl\g_msvg_pkgmutedyt_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 @@ -627,6 +703,7 @@ \bool_new:N\g_msvg_draft_bool \bool_new:N\g_msvg_iso_bool \bool_new:N\g_msvg_embed_bool +\bool_new:N\g_msvg_yt_bool \keys_define:nn{media4svg/user}{ %user override automatic id @@ -650,26 +727,53 @@ 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 / true .code:n = { + \tl_gset:Nn\g_msvg_autoplay_tl{autoplay=''~} + \tl_gset:Nn\g_msvg_autoplayyt_tl{\msvg_amp: autoplay=1} + }, + autoplay / false .code:n = { + \tl_gclear:N\g_msvg_autoplay_tl + \tl_gclear:N\g_msvg_autoplayyt_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 / true .code:n = { + \tl_gset:Nn\g_msvg_loop_tl{loop=''~} + \tl_gset:Nn\g_msvg_loopyt_tl{\msvg_amp: loop=1} + }, + loop / false .code:n = { + \tl_gclear:N\g_msvg_loop_tl + \tl_gclear:N\g_msvg_loopyt_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 / true .code:n = { + \tl_gset:Nn\g_msvg_controls_tl{controls=''~} + \tl_gset:Nn\g_msvg_controlsyt_tl{\msvg_amp: controls=1} + }, + controls / false .code:n = { + \tl_gclear:N\g_msvg_controls_tl + \tl_gset:Nn\g_msvg_controlsyt_tl{\msvg_amp: controls=0} + }, 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 / true .code:n = { + \tl_gset:Nn\g_msvg_muted_tl{muted=''~} + \tl_gset:Nn\g_msvg_mutedyt_tl{\msvg_amp: mute=1} + }, + muted / false .code:n = { + \tl_gclear:N\g_msvg_muted_tl + \tl_gclear:N\g_msvg_mutedyt_tl + }, muted .default:n = {true}, - time .code:n = {\tl_gset:Nn\g_msvg_time_tl{#1}}, + time .code:n = { + \tl_gset:Nn\g_msvg_time_tl{currentTime='#1'~} + \tl_gset:Nn\g_msvg_timeyt_tl{\msvg_amp: start=#1} + }, time .value_required:n = {true}, mimetype .tl_gset:N = \g_msvg_mtype_tl, @@ -678,6 +782,8 @@ embed .bool_gset:N = \g_msvg_embed_bool, + youtube .bool_gset:N = \g_msvg_yt_bool, + width .code:n = { \tl_gset:Nn\g_msvg_wdarg_tl{#1} \tl_if_exist:NF\l_msvg_wd_tl{ |