• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 9400953783

06 Jun 2024 12:32PM UTC coverage: 62.819% (-11.3%) from 74.124%
9400953783

push

github

alerque
Merge branch 'develop'

1752 of 2644 new or added lines in 109 files covered. (66.26%)

2019 existing lines in 84 files now uncovered.

10830 of 17240 relevant lines covered (62.82%)

3306.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.97
/packages/pdfstructure/init.lua
1
local base = require("packages.base")
1✔
2

3
local package = pl.class(base)
1✔
4
package._name = "pdfstructure"
1✔
5

6
local pdf
7
local stPointer
8
local mcid = 0
1✔
9
local actualtext = {}
1✔
10
local structureNumberTree
11
local numberTreeIndex = 0
1✔
12

13
local function stNode (notetype)
14
   return {
6✔
15
      notetype = notetype,
6✔
16
      lang = SILE.settings:get("document.language"),
12✔
17
      kids = {},
6✔
18
      parent = stPointer,
6✔
19
   }
6✔
20
end
21

22
local function addChild (node)
23
   stPointer.kids[#stPointer.kids + 1] = node
5✔
24
   node.parent = stPointer
5✔
25
end
26

27
local function ensureStructureNumber (node, pdfnode)
28
   local p = node.page
5✔
29
   if not pdf.lookup_dictionary(p, "StructParents") then
5✔
30
      pdf.add_dict(p, pdf.parse("/StructParents"), pdf.parse(numberTreeIndex))
1✔
31
      local nums = pdf.lookup_dictionary(structureNumberTree, "Nums")
1✔
32
      pdf.push_array(nums, pdf.parse(numberTreeIndex))
1✔
33
      pdf.push_array(nums, pdf.parse("[]"))
1✔
34
      numberTreeIndex = numberTreeIndex + 1
1✔
35
   end
36
   local nums = pdf.lookup_dictionary(structureNumberTree, "Nums")
5✔
37
   -- This is an array and its last element is an array
38
   local r = pdf.get_array(nums, pdf.array_length(nums) - 1)
5✔
39
   pdf.push_array(r, pdf.reference(pdfnode))
5✔
40
end
41

42
local function dumpTree (node)
43
   local k = {}
6✔
44
   local pdfNode = pdf.parse("<< /Type /StructElem /S /" .. node.notetype .. ">>")
6✔
45
   if #node.kids > 0 then
6✔
46
      for i = 1, #node.kids do
8✔
47
         k[#k + 1] = dumpTree(node.kids[i])
10✔
48
      end
49
      local kArray = pdf.parse("[]")
3✔
50
      for i = 1, #k do
8✔
51
         pdf.push_array(kArray, k[i])
5✔
52
      end
53
      pdf.add_dict(pdfNode, pdf.parse("/K"), kArray)
3✔
54
   else
55
      pdf.add_dict(pdfNode, pdf.parse("/K"), pdf.parse(node.mcid))
3✔
56
   end
57
   if node.page then
6✔
58
      pdf.add_dict(pdfNode, pdf.parse("/Pg"), pdf.reference(node.page))
5✔
59
      ensureStructureNumber(node, pdfNode)
5✔
60
   end
61
   if node.lang then
6✔
62
      pdf.add_dict(pdfNode, pdf.parse("/Lang"), pdf.parse("(" .. node.lang:upper() .. ")"))
12✔
63
   end
64

65
   if node.actualtext then
6✔
66
      pdf.add_dict(pdfNode, pdf.parse("/ActualText"), pdf.string(node.actualtext))
5✔
67
   end
68
   local ref = pdf.reference(pdfNode)
6✔
69
   pdf.release(pdfNode)
6✔
70
   return ref
6✔
71
end
72

73
function package:_init ()
1✔
74
   base._init(self)
1✔
75
   pdf = require("justenoughlibtexpdf")
1✔
76
   local _typeset = SILE.typesetter.typeset
1✔
77
   SILE.typesetter.typeset = function (node, text)
1✔
78
      actualtext[#actualtext] = tostring(actualtext[#actualtext]) .. text
22✔
79
      _typeset(node, text)
22✔
80
   end
81
   local stRoot = stNode("Document")
1✔
82
   stPointer = stRoot
1✔
83
   self:loadPackage("pdf")
1✔
84
   SILE.outputter:registerHook("prefinish", function ()
2✔
85
      local catalog = pdf.get_dictionary("Catalog")
1✔
86
      local structureTree = pdf.parse("<< /Type /StructTreeRoot >>")
1✔
87
      pdf.add_dict(catalog, pdf.parse("/StructTreeRoot"), pdf.reference(structureTree))
1✔
88
      structureNumberTree = pdf.parse("<< /Nums [] >>")
1✔
89
      pdf.add_dict(structureTree, pdf.parse("/ParentTree"), pdf.reference(structureNumberTree))
1✔
90
      pdf.add_dict(structureTree, pdf.parse("/K"), dumpTree(stRoot))
2✔
91
      if structureNumberTree then
1✔
92
         pdf.release(structureNumberTree)
1✔
93
      end
94
      if structureTree then
1✔
95
         pdf.release(structureTree)
1✔
96
      end
97
   end)
98
end
99

100
function package:registerCommands ()
1✔
101
   self:registerCommand("pdf:structure", function (options, content)
2✔
102
      local notetype = SU.required(options, "type", "pdf structure")
5✔
103
      local node = stNode(notetype)
5✔
104
      addChild(node)
5✔
105
      node.lang = SILE.settings:get("document.language")
10✔
106
      if type(SILE.outputter._ensureInit) == "function" then
5✔
107
         SILE.outputter:_ensureInit()
5✔
108
      end
109
      node.page = pdf.get_dictionary("@THISPAGE")
5✔
110
      node.mcid = mcid
5✔
111
      local oldstPointer = stPointer
5✔
112
      stPointer = node
5✔
113
      actualtext[#actualtext + 1] = ""
5✔
114
      if not options.block then
5✔
115
         SILE.call("pdf:literal", {}, { "/" .. notetype .. " <</MCID " .. mcid .. " >>BDC" })
3✔
116
         mcid = mcid + 1
3✔
117
         SILE.process(content)
3✔
118
         SILE.call("pdf:literal", {}, { "EMC" })
6✔
119
      else
120
         SILE.process(content)
2✔
121
      end
122
      stPointer.actualtext = actualtext[#actualtext]
5✔
123
      actualtext[#actualtext] = nil
5✔
124
      stPointer = oldstPointer
5✔
125
   end)
126

127
   self:registerCommand("pdf:literal", function (_, content)
2✔
128
      -- NOTE: This method is used by the pdfstructure package and should
129
      -- probably be moved elsewhere, so there's no attempt here to delegate
130
      -- the low-level libtexpdf call to te outputter.
131
      if SILE.outputter._name ~= "libtexpdf" then
6✔
NEW
132
         SU.error("pdf package requires libtexpdf backend")
×
133
      end
134
      SILE.typesetter:pushHbox({
12✔
135
         value = nil,
136
         height = SILE.types.measurement(0),
12✔
137
         width = SILE.types.measurement(0),
12✔
138
         depth = SILE.types.measurement(0),
12✔
139
         outputYourself = function (_, _, _)
140
            SILE.outputter:drawRaw(content[1])
6✔
141
         end,
142
      })
143
   end)
144
end
145

146
package.documentation = [[
147
\begin{document}
148
\use[module=packages.pdfstructure]
149
\pdf:structure[type=P]{%
150
For PDF documents to be considered accessible, they must contain a description of the PDF’s document structure.
151
This package allows structure trees to be created and saved to the PDF file.
152
Currently this provides a low-level interface to creating nodes in the tree;
153
   classes which require PDF accessibility should use the \autodoc:command{\pdf:structure} command in their sectioning implementation to declare the document structure.
154
}
155

156
\pdf:structure[type=P]{%
157
See \code{tests/pdf.sil} for an example of using the \autodoc:package{pdfstructure} package to create a PDF/UA compatible document.
158
}
159
\end{document}
160
]]
1✔
161

162
return package
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc