\pdfcatalog openaction and page actions

This commit is contained in:
Marcel Krüger 2020-07-02 11:02:38 +02:00
parent f6895d8b50
commit b8dbb5a4c8
3 changed files with 67 additions and 20 deletions

View File

@ -57,6 +57,7 @@ end, 'force', 'protected')
local infodir = "" local infodir = ""
local namesdir = "" local namesdir = ""
local catalogdir = "" local catalogdir = ""
local catalog_openaction
local creationdate = os.date("D:%Y%m%d%H%M%S%z"):gsub("+0000$", "Z"):gsub("%d%d$", "'%0") local creationdate = os.date("D:%Y%m%d%H%M%S%z"):gsub("+0000$", "Z"):gsub("%d%d$", "'%0")
local function write_infodir(p) local function write_infodir(p)
local additional = "" local additional = ""
@ -118,6 +119,9 @@ callback.register("stop_run", function()
if outline then if outline then
catalogdir = string.format("/Outlines %i 0 R%s", outline:write(pfile), catalogdir) catalogdir = string.format("/Outlines %i 0 R%s", outline:write(pfile), catalogdir)
end end
if catalog_openaction then
catalogdir = catalogdir .. '/OpenAction' .. catalog_openaction
end
pfile:indirect(pfile.root, string.format([[<</Type/Catalog/Version/%s/Pages %i 0 R%s>>]], pfile.version, pfile:writepages(), catalogdir)) pfile:indirect(pfile.root, string.format([[<</Type/Catalog/Version/%s/Pages %i 0 R%s>>]], pfile.version, pfile:writepages(), catalogdir))
pfile.info = write_infodir(pfile) pfile.info = write_infodir(pfile)
local size = pfile:close() local size = pfile:close()
@ -198,19 +202,30 @@ local function get_action_attr(p, action, is_link)
error[[FIXME]] error[[FIXME]]
elseif action_type == 1 then -- GoTo elseif action_type == 1 then -- GoTo
local id = action.id local id = action.id
if file then if id then
assert(type(id) == "string") if file then
action_attr = action_attr .. "/S/GoToR/D" .. pdf_bytestring(id) .. ">>" assert(type(id) == "string")
else action_attr = action_attr .. "/S/GoToR/D" .. pdf_bytestring(id) .. ">>"
local dest = dests[id]
if not dest then
dest = pfile:getobj()
dests[id] = dest
end
if type(id) == "string" then
action_attr = action_attr .. "/S/GoTo/D" .. pdf_bytestring(id) .. ">>"
else else
action_attr = string.format("%s/S/GoTo/D %i 0 R>>", action_attr, dest) local dest = dests[id]
if not dest then
dest = pfile:getobj()
dests[id] = dest
end
if type(id) == "string" then
action_attr = action_attr .. "/S/GoTo/D" .. pdf_bytestring(id) .. ">>"
else
action_attr = string.format("%s/S/GoTo/D %i 0 R>>", action_attr, dest)
end
end
else
id = assert(action.page, 'GoTo action must contain either an id or a page')
local tokens = action.tokens
if file then
action_attr = string.format("%s/S/GoToR/D[%i %s]>>", action_attr, id-1, tokens)
else
local page_objnum = pfile:reservepage(id)
action_attr = string.format("%s/S/GoTo/D[%i 0 R %s]>>", action_attr, page_objnum, tokens)
end end
end end
end end
@ -486,9 +501,15 @@ local function scan_action()
file = token.scan_keyword'file' and token.scan_string(), file = token.scan_keyword'file' and token.scan_string(),
} }
if token.scan_keyword'page' then if token.scan_keyword'page' then
error[[TODO]] assert(action_type == 1)
local page = token.scan_int()
if page <= 0 then
error[[page must be positive in action specified]]
end
action.page = page
action.tokens = token.scan_string()
elseif token.scan_keyword'num' then elseif token.scan_keyword'num' then
if action.file and action_type == 3 then if action.file and action_type == 1 then
error[[num style GoTo actions must be internal]] error[[num style GoTo actions must be internal]]
end end
action.id = token.scan_int() action.id = token.scan_int()
@ -585,6 +606,15 @@ token.luacmd("pdfextension", function(_, imm)
infodir = infodir .. token.scan_string() infodir = infodir .. token.scan_string()
elseif token.scan_keyword"catalog" then elseif token.scan_keyword"catalog" then
catalogdir = catalogdir .. ' ' .. token.scan_string() catalogdir = catalogdir .. ' ' .. token.scan_string()
if token.scan_keyword'openaction' then
if catalog_openaction then
tex.error("Duplicate openaction", {"Only one use of \\pdfextension catalog is allowed to \z
have an openaction."})
else
local action = scan_action()
catalog_openaction = get_action_attr(get_pfile(), action)
end
end
elseif token.scan_keyword"names" then elseif token.scan_keyword"names" then
namesdir = namesdir .. ' ' .. token.scan_string() namesdir = namesdir .. ' ' .. token.scan_string()
elseif token.scan_keyword"obj" then elseif token.scan_keyword"obj" then

View File

@ -35,15 +35,31 @@ local function write(pdf, tree, total, max)
return newtree[1] return newtree[1]
end end
local function newpage(pdf) local function newpage(pdf)
local pageid = pdf:getobj() local pages = pdf.pages
local pagenumber = #pdf.pages local pagenumber = #pages+1
pdf.pages[pagenumber+1] = pageid local pageid = pages.reserved and pages.reserved[pagenumber] or pdf:getobj()
if 0 == pagenumber % 6 then pages.reserved[pagenumber] = nil
pdf.pages[-(pagenumber//6)] = pdf:getobj() pages[pagenumber] = pageid
if 1 == pagenumber % 6 then
pages[-((pagenumber-1)//6)] = pdf:getobj()
end end
return pageid, pdf.pages[-(pagenumber//6)] return pageid, pages[-((pagenumber-1)//6)]
end
local function reservepage(pdf, num)
local pages = pdf.pages
if pages[num] then return pages[num] end
local reserved = pages.reserved
if reserved then
if reserved[num] then return reserved[num] end
else
reserved = {}
pages.reserved = reserved
end
reserved[num] = pdf:getobj()
return reserved[num]
end end
return { return {
write = write, write = write,
newpage = newpage, newpage = newpage,
reservepage = reservepage,
} }

View File

@ -134,6 +134,7 @@ local pdfmeta = {
indirect = indirect, indirect = indirect,
stream = stream, stream = stream,
newpage = pagetree.newpage, newpage = pagetree.newpage,
reservepage = pagetree.reservepage,
writepages = pagetree.write, writepages = pagetree.write,
delayed = delay, delayed = delay,
delayedstream = delayedstream, delayedstream = delayedstream,