-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
init.lua
158 lines (143 loc) · 5.17 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
local base = require("packages.base")
local package = pl.class(base)
package._name = "pdfstructure"
local pdf
local stPointer
local mcid = 0
local actualtext = {}
local structureNumberTree
local numberTreeIndex = 0
local function stNode (notetype)
return {
notetype = notetype,
lang = SILE.settings:get("document.language"),
kids = {},
parent = stPointer
}
end
local function addChild (node)
stPointer.kids[#(stPointer.kids)+1] = node
node.parent = stPointer
end
local function ensureStructureNumber (node, pdfnode)
local p = node.page
if not pdf.lookup_dictionary(p, "StructParents") then
pdf.add_dict(p, pdf.parse("/StructParents"), pdf.parse(numberTreeIndex))
local nums = pdf.lookup_dictionary(structureNumberTree, "Nums")
pdf.push_array(nums, pdf.parse(numberTreeIndex))
pdf.push_array(nums, pdf.parse("[]"))
numberTreeIndex = numberTreeIndex + 1
end
local nums = pdf.lookup_dictionary(structureNumberTree, "Nums")
-- This is an array and its last element is an array
local r = pdf.get_array(nums, pdf.array_length(nums)-1)
pdf.push_array(r, pdf.reference(pdfnode))
end
local function dumpTree (node)
local k = {}
local pdfNode = pdf.parse("<< /Type /StructElem /S /"..(node.notetype)..">>")
if #(node.kids) > 0 then
for i = 1, #(node.kids) do
k[#k+1] = dumpTree(node.kids[i])
end
local kArray = pdf.parse("[]")
for i = 1, #k do pdf.push_array(kArray, k[i]) end
pdf.add_dict(pdfNode, pdf.parse("/K"), kArray)
else
pdf.add_dict(pdfNode, pdf.parse("/K"), pdf.parse(node.mcid))
end
if node.page then
pdf.add_dict(pdfNode, pdf.parse("/Pg"), pdf.reference(node.page))
ensureStructureNumber(node, pdfNode)
end
if node.lang then
pdf.add_dict(pdfNode, pdf.parse("/Lang"), pdf.parse("("..node.lang:upper()..")"))
end
if node.actualtext then
pdf.add_dict(pdfNode, pdf.parse("/ActualText"), pdf.string(node.actualtext))
end
local ref = pdf.reference(pdfNode)
pdf.release(pdfNode)
return ref
end
function package:_init ()
base._init(self)
pdf = require("justenoughlibtexpdf")
local _typeset = SILE.typesetter.typeset
SILE.typesetter.typeset = function (node, text)
actualtext[#actualtext] = tostring(actualtext[#actualtext]) .. text
_typeset(node, text)
end
local stRoot = stNode("Document")
stPointer = stRoot
self:loadPackage("pdf")
SILE.outputter:registerHook("prefinish", function()
local catalog = pdf.get_dictionary("Catalog")
local structureTree = pdf.parse("<< /Type /StructTreeRoot >>")
pdf.add_dict(catalog, pdf.parse("/StructTreeRoot"), pdf.reference(structureTree))
structureNumberTree = pdf.parse("<< /Nums [] >>")
pdf.add_dict(structureTree, pdf.parse("/ParentTree"), pdf.reference(structureNumberTree))
pdf.add_dict(structureTree, pdf.parse("/K"), dumpTree(stRoot))
if structureNumberTree then pdf.release(structureNumberTree) end
if structureTree then pdf.release(structureTree) end
end)
end
function package:registerCommands ()
self:registerCommand("pdf:structure", function (options, content)
local notetype = SU.required(options, "type", "pdf structure")
local node = stNode(notetype)
addChild(node)
node.lang = SILE.settings:get("document.language")
if type(SILE.outputter._ensureInit) == "function" then
SILE.outputter:_ensureInit()
end
node.page = pdf.get_dictionary("@THISPAGE")
node.mcid = mcid
local oldstPointer = stPointer
stPointer = node
actualtext[#actualtext+1] = ""
if not options.block then
SILE.call("pdf:literal", {}, {"/"..notetype.." <</MCID "..mcid.." >>BDC"})
mcid = mcid + 1
SILE.process(content)
SILE.call("pdf:literal", {}, {"EMC"})
else
SILE.process(content)
end
stPointer.actualtext = actualtext[#actualtext]
actualtext[#actualtext] = nil
stPointer = oldstPointer
end)
self:registerCommand("pdf:literal", function (_, content)
-- NOTE: This method is used by the pdfstructure package and should
-- probably be moved elsewhere, so there's no attempt here to delegate
-- the low-level libtexpdf call to te outputter.
if SILE.outputter._name ~= "libtexpdf" then
SU.error("pdf package requires libtexpdf backend")
end
SILE.typesetter:pushHbox({
value = nil,
height = SILE.measurement(0),
width = SILE.measurement(0),
depth = SILE.measurement(0),
outputYourself = function (_, _, _)
SILE.outputter:drawRaw (content[1])
end
})
end)
end
package.documentation = [[
\begin{document}
\use[module=packages.pdfstructure]
\pdf:structure[type=P]{%
For PDF documents to be considered accessible, they must contain a description of the PDF’s document structure.
This package allows structure trees to be created and saved to the PDF file.
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.
}
\pdf:structure[type=P]{%
See \code{tests/pdf.sil} for an example of using the \autodoc:package{pdfstructure} package to create a PDF/UA compatible document.
}
\end{document}
]]
return package