diff --git a/luametalatex-back-pdf.lua b/luametalatex-back-pdf.lua index dff1b64..49c1e0e 100644 --- a/luametalatex-back-pdf.lua +++ b/luametalatex-back-pdf.lua @@ -57,6 +57,7 @@ end, 'force', 'protected') local infodir = "" local namesdir = "" 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 function write_infodir(p) local additional = "" @@ -118,6 +119,9 @@ callback.register("stop_run", function() if outline then catalogdir = string.format("/Outlines %i 0 R%s", outline:write(pfile), catalogdir) end + if catalog_openaction then + catalogdir = catalogdir .. '/OpenAction' .. catalog_openaction + end pfile:indirect(pfile.root, string.format([[<>]], pfile.version, pfile:writepages(), catalogdir)) pfile.info = write_infodir(pfile) local size = pfile:close() @@ -198,19 +202,30 @@ local function get_action_attr(p, action, is_link) error[[FIXME]] elseif action_type == 1 then -- GoTo local id = action.id - if file then - assert(type(id) == "string") - action_attr = action_attr .. "/S/GoToR/D" .. pdf_bytestring(id) .. ">>" - else - 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) .. ">>" + if id then + if file then + assert(type(id) == "string") + action_attr = action_attr .. "/S/GoToR/D" .. pdf_bytestring(id) .. ">>" 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 @@ -486,9 +501,15 @@ local function scan_action() file = token.scan_keyword'file' and token.scan_string(), } 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 - if action.file and action_type == 3 then + if action.file and action_type == 1 then error[[num style GoTo actions must be internal]] end action.id = token.scan_int() @@ -585,6 +606,15 @@ token.luacmd("pdfextension", function(_, imm) infodir = infodir .. token.scan_string() elseif token.scan_keyword"catalog" then 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 namesdir = namesdir .. ' ' .. token.scan_string() elseif token.scan_keyword"obj" then diff --git a/luametalatex-pdf-pagetree.lua b/luametalatex-pdf-pagetree.lua index 277fc3f..8a06381 100644 --- a/luametalatex-pdf-pagetree.lua +++ b/luametalatex-pdf-pagetree.lua @@ -35,15 +35,31 @@ local function write(pdf, tree, total, max) return newtree[1] end local function newpage(pdf) - local pageid = pdf:getobj() - local pagenumber = #pdf.pages - pdf.pages[pagenumber+1] = pageid - if 0 == pagenumber % 6 then - pdf.pages[-(pagenumber//6)] = pdf:getobj() + local pages = pdf.pages + local pagenumber = #pages+1 + local pageid = pages.reserved and pages.reserved[pagenumber] or pdf:getobj() + pages.reserved[pagenumber] = nil + pages[pagenumber] = pageid + if 1 == pagenumber % 6 then + pages[-((pagenumber-1)//6)] = pdf:getobj() 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 return { write = write, newpage = newpage, + reservepage = reservepage, } diff --git a/luametalatex-pdf.lua b/luametalatex-pdf.lua index 3741637..d9b2b2b 100644 --- a/luametalatex-pdf.lua +++ b/luametalatex-pdf.lua @@ -134,6 +134,7 @@ local pdfmeta = { indirect = indirect, stream = stream, newpage = pagetree.newpage, + reservepage = pagetree.reservepage, writepages = pagetree.write, delayed = delay, delayedstream = delayedstream,