diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua | 783 |
1 files changed, 659 insertions, 124 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua index 89b2c6e0e59..570d738817f 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua @@ -6,49 +6,79 @@ if not modules then modules = { } end modules ['lpdf-epa'] = { license = "see context related readme files" } --- This is a rather experimental feature and the code will probably change. +-- Links can also have quadpoint -local type, tonumber = type, tonumber -local format, gsub, lower = string.format, string.gsub, string.lower +-- embedded files ... not bound to a page + +local type, tonumber, next = type, tonumber, next +local format, gsub, lower, find = string.format, string.gsub, string.lower, string.find local formatters = string.formatters +local concat, merged = table.concat, table.merged local abs = math.abs local expandname = file.expandname local allocate = utilities.storage.allocate +local bor, band = bit32.bor, bit32.band local isfile = lfs.isfile ------ lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns +local trace_links = false trackers.register("figures.links", function(v) trace_links = v end) +local trace_comments = false trackers.register("figures.comments", function(v) trace_comments = v end) +local trace_fields = false trackers.register("figures.fields", function(v) trace_fields = v end) +local trace_outlines = false trackers.register("figures.outlines", function(v) trace_outlines = v end) + +local report_link = logs.reporter("backend","link") +local report_comment = logs.reporter("backend","comment") +local report_field = logs.reporter("backend","field") +local report_outline = logs.reporter("backend","outline") + +local lpdf = lpdf +local epdf = epdf +local backends = backends +local context = context + +local nodeinjections = backends.pdf.nodeinjections + +local pdfarray = lpdf.array +local pdfdictionary = lpdf.dictionary +local pdfconstant = lpdf.constant +local pdfreserveobject = lpdf.reserveobject +local pdfreference = lpdf.reference -local trace_links = false trackers.register("figures.links", function(v) trace_links = v end) -local trace_outlines = false trackers.register("figures.outliness", function(v) trace_outlines = v end) +local pdfcopyboolean = lpdf.copyboolean +local pdfcopyunicode = lpdf.copyunicode +local pdfcopyarray = lpdf.copyarray +local pdfcopydictionary = lpdf.copydictionary +local pdfcopynumber = lpdf.copynumber +local pdfcopyinteger = lpdf.copyinteger +local pdfcopystring = lpdf.copystring +local pdfcopyconstant = lpdf.copyconstant -local report_link = logs.reporter("backend","link") -local report_comment = logs.reporter("backend","comment") -local report_field = logs.reporter("backend","field") -local report_outline = logs.reporter("backend","outline") +local createimage = images.create +local embedimage = images.embed -local epdf = epdf -local backends = backends -local lpdf = lpdf -local context = context +local hpack_node = nodes.hpack -local loadpdffile = lpdf.epdf.load +local loadpdffile = lpdf.epdf.load -local nameonly = file.nameonly +local nameonly = file.nameonly -local variables = interfaces.variables -local codeinjections = backends.pdf.codeinjections ------ urlescaper = lpegpatterns.urlescaper ------ utftohigh = lpegpatterns.utftohigh -local escapetex = characters.filters.utf.private.escape +local variables = interfaces.variables +local codeinjections = backends.pdf.codeinjections +----- urlescaper = lpegpatterns.urlescaper +----- utftohigh = lpegpatterns.utftohigh +local escapetex = characters.filters.utf.private.escape -local bookmarks = structures.bookmarks +local bookmarks = structures.bookmarks -local maxdimen = 0x3FFFFFFF -- 2^30-1 +local maxdimen = 0x3FFFFFFF -- 2^30-1 + +local bpfactor = number.dimenfactors.bp local layerspec = { -- predefining saves time - "epdflinks" + "epdfcontent" } +local getpos = function() getpos = backends.codeinjections.getpos return getpos () end + local collected = allocate() local tobesaved = allocate() @@ -66,6 +96,68 @@ end job.register('job.embedded.collected',tobesaved,initializer) +local function validdocument(specification) + if figures and not specification then + specification = figures and figures.current() + specification = specification and specification.status + end + if specification then + local fullname = specification.fullname + local expanded = lower(expandname(fullname)) + -- we could add a check for duplicate page insertion + tobesaved[expanded] = true + --- but that is messy anyway so we forget about it + return specification, fullname, loadpdffile(fullname) -- costs time + end +end + +local function getmediasize(specification,pagedata) + local xscale = specification.xscale or 1 + local yscale = specification.yscale or 1 + ----- size = specification.size or "crop" -- todo + local mediabox = pagedata.MediaBox + local llx = mediabox[1] + local lly = mediabox[2] + local urx = mediabox[3] + local ury = mediabox[4] + local width = xscale * (urx - llx) -- \\overlaywidth, \\overlayheight + local height = yscale * (ury - lly) -- \\overlaywidth, \\overlayheight + return llx, lly, urx, ury, width, height, xscale, yscale +end + +local function getdimensions(annotation,llx,lly,xscale,yscale,width,height,report) + local rectangle = annotation.Rect + local a_llx = rectangle[1] + local a_lly = rectangle[2] + local a_urx = rectangle[3] + local a_ury = rectangle[4] + local x = xscale * (a_llx - llx) + local y = yscale * (a_lly - lly) + local w = xscale * (a_urx - a_llx) + local h = yscale * (a_ury - a_lly) + if w > width or h > height or w < 0 or h < 0 or abs(x) > (maxdimen/2) or abs(y) > (maxdimen/2) then + report("broken rectangle [%.6F %.6F %.6F %.6F] (max: %.6F)",a_llx,a_lly,a_urx,a_ury,maxdimen/2) + return + end + return x, y, w, h, a_llx, a_lly, a_urx, a_ury +end + +local layerused = false + +local function initializelayer(height,width) + if not layerused then + context.definelayer(layerspec, { height = height .. "bp", width = width .. "bp" }) + layerused = true + end +end + +function codeinjections.flushmergelayer() + if layerused then + context.flushlayer(layerspec) + layerused = false + end +end + local f_namespace = formatters["lpdf-epa-%s-"] local function makenamespace(filename) @@ -182,82 +274,51 @@ local function link_file(x,y,w,h,document,annotation) end end +-- maybe handler per subtype and then one loop but then what about order ... + function codeinjections.mergereferences(specification) - if figures and not specification then - specification = figures and figures.current() - specification = specification and specification.status - end - if not specification then - return "" - end - local fullname = specification.fullname - local expanded = lower(expandname(fullname)) - -- we could add a check for duplicate page insertion - tobesaved[expanded] = true - --- but that is messy anyway so we forget about it - local document = loadpdffile(fullname) -- costs time + local specification, fullname, document = validdocument(specification) if not document then return "" end - local pagenumber = specification.page or 1 - local xscale = specification.yscale or 1 - local yscale = specification.yscale or 1 - local size = specification.size or "crop" -- todo + local pagenumber = specification.page or 1 local pagedata = document.pages[pagenumber] local annotations = pagedata and pagedata.Annots local namespace = makenamespace(fullname) local reference = namespace .. pagenumber - if annotations and annotations.n > 0 then - local mediabox = pagedata.MediaBox - local llx = mediabox[1] - local lly = mediabox[2] - local urx = mediabox[3] - local ury = mediabox[4] - local width = xscale * (urx - llx) -- \\overlaywidth, \\overlayheight - local height = yscale * (ury - lly) -- \\overlaywidth, \\overlayheight - context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" }) - for i=1,annotations.n do + if annotations and #annotations > 0 then + local llx, lly, urx, ury, width, height, xscale, yscale = getmediasize(specification,pagedata,xscale,yscale) + initializelayer(height,width) + for i=1,#annotations do local annotation = annotations[i] if annotation then - local subtype = annotation.Subtype - local rectangle = annotation.Rect - local a_llx = rectangle[1] - local a_lly = rectangle[2] - local a_urx = rectangle[3] - local a_ury = rectangle[4] - local x = xscale * (a_llx - llx) - local y = yscale * (a_lly - lly) - local w = xscale * (a_urx - a_llx) - local h = yscale * (a_ury - a_lly) - if subtype == "Link" then + if annotation.Subtype == "Link" then local a = annotation.A if not a then report_link("missing link annotation") - elseif w > width or h > height or w < 0 or h < 0 or abs(x) > (maxdimen/2) or abs(y) > (maxdimen/2) then - report_link("broken link rectangle [%.6F %.6F %.6F %.6F] (max: %.6F)",a_llx,a_lly,a_urx,a_ury,maxdimen/2) else - local linktype = a.S - if linktype == "GoTo" then - link_goto(x,y,w,h,document,annotation,pagedata,namespace) - elseif linktype == "GoToR" then - link_file(x,y,w,h,document,annotation) - elseif linktype == "URI" then - link_uri(x,y,w,h,document,annotation) - elseif trace_links then - report_link("unsupported link annotation %a",linktype) + local x, y, w, h = getdimensions(annotation,llx,lly,xscale,yscale,width,height,report_link) + if x then + local linktype = a.S + if linktype == "GoTo" then + link_goto(x,y,w,h,document,annotation,pagedata,namespace) + elseif linktype == "GoToR" then + link_file(x,y,w,h,document,annotation) + elseif linktype == "URI" then + link_uri(x,y,w,h,document,annotation) + elseif trace_links then + report_link("unsupported link annotation %a",linktype) + end end end - elseif trace_links then - report_link("unsupported annotation %a",subtype) end elseif trace_links then report_link("broken annotation, index %a",i) end end - context.flushlayer { "epdflinks" } end -- moved outside previous test - context.setgvalue("figurereference",reference) -- global + context.setgvalue("figurereference",reference) -- global, todo: setmacro if trace_links then report_link("setting figure reference to %a",reference) end @@ -270,43 +331,527 @@ function codeinjections.mergeviewerlayers(specification) if true then return end - if not specification then - specification = figures and figures.current() - specification = specification and specification.status + local specification, fullname, document = validdocument(specification) + if not document then + return "" end - if specification then - local fullname = specification.fullname - local document = loadpdffile(fullname) - if document then - local namespace = makenamespace(fullname) - local layers = document.layers - if layers then - for i=1,layers.n do - local layer = layers[i] - if layer then - local tag = namespace .. gsub(layer," ",":") - local title = tag - if trace_links then - report_link("using layer %a",tag) + local namespace = makenamespace(fullname) + local layers = document.layers + if layers then + for i=1,#layers do + local layer = layers[i] + if layer then + local tag = namespace .. gsub(layer," ",":") + local title = tag + if trace_links then + report_link("using layer %a",tag) + end + attributes.viewerlayers.define { -- also does some cleaning + tag = tag, -- todo: #3A or so + title = title, + visible = variables.start, + editable = variables.yes, + printable = variables.yes, + } + codeinjections.useviewerlayer(tag) + elseif trace_links then + report_link("broken layer, index %a",i) + end + end + end +end + +-- It took a bit of puzzling and playing around to come to the following +-- implementation. In the end it looks simple but as usual it takes a while +-- to see what the specification (and implementation) boils down to. Lots of +-- shared properties and such. The scaling took some trial and error as +-- viewers differ. I had to extend some low level helpers to make it more +-- comfortable. Hm, the specification is somewhat incomplete as some fields +-- are permitted even if not mentioned so in the end we can share more code. +-- +-- If all works ok, we can get rid of some copies which saves time and space. + +local commentlike = { + Text = "text", + FreeText = "freetext", + Line = "line", + Square = "shape", + Circle = "shape", + Polygon = "poly", + PolyLine = "poly", + Highlight = "markup", + Underline = "markup", + Squiggly = "markup", + StrikeOut = "markup", + Caret = "text", + Stamp = "stamp", + Ink = "ink", + Popup = "popup", +} + +local function copyBS(v) -- dict can be shared + if v then + -- return pdfdictionary { + -- Type = copypdfconstant(V.Type), + -- W = copypdfnumber (V.W), + -- S = copypdfstring (V.S), + -- D = copypdfarray (V.D), + -- } + return copypdfdictionary(v) + end +end + +local function copyBE(v) -- dict can be shared + if v then + -- return pdfdictionary { + -- S = copypdfstring(V.S), + -- I = copypdfnumber(V.I), + -- } + return copypdfdictionary(v) + end +end + +local function copyBorder(v) -- dict can be shared + if v then + -- todo + return copypdfarray(v) + end +end + +local function copyPopup(v,references) + if v then + local p = references[v] + if p then + return pdfreference(p) + end + end +end + +local function copyParent(v,references) + if v then + local p = references[v] + if p then + return pdfreference(p) + end + end +end + +local function copyIRT(v,references) + if v then + local p = references[v] + if p then + return pdfreference(p) + end + end +end + +local function copyC(v) + if v then + -- todo: check color space + return pdfcopyarray(v) + end +end + +local function finalizer(d,xscale,yscale,a_llx,a_ury) + local q = d.QuadPoints or d.Vertices or d.CL + if q then + return function() + local h, v = pdfgetpos() -- already scaled + for i=1,#q,2 do + q[i] = xscale * q[i] + (h*bpfactor - xscale * a_llx) + q[i+1] = yscale * q[i+1] + (v*bpfactor - yscale * a_ury) + end + return d() + end + end + q = d.InkList or d.Path + if q then + return function() + local h, v = pdfgetpos() -- already scaled + for i=1,#q do + local q = q[i] + for i=1,#q,2 do + q[i] = xscale * q[i] + (h*bpfactor - xscale * a_llx) + q[i+1] = yscale * q[i+1] + (v*bpfactor - yscale * a_ury) + end + end + return d() + end + end + return d() +end + +local validstamps = { + Approved = true, + Experimental = true, + NotApproved = true, + AsIs = true, + Expired = true, + NotForPublicRelease = true, + Confidential = true, + Final = true, + Sold = true, + Departmental = true, + ForComment = true, + TopSecret = true, + Draft = true, + ForPublicRelease = true, +} + +-- todo: we can use runtoks instead of steps + +local function validStamp(v) + local name = "Stamped" -- fallback + if v then + local ok = validstamps[v] + if ok then + name = ok + else + for k in next, validstamps do + if find(v,k.."$") then + name = k + validstamps[v] = k + break + end + end + end + end + -- we temporary return to \TEX: + context.predefinesymbol { name } + context.step() + -- beware, an error is not reported + return pdfconstant(name), codeinjections.analyzenormalsymbol(name) +end + +local annotationflags = lpdf.flags.annotations + +local function copyF(v,lock) -- todo: bxor 24 + if lock then + v = bor(v or 0,annotationflags.ReadOnly + annotationflags.Locked + annotationflags.LockedContents) + end + if v then + return pdfcopyinteger(v) + end +end + +-- Speed is not really an issue so we don't optimize this code too much. In the end (after +-- testing we end up with less code that we started with. + +function codeinjections.mergecomments(specification) + local specification, fullname, document = validdocument(specification) + if not document then + return "" + end + local pagenumber = specification.page or 1 + local pagedata = document.pages[pagenumber] + local annotations = pagedata and pagedata.Annots + if annotations and #annotations > 0 then + local llx, lly, urx, ury, width, height, xscale, yscale = getmediasize(specification,pagedata,xscale,yscale) + initializelayer(height,width) + -- + local lockflags = specification.lock -- todo: proper parameter + local references = { } + local usedpopups = { } + for i=1,#annotations do + local annotation = annotations[i] + if annotation then + local subtype = annotation.Subtype + if commentlike[subtype] then + references[annotation] = pdfreserveobject() + local p = annotation.Popup + if p then + usedpopups[p] = true + end + end + end + end + -- + for i=1,#annotations do + -- we keep the order + local annotation = annotations[i] + if annotation then + local reference = references[annotation] + if reference then + local subtype = annotation.Subtype + local kind = commentlike[subtype] + if kind ~= "popup" or usedpopups[annotation] then + local x, y, w, h, a_llx, a_lly, a_urx, a_ury = getdimensions(annotation,llx,lly,xscale,yscale,width,height,report_comment) + if x then + local voffset = h + local dictionary = pdfdictionary { + Subtype = pdfconstant (subtype), + -- common (skipped: P AP AS OC AF BM StructParent) + Contents = pdfcopyunicode(annotation.Contents), + NM = pdfcopystring (annotation.NM), + M = pdfcopystring (annotation.M), + F = copyF (annotation.F,lockflags), + C = copyC (annotation.C), + ca = pdfcopynumber (annotation.ca), + CA = pdfcopynumber (annotation.CA), + Lang = pdfcopystring (annotation.Lang), + -- also common + CreationDate = pdfcopystring (annotation.CreationDate), + T = pdfcopyunicode(annotation.T), + Subj = pdfcopyunicode(annotation.Subj), + -- border + Border = pdfcopyarray (annotation.Border), + BS = copyBS (annotation.BS), + BE = copyBE (annotation.BE), + -- sort of common + Popup = copyPopup (annotation.Popup,references), + RC = pdfcopyunicode(annotation.RC) -- string or stream + } + if kind == "markup" then + dictionary.IRT = copyIRT (annotation.IRT,references) + dictionary.RT = pdfconstant (annotation.RT) + dictionary.IT = pdfcopyconstant (annotation.IT) + dictionary.QuadPoints = pdfcopyarray (annotation.QuadPoints) + -- dictionary.RD = pdfcopyarray (annotation.RD) + elseif kind == "text" then + -- somehow F fails to view : /F 24 : bit4=nozoom bit5=norotate + dictionary.F = nil + dictionary.Open = pdfcopyboolean (annotation.Open) + dictionary.Name = pdfcopyunicode (annotation.Name) + dictionary.State = pdfcopystring (annotation.State) + dictionary.StateModel = pdfcopystring (annotation.StateModel) + dictionary.IT = pdfcopyconstant (annotation.IT) + dictionary.QuadPoints = pdfcopyarray (annotation.QuadPoints) + dictionary.RD = pdfcopyarray (annotation.RD) -- caret + dictionary.Sy = pdfcopyconstant (annotation.Sy) -- caret + voffset = 0 + elseif kind == "freetext" then + dictionary.DA = pdfcopystring (annotation.DA) + dictionary.Q = pdfcopyinteger (annotation.Q) + dictionary.DS = pdfcopystring (annotation.DS) + dictionary.CL = pdfcopyarray (annotation.CL) + dictionary.IT = pdfcopyconstant (annotation.IT) + dictionary.LE = pdfcopyconstant (annotation.LE) + -- dictionary.RC = pdfcopystring (annotation.RC) + elseif kind == "line" then + dictionary.LE = pdfcopyarray (annotation.LE) + dictionary.IC = pdfcopyarray (annotation.IC) + dictionary.LL = pdfcopynumber (annotation.LL) + dictionary.LLE = pdfcopynumber (annotation.LLE) + dictionary.Cap = pdfcopyboolean (annotation.Cap) + dictionary.IT = pdfcopyconstant (annotation.IT) + dictionary.LLO = pdfcopynumber (annotation.LLO) + dictionary.CP = pdfcopyconstant (annotation.CP) + dictionary.Measure = pdfcopydictionary(annotation.Measure) -- names + dictionary.CO = pdfcopyarray (annotation.CO) + voffset = 0 + elseif kind == "shape" then + dictionary.IC = pdfcopyarray (annotation.IC) + -- dictionary.RD = pdfcopyarray (annotation.RD) + voffset = 0 + elseif kind == "stamp" then + local name, appearance = validStamp(annotation.Name) + dictionary.Name = name + dictionary.AP = appearance + voffset = 0 + elseif kind == "ink" then + dictionary.InkList = pdfcopyarray (annotation.InkList) + elseif kind == "poly" then + dictionary.Vertices = pdfcopyarray (annotation.Vertices) + -- dictionary.LE = pdfcopyarray (annotation.LE) -- todo: names in array + dictionary.IC = pdfcopyarray (annotation.IC) + dictionary.IT = pdfcopyconstant (annotation.IT) + dictionary.Measure = pdfcopydictionary(annotation.Measure) + dictionary.Path = pdfcopyarray (annotation.Path) + -- dictionary.RD = pdfcopyarray (annotation.RD) + elseif kind == "popup" then + dictionary.Open = pdfcopyboolean (annotation.Open) + dictionary.Parent = copyParent (annotation.Parent,references) + voffset = 0 + end + if dictionary then + local locationspec = { + x = x .. "bp", + y = y .. "bp", + voffset = voffset .. "bp", + preset = "leftbottom", + } + local finalize = finalizer(dictionary,xscale,yscale,a_llx,a_ury) + context.setlayer(layerspec,locationspec,function() + context(hpack_node(nodeinjections.annotation(w/bpfactor,h/bpfactor,0,finalize,reference))) + end) + end end - attributes.viewerlayers.define { -- also does some cleaning - tag = tag, -- todo: #3A or so - title = title, - visible = variables.start, - editable = variables.yes, - printable = variables.yes, - } - codeinjections.useviewerlayer(tag) - elseif trace_links then - report_link("broken layer, index %a",i) + else + -- report_comment("skipping annotation, index %a",i) end end + elseif trace_comments then + report_comment("broken annotation, index %a",i) end end end + return namespace end --- new: for taco +local widgetflags = lpdf.flags.widgets + +local function flagstoset(flag,flags) + local t = { } + if flags then + for k, v in next, flags do + if band(flag,v) ~= 0 then + t[k] = true + end + end + end + return t +end + +-- BS : border style dict +-- R : rotation 0 90 180 270 +-- BG : background array +-- CA : caption string +-- RC : roll over caption +-- AC : down caption +-- I/RI/IX : icon streams +-- IF : fit dictionary +-- TP : text position number + +-- Opt : array of texts +-- TI : top index + +-- V : value +-- DV : default value +-- DS : default string +-- RV : rich +-- Q : quadding (0=left 1=middle 2=right) + +function codeinjections.mergefields(specification) + local specification, fullname, document = validdocument(specification) + if not document then + return "" + end + local pagenumber = specification.page or 1 + local pagedata = document.pages[pagenumber] + local annotations = pagedata and pagedata.Annots + if annotations and #annotations > 0 then + local llx, lly, urx, ury, width, height, xscale, yscale = getmediasize(specification,pagedata,xscale,yscale) + initializelayer(height,width) + -- + for i=1,#annotations do + -- we keep the order + local annotation = annotations[i] + if annotation then + local subtype = annotation.Subtype + if subtype == "Widget" then + local parent = annotation.Parent or { } + local name = annotation.T or parent.T + local what = annotation.FT or parent.FT + if name and what then + local x, y, w, h, a_llx, a_lly, a_urx, a_ury = getdimensions(annotation,llx,lly,xscale,yscale,width,height,report_field) + if x then + x = x .. "bp" + y = y .. "bp" + local W, H = w, h + w = w .. "bp" + h = h .. "bp" + if trace_fields then + report_field("field %a, type %a, dx %s, dy %s, wd %s, ht %s",name,what,x,y,w,h) + end + local locationspec = { + x = x, + y = y, + preset = "leftbottom", + } + -- + local aflags = flagstoset(annotation.F or parent.F, annotationflags) + local wflags = flagstoset(annotation.Ff or parent.Ff, widgetflags) + if what == "Tx" then + -- DA DV F FT MaxLen MK Q T V | AA OC + if wflags.MultiLine then + wflags.MultiLine = nil + what = "text" + else + what = "line" + end + -- via context + local fieldspec = { + width = w, + height = h, + offset = variables.overlay, + frame = trace_links and variables.on or variables.off, + n = annotation.MaxLen or (parent and parent.MaxLen), + type = what, + option = concat(merged(aflags,wflags),","), + } + context.setlayer (layerspec,locationspec,function() + context.definefieldbody ( { name } , fieldspec ) + context.fieldbody ( { name } ) + end) + -- + elseif what == "Btn" then + if wflags.Radio or wflags.RadiosInUnison then + -- AP AS DA F Ff FT H MK T V | AA OC + wflags.Radio = nil + wflags.RadiosInUnison = nil + what = "radio" + elseif wflags.PushButton then + -- AP DA F Ff FT H MK T | AA OC + -- + -- Push buttons only have an appearance and some associated + -- actions so they are not worth copying. + -- + wflags.PushButton = nil + what = "push" + else + -- AP AS DA F Ff FT H MK T V | OC AA + what = "check" + -- direct + local AP = annotation.AP or (parent and parent.AP) + if AP then + local a = document.__xrefs__[AP] + if a and pdfe.copyappearance then + local o = pdfe.copyappearance(document,a) + if o then + AP = pdfreference(o) + end + end + end + local dictionary = pdfdictionary { + Subtype = pdfconstant("Widget"), + FT = pdfconstant("Btn"), + T = pdfcopyunicode(annotation.T or parent.T), + F = pdfcopyinteger(annotation.F or parent.F), + Ff = pdfcopyinteger(annotation.Ff or parent.Ff), + AS = pdfcopyconstant(annotation.AS or (parent and parent.AS)), + AP = AP and pdfreference(AP), + } + local finalize = dictionary() + context.setlayer(layerspec,locationspec,function() + context(hpack_node(nodeinjections.annotation(W/bpfactor,H/bpfactor,0,finalize))) + end) + -- + end + elseif what == "Ch" then + -- F Ff FT Opt T | AA OC (rest follows) + if wflags.PopUp then + wflags.PopUp = nil + if wflags.Edit then + wflags.Edit = nil + what = "combo" + else + what = "popup" + end + else + what = "choice" + end + elseif what == "Sig" then + what = "signature" + else + what = nil + end + end + end + end + end + end + end +end -- Beware, bookmarks can be in pdfdoc encoding or in unicode. However, in mkiv we -- write out the strings in unicode (hex). When we read them in, we check for a bom @@ -337,7 +882,7 @@ function codeinjections.getbookmarks(filename) local outlines = document.Catalog.Outlines local pages = document.pages - local nofpages = pages.n -- we need to access once in order to initialize + local nofpages = document.nofpages local destinations = document.destinations -- I need to check this destination analyzer with the one in annotations .. best share @@ -359,7 +904,7 @@ function codeinjections.getbookmarks(filename) entry.realpage = pagedata.number end elseif kind == "table" then - local pageref = destination.n + local pageref = #destination if pageref then local pagedata = pages[pageref] if pagedata then @@ -367,8 +912,8 @@ function codeinjections.getbookmarks(filename) end end end - else - -- maybe + -- elseif subtype then + -- report("unsupported bookmark action %a",subtype) end else local destination = current.Dest @@ -383,6 +928,8 @@ function codeinjections.getbookmarks(filename) local pagedata = destination and destination[1] if pagedata and pagedata.Type == "Page" then entry.realpage = pagedata.number + -- else + -- report("unsupported bookmark destination (no page)") end end end @@ -471,16 +1018,6 @@ function codeinjections.mergebookmarks(specification) end end --- placeholders: - -function codeinjections.mergecomments(specification) - report_comment("unfinished experimental code, not used yet") -end - -function codeinjections.mergefields(specification) - report_field("unfinished experimental code, not used yet") -end - -- A bit more than a placeholder but in the same perspective as -- inclusion of comments and fields: -- @@ -501,7 +1038,7 @@ function codeinjections.getinfo(specification) local catalog = pdffile.Catalog local info = pdffile.Info local pages = pdffile.pages - local nofpages = pages.n + local nofpages = pdffile.nofpages if metadata then local m = catalog.Metadata if m then @@ -525,10 +1062,8 @@ function codeinjections.getinfo(specification) local media = nobox local page = pages[pagenumber] if page then - crop = page.CropBox or nobox - media = page.MediaBox or crop or nobox - crop.n = nil -- nicer - media.n = nil -- nicer + crop = page.CropBox or nobox + media = page.MediaBox or crop or nobox end local bbox = crop or media or nobox return { |