\ProvidesExplPackage {tagpdf-tree-code} {2019/07/02} {0.61} {part of tagpdf - code related to writing trees and dictionaries to the pdf} %this does the actual finishing: \AtBeginDocument { \bool_if:NT \g_uftag_active_tree_bool { \AfterEndDocument { \uftag_finish_structure: } } } % the StructTreeRoot % we better get the object number in any case: \__uftag_pdfreserveobjnum:N \l_tmpa_tl \tl_const:Nx \c_uftag_tree_obj_structtreeroot_tl { \l_tmpa_tl } \cs_new:Nn \__uftag_tree_write_structtreeroot: { \__uftag_pdfcatalog:n { /StructTreeRoot~\c_uftag_tree_obj_structtreeroot_tl\c_space_tl0~R } \__uftag_struct_write_obj:n { 0 } } \cs_new:Nn \__uftag_tree_write_structelements: { \int_step_inline:nnnn {1}{1}{\c@g__uftag_struct_abs_int} { %\prop_show:c {g__uftag_struct_##1_prop} \__uftag_struct_write_obj:n { ##1 } %write the object } } %the ParentTree \__uftag_pdfreserveobjnum:N \l_tmpa_tl \tl_const:Nx \c__uftag_tree_obj_parenttree_tl { \l_tmpa_tl } % we have two sets of entries in the parent tree: % page streams and real objects. % The numbers must be distinct and ordered % So we rely on abspage and put the real objects at the end % I use a counter to have a chance to get the correct number % if code is process twice. \newcounter { g__uftag_parenttree_obj_int } \AtBeginDocument { \int_gset:Nn \c@g__uftag_parenttree_obj_int { \zref@extractdefault{LastPage}{abspage}{100} } } % we need to record the obj references: \tl_new:N \g__uftag_parenttree_objr_tl \cs_new:Nn \__uftag_parenttree_add_objr:nn %#1 Structparent number, #2 obj number { \tl_gput_right:Nx \g__uftag_parenttree_objr_tl { #1 \c_space_tl #2\c_space_tl 0 \c_space_tl R\c_space_tl ^^J } } \tl_new:N \l__uftag_parenttree_content_tl \cs_new:Nn \__uftag_tree_fill_parenttree: { \int_step_inline:nnnn{1}{1}{\zref@extractdefault{LastPage}{abspage}{-1}} %not quite clear if labels are needed. See lua code { %page ##1\par \prop_clear:N \l_tmpa_prop \int_step_inline:nnnn{1}{1}{\zref@extractdefault{LastPage}{tagmcabs}{-1}} { %mcid####1 \int_compare:nT%F {\zref@extractdefault{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page {% yes\par \prop_put:Nxx \l_tmpa_prop {\zref@extractdefault{mcid-####1}{tagmcid}{-1}} {\prop_item:Nn \g__uftag_mc_parenttree_prop {####1}} } } %\prop_show:N \l_tmpa_prop \tl_put_right:Nx\l__uftag_parenttree_content_tl {\int_eval:n {##1-1}\c_space_tl[\c_space_tl} %%brackt \int_step_inline:nnnn {0}{1}{ \prop_map_function:NN \l_tmpa_prop\__uftag_prop_count:nn -1 } { \prop_get:NnNTF \l_tmpa_prop {####1} \l_tmpb_tl {% page#1:mcid##1:\l_tmpb_tl :content \tl_put_right:Nx \l__uftag_parenttree_content_tl { \prop_item:cn { g__uftag_struct_\l_tmpb_tl _prop } {objnum}~0~R~ } } {\msg_warning:nn {uftag} {tree-mcid-index-wrong} } } \tl_put_right:Nn \l__uftag_parenttree_content_tl {]^^J} % } } %lua mode must/can do it differently \cs_new:Nn \__uftag_tree_lua_fill_parenttree: { \tl_set:Nn \l__uftag_parenttree_content_tl { \directlua{uftag.func.output_parenttree(\int_use:N\g__uftag_abspage_int)} } } \cs_new:Nn \__uftag_tree_write_parenttree: { \bool_if:NTF \g__uftag_mode_lua_bool { \__uftag_tree_lua_fill_parenttree: } { \__uftag_tree_fill_parenttree: } \tl_put_right:NV \l__uftag_parenttree_content_tl\g__uftag_parenttree_objr_tl \__uftag_pdfuseobjnum:xx { \c__uftag_tree_obj_parenttree_tl } { <<\c_space_tl/Nums\c_space_tl [\l__uftag_parenttree_content_tl] \c_space_tl >> } } %the Rolemap tree \__uftag_pdfreserveobjnum:N \l_tmpa_tl \tl_const:Nx \c__uftag_tree_obj_rolemap_tl { \l_tmpa_tl } \tl_new:N \l__uftag_rolemap_content_tl \cs_new:Nn \__uftag_tree_fill_rolemap: { \prop_map_inline:Nn \g__uftag_role_rolemap_prop { \tl_put_right:Nx \l__uftag_rolemap_content_tl { /##1\c_space_tl/##2^^J } } } \cs_new:Nn \__uftag_tree_write_rolemap: { \__uftag_tree_fill_rolemap: \__uftag_pdfuseobjnum:xx { \c__uftag_tree_obj_rolemap_tl } { <<\l__uftag_rolemap_content_tl >> } } %classmap, should only be written, if values has been used \cs_new_protected:Nn \__uftag_tree_class_write_map: { \tl_gclear:N \g__uftag_attr_class_content_tl \seq_gremove_duplicates:N \g__uftag_attr_class_used_seq \seq_set_map:NNn \l_tmpa_seq \g__uftag_attr_class_used_seq { /##1\c_space_tl \prop_item:Nn \g__uftag_attr_entries_prop {##1} } \tl_gset:Nx \g__uftag_attr_class_content_tl { \seq_use:Nn \l_tmpa_seq { \iow_newline: } } \tl_if_empty:NF \g__uftag_attr_class_content_tl { \__uftag_pdfreserveobjnum:N \l_tmpa_tl \tl_const:Nx \c__uftag_tree_obj_classmap_tl { \l_tmpa_tl } \__uftag_pdfuseobjnum:Nx \c__uftag_tree_obj_classmap_tl { <<\g__uftag_attr_class_content_tl>> } \__uftag_prop_gput:cnx { g__uftag_struct_0_prop } { ClassMap } { \c__uftag_tree_obj_classmap_tl\c_space_tl0\c_space_tl R } } } \cs_new:Nn \uftag_finish_structure: { \__uftag_pdfcatalog:n {^^J/MarkInfo\c_space_tl<> } \__uftag_tree_write_parenttree: \__uftag_tree_write_rolemap: \__uftag_tree_class_write_map: \__uftag_tree_write_structelements: \__uftag_tree_write_structtreeroot: } %StructParents + tabs order. Tabs order should be probably be changeable by page. \cs_new:Nn \__uftag_tree_write_pageattr: { \__uftag_get_pdfpageattr:N \l_tmpa_tl \regex_replace_once:nnN {/StructParents\s*\d+} {}\l_tmpa_tl \regex_replace_once:nnN {/Tabs\s*/[SCR]} {}\l_tmpa_tl \__uftag_gset_pdfpageattr:x { \l_tmpa_tl / StructParents \c_space_tl \int_eval:n { \g__uftag_abspage_int } \l__uftag_tree_tabs_order_tl } } \endinput