diff options
author | Karl Berry <karl@freefriends.org> | 2021-06-03 20:49:47 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-06-03 20:49:47 +0000 |
commit | 4c14c1a96076aa912e6494fd56fc8d326a8a34c5 (patch) | |
tree | 3e8b873d8ea1cf75661c0c6d686849500ad38c17 /Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty | |
parent | 41b9db706f551dc06872663be27b26beaa43f58d (diff) |
ocgx2 (3jun21)
git-svn-id: svn://tug.org/texlive/trunk@59455 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty | 387 |
1 files changed, 385 insertions, 2 deletions
diff --git a/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty b/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty index 7c97c37ab04..6e514c22367 100644 --- a/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty +++ b/Master/texmf-dist/tex/latex/ocgx2/ocgbase.sty @@ -1,3 +1,11 @@ +%%%%%%%%%%%%%%%%%%%%%% pdfmanagement-testphase %%%%%%%%%%%%%%%%%%% +\newif\if@ocgbase@testphase +\ExplSyntaxOn +\bool_if:nT { + \bool_lazy_and_p:nn {\cs_if_exist_p:N \pdfmanagement_if_active_p:} { \pdfmanagement_if_active_p: } +}{\@ocgbase@testphasetrue} +\ExplSyntaxOff +\if@ocgbase@testphase\else %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ocgbase.sty @@ -94,8 +102,8 @@ \RequirePackage{l3keys2e} -\def\g@ocgbase@date@tl{2021/01/25} -\def\g@ocgbase@version@tl{0.18} +\def\g@ocgbase@date@tl{2021/06/03} +\def\g@ocgbase@version@tl{0.19} \ProvidesExplPackage{ocgbase}{\g@ocgbase@date@tl}{\g@ocgbase@version@tl} {support package for ocgx2.sty} @@ -364,3 +372,378 @@ \cs_gset_eq:NN\ocgbase@oc@emc\ocgbase_oc_emc: \cs_gset_eq:NN\ocgbase@open@stack@pop\ocgbase_open_stack_pop:N \cs_gset_eq:NN\ocgbase@open@stack@push\ocgbase_open_stack_push:n +\endinput +\fi +%%%%%%%%%%%%%%%%%%%%%% /pdfmanagement-testphase %%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ocgbase.sty +% +% low-level macros for OCG creation, marking optional content and +% for managment of global (document-wide) OCG related lists; +% +% (automatic) OCG configuration in the PDF catalog +% +% Copyright 2015--\today, Alexander Grahn +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Support package for ocgx2.sty, media9.sty, animate.sty +% +% Supported workflows: +% +% pdflatex, lualatex +% latex-->dvips-->ps2pdf or Distiller +% latex-->dvipdfmx +% xelatex +% +% for `dvipdfmx', set it as document class option +% +% +% Commands defined: +% +% \ocgbase_new_ocg:nnn +% \ocgbase@new@ocg (LaTeX2e version) +% #1: name (as shown in the Layers Tab of the Reader GUI) +% #2: usage dict (may be empty), see PDF reference: +% http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/ +% pdf_reference_1-7.pdf#G9.3858276 +% #3: initial visibility (1|0|true|false|on|off|visible|invisible) +% +% \ocgbase_last_ocg: +% \ocgbase@last@ocg (LaTeX2e version) +% inserts ID of PDF object created during most recent call of +% \ocgbase_new_ocg:nnn +% +% -------- +% +% \ocgbase_tree_node_begin:n +% \ocgbase_tree_node_end: +% \ocgbase@tree@node@begin (LaTeX2e versions) +% \ocgbase@tree@node@end +% #1: OCG PDF object +% macro pair (begin and end) for inserting OCG object and its children +% into Order hierarchy (shown as tree structure in the viewers `Layers' tab +% +% -------- +% +% \ocgbase_add_to_off_list:n +% \ocgbase@add@to@off@list (LaTeX2e version) +% #1: PDF object ID of OCG +% macro for setting initial visibility to `off' +% +% -------- +% +% \ocgbase_del_from_off_list:n +% \ocgbase@del@from@off@list (LaTeX2e version) +% #1: PDF object ID of OCG +% macro for setting initial visibility to `on' +% +% -------- +% +% \ocgbase_add_ocg_to_radiobtn_grp:nn +% \ocgbase@add@ocg@to@radiobtn@grp +% add OCG #2 (obj ref) to radio button group `#1' (string), +% +% -------- +% +% \ocgbase_oc_bdc:n +% \ocgbase@oc@bdc +% #1: OCG obj ref +% mark begin of optional content belonging to OCG #1 in the current +% content stream +% +% \ocgbase_oc_emc: +% \ocgbase@oc@emc +% mark end of optional content in the current content 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. + +\RequirePackage{l3keys2e} + +\def\g@ocgbase@date@tl{2021/06/03} +\def\g@ocgbase@version@tl{0.19} + +\ProvidesExplPackage{ocgbase}{\g@ocgbase@date@tl}{\g@ocgbase@version@tl} +{support package for ocgx2.sty} + +%package options + +%unknown package option error message +\msg_set:nnnn{ocgbase}{unknown~package~option}{Unknown~package~option~`#1'.}{ + Package option~'#1'~is~unknown;\\ + perhaps~it~is~spelled~incorrectly. +} + +\keys_define:nn{ocgbase}{ + xetex .code:n = {}, %dummy + + dvipdfmx .choice:, + dvipdfmx / true .code:n = {\PassOptionsToPackage{dvipdfmx}{pdfbase}}, + dvipdfmx / false .code:n = {}, + dvipdfmx .default:n = {true}, + + unknown .code:n = { + \msg_error:nnx{ocgbase}{unknown~package~option}{\l_keys_key_tl} + } +} +\ProcessKeysOptions{ocgbase} + +\RequirePackage{pdfbase} + +\msg_set:nnnn{ocgbase}{support~outdated}{ + Support~package~`#1'~too~old. +}{ + Get~an~up~to~date~version~of~`#1'.\\ + Aborting. +} +\@ifpackagelater{pdfbase}{2017/09/29}{}{ + \msg_error:nnn{ocgbase}{support~outdated}{pdfbase.sty} + \tex_endinput:D +} + +\tl_new:N\g_ocgbase_ocgs_tl %takes ocg object refs +\seq_new:N\g_ocgbase_offocgs_seq + +\AddToHook{shipout/lastpage}{ + \tl_if_empty:NF\g_ocgbase_ocgs_tl{ + %global OCG array + \pbs_pdfobj:nnn{}{array}{\g_ocgbase_ocgs_tl} + \tl_set:Nx\l_ocgbase_ocgarray_tl{\pbs_pdflastobj:} + \tl_new:N\l_ocgbase_offocgentry_tl + %global OFF list + \seq_if_empty:NF\g_ocgbase_offocgs_seq{ + \pbs_pdfobj:nnn{}{array}{\seq_use:Nn\g_ocgbase_offocgs_seq{~}} + \tl_set:Nx\l_ocgbase_offocgentry_tl{/OFF~\pbs_pdflastobj:} + } + %global Order list + \tl_new:N\l_ocgbase_ocgorderentry_tl + \tl_new:N\l_ocgbase_ocgorder_tl + \tl_if_exist:cT{g_ocgbase_nd_0_chld_tl}{ + \ocgbase_build_order:Nn\l_ocgbase_ocgorder_tl{ + \tl_use:c{g_ocgbase_nd_0_chld_tl} + } + } + \tl_if_empty:NF\l_ocgbase_ocgorder_tl{ + \pbs_pdfobj:nnn{}{array}{\l_ocgbase_ocgorder_tl} + \tl_set:Nx\l_ocgbase_ocgorderentry_tl{/Order~\pbs_pdflastobj:} + } + %generate RBGroups entry (radio button groups) + \tl_new:N\l_ocgbase_rbtn_groups_tl + \seq_map_inline:Nn\g_ocgbase_rbtn_groups_seq{ + \int_compare:nT{\seq_count:c{g_ocgbase_rbtn_group_#1_seq}>\c_one_int}{ + \tl_put_right:Nx\l_ocgbase_rbtn_groups_tl{ + ~[\seq_use:cn{g_ocgbase_rbtn_group_#1_seq}{~}] + } + } + } + \tl_new:N\l_ocgbase_rbgroupsentry_tl + \tl_if_empty:NF\l_ocgbase_rbtn_groups_tl{ + \pbs_pdfobj:nnn{}{array}{\l_ocgbase_rbtn_groups_tl} + \tl_set:Nx\l_ocgbase_rbgroupsentry_tl{/RBGroups~\pbs_pdflastobj:} + } + \pdfmanagement_add:nnx{Catalog/OCProperties}{OCGs}{\g_ocgbase_ocgs_tl} + \pdfmanagement_add:nnx{Catalog/OCProperties}{D}{<< + /AS~[ + <</Event/View /Category[/View] /OCGs~\l_ocgbase_ocgarray_tl>> + <</Event/Print /Category[/Print] /OCGs~\l_ocgbase_ocgarray_tl>> + <</Event/Export/Category[/Export]/OCGs~\l_ocgbase_ocgarray_tl>> + ] + /BaseState/ON~\l_ocgbase_offocgentry_tl + \l_ocgbase_ocgorderentry_tl + \l_ocgbase_rbgroupsentry_tl + /ListMode/VisiblePages + >> + } + } +} + +%macro for inserting new OCG object +\cs_generate_variant:Nn\pdf_object_new:nn{xn} +\cs_generate_variant:Nn\pdf_object_write:nn{xx} +\int_new:N\g_ocgbase_int +\cs_new_protected_nopar:Nn\ocgbase_new_ocg:nnn{ + \pdf_object_new:xn{g_object_\int_use:N\g_ocgbase_int _pdf}{dict} + \pdf_object_write:xx{g_object_\int_use:N\g_ocgbase_int _pdf}{ + /Type/OCG/Name~(#1)~\str_if_eq:eeF{#2}{}{/Usage<<#2>>} + } + \tl_gput_right:Nx\g_ocgbase_ocgs_tl{~\pdf_object_ref_last:} + \bool_if:nT{ + \str_if_eq_p:ee{#3}{0} || + \str_if_eq_p:ee{#3}{off} || + \str_if_eq_p:ee{#3}{false} || + \str_if_eq_p:ee{#3}{invisible} + }{ + \ocgbase_add_to_off_list:n{\pdf_object_ref_last:} + } + \tl_gset:Nx\g_ocgbase_last_ocg_tl{\pdf_object_ref_last:} + \tl_gset:cx{g_pbs_objname_\pdf_object_ref_last: _tl}{ + g_object_\int_use:N\g_ocgbase_int _pdf + } + \int_gincr:N\g_ocgbase_int +} + +\cs_new_nopar:Nn\ocgbase_last_ocg:{\g_ocgbase_last_ocg_tl} + +\int_new:N\g_ocgbase_nd_int %node id +\seq_new:N\g_ocgbase_tree_nd_stack_seq %stack with open ocg node id +\seq_new:N\g_ocgbase_tree_ocg_stack_seq %stack with open ocg obj number +\seq_gpush:Nn\g_ocgbase_tree_nd_stack_seq{0} %push root node +\seq_gpush:Nn\g_ocgbase_tree_ocg_stack_seq{null} %push root node + +%macro for starting OCG object (and nested children) insertion into Order +%hierarchy (shown as tree structure in the viewers `Layers' tab +\cs_new_protected:Nn\ocgbase_tree_node_begin:n{ % #1: OCG obj + %get the parent node from stack + \seq_get:NN\g_ocgbase_tree_nd_stack_seq\l__ocgbase_prnt_tl + \tl_if_exist:cTF{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl}{ + %parent has >=1 children (i. e. my older siblings), traverse them + \tl_set:Nv\l__ocgbase_prev_sbl_tl{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl} + \tl_set:Nx\l__ocgbase_cur_ocg_tl{#1} + \ocgbase_traverse_siblings:NN\l__ocgbase_prev_sbl_tl\l__ocgbase_cur_ocg_tl + \str_if_empty:NTF\l__ocgbase_cur_ocg_tl{ + %I am the first child of my parent to refer to OCG #1 + \int_gincr:N\g_ocgbase_nd_int + \tl_set:Nx\l__ocgbase_cur_nd_tl{\int_use:N\g_ocgbase_nd_int} + %set myself as my next-older sibling's `next sibling' + \tl_gset:cV{ + g_ocgbase_nd_\l__ocgbase_prev_sbl_tl _sbl_tl}\l__ocgbase_cur_nd_tl + }{ + %there is already a sibling referring to OCG #1; no new node needs be + %created + \tl_set:NV\l__ocgbase_cur_nd_tl\l__ocgbase_prev_sbl_tl + } + }{ + %I am the very first child of my parent + \int_gincr:N\g_ocgbase_nd_int + \tl_set:Nx\l__ocgbase_cur_nd_tl{\int_use:N\g_ocgbase_nd_int} + %set myself as my parent's first child + \tl_gset:cV{g_ocgbase_nd_\l__ocgbase_prnt_tl _chld_tl}\l__ocgbase_cur_nd_tl + } + %set the OCG I am referring to + \tl_gset:cx{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _ocg_tl}{#1} + %push current node and its associated OCG obj on the stacks + \seq_gpush:NV\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl + \seq_gpush:Nx\g_ocgbase_tree_ocg_stack_seq{#1} +} + +%macro that ends insertion of OCG and sub-OCGs into Order tree +\cs_new_protected:Nn\ocgbase_tree_node_end:{ + \seq_get:NN\g_ocgbase_tree_nd_stack_seq\l_tempa_tl + \seq_get:NN\g_ocgbase_tree_ocg_stack_seq\l_tempb_tl + \str_if_eq:eeT{ + \cs_if_exist_use:c{g_ocgbase_nd_\l_tempa_tl _ocg_tl} + }{ + \l_tempb_tl + }{ + \seq_gpop:NN\g_ocgbase_tree_nd_stack_seq\g_trash_tl + \seq_gpop:NN\g_ocgbase_tree_ocg_stack_seq\g_trash_tl + } +} + +% helper macro (recursive); traverses siblings to find either +% the node which refers to the same OCG (arg #2 remains un-modified), or +% the last sibling inserted (arg #2 is cleared); +% the node id of the sibling found is returned in arg #1 +\cs_new:Nn\ocgbase_traverse_siblings:NN{ + % #1: current node (in/out), #2: OCG obj (in/out) + \str_if_eq:eeF{#2}{\tl_use:c{g_ocgbase_nd_#1_ocg_tl}}{ + \tl_if_exist:cTF{g_ocgbase_nd_#1_sbl_tl}{ + \tl_set:Nv#1{g_ocgbase_nd_#1_sbl_tl} + \ocgbase_traverse_siblings:NN#1#2 + }{ + \tl_clear:N#2 + } + } +} + +\cs_new:Nn\ocgbase_build_order:Nn{ + % (recursive macro) + % #1: tl var to which the OCG order is written (output) + % #2: starting node id (input; usually `1') + \tl_set:Nx\l__ocgbase_cur_nd_tl{#2} + % first, append the OCG obj the current node is referring to + \tl_put_right:Nx#1{~\tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _ocg_tl}} + % second, traverse the tree starting with the first child node + \tl_if_exist:cT{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _chld_tl}{ + \seq_gpush:NV\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl + \tl_put_right:Nn#1{~[} + \ocgbase_build_order:Nn#1{ + \tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _chld_tl}} + \tl_put_right:Nn#1{~]} + \seq_gpop:NN\g_ocgbase_tree_nd_stack_seq\l__ocgbase_cur_nd_tl + } + % third, traverse the tree starting with the next sibling node + \tl_if_exist:cT{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _sbl_tl}{ + \ocgbase_build_order:Nn#1{ + \tl_use:c{g_ocgbase_nd_\l__ocgbase_cur_nd_tl _sbl_tl}} + } +} + +%macro for appending an OCG object to the global `OFF' list +%(initial non-visibility) +\cs_new_protected_nopar:Nn\ocgbase_add_to_off_list:n{ + \seq_if_in:NxF\g_ocgbase_offocgs_seq{#1}{ + \seq_gput_right:Nx\g_ocgbase_offocgs_seq{#1} + } +} + +%macro for removing an OCG object from global `OFF' list +%(initial non-visibility) +\cs_new_protected_nopar:Nn\ocgbase_del_from_off_list:n{ + \seq_if_in:NxT\g_ocgbase_offocgs_seq{#1}{ + \ocgbase_seq_gremove_all:Nx\g_ocgbase_offocgs_seq{#1} + } +} +\cs_set_eq:NN\ocgbase_seq_gremove_all:Nn\seq_gremove_all:Nn +\cs_generate_variant:Nn\ocgbase_seq_gremove_all:Nn{Nx} + +\seq_new:N\g_ocgbase_rbtn_groups_seq +\cs_new_protected_nopar:Nn\ocgbase_add_ocg_to_radiobtn_grp:nn{ + % #1: rbtn group name, + % #2: OCG obj ref + \seq_if_exist:cF{g_ocgbase_rbtn_group_#1_seq}{ + \seq_new:c{g_ocgbase_rbtn_group_#1_seq} + \seq_gput_right:Nx\g_ocgbase_rbtn_groups_seq{#1} + } + \seq_if_in:cxF{g_ocgbase_rbtn_group_#1_seq}{#2}{ + \seq_gput_right:cx{g_ocgbase_rbtn_group_#1_seq}{#2} + } +} + +% OC-marked content +\cs_new_protected_nopar:Nn\ocgbase_oc_bdc:n{\pbs_pdfbdc:nn{OC}{#1}} +\cs_new_protected_nopar:Nn\ocgbase_oc_emc:{\pbs_pdfemc:} + +%stack of PDF obj references of currently open OCGs +\seq_new:N\g_ocgbase_open_stack_seq +%push OCG to stack +\cs_new_protected_nopar:Nn\ocgbase_open_stack_push:n{ + \seq_gpush:Nx\g_ocgbase_open_stack_seq{#1}} +%pop OCG from stack into tl +\cs_new_protected_nopar:Nn\ocgbase_open_stack_pop:N{ + \seq_gpop:NN\g_ocgbase_open_stack_seq#1} + +%l2e versions +\cs_gset_eq:NN\ocgbase@new@ocg\ocgbase_new_ocg:nnn +\cs_gset_eq:NN\ocgbase@last@ocg\ocgbase_last_ocg: +\cs_gset_eq:NN\ocgbase@tree@node@begin\ocgbase_tree_node_begin:n +\cs_gset_eq:NN\ocgbase@tree@node@end\ocgbase_tree_node_end: +\cs_gset_eq:NN\ocgbase@add@to@off@list\ocgbase_add_to_off_list:n +\cs_gset_eq:NN\ocgbase@del@from@off@list\ocgbase_del_from_off_list:n +\cs_gset_eq:NN\ocgbase@add@ocg@to@radiobtn@grp\ocgbase_add_ocg_to_radiobtn_grp:nn +\cs_gset_eq:NN\ocgbase@oc@bdc\ocgbase_oc_bdc:n +\cs_gset_eq:NN\ocgbase@oc@emc\ocgbase_oc_emc: +\cs_gset_eq:NN\ocgbase@open@stack@pop\ocgbase_open_stack_pop:N +\cs_gset_eq:NN\ocgbase@open@stack@push\ocgbase_open_stack_push:n |