diff options
author | Karl Berry <karl@freefriends.org> | 2020-04-11 22:37:12 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-04-11 22:37:12 +0000 |
commit | 9216d7c2a0f073d14022adb937da9faa5e89ae8f (patch) | |
tree | 56180bac8998d581d6e89bdf418afb92bddc2b9d /Master/texmf-dist/tex/latex/media4svg | |
parent | 01f3d11f566adcadedd4374cf8c6aaeacd975d21 (diff) |
media4svg (9apr20)
git-svn-id: svn://tug.org/texlive/trunk@54665 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/media4svg')
-rwxr-xr-x | Master/texmf-dist/tex/latex/media4svg/media4svg.lua | 102 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/media4svg/media4svg.sty | 736 |
2 files changed, 838 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/media4svg/media4svg.lua b/Master/texmf-dist/tex/latex/media4svg/media4svg.lua new file mode 100755 index 00000000000..5714ffb241c --- /dev/null +++ b/Master/texmf-dist/tex/latex/media4svg/media4svg.lua @@ -0,0 +1,102 @@ +#!/usr/bin/env texlua +------------------------------------------------------------------------------- +-- +-- media4svg.lua +-- +-- base64 encoding utility, version 2020/04/09 +-- +-- (C) 2020-today, Alexander Grahn, using code by Alex Kloss +-- +-- Usage: +-- +-- 1. as a commandline utility: +-- +-- texlua media4svg.lua <file> +-- +-- 2. as a library from within LuaTeX input: +-- +-- \directlua{require('media4svg')} +-- \directlua{media4svg.base64("<file>",<chunksize>,"<end-of-line string>")} +-- +-- <file> string; file name +-- <chunksize> integer, multiple of 3; size of binary data (bytes) +-- to be converted at a time +-- <end-of-line string> a string to be appended at the end of every output +-- line +-- +-- The output is placed into LuaTeX's input stream. +-- +------------------------------------------------------------------------------- + +-- 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. + +local P = {} +media4svg = P + +----------------------------------------------------------------------- +-- function `base64' taken from http://lua-users.org/wiki/BaseSixtyFour +-- code by Alex Kloss <alexthkloss@web.de> +----------------------------------------------------------------------- +local bs = { [0] = + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', +} + +local function base64(s) + local byte, rep = string.byte, string.rep + local pad = 2 - ((#s-1) % 3) + s = (s..rep('\0', pad)):gsub("...", function(cs) + local a, b, c = byte(cs, 1, 3) + return bs[a>>2] .. bs[(a&3)<<4|b>>4] .. bs[(b&15)<<2|c>>6] .. bs[c&63] + end) + return s:sub(1, #s-pad) .. rep('=', pad) +end +----------------------------------------------------------------------- + +-- wrapper, to be called from within TeX code +function P.base64(filename, chunksize, endofline) + local foundfile = kpse.find_file(filename, 'tex', true) + if foundfile then + local filehandle = io.open(foundfile, 'rb') + chunksize = tonumber(chunksize) + if filehandle then + while true do + local data = filehandle:read(chunksize) + if not data then break end + tex.write('', base64(data), endofline) + end + filehandle:close() + end + end +end + +-- if used as command line utility, encodes the file given +-- as the first argument +if (string.find(arg[0],'media4svg%.lua$') and arg[1] ~= nil) then + kpse.set_program_name('kpsewhich') + local foundfile = kpse.find_file(arg[1], 'tex', true) + if not foundfile then + io.stderr:write(arg[1]..': File not found.\n') + os.exit(1) + end + local filehandle = io.open(foundfile,'rb') + if not filehandle then os.exit(1) end + while true do + local data = filehandle:read(72) + if not data then break end + print(base64(data)) + end + filehandle:close() +end + +return P diff --git a/Master/texmf-dist/tex/latex/media4svg/media4svg.sty b/Master/texmf-dist/tex/latex/media4svg/media4svg.sty new file mode 100644 index 00000000000..a14c4cd00fd --- /dev/null +++ b/Master/texmf-dist/tex/latex/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> + } + } +} |