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

sile-typesetter / sile / 6713098919

31 Oct 2023 10:21PM UTC coverage: 52.831% (-21.8%) from 74.636%
6713098919

push

github

web-flow
Merge d0a2a1ee9 into b185d4972

45 of 45 new or added lines in 3 files covered. (100.0%)

8173 of 15470 relevant lines covered (52.83%)

6562.28 hits per line

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

0.0
/packages/pdfstructure/init.lua
1
local base = require("packages.base")
×
2

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

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

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

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

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

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

63
  if node.actualtext then
×
64
    pdf.add_dict(pdfNode, pdf.parse("/ActualText"), pdf.string(node.actualtext))
×
65
  end
66
  local ref = pdf.reference(pdfNode)
×
67
  pdf.release(pdfNode)
×
68
  return ref
×
69
end
70

71
function package:_init ()
×
72
  base._init(self)
×
73
  pdf = require("justenoughlibtexpdf")
×
74
  local _typeset = SILE.typesetter.typeset
×
75
  SILE.typesetter.typeset = function (node, text)
×
76
    actualtext[#actualtext] = tostring(actualtext[#actualtext]) .. text
×
77
    _typeset(node, text)
×
78
  end
79
  local stRoot = stNode("Document")
×
80
  stPointer = stRoot
×
81
  self:loadPackage("pdf")
×
82
  function SILE.outputters.libtexpdf._endHook (_)
×
83
    local catalog = pdf.get_dictionary("Catalog")
×
84
    local structureTree = pdf.parse("<< /Type /StructTreeRoot >>")
×
85
    pdf.add_dict(catalog, pdf.parse("/StructTreeRoot"), pdf.reference(structureTree))
×
86
    structureNumberTree = pdf.parse("<< /Nums [] >>")
×
87
    pdf.add_dict(structureTree, pdf.parse("/ParentTree"), pdf.reference(structureNumberTree))
×
88
    pdf.add_dict(structureTree, pdf.parse("/K"), dumpTree(stRoot))
×
89
    if structureNumberTree then pdf.release(structureNumberTree) end
×
90
    if structureTree then pdf.release(structureTree) end
×
91
  end
92
end
93

94
function package:registerCommands ()
×
95

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

122
end
123

124
package.documentation = [[
125
\begin{document}
126
\use[module=packages.pdfstructure]
127
\pdf:structure[type=P]{%
128
For PDF documents to be considered accessible, they must contain a description of the PDF’s document structure.
129
This package allows structure trees to be created and saved to the PDF file.
130
Currently this provides a low-level interface to creating nodes in the tree; classes which require PDF accessibility should use the \autodoc:command{\pdf:structure} command in their sectioning implementation to declare the document structure.
131
}
132

133
\pdf:structure[type=P]{%
134
See \code{tests/pdf.sil} for an example of using the \autodoc:package{pdfstructure} package to create a PDF/UA compatible document.
135
}
136
\end{document}
137
]]
×
138

139
return package
×
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

© 2025 Coveralls, Inc