% \iffalse meta-comment % %% File: tagpdf-tree.dtx % % Copyright (C) 2019-2020 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. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/u-fischer/tagpdf % % for those people who are interested. % % \fi % % \begin{macrocode} %<@@=tag> %<*tree> \ProvidesExplPackage {tagpdf-tree-code} {2021/05/14} {0.81} {part of tagpdf - code related to writing trees and dictionaries to the pdf} %this does the actual finishing: %Is \AddToHook{enddocument/end} the best places?? \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT \g_@@_active_tree_bool { \sys_if_output_pdf:TF { \AddToHook{enddocument/end} { \tag_finish_structure: } } { \AddToHook{shipout/lastpage} { \tag_finish_structure: } } } } % the StructTreeRoot % we better get the object number in any case: % deprecated %\@@_pdfreserveobjnum:N \l_tmpa_tl %\tl_const:Nx \c_@@_tree_obj_structtreeroot_tl { \l_tmpa_tl } %new \pdf_object_new:nn { @@/struct/0 }{ dict } %need to think about the best place ... \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT \g_@@_active_struct_bool { \pdfmanagement_add:nnx { Catalog } { StructTreeRoot } { \pdf_object_ref:n { @@/struct/0 } } } } \cs_new_protected:Nn \@@_tree_write_structtreeroot: { \@@_struct_write_obj:n { 0 } } \cs_new_protected:Nn \@@_tree_write_structelements: { \int_step_inline:nnnn {1}{1}{\c@g_@@_struct_abs_int} { %\prop_show:c {g_@@_struct_##1_prop} \@@_struct_write_obj:n { ##1 } %write the object } } %the ParentTree % deprecated %\@@_pdfreserveobjnum:N \l_tmpa_tl %\tl_const:Nx \c_@@_tree_obj_parenttree_tl { \l_tmpa_tl } %new \pdf_object_new:nn { @@/tree/parenttree }{ dict } % 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_@@_parenttree_obj_int } \hook_gput_code:nnn{begindocument}{tagpdf} { \int_gset:Nn \c@g_@@_parenttree_obj_int { \@@_ref_value_lastpage:nn{abspage}{100} } } % we need to record the obj references: \tl_new:N \g_@@_parenttree_objr_tl \cs_new_protected:Nn \@@_parenttree_add_objr:nn %#1 Structparent number, #2 objref { \tl_gput_right:Nx \g_@@_parenttree_objr_tl { #1 \c_space_tl #2 ^^J } } \tl_new:N \l_@@_parenttree_content_tl \cs_new_protected:Nn \@@_tree_fill_parenttree: { \int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{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}{\@@_ref_value_lastpage:nn{tagmcabs}{-1}} { %mcid####1 \int_compare:nT%F {\@@_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page {% yes\par \prop_put:Nxx \l_tmpa_prop {\@@_ref_value:enn{mcid-####1}{tagmcid}{-1}} {\prop_item:Nn \g_@@_mc_parenttree_prop {####1}} } } %\prop_show:N \l_tmpa_prop \tl_put_right:Nx\l_@@_parenttree_content_tl { \int_eval:n {##1-1}\c_space_tl [\c_space_tl %] } \int_step_inline:nnnn {0} {1} { \prop_map_function:NN \l_tmpa_prop\@@_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_@@_parenttree_content_tl { \prop_item:cn { g_@@_struct_\l_tmpb_tl _prop } {objref} \c_space_tl } %\tl_show:N \l_@@_parenttree_content_tl } { \msg_warning:nn { tag } {tree-mcid-index-wrong} } } \tl_put_right:Nn \l_@@_parenttree_content_tl {%[ ]^^J } } } %lua mode must/can do it differently \cs_new_protected:Nn \@@_tree_lua_fill_parenttree: { \tl_set:Nn \l_@@_parenttree_content_tl { \directlua { ltx.@@.func.output_parenttree ( \int_use:N\g_shipout_readonly_int ) } } } \cs_new_protected:Nn \@@_tree_write_parenttree: { \bool_if:NTF \g_@@_mode_lua_bool { \@@_tree_lua_fill_parenttree: } { \@@_tree_fill_parenttree: } \tl_put_right:NV \l_@@_parenttree_content_tl\g_@@_parenttree_objr_tl \pdf_object_write:nx { @@/tree/parenttree } { /Nums\c_space_tl [\l_@@_parenttree_content_tl] } } %the Rolemap tree \pdf_object_new:nn { @@/tree/rolemap }{ dict } \cs_new_protected:Nn \@@_tree_write_rolemap: { \pdf_object_write:nx { @@/tree/rolemap } { \pdfdict_use:n{g_@@_role/RoleMap_dict} } } %classmap, should only be written, if values has been used \cs_new_protected:Nn \@@_tree_write_classmap: { \tl_gclear:N \g_@@_attr_class_content_tl \seq_gremove_duplicates:N \g_@@_attr_class_used_seq \seq_set_map:NNn \l_tmpa_seq \g_@@_attr_class_used_seq { /##1\c_space_tl << \prop_item:Nn \g_@@_attr_entries_prop {##1} >> } \tl_gset:Nx \g_@@_attr_class_content_tl { \seq_use:Nn \l_tmpa_seq { \iow_newline: } } \tl_if_empty:NF \g_@@_attr_class_content_tl { \pdf_object_new:nn { @@/tree/classmap }{ dict } % \@@_pdfreserveobjnum:N \l_tmpa_tl % \tl_const:Nx \c_@@_tree_obj_classmap_tl { \l_tmpa_tl } \pdf_object_write:nx { @@/tree/classmap } { \g_@@_attr_class_content_tl } \@@_prop_gput:cnx { g_@@_struct_0_prop } { ClassMap } { \pdf_object_ref:n { @@/tree/classmap } } } } % namespaces are only relevant for pdf2.0 but we don't care \pdf_object_new:nn{ @@/tree/namespaces }{array} \cs_new_protected:Npn \@@_tree_write_namespaces: { \prop_map_inline:Nn \g_@@_role_NS_prop { \pdfdict_if_empty:nF {g_@@_role/RoleMapNS_##1_dict} { \pdf_object_write:nx {@@/RoleMapNS/##1} { \pdfdict_use:n {g_@@_role/RoleMapNS_##1_dict} } \pdfdict_gput:nnx{g_@@_role/Namespace_##1_dict} {RoleMapNS}{\pdf_object_ref:n {@@/RoleMapNS/##1}} } \pdf_object_write:nx{tag/NS/##1} { \pdfdict_use:n {g_@@_role/Namespace_##1_dict} } } \pdf_object_write:nx {@@/tree/namespaces} { \prop_map_tokens:Nn \g_@@_role_NS_prop{\use_ii:nn} } } \cs_new_protected:Nn \tag_finish_structure: { \@@_tree_write_parenttree: \@@_tree_write_rolemap: \@@_tree_write_classmap: \@@_tree_write_namespaces: \@@_tree_write_structelements: %this is rather slow!! \@@_tree_write_structtreeroot: } %StructParents !!! we need a better hook for \g__pdf_BACKEND_thispage_shipout_tl!! % No actually \hook_gput_code:nnn{begindocument}{tagpdf} { \bool_if:NT\g_@@_active_tree_bool { \hook_gput_code:nnn{shipout/before} { tagpdf/structparents } { \pdfmanagement_add:nnx { Page } {StructParents} {\int_eval:n { \g_shipout_readonly_int}} } } } % % \end{macrocode}