%% %% This is file `tagpdf.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% tagpdf.dtx (with options: `package') %% tagpdf-checks.dtx (with options: `package') %% tagpdf-mc-shared.dtx (with options: `shared') %% tagpdf.dtx (with options: `mcloading') %% tagpdf-tree.dtx (with options: `package') %% tagpdf-roles.dtx (with options: `package') %% tagpdf-struct.dtx (with options: `package') %% tagpdf-space.dtx (with options: `package') %% tagpdf-user.dtx (with options: `package') %% %% Copyright (C) 2019-2022 Ulrike Fischer %% %% It may be distributed and/or modified under the conditions of %% the LaTeX Project Public License (LPPL), either version 1.3c of %% this license or (at your option) any later version. The latest %% version of this license is in the file: %% %% https://www.latex-project.org/lppl.txt %% %% This file is part of the "tagpdf bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% File: tagpdf.dtx \ProvidesExplPackage {tagpdf} {2022-01-13} {0.93} { A package to experiment with pdf tagging } \bool_if:nF { \bool_lazy_and_p:nn {\cs_if_exist_p:N \pdfmanagement_if_active_p:} { \pdfmanagement_if_active_p: } } { %error for now, perhaps warning later. \PackageError{tagpdf} { PDF~resource~management~is~no~active!\MessageBreak tagpdf~will~no~work. } { Activate~it~with \MessageBreak \string\RequirePackage{pdfmanagement-testphase}\MessageBreak \string\DeclareDocumentMetadata{}\MessageBreak before~\string\documentclass } } \prop_gput:Nnn \g_msg_module_name_prop { tag }{ tagpdf } \bool_new:N\g__tag_mode_lua_bool \DeclareOption {luamode} { \sys_if_engine_luatex:T { \bool_gset_true:N \g__tag_mode_lua_bool } } \DeclareOption {genericmode}{ \bool_gset_false:N\g__tag_mode_lua_bool } \ExecuteOptions{luamode} \ProcessOptions \RequirePackage{l3ref-tmp} \cs_new_protected:Npn \__tag_lastpagelabel: { \legacy_if:nT { @filesw } { \exp_args:NNnx \exp_args:NNx\iow_now:Nn \@auxout { \token_to_str:N \newlabeldata {__tag_LastPage} { {abspage} { \int_use:N \g_shipout_readonly_int} {tagmcabs}{ \int_use:N \c@g__tag_MCID_abs_int } } } } } \AddToHook{enddocument/afterlastpage} {\__tag_lastpagelabel:} \cs_if_exist:NF \ref_value:nnn { \cs_new:Npn \ref_value:nnn #1#2#3 { \exp_args:Nee \__ref_value:nnn { \tl_to_str:n {#1} } { \tl_to_str:n {#2} } {#3} } \cs_new:Npn \__ref_value:nnn #1#2#3 { \tl_if_exist:cTF { g__ref_label_ #1 _ #2 _tl } { \tl_use:c { g__ref_label_ #1 _ #2 _tl } } { #3 } } } \tl_new:N \l__tag_tmpa_tl \str_new:N \l__tag_tmpa_str \prop_new:N \l__tag_tmpa_prop \seq_new:N \l__tag_tmpa_seq \seq_new:N \l__tag_tmpb_seq \clist_new:N \l__tag_tmpa_clist \int_new:N \l__tag_tmpa_int \box_new:N \l__tag_tmpa_box \box_new:N \l__tag_tmpb_box \clist_const:Nn \c__tag_refmc_clist {tagabspage,tagmcabs,tagmcid} \clist_const:Nn \c__tag_refstruct_clist {tagstruct,tagstructobj} \int_new:N \l__tag_loglevel_int \bool_new:N \g__tag_active_space_bool \bool_new:N \g__tag_active_mc_bool \bool_new:N \g__tag_active_tree_bool \bool_new:N \g__tag_active_struct_bool \bool_new:N \g__tag_active_struct_dest_bool \bool_gset_true:N \g__tag_active_struct_dest_bool \bool_new:N \l__tag_active_mc_bool \bool_set_true:N \l__tag_active_mc_bool \bool_new:N \l__tag_active_struct_bool \bool_set_true:N \l__tag_active_struct_bool \bool_new:N \g__tag_tagunmarked_bool \prg_generate_conditional_variant:Nnn \pdf_object_if_exist:n {e}{T,F} \cs_generate_variant:Nn \pdf_object_ref:n {e} \cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx} \cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx} \cs_generate_variant:Nn \prop_gput:Nnn {Nxx} \cs_generate_variant:Nn \prop_put:Nnn {Nxx} \cs_generate_variant:Nn \ref_label:nn { nv } \cs_generate_variant:Nn \seq_set_split:Nnn{Nne} \cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon } \ref_attribute_gset:nnnn { tagstruct } {0} { now } { \int_use:N \c@g__tag_struct_abs_int } \ref_attribute_gset:nnnn { tagstructobj } {} { now } { \pdf_object_if_exist:eT {__tag/struct/\int_use:N \c@g__tag_struct_abs_int} { \pdf_object_ref:e{__tag/struct/\int_use:N \c@g__tag_struct_abs_int} } } \ref_attribute_gset:nnnn { tagabspage } {0} { shipout } { \int_use:N \g_shipout_readonly_int } \ref_attribute_gset:nnnn { tagmcabs } {0} { now } { \int_use:N \c@g__tag_MCID_abs_int } \ref_attribute_gset:nnnn {tagmcid } {0} { now } { \int_use:N \g__tag_MCID_tmp_bypage_int } \cs_new_protected:Npn \__tag_ref_label:nn #1 #2 %#1 label, #2 name of list mc or struct { \@bsphack \ref_label:nv {#1}{c__tag_ref#2_clist} \@esphack } \cs_generate_variant:Nn \__tag_ref_label:nn {en} \cs_new:Npn \__tag_ref_value:nnn #1 #2 #3 %#1 label, #2 attribute, #3 default { \ref_value:nnn {#1}{#2}{#3} } \cs_generate_variant:Nn \__tag_ref_value:nnn {enn} \cs_new:Npn \__tag_ref_value_lastpage:nn #1 #2 { \ref_value:nnn {__tag_LastPage}{#1}{#2} } \cs_set_eq:NN \__tag_prop_new:N \prop_new:N \cs_set_eq:NN \__tag_seq_new:N \seq_new:N \cs_set_eq:NN \__tag_prop_gput:Nnn \prop_gput:Nnn \cs_set_eq:NN \__tag_seq_gput_right:Nn \seq_gput_right:Nn \cs_set_eq:NN \__tag_seq_item:cn \seq_item:cn \cs_set_eq:NN \__tag_prop_item:cn \prop_item:cn \cs_set_eq:NN \__tag_seq_show:N \seq_show:N \cs_set_eq:NN \__tag_prop_show:N \prop_show:N \cs_generate_variant:Nn \__tag_prop_gput:Nnn { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno} \cs_generate_variant:Nn \__tag_seq_gput_right:Nn { Nx , No, cn, cx } \cs_generate_variant:Nn \__tag_prop_new:N { c } \cs_generate_variant:Nn \__tag_seq_new:N { c } \cs_generate_variant:Nn \__tag_seq_show:N { c } \cs_generate_variant:Nn \__tag_prop_show:N { c } \cs_new_protected:Npn \tag_stop_group_begin: { \group_begin: \bool_set_false:N \l__tag_active_struct_bool \bool_set_false:N \l__tag_active_mc_bool } \cs_set_eq:NN \tag_stop_group_end: \group_end: \keys_define:nn { __tag / setup } { activate-space .bool_gset:N = \g__tag_active_space_bool, activate-mc .bool_gset:N = \g__tag_active_mc_bool, activate-tree .bool_gset:N = \g__tag_active_tree_bool, activate-struct .bool_gset:N = \g__tag_active_struct_bool, activate-all .meta:n = {activate-mc={#1},activate-tree={#1},activate-struct={#1}}, activate-all .default:n = true, no-struct-dest .bool_gset_inverse:N = \g__tag_active_struct_dest_bool, % \end{macrocode} log .choice:, log / none .code:n = {\int_set:Nn \l__tag_loglevel_int { 0 }}, log / v .code:n = { \int_set:Nn \l__tag_loglevel_int { 1 } \cs_set_protected:Nn \__tag_check_typeout_v:n { \iow_term:x {##1} } }, log / vv .code:n = {\int_set:Nn \l__tag_loglevel_int { 2 }}, log / vvv .code:n = {\int_set:Nn \l__tag_loglevel_int { 3 }}, log / all .code:n = {\int_set:Nn \l__tag_loglevel_int { 10 }}, tagunmarked .bool_gset:N = \g__tag_tagunmarked_bool, tagunmarked .initial:n = true, tabsorder .choice:, tabsorder / row .code:n = \pdfmanagement_add:nnn { Page } {Tabs}{/R}, tabsorder / column .code:n = \pdfmanagement_add:nnn { Page } {Tabs}{/C}, tabsorder / structure .code:n = \pdfmanagement_add:nnn { Page } {Tabs}{/S}, tabsorder / none .code:n = \pdfmanagement_remove:nn {Page} {Tabs}, tabsorder .initial:n = structure, uncompress .code:n = { \pdf_uncompress: }, } \sys_if_engine_luatex:T { \file_input:n {tagpdf-luatex.def} } %% File: tagpdf-checks.dtx \msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 } \msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 } \msg_new:nnn { tag } {mc-label-unknown} { label~#1~unknown~or~has~been~already~used.\\ Either~rerun~or~remove~one~of~the~uses. } \msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used } \msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 } \msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack} \msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack } \msg_new:nnn { tag } {mc-current} { current~MC:~ \bool_if:NTF\g__tag_in_mc_bool {abscnt=\__tag_get_mc_abs_cnt:,~tag=\g__tag_mc_key_tag_tl} {no~MC~open,~current~abscnt=\__tag_get_mc_abs_cnt:"} } \msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 } \msg_new:nnn { tag } {struct-faulty-nesting} { there~is~no~open~structure~on~the~stack } \msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! } \msg_new:nnn { tag } {struct-used-twice} { structure~with~label~#1~has~already~been~used} \msg_new:nnn { tag } {struct-label-unknown} { structure~with~label~#1~is~unknown~rerun} \msg_new:nnn { tag } {struct-show-closing} { closing~structure~#1~tagged~\prop_item:cn{g__tag_struct_#1_prop}{S} } \msg_new:nnn { tag } {attr-unknown} { attribute~#1~is~unknown} \msg_new:nnn { tag } {role-missing} { tag~#1~has~no~role~assigned } \msg_new:nnn { tag } {role-unknown} { role~#1~is~not~known } \msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known } \msg_new:nnn { tag } {role-tag} { mapping~tag~#1~to~role~#2 } \msg_new:nnn { tag } {new-tag} { adding~new~tag~#1 } \msg_new:nnn { tag } {tree-mcid-index-wrong} {something~is~wrong~with~the~mcid--rerun} \msg_new:nnn { tag } {sys-no-interwordspace} {engine/output~mode~#1~doesn't~support~the~interword~spaces} \cs_set_eq:NN \__tag_check_typeout_v:n \use_none:n \msg_new:nnnn { tag } {para-hook-count-wrong} {The~number~of~automatic~begin~(#1)~and~end~(#2)~para~hooks~differ!} {This~quite~probably~a~coding~error~and~the~structure~will~be~wrong!} \cs_new:Npn \tag_get:n #1 { \use:c {__tag_get_data_#1: } } \prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F } { \bool_lazy_all:nTF { {\g__tag_active_struct_bool} {\g__tag_active_mc_bool} {\g__tag_active_tree_bool} {\l__tag_active_struct_bool} {\l__tag_active_mc_bool} } { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \__tag_check_if_active_mc: {T,F,TF} { \bool_lazy_and:nnTF { \g__tag_active_mc_bool } { \l__tag_active_mc_bool } { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \__tag_check_if_active_struct: {T,F,TF} { \bool_lazy_and:nnTF { \g__tag_active_struct_bool } { \l__tag_active_struct_bool } { \prg_return_true: } { \prg_return_false: } } \cs_new_protected:Npn \__tag_check_structure_has_tag:n #1 %#1 struct num { \prop_if_in:cnF { g__tag_struct_#1_prop } {S} { \msg_error:nn { tag } {struct-missing-tag} } } \cs_new_protected:Npn \__tag_check_structure_tag:N #1 { \prop_if_in:NoF \g__tag_role_tags_prop {#1} { \msg_warning:nnx { tag } {role-unknown-tag} {#1} } } \cs_new_protected:Npn \__tag_check_info_closing_struct:n #1 %#1 struct num { \int_compare:nNnT {\l__tag_loglevel_int} > { 0 } { \msg_info:nnn { tag } {struct-show-closing} {#1} } } \cs_generate_variant:Nn \__tag_check_info_closing_struct:n {o,x} \cs_new_protected:Npn \__tag_check_no_open_struct: { \msg_error:nn { tag } {struct-faulty-nesting} } \cs_new_protected:Npn \__tag_check_struct_used:n #1 %#1 label { \prop_get:cnNT {g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop} {P} \l_tmpa_tl { \msg_warning:nnn { tag } {struct-used-twice} {#1} } } \cs_new_protected:Npn \__tag_check_add_tag_role:nn #1 #2 %#1 tag, #2 role { \tl_if_empty:nTF {#2} { \msg_warning:nnn { tag } {role-missing} {#1} } { \prop_get:NnNTF \g__tag_role_tags_prop {#2} \l_tmpa_tl { \int_compare:nNnT {\l__tag_loglevel_int} > { 0 } { \msg_info:nnnn { tag } {role-tag} {#1} {#2} } } { \msg_warning:nnn { tag } {role-unknown} {#2} } } } \cs_new_protected:Npn \__tag_check_mc_if_nested: { \__tag_mc_if_in:T { \msg_warning:nnx { tag } {mc-nested} { \__tag_get_mc_abs_cnt: } } } \cs_new_protected:Npn \__tag_check_mc_if_open: { \__tag_mc_if_in:F { \msg_warning:nnx { tag } {mc-not-open} { \__tag_get_mc_abs_cnt: } } } \cs_new_protected:Npn \__tag_check_mc_pushed_popped:nn #1 #2 { \int_compare:nNnT { \l__tag_loglevel_int } ={ 2 } { \msg_info:nnx {tag}{mc-#1}{#2} } \int_compare:nNnT { \l__tag_loglevel_int } > { 2 } { \msg_info:nnx {tag}{mc-#1}{#2} \seq_log:N \g__tag_mc_stack_seq } } \cs_new_protected:Npn \__tag_check_mc_tag:N #1 %#1 is var with a tag name in it { \tl_if_empty:NT #1 { \msg_error:nnx { tag } {mc-tag-missing} { \__tag_get_mc_abs_cnt: } } \prop_if_in:NoF \g__tag_role_tags_NS_prop {#1} { \msg_warning:nnx { tag } {role-unknown-tag} {#1} } } \cs_new_protected:Npn \__tag_check_init_mc_used: { \intarray_new:Nn \g__tag_check_mc_used_intarray { 65536 } \cs_gset_eq:NN \__tag_check_init_mc_used: \prg_do_nothing: } \cs_new_protected:Npn \__tag_check_mc_used:n #1 %#1 mcid abscnt { \int_compare:nNnT {\l__tag_loglevel_int} > { 2 } { \__tag_check_init_mc_used: \intarray_gset:Nnn \g__tag_check_mc_used_intarray {#1} { \intarray_item:Nn \g__tag_check_mc_used_intarray {#1} + 1 } \int_compare:nNnT { \intarray_item:Nn \g__tag_check_mc_used_intarray {#1} } > { 1 } { \msg_warning:nnn { tag } {mc-used-twice} {#1} } } } \cs_new_protected:Npn \__tag_check_show_MCID_by_page: { \tl_set:Nx \l__tag_tmpa_tl { \__tag_ref_value_lastpage:nn {abspage} {-1} } \int_step_inline:nnnn {1}{1} { \l__tag_tmpa_tl } { \seq_clear:N \l_tmpa_seq \int_step_inline:nnnn {1} {1} { \__tag_ref_value_lastpage:nn {tagmcabs} {-1} } { \int_compare:nT { \__tag_ref_value:enn {mcid-####1} {tagabspage} {-1} = ##1 } { \seq_gput_right:Nx \l_tmpa_seq { Page##1-####1- \__tag_ref_value:enn {mcid-####1} {tagmcid} {-1} } } } \seq_show:N \l_tmpa_seq } } \prg_new_conditional:Npnn \__tag_check_if_mc_in_galley: { T,F,TF } { \tl_if_eq:NNTF \l__tag_mc_firstmarks_seq \l__tag_mc_botmarks_seq { \prg_return_false: } { \prg_return_true: } } \prg_new_conditional:Npnn \__tag_check_if_mc_tmb_missing: { T,F,TF } { \bool_if:nTF { \str_if_eq_p:ee {\seq_item:Nn \l__tag_mc_firstmarks_seq {1}}{e-} || \str_if_eq_p:ee {\seq_item:Nn \l__tag_mc_firstmarks_seq {1}}{b+} } { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \__tag_check_if_mc_tme_missing: { T,F,TF } { \str_if_eq:eeTF {\seq_item:Nn \l__tag_mc_botmarks_seq {1}}{b+} { \prg_return_true: } { \prg_return_false: } } %% File: tagpdf-mc.dtx \newcounter { g__tag_MCID_abs_int } \cs_new:Npn \__tag_get_mc_abs_cnt: { \int_use:N \c@g__tag_MCID_abs_int } \int_new:N \g__tag_MCID_tmp_bypage_int \bool_new:N \g__tag_in_mc_bool \__tag_prop_new:N \g__tag_mc_parenttree_prop \seq_new:N \g__tag_mc_stack_seq \tl_new:N \l__tag_mc_artifact_type_tl \bool_new:N \l__tag_mc_key_stash_bool \bool_new:N \l__tag_mc_artifact_bool \tl_new:N \l__tag_mc_key_tag_tl \tl_new:N \g__tag_mc_key_tag_tl \tl_new:N \l__tag_mc_key_label_tl \tl_new:N \l__tag_mc_key_properties_tl \cs_new:Nn \__tag_mc_handle_mc_label:n { \__tag_ref_label:en{tagpdf-#1}{mc} } \cs_new_protected:Npn \__tag_mc_set_label_used:n #1 %#1 labelname { \tl_new:c { g__tag_mc_label_\tl_to_str:n{#1}_used_tl } } \cs_new_protected:Npn \tag_mc_use:n #1 %#1: label name { \__tag_check_if_active_struct:T { \tl_set:Nx \l__tag_tmpa_tl { \__tag_ref_value:nnn{tagpdf-#1}{tagmcabs}{} } \tl_if_empty:NTF\l__tag_tmpa_tl { \msg_warning:nnn {tag} {mc-label-unknown} {#1} } { \cs_if_free:cTF { g__tag_mc_label_\tl_to_str:n{#1}_used_tl } { \__tag_mc_handle_stash:x { \l__tag_tmpa_tl } \__tag_mc_set_label_used:n {#1} } { \msg_warning:nnn {tag}{mc-used-twice}{#1} } } } } \cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1 { \tag_mc_end_push: \tag_mc_begin:n {artifact=#1} \tag_stop_group_begin: } \cs_new_protected:Npn \tag_mc_artifact_group_end: { \tag_stop_group_end: \tag_mc_end: \tag_mc_begin_pop:n{} } \cs_new_protected:Npn \tag_mc_end_push: { \__tag_check_if_active_mc:T { \__tag_mc_if_in:TF { \seq_gpush:Nx \g__tag_mc_stack_seq { \tag_get:n {mc_tag} } \__tag_check_mc_pushed_popped:nn { pushed } { \tag_get:n {mc_tag} } \tag_mc_end: } { \seq_gpush:Nn \g__tag_mc_stack_seq {-1} \__tag_check_mc_pushed_popped:nn { pushed }{-1} } } } \cs_new_protected:Npn \tag_mc_begin_pop:n #1 { \__tag_check_if_active_mc:T { \seq_gpop:NNTF \g__tag_mc_stack_seq \l__tag_tmpa_tl { \tl_if_eq:NnTF \l__tag_tmpa_tl {-1} { \__tag_check_mc_pushed_popped:nn {popped}{-1} } { \__tag_check_mc_pushed_popped:nn {popped}{\l__tag_tmpa_tl} \tag_mc_begin:n {tag=\l__tag_tmpa_tl,#1} } } { \__tag_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing} } } } \keys_define:nn { __tag / mc } { stash .bool_set:N = \l__tag_mc_key_stash_bool, __artifact-bool .bool_set:N = \l__tag_mc_artifact_bool, __artifact-type .choice:, __artifact-type / pagination .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination } }, __artifact-type / pagination/header .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination/Subtype/Header } }, __artifact-type / pagination/footer .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination/Subtype/Footer } }, __artifact-type / layout .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Layout } }, __artifact-type / page .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Page } }, __artifact-type / background .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl { Background } }, __artifact-type / notype .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl {} }, __artifact-type / .code:n = { \tl_set:Nn \l__tag_mc_artifact_type_tl {} }, } %% File: tagpdf.dtx \bool_if:NTF \g__tag_mode_lua_bool { \RequirePackage {tagpdf-mc-code-lua} } { \RequirePackage {tagpdf-mc-code-generic} % } %% File: tagpdf-tree.dtx \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT \g__tag_active_tree_bool { \sys_if_output_pdf:TF { \AddToHook{enddocument/end} { \__tag_finish_structure: } } { \AddToHook{shipout/lastpage} { \__tag_finish_structure: } } } } \pdf_object_new:nn { __tag/struct/0 }{ dict } \hook_gput_code:nnn{shipout/lastpage}{tagpdf} { \bool_if:NT \g__tag_active_tree_bool { \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true } \pdfmanagement_add:nnx { Catalog } { StructTreeRoot } { \pdf_object_ref:n { __tag/struct/0 } } } } \cs_new_protected:Npn \__tag_tree_write_structtreeroot: { \__tag_prop_gput:cnx { g__tag_struct_0_prop } { ParentTree } { \pdf_object_ref:n { __tag/tree/parenttree } } \__tag_prop_gput:cnx { g__tag_struct_0_prop } { RoleMap } { \pdf_object_ref:n { __tag/tree/rolemap } } \__tag_struct_write_obj:n { 0 } } \cs_new_protected:Npn \__tag_tree_write_structelements: { \int_step_inline:nnnn {1}{1}{\c@g__tag_struct_abs_int} { \__tag_struct_write_obj:n { ##1 } } } \pdf_object_new:nn { __tag/tree/parenttree }{ dict } \newcounter { g__tag_parenttree_obj_int } \hook_gput_code:nnn{begindocument}{tagpdf} { \int_gset:Nn \c@g__tag_parenttree_obj_int { \__tag_ref_value_lastpage:nn{abspage}{100} } } \tl_new:N \g__tag_parenttree_objr_tl \cs_new_protected:Npn \__tag_parenttree_add_objr:nn #1 #2 %#1 StructParent number, #2 objref { \tl_gput_right:Nx \g__tag_parenttree_objr_tl { #1 \c_space_tl #2 ^^J } } \tl_new:N \l__tag_parenttree_content_tl \cs_new_protected:Npn \__tag_tree_fill_parenttree: { \int_step_inline:nnnn{1}{1}{\__tag_ref_value_lastpage:nn{abspage}{-1}} %not quite clear if labels are needed. See lua code { %page ##1 \prop_clear:N \l__tag_tmpa_prop \int_step_inline:nnnn{1}{1}{\__tag_ref_value_lastpage:nn{tagmcabs}{-1}} { %mcid####1 \int_compare:nT {\__tag_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page {% yes \prop_put:Nxx \l__tag_tmpa_prop {\__tag_ref_value:enn{mcid-####1}{tagmcid}{-1}} {\prop_item:Nn \g__tag_mc_parenttree_prop {####1}} } } \tl_put_right:Nx\l__tag_parenttree_content_tl { \int_eval:n {##1-1}\c_space_tl [\c_space_tl %] } \int_step_inline:nnnn {0} {1} { \prop_count:N \l__tag_tmpa_prop -1 } { \prop_get:NnNTF \l__tag_tmpa_prop {####1} \l__tag_tmpa_tl {% page#1:mcid##1:\l__tag_tmpa_tl :content \tl_put_right:Nx \l__tag_parenttree_content_tl { \pdf_object_if_exist:eT { __tag/struct/\l__tag_tmpa_tl } { \pdf_object_ref:e { __tag/struct/\l__tag_tmpa_tl } } \c_space_tl } } { \msg_warning:nn { tag } {tree-mcid-index-wrong} } } \tl_put_right:Nn \l__tag_parenttree_content_tl {%[ ]^^J } } } \cs_new_protected:Npn \__tag_tree_lua_fill_parenttree: { \tl_set:Nn \l__tag_parenttree_content_tl { \lua_now:e { ltx.__tag.func.output_parenttree ( \int_use:N\g_shipout_readonly_int ) } } } \cs_new_protected:Npn \__tag_tree_write_parenttree: { \bool_if:NTF \g__tag_mode_lua_bool { \__tag_tree_lua_fill_parenttree: } { \__tag_tree_fill_parenttree: } \tl_put_right:NV \l__tag_parenttree_content_tl\g__tag_parenttree_objr_tl \pdf_object_write:nx { __tag/tree/parenttree } { /Nums\c_space_tl [\l__tag_parenttree_content_tl] } } \pdf_object_new:nn { __tag/tree/rolemap }{ dict } \cs_new_protected:Npn \__tag_tree_write_rolemap: { \pdf_object_write:nx { __tag/tree/rolemap } { \pdfdict_use:n{g__tag_role/RoleMap_dict} } } \cs_new_protected:Npn \__tag_tree_write_classmap: { \tl_clear:N \l__tag_tmpa_tl \seq_gremove_duplicates:N \g__tag_attr_class_used_seq \seq_set_map:NNn \l__tag_tmpa_seq \g__tag_attr_class_used_seq { /##1\c_space_tl << \prop_item:Nn \g__tag_attr_entries_prop {##1} >> } \tl_set:Nx \l__tag_tmpa_tl { \seq_use:Nn \l__tag_tmpa_seq { \iow_newline: } } \tl_if_empty:NF \l__tag_tmpa_tl { \pdf_object_new:nn { __tag/tree/classmap }{ dict } \pdf_object_write:nx { __tag/tree/classmap } { \l__tag_tmpa_tl } \__tag_prop_gput:cnx { g__tag_struct_0_prop } { ClassMap } { \pdf_object_ref:n { __tag/tree/classmap } } } } \pdf_object_new:nn{ __tag/tree/namespaces }{array} \cs_new_protected:Npn \__tag_tree_write_namespaces: { \prop_map_inline:Nn \g__tag_role_NS_prop { \pdfdict_if_empty:nF {g__tag_role/RoleMapNS_##1_dict} { \pdf_object_write:nx {__tag/RoleMapNS/##1} { \pdfdict_use:n {g__tag_role/RoleMapNS_##1_dict} } \pdfdict_gput:nnx{g__tag_role/Namespace_##1_dict} {RoleMapNS}{\pdf_object_ref:n {__tag/RoleMapNS/##1}} } \pdf_object_write:nx{tag/NS/##1} { \pdfdict_use:n {g__tag_role/Namespace_##1_dict} } } \pdf_object_write:nx {__tag/tree/namespaces} { \prop_map_tokens:Nn \g__tag_role_NS_prop{\use_ii:nn} } } \cs_new_protected:Npn \__tag_finish_structure: { \bool_if:NT\g__tag_active_tree_bool { \hook_use:n {tagpdf/finish/before} \__tag_tree_write_parenttree: \__tag_tree_write_rolemap: \__tag_tree_write_classmap: \__tag_tree_write_namespaces: \__tag_tree_write_structelements: %this is rather slow!! \__tag_tree_write_structtreeroot: } } \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT\g__tag_active_tree_bool { \hook_gput_code:nnn{shipout/before} { tagpdf/structparents } { \pdfmanagement_add:nnx { Page } { StructParents } { \int_eval:n { \g_shipout_readonly_int} } } } } %% File: tagpdf-roles.dtx \__tag_seq_new:N \g__tag_role_tags_seq %to get names (type/NS) from numbers \__tag_prop_new:N \g__tag_role_tags_prop %to get numbers from names (type/NS) \prop_new:N \g__tag_role_tags_NS_prop %to namespace info \prop_new:N \g__tag_role_NS_prop % collect namespaces \tl_new:N \l__tag_role_tag_tmpa_tl \tl_new:N \l__tag_role_tag_namespace_tmpa_tl \tl_new:N \l__tag_role_role_tmpa_tl \tl_new:N \l__tag_role_role_namespace_tmpa_tl \cs_new_protected:Npn \__tag_role_NS_new:nnn #1 #2 #3 { \pdf_object_new:nn {tag/NS/#1}{dict} \pdfdict_new:n {g__tag_role/Namespace_#1_dict} \pdf_object_new:nn {__tag/RoleMapNS/#1}{dict} \pdfdict_new:n {g__tag_role/RoleMapNS_#1_dict} \pdfdict_gput:nnn {g__tag_role/Namespace_#1_dict} {Type} {/Namespace} \pdf_string_from_unicode:nnN{utf8/string}{#2}\l_tmpa_str \tl_if_empty:NF \l_tmpa_str { \pdfdict_gput:nnx {g__tag_role/Namespace_#1_dict} {NS} {\l_tmpa_str} } %RoleMapNS is added in tree \tl_if_empty:nF {#3} { \pdfdict_gput:nnx{g__tag_role/Namespace_#1_dict} {Schema}{#3} } \prop_gput:Nnx \g__tag_role_NS_prop {#1}{\pdf_object_ref:n{tag/NS/#1}~} } \str_const:Nx \c__tag_role_userNS_id_str { data:, \int_to_Hex:n{\int_rand:n {65535}} \int_to_Hex:n{\int_rand:n {65535}} - \int_to_Hex:n{\int_rand:n {65535}} - \int_to_Hex:n{\int_rand:n {65535}} - \int_to_Hex:n{\int_rand:n {65535}} - \int_to_Hex:n{\int_rand:n {16777215}} \int_to_Hex:n{\int_rand:n {16777215}} } \pdf_version_compare:NnT > {1.9} { \__tag_role_NS_new:nnn {pdf} {http://iso.org/pdf/ssn}{} \__tag_role_NS_new:nnn {pdf2} {http://iso.org/pdf2/ssn}{} \__tag_role_NS_new:nnn {mathml}{http://www.w3.org/1998/Math/MathML}{} \exp_args:Nnx \__tag_role_NS_new:nnn {user}{\c__tag_role_userNS_id_str}{} } \clist_const:Nn \c__tag_role_sttags_pdf_pdfII_clist { Document, %A complete document. This is the root element %of any structure tree containing %multiple parts or multiple articles. Part, %A large-scale division of a document. Sect, %A container for grouping related content elements. Div, %A generic block-level element or group of elements Caption, %A brief portion of text describing a table or figure. Index, NonStruct, %probably not needed H, H1, H2, H3, H4, H5, H6, P, L, %list LI, %list item (around label and list item body) Lbl, %list label LBody, %list item body Table, TR, %table row TH, %table header cell TD, %table data cell THead, %table header (n rows) TBody, %table rows TFoot, %table footer Span, %generic inline marker Link, % Annot, Figure, Formula, Form, % ruby warichu etc .. Ruby, RB, RT, Warichu, WT, WP, Artifact % only MC-tag ?... } \clist_const:Nn \c__tag_role_sttags_only_pdf_clist { Art, %A relatively self-contained body of text %constituting a single narrative or exposition BlockQuote, %A portion of text consisting of one or more paragraphs %attributed to someone other than the author of the %surrounding text. TOC, %A list made up of table of contents item entries %(structure tag TOCI; see below) and/or other %nested table of contents entries TOCI, %An individual member of a table of contents. %This entry's children can be any of the following structure tags: %Lbl,Reference,NonStruct,P,TOC Index, Private, Quote, %inline quote Note, %footnote, endnote. Lbl can be child Reference, %A citation to content elsewhere in the document. BibEntry, %bibentry Code } \clist_const:Nn \c__tag_role_sttags_only_pdfII_clist { DocumentFragment ,Aside ,H7 ,H8 ,H9 ,H10 ,Title ,FENote ,Sub ,Em ,Strong ,Artifact } \clist_const:Nn \c__tag_role_sttags_mathml_clist { abs ,and ,annotation ,apply ,approx ,arccos ,arccosh ,arccot ,arccoth ,arccsc ,arccsch ,arcsec ,arcsech ,arcsin ,arcsinh ,arctan ,arctanh ,arg ,bind ,bvar ,card ,cartesianproduct ,cbytes ,ceiling ,cerror ,ci ,cn ,codomain ,complexes ,compose ,condition ,conjugate ,cos ,cosh ,cot ,coth ,cs ,csc ,csch ,csymbol ,curl ,declare ,degree ,determinant ,diff ,divergence ,divide ,domain ,domainofapplication ,emptyset ,eq ,equivalent ,eulergamma ,exists ,exp ,exponentiale ,factorial ,factorof ,false ,floor ,fn ,forall ,gcd ,geq ,grad ,gt ,ident ,image ,imaginary ,imaginaryi ,implies ,in ,infinity ,int ,integers ,intersect ,interval ,inverse ,lambda ,laplacian ,lcm ,leq ,limit ,ln ,log ,logbase ,lowlimit ,lt ,maction ,maligngroup ,malignmark ,math ,matrix ,matrixrow ,max ,mean ,median ,menclose ,merror ,mfenced ,mfrac ,mglyph ,mi ,min ,minus ,mlabeledtr ,mlongdiv ,mmultiscripts ,mn ,mo ,mode ,moment ,momentabout ,mover ,mpadded ,mphantom ,mprescripts ,mroot ,mrow ,ms ,mscarries ,mscarry ,msgroup ,msline ,mspace ,msqrt ,msrow ,mstack ,mstyle ,msub ,msubsup ,msup ,mtable ,mtd ,mtext ,mtr ,munder ,munderover ,naturalnumbers ,neq ,none ,not ,notanumber ,notin ,notprsubset ,notsubset ,or ,otherwise ,outerproduct ,partialdiff ,pi ,piece ,piecewise ,plus ,power ,primes ,product ,prsubset ,quotient ,rationals ,real ,reals ,reln ,rem ,root ,scalarproduct ,sdev ,sec ,sech ,selector ,semantics ,sep ,set ,setdiff ,share ,sin ,sinh ,subset ,sum ,tan ,tanh ,tendsto ,times ,transpose ,true ,union ,uplimit ,variance ,vector ,vectorproduct ,xor } \prop_const_from_keyval:Nn \c__tag_role_sttags_pdfII_to_pdf_prop { DocumentFragment = Art, Aside = Note, Title = H1, Sub = Span, H7 = H6 , H8 = H6 , H9 = H6 , H10 = H6, FENote= Note, Em = Span, Strong= Span, } \clist_map_inline:Nn \c__tag_role_sttags_pdf_pdfII_clist { \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ pdf2 } } \clist_map_inline:Nn \c__tag_role_sttags_only_pdf_clist { \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ pdf } } \clist_map_inline:Nn \c__tag_role_sttags_only_pdfII_clist { \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ pdf2 } } \pdf_version_compare:NnT > {1.9} { \clist_map_inline:Nn \c__tag_role_sttags_mathml_clist { \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ mathml } } } \int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g__tag_role_tags_seq } { \__tag_prop_gput:Nxn \g__tag_role_tags_prop { \seq_item:Nn \g__tag_role_tags_seq { #1 } } { #1 } } \pdfdict_new:n {g__tag_role/RoleMap_dict} \cs_new_protected:Nn \__tag_role_add_tag:nn %(new) name, reference to old { \prop_if_in:NnF \g__tag_role_tags_prop {#1} { \int_compare:nNnT {\l__tag_loglevel_int} > { 0 } { \msg_info:nnn { tag }{new-tag}{#1} } \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \__tag_prop_gput:Nnx \g__tag_role_tags_prop { #1 } { \seq_count:N \g__tag_role_tags_seq } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ user } } \__tag_check_add_tag_role:nn {#1}{#2} \tl_if_empty:nF { #2 } { \pdfdict_gput:nnx {g__tag_role/RoleMap_dict} {#1} {\pdf_name_from_unicode_e:n{#2}} } } \cs_generate_variant:Nn \__tag_role_add_tag:nn {VV} \pdf_version_compare:NnT < {2.0} { \prop_map_inline:Nn \c__tag_role_sttags_pdfII_to_pdf_prop { \__tag_role_add_tag:nn {#1}{#2} } } \cs_new_protected:Nn \__tag_role_add_tag:nnnn %tag/namespace/role/namespace { \int_compare:nNnT {\l__tag_loglevel_int} > { 0 } { \msg_info:nnn { tag }{new-tag}{#1} } \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 } \__tag_prop_gput:Nnx \g__tag_role_tags_prop { #1 } { \seq_count:N \g__tag_role_tags_seq } \prop_gput:Nnn \g__tag_role_tags_NS_prop { #1 }{ #2 } \__tag_check_add_tag_role:nn {#1}{#3} \pdfdict_gput:nnx {g__tag_role/RoleMapNS_#2_dict}{#1} { [ \pdf_name_from_unicode_e:n{#3} \c_space_tl \pdf_object_ref:n {tag/NS/#4} ] } } \cs_generate_variant:Nn \__tag_role_add_tag:nnnn {VVVV} \keys_define:nn { __tag / tag-role } { ,tag .tl_set:N = \l__tag_role_tag_tmpa_tl ,tag-namespace .tl_set:N = \l__tag_role_tag_namespace_tmpa_tl ,role .tl_set:N = \l__tag_role_role_tmpa_tl ,role-namespace .tl_set:N = \l__tag_role_role_namespace_tmpa_tl } \keys_define:nn { __tag / setup } { add-new-tag .code:n = { \keys_set_known:nnnN {__tag/tag-role} { tag-namespace=user, role-namespace=, %so that we can test for it. #1 }{__tag/tag-role}\l_tmpa_tl \tl_if_empty:NF \l_tmpa_tl { \exp_args:NNno \seq_set_split:Nnn \l_tmpa_seq { / } {\l_tmpa_tl/} \tl_set:Nx \l__tag_role_tag_tmpa_tl { \seq_item:Nn \l_tmpa_seq {1} } \tl_set:Nx \l__tag_role_role_tmpa_tl { \seq_item:Nn \l_tmpa_seq {2} } } \tl_if_empty:NT \l__tag_role_role_namespace_tmpa_tl { \prop_get:NVNTF \g__tag_role_tags_NS_prop \l__tag_role_role_tmpa_tl \l__tag_role_role_namespace_tmpa_tl { \prop_if_in:NVF\g__tag_role_NS_prop \l__tag_role_role_namespace_tmpa_tl { \tl_set:Nn \l__tag_role_role_namespace_tmpa_tl {user} } } { \tl_set:Nn \l__tag_role_role_namespace_tmpa_tl {user} } } \pdf_version_compare:NnTF < {2.0} { %TODO add check for emptyness? \__tag_role_add_tag:VV \l__tag_role_tag_tmpa_tl \l__tag_role_role_tmpa_tl } { \__tag_role_add_tag:VVVV \l__tag_role_tag_tmpa_tl \l__tag_role_tag_namespace_tmpa_tl \l__tag_role_role_tmpa_tl \l__tag_role_role_namespace_tmpa_tl } } } %% File: tagpdf-struct.dtx \newcounter { g__tag_struct_abs_int } \int_gzero:N \c@g__tag_struct_abs_int \__tag_seq_new:N \g__tag_struct_objR_seq \__tag_prop_new:N \g__tag_struct_cont_mc_prop \seq_new:N \g__tag_struct_stack_seq \seq_gpush:Nn \g__tag_struct_stack_seq {0} \seq_new:N \g__tag_struct_tag_stack_seq \seq_gpush:Nn \g__tag_struct_tag_stack_seq {Root} \tl_new:N \g__tag_struct_stack_current_tl \tl_new:N \l__tag_struct_stack_parent_tmpa_tl \seq_const_from_clist:Nn \c__tag_struct_StructTreeRoot_entries_seq {%p. 857/858 Type, % always /StructTreeRoot K, % kid, dictionary or array of dictionaries IDTree, % currently unused ParentTree, % required,obj ref to the parent tree ParentTreeNextKey, % optional RoleMap, ClassMap, Namespaces, AF %pdf 2.0 } \seq_const_from_clist:Nn \c__tag_struct_StructElem_entries_seq {%p 858 f Type, %always /StructElem S, %tag/type P, %parent ID, %optional Ref, %optional, pdf 2.0 Use? Pg, %obj num of starting page, optional K, %kids A, %attributes, probably unused C, %class "" %R, %attribute revision number, irrelevant for us as we % don't update/change existing PDF and (probably) % deprecated in PDF 2.0 T, %title, value in () or <> Lang, %language Alt, % value in () or <> E, % abreviation ActualText, AF, %pdf 2.0, array of dict, associated files NS, %pdf 2.0, dict, namespace PhoneticAlphabet, %pdf 2.0 Phoneme %pdf 2.0 } \tl_new:N \g__tag_struct_tag_tl \tl_new:N \g__tag_struct_tag_NS_tl \tl_new:N \l__tag_struct_key_label_tl \bool_new:N \l__tag_struct_elem_stash_bool \cs_new:Npn \__tag_struct_output_prop_aux:nn #1 #2 %#1 num, #2 key { \prop_if_in:cnT { g__tag_struct_#1_prop } { #2 } { \c_space_tl/#2~ \prop_item:cn{ g__tag_struct_#1_prop } { #2 } } } \cs_new_protected:Npn \__tag_new_output_prop_handler:n #1 { \cs_new:cn { __tag_struct_output_prop_#1:n } { \__tag_struct_output_prop_aux:nn {#1}{##1} } } \tl_gset:Nn \g__tag_struct_stack_current_tl {0} \__tag_prop_new:c { g__tag_struct_0_prop } \__tag_new_output_prop_handler:n {0} \__tag_seq_new:c { g__tag_struct_kids_0_seq } \__tag_prop_gput:cnn { g__tag_struct_0_prop } { Type } { /StructTreeRoot } \__tag_prop_gput:cnx { g__tag_struct_0_prop } { Namespaces } { \pdf_object_ref:n { __tag/tree/namespaces } } \cs_new:Npn \__tag_struct_mcid_dict:n #1 %#1 MCID absnum { << /Type \c_space_tl /MCR \c_space_tl /Pg \c_space_tl \pdf_pageobject_ref:n { \__tag_ref_value:enn{mcid-#1}{tagabspage}{1} } /MCID \c_space_tl \__tag_ref_value:enn{mcid-#1}{tagmcid}{1} >> } \cs_new_protected:Npn \__tag_struct_kid_mc_gput_right:nn #1 #2 %#1 structure num, #2 MCID absnum% { \__tag_seq_gput_right:cx { g__tag_struct_kids_#1_seq } { \__tag_struct_mcid_dict:n {#2} } \__tag_seq_gput_right:cn { g__tag_struct_kids_#1_seq } { \prop_item:Nn \g__tag_struct_cont_mc_prop {#2} } } \cs_generate_variant:Nn \__tag_struct_kid_mc_gput_right:nn {nx} \cs_new_protected:Npn\__tag_struct_kid_struct_gput_right:nn #1 #2 %#1 num of parent struct, #2 kid struct { \__tag_seq_gput_right:cx { g__tag_struct_kids_#1_seq } { \pdf_object_ref:n { __tag/struct/#2 } } } \cs_generate_variant:Nn \__tag_struct_kid_struct_gput_right:nn {xx} \cs_new_protected:Npn\__tag_struct_kid_OBJR_gput_right:nn #1 #2 %#1 num of parent struct, %#2 obj reference { \pdf_object_unnamed_write:nn { dict } { /Type/OBJR/Obj~#2 } \__tag_seq_gput_right:cx { g__tag_struct_kids_#1_seq } { \pdf_object_ref_last: } } \cs_generate_variant:Nn\__tag_struct_kid_OBJR_gput_right:nn { xx } \cs_new_protected:Npn\__tag_struct_exchange_kid_command:N #1 %#1 = seq var { \seq_gpop_left:NN #1 \l__tag_tmpa_tl \regex_replace_once:nnN { \c{\__tag_mc_insert_mcid_kids:n} } { \c{\__tag_mc_insert_mcid_single_kids:n} } \l__tag_tmpa_tl \seq_gput_left:NV #1 \l__tag_tmpa_tl } \cs_generate_variant:Nn\__tag_struct_exchange_kid_command:N { c } \cs_new_protected:Npn \__tag_struct_fill_kid_key:n #1 %#1 is the struct num { \bool_if:NF\g__tag_mode_lua_bool { \seq_clear:N \l__tag_tmpa_seq \seq_map_inline:cn { g__tag_struct_kids_#1_seq } { \seq_put_right:Nx \l__tag_tmpa_seq { ##1 } } %\seq_show:c { g__tag_struct_kids_#1_seq } %\seq_show:N \l__tag_tmpa_seq \seq_remove_all:Nn \l__tag_tmpa_seq {} %\seq_show:N \l__tag_tmpa_seq \seq_gset_eq:cN { g__tag_struct_kids_#1_seq } \l__tag_tmpa_seq } \int_case:nnF { \seq_count:c { g__tag_struct_kids_#1_seq } } { { 0 } { } %no kids, do nothing { 1 } % 1 kid, insert { % in this case we need a special command in % luamode to get the array right. See issue #13 \bool_if:NT\g__tag_mode_lua_bool { \__tag_struct_exchange_kid_command:c {g__tag_struct_kids_#1_seq} } \__tag_prop_gput:cnx { g__tag_struct_#1_prop } {K} { \seq_item:cn { g__tag_struct_kids_#1_seq } {1} } } % } { %many kids, use an array \__tag_prop_gput:cnx { g__tag_struct_#1_prop } {K} { [ \seq_use:cn { g__tag_struct_kids_#1_seq } { \c_space_tl } ] } } } \cs_new_protected:Npn \__tag_struct_get_dict_content:nN #1 #2 %#1: stucture num { \tl_clear:N #2 \seq_map_inline:cn { c__tag_struct_ \int_compare:nNnTF{#1}={0}{StructTreeRoot}{StructElem} _entries_seq } { \tl_put_right:Nx #2 { \prop_if_in:cnT { g__tag_struct_#1_prop } { ##1 } { \c_space_tl/##1~\prop_item:cn{ g__tag_struct_#1_prop } { ##1 } } } } } \cs_new_protected:Npn \__tag_struct_write_obj:n #1 % #1 is the struct num { \pdf_object_if_exist:nTF { __tag/struct/#1 } { \__tag_struct_fill_kid_key:n { #1 } \__tag_struct_get_dict_content:nN { #1 } \l__tag_tmpa_tl \exp_args:Nx \pdf_object_write:nx { __tag/struct/#1 } { \l__tag_tmpa_tl } } { \msg_error:nnn { tag } { struct-no-objnum } { #1} } } \cs_new_protected:Npn \__tag_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform %#2 structparent number { \bool_if:NT \g__tag_active_struct_bool { %get the number of the parent structure: \seq_get:NNF \g__tag_struct_stack_seq \l__tag_struct_stack_parent_tmpa_tl { \msg_error:nn { tag } { struct-faulty-nesting } } %put the obj number of the annot in the kid entry, this also creates %the OBJR object \__tag_struct_kid_OBJR_gput_right:xx { \l__tag_struct_stack_parent_tmpa_tl } { #1 % } % add the parent obj number to the parent tree: \exp_args:Nnx \__tag_parenttree_add_objr:nn { #2 } { \pdf_object_ref:e { __tag/struct/\l__tag_struct_stack_parent_tmpa_tl } } % increase the int: \stepcounter{ g__tag_parenttree_obj_int } } } \cs_new:Npn \__tag_get_data_struct_tag: { \exp_args:Ne \tl_tail:n { \prop_item:cn {g__tag_struct_\g__tag_struct_stack_current_tl _prop}{S} } } \keys_define:nn { __tag / struct } { label .tl_set:N = \l__tag_struct_key_label_tl, stash .bool_set:N = \l__tag_struct_elem_stash_bool, tag .code:n = % S property { \seq_set_split:Nne \l__tag_tmpa_seq { / } {#1/\prop_item:Nn\g__tag_role_tags_NS_prop{#1}} \tl_gset:Nx \g__tag_struct_tag_tl { \seq_item:Nn\l__tag_tmpa_seq {1} } \tl_gset:Nx \g__tag_struct_tag_NS_tl { \seq_item:Nn\l__tag_tmpa_seq {2} } \__tag_check_structure_tag:N \g__tag_struct_tag_tl \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { S } { \pdf_name_from_unicode_e:n{ \g__tag_struct_tag_tl} } % \prop_get:NVNT \g__tag_role_NS_prop\g__tag_struct_tag_NS_tl\l__tag_tmpa_tl { \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { NS } { \l__tag_tmpa_tl } % } }, title .code:n = % T property { \str_set_convert:Nnon \l__tag_tmpa_str { #1 } { default } { utf16/hex } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { T } { <\l__tag_tmpa_str> } }, title-o .code:n = % T property { \str_set_convert:Nnon \l__tag_tmpa_str { #1 } { default } { utf16/hex } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { T } { <\l__tag_tmpa_str> } }, alttext .code:n = % Alt property { \str_set_convert:Noon \l__tag_tmpa_str { #1 } { default } { utf16/hex } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { Alt } { <\l__tag_tmpa_str> } }, actualtext .code:n = % ActualText property { \str_set_convert:Noon \l__tag_tmpa_str { #1 } { default } { utf16/hex } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { ActualText } { <\l__tag_tmpa_str>} }, lang .code:n = % Lang property { \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { Lang } { (#1) } }, ref .code:n = % Lang property { \tl_clear:N\l__tag_tmpa_tl \clist_map_inline:nn {#1} { \tl_put_right:Nx \l__tag_tmpa_tl {~\ref_value:nn{tagpdfstruct-##1}{tagstructobj} } } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { Ref } { [\l__tag_tmpa_tl] } }, E .code:n = % E property { \str_set_convert:Nnon \l__tag_tmpa_str { #1 } { default } { utf16/hex } \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { E } { <\l__tag_tmpa_str> } }, } \cs_new_protected:Npn \__tag_struct_add_AF:nn #1 #2 % #1 struct num #2 object name { \tl_if_exist:cTF { g__tag_struct_#1_AF_tl } { \tl_gput_right:cx { g__tag_struct_#1_AF_tl } { ~ \pdf_object_ref:n {#2} } } { \tl_new:c { g__tag_struct_#1_AF_tl } \tl_gset:cx { g__tag_struct_#1_AF_tl } { \pdf_object_ref:n {#2} } } } \cs_generate_variant:Nn \__tag_struct_add_AF:nn {en,ee} \keys_define:nn { __tag / struct } { AF .code:n = % AF property { \pdf_object_if_exist:nTF {#1} { \__tag_struct_add_AF:en { \int_eval:n {\c@g__tag_struct_abs_int} }{#1} \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { AF } { [ \tl_use:c { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl } ] } } { } }, ,AFinline .code:n = { \group_begin: \pdf_object_if_exist:eF {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int} { \pdffile_embed_stream:nxx {#1} {tag-AFfile\int_use:N\c@g__tag_struct_abs_int.txt} {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int} \__tag_struct_add_AF:ee { \int_eval:n {\c@g__tag_struct_abs_int} } { __tag/fileobj\int_use:N\c@g__tag_struct_abs_int } \__tag_prop_gput:cnx { g__tag_struct_\int_use:N\c@g__tag_struct_abs_int _prop } { AF } { [ \tl_use:c { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl } ] } } \group_end: } ,AFinline-o .code:n = { \group_begin: \pdf_object_if_exist:eF {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int} { \pdffile_embed_stream:oxx {#1} {tag-AFfile\int_use:N\c@g__tag_struct_abs_int.txt} {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int} \__tag_struct_add_AF:ee { \int_eval:n {\c@g__tag_struct_abs_int} } { __tag/fileobj\int_use:N\c@g__tag_struct_abs_int } \__tag_prop_gput:cnx { g__tag_struct_\int_use:N\c@g__tag_struct_abs_int _prop } { AF } { [ \tl_use:c { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl } ] } } \group_end: } } \keys_define:nn { __tag / setup } { root-AF .code:n = { \pdf_object_if_exist:nTF {#1} { \__tag_struct_add_AF:en { 0 }{#1} \__tag_prop_gput:cnx { g__tag_struct_0_prop } { AF } { [ \tl_use:c { g__tag_struct_0_AF_tl } ] } } { } }, } \cs_new_protected:Npn \tag_struct_begin:n #1 %#1 key-val { \__tag_check_if_active_struct:T { \group_begin: \int_gincr:N \c@g__tag_struct_abs_int \__tag_prop_new:c { g__tag_struct_\int_eval:n { \c@g__tag_struct_abs_int }_prop } \__tag_new_output_prop_handler:n {\int_eval:n { \c@g__tag_struct_abs_int }} \__tag_seq_new:c { g__tag_struct_kids_\int_eval:n { \c@g__tag_struct_abs_int }_seq} \exp_args:Ne \pdf_object_new:nn { __tag/struct/\int_eval:n { \c@g__tag_struct_abs_int } } { dict } \__tag_prop_gput:cno { g__tag_struct_\int_eval:n { \c@g__tag_struct_abs_int }_prop } { Type } { /StructElem } \keys_set:nn { __tag / struct} { #1 } \__tag_check_structure_has_tag:n { \int_eval:n {\c@g__tag_struct_abs_int} } \tl_if_empty:NF \l__tag_struct_key_label_tl { \__tag_ref_label:en{tagpdfstruct-\l__tag_struct_key_label_tl}{struct} } %get the potential parent from the stack: \seq_get:NNF \g__tag_struct_stack_seq \l__tag_struct_stack_parent_tmpa_tl { \msg_error:nn { tag } { struct-faulty-nesting } } \seq_gpush:NV \g__tag_struct_stack_seq \c@g__tag_struct_abs_int \seq_gpush:NV \g__tag_struct_tag_stack_seq \g__tag_struct_tag_tl \tl_gset:NV \g__tag_struct_stack_current_tl \c@g__tag_struct_abs_int %\seq_show:N \g__tag_struct_stack_seq \bool_if:NF \l__tag_struct_elem_stash_bool {%set the parent \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { P } { \pdf_object_ref:e { __tag/struct/\l__tag_struct_stack_parent_tmpa_tl } } %record this structure as kid: %\tl_show:N \g__tag_struct_stack_current_tl %\tl_show:N \l__tag_struct_stack_parent_tmpa_tl \__tag_struct_kid_struct_gput_right:xx { \l__tag_struct_stack_parent_tmpa_tl } { \g__tag_struct_stack_current_tl } %\prop_show:c { g__tag_struct_\g__tag_struct_stack_current_tl _prop } %\seq_show:c {g__tag_struct_kids_\l__tag_struct_stack_parent_tmpa_tl _seq} } %\prop_show:c { g__tag_struct_\g__tag_struct_stack_current_tl _prop } %\seq_show:c {g__tag_struct_kids_\l__tag_struct_stack_parent_tmpa_tl _seq} \group_end: } } \cs_new_protected:Nn \tag_struct_end: { %take the current structure num from the stack: %the objects are written later, lua mode hasn't all needed info yet %\seq_show:N \g__tag_struct_stack_seq \__tag_check_if_active_struct:T { \seq_gpop:NN \g__tag_struct_tag_stack_seq \l__tag_tmpa_tl \seq_gpop:NNTF \g__tag_struct_stack_seq \l__tag_tmpa_tl { \__tag_check_info_closing_struct:o { \g__tag_struct_stack_current_tl } } { \__tag_check_no_open_struct: } % get the previous one, shouldn't be empty as the root should be there \seq_get:NNTF \g__tag_struct_stack_seq \l__tag_tmpa_tl { \tl_gset:NV \g__tag_struct_stack_current_tl \l__tag_tmpa_tl } { \__tag_check_no_open_struct: } \seq_get:NNT \g__tag_struct_tag_stack_seq \l__tag_tmpa_tl { \tl_gset:NV \g__tag_struct_tag_tl \l__tag_tmpa_tl } } } \cs_new_protected:Nn \tag_struct_use:n %#1 is the label { \__tag_check_if_active_struct:T { \prop_if_exist:cTF { g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } % { \__tag_check_struct_used:n {#1} %add the label structure as kid to the current structure (can be the root) \__tag_struct_kid_struct_gput_right:xx { \g__tag_struct_stack_current_tl } { \__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} } %add the current structure to the labeled one as parents \__tag_prop_gput:cnx { g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop } { P } { \pdf_object_ref:e { __tag/struct/\g__tag_struct_stack_current_tl } } } { \msg_warning:nnn{ tag }{struct-label-unknown}{#1} } } } \cs_new_protected:Npn \tag_struct_insert_annot:nn #1 #2 %#1 should be an object reference %#2 struct parent num { \__tag_check_if_active_struct:T { \__tag_struct_insert_annot:nn {#1}{#2} } } \cs_generate_variant:Nn \tag_struct_insert_annot:nn {xx} \cs_new:Npn \tag_struct_parent_int: {\int_use:c { c@g__tag_parenttree_obj_int }} \prop_new:N \g__tag_attr_entries_prop \seq_new:N \g__tag_attr_class_used_seq \tl_new:N \l__tag_attr_value_tl \prop_new:N \g__tag_attr_objref_prop %will contain obj num of used attributes \cs_new_protected:Npn \__tag_attr_new_entry:nn #1 #2 %#1:name, #2: content { \prop_gput:Nnn \g__tag_attr_entries_prop {#1}{#2} } \keys_define:nn { __tag / setup } { newattribute .code:n = { \__tag_attr_new_entry:nn #1 } } \keys_define:nn { __tag / struct } { attribute-class .code:n = { \clist_set:No \l__tag_tmpa_clist { #1 } \seq_set_from_clist:NN \l__tag_tmpa_seq \l__tag_tmpa_clist \seq_map_inline:Nn \l__tag_tmpa_seq { \prop_if_in:NnF \g__tag_attr_entries_prop {##1} { \msg_error:nnn { tag } { attr-unknown } { ##1 } } \seq_gput_left:Nn\g__tag_attr_class_used_seq { ##1} } \seq_set_map:NNn \l__tag_tmpb_seq \l__tag_tmpa_seq { /##1 } \tl_set:Nx \l__tag_tmpa_tl { \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{[} \seq_use:Nn \l__tag_tmpb_seq { \c_space_tl } \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{]} } \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 0 } { \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { C } { \l__tag_tmpa_tl } %\prop_show:c { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } } } } \keys_define:nn { __tag / struct } { attribute .code:n = % A property (attribute, value currently a dictionary) { \clist_set:No \l__tag_tmpa_clist { #1 } \seq_set_from_clist:NN \l__tag_tmpa_seq \l__tag_tmpa_clist \tl_set:Nx \l__tag_attr_value_tl { \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{[}%] } \seq_map_inline:Nn \l__tag_tmpa_seq { \prop_if_in:NnF \g__tag_attr_entries_prop {##1} { \msg_error:nnn { tag } { attr-unknown } { ##1 } } \prop_if_in:NnF \g__tag_attr_objref_prop {##1} {%\prop_show:N \g__tag_attr_entries_prop \pdf_object_unnamed_write:nx { dict } { \prop_item:Nn\g__tag_attr_entries_prop {##1} } \prop_gput:Nnx \g__tag_attr_objref_prop {##1} {\pdf_object_ref_last:} } \tl_put_right:Nx \l__tag_attr_value_tl { \c_space_tl \prop_item:Nn \g__tag_attr_objref_prop {##1} } % \tl_show:N \l__tag_attr_value_tl } \tl_put_right:Nx \l__tag_attr_value_tl { %[ \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{]}% } % \tl_show:N \l__tag_attr_value_tl \__tag_prop_gput:cnx { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop } { A } { \l__tag_attr_value_tl } }, } %% File: tagpdf-space.dtx \sys_if_engine_pdftex:T { \sys_if_output_pdf:TF { \pdfglyphtounicode{space}{0020} \keys_define:nn { __tag / setup } { interwordspace .choices:nn = { true, on } { \pdfinterwordspaceon }, interwordspace .choices:nn = { false, off }{ \pdfinterwordspaceon }, interwordspace .default:n = true, show-spaces .bool_set:N = \l__tag_showspaces_bool } } { \keys_define:nn { __tag / setup } { interwordspace .choices:nn = { true, on, false, off } { \msg_warning:nnn {tag}{sys-no-interwordspace}{dvi} }, interwordspace .default:n = true, show-spaces .bool_set:N = \l__tag_showspaces_bool } } } \sys_if_engine_luatex:T { \keys_define:nn { __tag / setup } { interwordspace .choices:nn = { true, on } { \bool_gset_true:N \g__tag_active_space_bool \lua_now:e{ltx.__tag.func.markspaceon()} }, interwordspace .choices:nn = { false, off } { \bool_gset_false:N \g__tag_active_space_bool \lua_now:e{ltx.__tag.func.markspaceoff()} }, interwordspace .default:n = true, show-spaces .choice:, show-spaces / true .code:n = {\lua_now:e{ltx.__tag.trace.showspaces=true}}, show-spaces / false .code:n = {\lua_now:e{ltx.__tag.trace.showspaces=nil}}, show-spaces .default:n = true } } \sys_if_engine_xetex:T { \keys_define:nn { __tag / setup } { interwordspace .choices:nn = { true, on } { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} }, interwordspace .choices:nn = { false, off } { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} }, interwordspace .default:n = true, show-spaces .bool_set:N = \l__tag_showspaces_bool } } \sys_if_engine_luatex:T { \cs_new_protected:Nn \__tag_fakespace: { \group_begin: \lua_now:e{ltx.__tag.func.fakespace()} \skip_horizontal:n{\c_zero_skip} \group_end: } } %% File: tagpdf-user.dtx \NewDocumentCommand \tagpdfsetup { m } { \keys_set:nn { __tag / setup } { #1 } } \NewDocumentCommand \tagmcbegin { m } { \tag_mc_begin:n {#1}%\ignorespaces } \NewDocumentCommand \tagmcend { } { %\if_mode_horizontal: \unskip \fi: % \tag_mc_end: } \NewDocumentCommand \tagmcuse { m } { \tag_mc_use:n {#1} } \NewDocumentCommand \tagmcifinTF { m m } { \tag_mc_if_in:TF { #1 } { #2 } } \NewDocumentCommand \tagstructbegin { m } { \tag_struct_begin:n {#1} } \NewDocumentCommand \tagstructend { } { \tag_struct_end: } \NewDocumentCommand \tagstructuse { m } { \tag_struct_use:n {#1} } \NewDocumentCommand\ShowTagging { m } { \keys_set:nn { __tag / show }{ #1} } \keys_define:nn { __tag / show } { mc-data .code:n = { \sys_if_engine_luatex:T { \lua_now:e{ltx.__tag.trace.show_all_mc_data(#1,\__tag_get_mc_abs_cnt:,0)} } } ,mc-data .default:n = 1 } \keys_define:nn { __tag / show } { mc-current .code:n = { \bool_if:NTF \g__tag_mode_lua_bool { \sys_if_engine_luatex:T { \int_compare:nNnTF { -2147483647 } = { \lua_now:e { tex.print (tex.getattribute (luatexbase.attributes.g__tag_mc_cnt_attr)) } } { \lua_now:e { ltx.__tag.trace.log ( "mc-current:~no~MC~open,~current~abscnt =\__tag_get_mc_abs_cnt:" ,0 ) texio.write_nl("") } } { \lua_now:e { ltx.__tag.trace.log ( "mc-current:~abscnt=\__tag_get_mc_abs_cnt:==" .. tex.getattribute(luatexbase.attributes.g__tag_mc_cnt_attr) .. "~=>tag=" .. tostring (ltx.__tag.func.get_tag_from (tex.getattribute (luatexbase.attributes.g__tag_mc_type_attr))) .. "=" .. tex.getattribute (luatexbase.attributes.g__tag_mc_type_attr) ,0 ) texio.write_nl("") } } } } { \msg_note:nn{ tag }{ mc-current } } } } \keys_define:nn { __tag / show } { mc-marks .choice: , mc-marks / show .code:n = { \__tag_mc_get_marks: \__tag_check_if_mc_in_galley:TF { \iow_term:n {Marks~from~this~page:~} } { \iow_term:n {Marks~from~a~previous~page:~} } \seq_show:N \l__tag_mc_firstmarks_seq \seq_show:N \l__tag_mc_botmarks_seq \__tag_check_if_mc_tmb_missing:T { \iow_term:n {BDC~missing~on~this~page!} } \__tag_check_if_mc_tme_missing:T { \iow_term:n {EMC~missing~on~this~page!} } }, mc-marks / use .code:n = { \__tag_mc_get_marks: \__tag_check_if_mc_in_galley:TF { Marks~from~this~page:~} { Marks~from~a~previous~page:~} \seq_use:Nn \l__tag_mc_firstmarks_seq {,~}\quad \seq_use:Nn \l__tag_mc_botmarks_seq {,~}\quad \__tag_check_if_mc_tmb_missing:T { BDC~missing~ } \__tag_check_if_mc_tme_missing:T { EMC~missing } }, mc-marks .default:n = show } \keys_define:nn { __tag / show } { struct-stack .choice: ,struct-stack / log .code:n = \seq_log:N \g__tag_struct_tag_stack_seq ,struct-stack / show .code:n = \seq_show:N \g__tag_struct_tag_stack_seq ,struct-stack .default:n = show } \cs_new_protected:Npn \__tag_add_document_structure:n #1 { \hook_gput_code:nnn{begindocument}{tagpdf}{\tagstructbegin{tag=#1}} \hook_gput_code:nnn{tagpdf/finish/before}{tagpdf}{\tagstructend} } \keys_define:nn { __tag / setup} { activate .code:n = { \keys_set:nn { __tag / setup } { activate-mc,activate-tree,activate-struct } \__tag_add_document_structure:n {#1} }, activate .default:n = Document } \AddToHook{begindocument/before} { \bool_lazy_all:nT { { \g__tag_active_struct_dest_bool } { \g__tag_active_struct_bool } { \cs_if_exist_p:N \pdf_activate_structure_destination: } { ! \pdf_version_compare_p:Nn < {2.0} } } { \tl_set:Nn \l_pdf_current_structure_destination_tl { __tag/struct/\g__tag_struct_stack_current_tl } \pdf_activate_structure_destination: } } \sys_if_engine_luatex:T { \NewDocumentCommand\pdffakespace { } { \__tag_fakespace: } } \bool_new:N \l__tag_para_bool \bool_new:N \l__tag_para_show_bool \int_new:N \g__tag_para_begin_int \int_new:N \g__tag_para_end_int \keys_define:nn { __tag / setup } { paratagging .bool_set:N = \l__tag_para_bool, paratagging-show .bool_set:N = \l__tag_para_show_bool, } \AddToHook{para/begin} { \bool_if:NT \l__tag_para_bool { \int_gincr:N \g__tag_para_begin_int \tag_struct_begin:n {tag=P} \bool_if:NT \l__tag_para_show_bool { \tag_mc_begin:n{artifact} \llap{\color_select:n{red}\tiny\int_use:N\g__tag_para_begin_int\ } \tag_mc_end: } \tag_mc_begin:n {tag=P} } } \AddToHook{para/end} { \bool_if:NT \l__tag_para_bool { \int_gincr:N \g__tag_para_end_int \tag_mc_end: \bool_if:NT \l__tag_para_show_bool { \tag_mc_begin:n{artifact} \rlap{\color_select:n{red}\tiny\ \int_use:N\g__tag_para_end_int} \tag_mc_end: } \tag_struct_end: } } \AddToHook{enddocument/info} { \int_compare:nNnF {\g__tag_para_begin_int}={\g__tag_para_end_int} { \msg_error:nnxx {tag} {para-hook-count-wrong} {\int_use:N\g__tag_para_begin_int} {\int_use:N\g__tag_para_end_int} } } \AddToHook{begindocument/before} { \bool_if:NF \g__tag_mode_lua_bool { \cs_if_exist:NT \@kernel@before@footins { \tl_put_right:Nn \@kernel@before@footins { \__tag_add_missing_mcs_to_stream:Nn \footins {footnote} } \tl_put_right:Nn \@kernel@before@cclv { \__tag_check_typeout_v:n {====>~In~\token_to_str:N \@makecol\c_space_tl\the\c@page} \__tag_add_missing_mcs_to_stream:Nn \@cclv {main} } \tl_put_right:Nn \@mult@ptagging@hook { \__tag_check_typeout_v:n {====>~In~\string\page@sofar} \process@cols\mult@firstbox { \__tag_add_missing_mcs_to_stream:Nn \count@ {multicol} } \__tag_add_missing_mcs_to_stream:Nn \mult@rightbox {multicol} } } } } \newcommand\tagpdfparaOn {\bool_set_true:N \l__tag_para_bool} \newcommand\tagpdfparaOff{\bool_set_false:N \l__tag_para_bool} \NewDocumentCommand\tagpdfsuppressmarks{m} {{\use:c{__tag_mc_disable_marks:} #1}} \cs_new_protected:Npn\__tag_hook_kernel_before_head:{} \cs_new_protected:Npn\__tag_hook_kernel_after_head:{} \cs_new_protected:Npn\__tag_hook_kernel_before_foot:{} \cs_new_protected:Npn\__tag_hook_kernel_after_foot:{} \AddToHook{begindocument} { \cs_if_exist:NT \@kernel@before@head { \tl_put_right:Nn \@kernel@before@head {\__tag_hook_kernel_before_head:} \tl_put_left:Nn \@kernel@after@head {\__tag_hook_kernel_after_head:} \tl_put_right:Nn \@kernel@before@foot {\__tag_hook_kernel_before_foot:} \tl_put_left:Nn \@kernel@after@foot {\__tag_hook_kernel_after_foot:} } } \bool_new:N \g__tag_saved_in_mc_bool \cs_new_protected:Npn \__tag_exclude_headfoot_begin: { \bool_set_false:N \l__tag_para_bool \bool_if:NTF \g__tag_mode_lua_bool { \tag_mc_end_push: } { \bool_gset_eq:NN \g__tag_saved_in_mc_bool \g__tag_in_mc_bool \bool_gset_false:N \g__tag_in_mc_bool } \tag_mc_begin:n {artifact} } \cs_new_protected:Npn \__tag_exclude_headfoot_end: { \tag_mc_end: \bool_if:NTF \g__tag_mode_lua_bool { \tag_mc_begin_pop:n{} } { \bool_gset_eq:NN \g__tag_in_mc_bool\g__tag_saved_in_mc_bool } } \__tag_attr_new_entry:nn {__tag/attr/pagination}{/O/Artifact/Type/Pagination} \cs_new_protected:Npn \__tag_exclude_struct_headfoot_begin:n #1 { \bool_set_false:N \l__tag_para_bool \bool_if:NTF \g__tag_mode_lua_bool { \tag_mc_end_push: } { \bool_gset_eq:NN \g__tag_saved_in_mc_bool \g__tag_in_mc_bool \bool_gset_false:N \g__tag_in_mc_bool } \tag_struct_begin:n{tag=Artifact,attribute-class=__tag/attr/#1} \tag_mc_begin:n {artifact=#1} } \cs_new_protected:Npn \__tag_exclude_struct_headfoot_end: { \tag_mc_end: \tag_struct_end: \bool_if:NTF \g__tag_mode_lua_bool { \tag_mc_begin_pop:n{} } { \bool_gset_eq:NN \g__tag_in_mc_bool\g__tag_saved_in_mc_bool } } \keys_define:nn { __tag / setup } { exclude-header-footer .choice:, exclude-header-footer / true .code:n = { \cs_set_eq:NN \__tag_hook_kernel_before_head: \__tag_exclude_headfoot_begin: \cs_set_eq:NN \__tag_hook_kernel_before_foot: \__tag_exclude_headfoot_begin: \cs_set_eq:NN \__tag_hook_kernel_after_head: \__tag_exclude_headfoot_end: \cs_set_eq:NN \__tag_hook_kernel_after_foot: \__tag_exclude_headfoot_end: }, exclude-header-footer / pagination .code:n = { \cs_set:Nn \__tag_hook_kernel_before_head: { \__tag_exclude_struct_headfoot_begin:n {pagination} } \cs_set:Nn \__tag_hook_kernel_before_foot: { \__tag_exclude_struct_headfoot_begin:n {pagination} } \cs_set_eq:NN \__tag_hook_kernel_after_head: \__tag_exclude_struct_headfoot_end: \cs_set_eq:NN \__tag_hook_kernel_after_foot: \__tag_exclude_struct_headfoot_end: }, exclude-header-footer / false .code:n = { \cs_set_eq:NN \__tag_hook_kernel_before_head: \prg_do_nothing: \cs_set_eq:NN \__tag_hook_kernel_before_foot: \prg_do_nothing: \cs_set_eq:NN \__tag_hook_kernel_after_head: \prg_do_nothing: \cs_set_eq:NN \__tag_hook_kernel_after_foot: \prg_do_nothing: }, exclude-header-footer .default:n = true, exclude-header-footer .initial:n = true } \hook_gput_code:nnn {pdfannot/link/URI/before} {tagpdf} { \tag_mc_end_push: \tag_struct_begin:n { tag=Link } \tag_mc_begin:n { tag=Link } \pdfannot_dict_put:nnx { link/URI } { StructParent } { \tag_struct_parent_int: } } \hook_gput_code:nnn {pdfannot/link/URI/after} {tagpdf} { \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } \hook_gput_code:nnn {pdfannot/link/GoTo/before} {tagpdf} { \tag_mc_end_push: \tag_struct_begin:n{tag=Link} \tag_mc_begin:n{tag=Link} \pdfannot_dict_put:nnx { link/GoTo } { StructParent } { \tag_struct_parent_int: } } \hook_gput_code:nnn {pdfannot/link/GoTo/after} {tagpdf} { \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } \pdfannot_dict_put:nnn { link/URI } { Contents } { (url) } \pdfannot_dict_put:nnn { link/GoTo } { Contents } { (ref) } %% %% %% End of file `tagpdf.sty'.