2020-06-07 03:22:07 +02:00
|
|
|
local function add_outline(outline, title, action, level, open, attr)
|
|
|
|
local entry = {title = title, action = action, attr = attr, open = open, level = level}
|
|
|
|
-- Now find the right nesting level. We have to deal with non-continuous
|
|
|
|
-- levels, so we search the last entry which still had a smaller level
|
|
|
|
-- and append under that
|
|
|
|
local parent
|
|
|
|
repeat
|
|
|
|
parent = outline
|
|
|
|
outline = outline[#outline]
|
|
|
|
until not outline or outline.level >= level
|
|
|
|
parent[#parent + 1] = entry
|
|
|
|
end
|
2020-06-07 13:10:33 +02:00
|
|
|
local function add_legacy(outline, title, action, count, attr)
|
|
|
|
local state = outline.legacy
|
|
|
|
if not state then
|
|
|
|
state = {}
|
|
|
|
outline.legacy = state
|
|
|
|
end
|
|
|
|
local level = #state
|
|
|
|
if level ~= 0 then
|
|
|
|
state[level] = state[level] - 1
|
|
|
|
end
|
|
|
|
local open
|
|
|
|
if count and count ~= 0 then
|
|
|
|
open = count > 0
|
|
|
|
if not open then
|
|
|
|
count = -count
|
|
|
|
end
|
|
|
|
state[level+1] = count
|
|
|
|
else
|
|
|
|
open = false -- Doesn't matter without children
|
|
|
|
while state[#state] == 0 do
|
|
|
|
state[#state] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return outline:add(title, action, level, open, attr)
|
|
|
|
end
|
2020-06-07 03:22:07 +02:00
|
|
|
local function assign_objnum(pdf, outline)
|
|
|
|
local objnum = pdf:getobj()
|
|
|
|
outline.objnum = objnum
|
|
|
|
local cur
|
|
|
|
for i=1,#outline do
|
|
|
|
local prev = cur
|
|
|
|
cur = outline[i]
|
|
|
|
cur.parent = objnum
|
|
|
|
assign_objnum(pdf, cur)
|
|
|
|
if prev then
|
|
|
|
cur.prev = prev.objnum
|
|
|
|
prev.next = cur.objnum
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if outline[1] then
|
|
|
|
outline.first, outline.last = outline[1].objnum, outline[#outline].objnum
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local function get_count(pdf, outline)
|
|
|
|
local count = 0
|
|
|
|
for i=1,#outline do
|
|
|
|
local child = outline[i]
|
|
|
|
local sub = get_count(pdf, child)
|
|
|
|
local open = child.open
|
|
|
|
child.count = sub ~= 0 and (open and sub or -sub) or nil
|
|
|
|
count = count + 1 + (open and sub or 0)
|
|
|
|
end
|
|
|
|
return count
|
|
|
|
end
|
|
|
|
local function write_objects(pdf, outline)
|
|
|
|
local content = "<<"
|
|
|
|
local title = outline.title
|
|
|
|
if title then
|
|
|
|
content = string.format("%s/Title%s", content, title)
|
|
|
|
end
|
|
|
|
local parent = outline.parent
|
|
|
|
if parent then
|
|
|
|
content = string.format("%s/Parent %i 0 R", content, parent)
|
|
|
|
end
|
|
|
|
local prev = outline.prev
|
|
|
|
if prev then
|
|
|
|
content = string.format("%s/Prev %i 0 R", content, prev)
|
|
|
|
end
|
|
|
|
local next = outline.next
|
|
|
|
if next then
|
|
|
|
content = string.format("%s/Next %i 0 R", content, next)
|
|
|
|
end
|
|
|
|
local first = outline.first
|
|
|
|
if first then
|
|
|
|
content = string.format("%s/First %i 0 R", content, first)
|
|
|
|
end
|
|
|
|
local last = outline.last
|
|
|
|
if last then
|
|
|
|
content = string.format("%s/Last %i 0 R", content, last)
|
|
|
|
end
|
|
|
|
local action = outline.action
|
|
|
|
if action then
|
|
|
|
content = string.format("%s/A %i 0 R", content, action)
|
|
|
|
end
|
|
|
|
local count = outline.count
|
|
|
|
if count then
|
|
|
|
content = string.format("%s/Count %i", content, count)
|
|
|
|
end
|
|
|
|
content = content .. (outline.attr or '') .. ">>"
|
|
|
|
pdf:indirect(outline.objnum, content)
|
|
|
|
for i=1,#outline do
|
|
|
|
write_objects(pdf, outline[i])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local function write_outline(outline, pdf)
|
|
|
|
assign_objnum(pdf, outline)
|
|
|
|
local count = get_count(pdf, outline)
|
|
|
|
outline.count = count == #outline and count or nil
|
|
|
|
write_objects(pdf, outline)
|
|
|
|
return outline.objnum
|
|
|
|
end
|
|
|
|
local meta = {__index = {
|
|
|
|
write = write_outline,
|
|
|
|
add = add_outline,
|
2020-06-07 13:10:33 +02:00
|
|
|
add_legacy = add_legacy,
|
2020-06-07 03:22:07 +02:00
|
|
|
}}
|
|
|
|
return function()
|
|
|
|
return setmetatable({}, meta)
|
|
|
|
end
|