From d7ccb42582f85acf30568913610ccf4d602023fb Mon Sep 17 00:00:00 2001 From: Taco Hoekwater Date: Wed, 1 Jun 2011 08:54:21 +0000 Subject: commit context 2011.05.18 git-svn-id: svn://tug.org/texlive/trunk@22719 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/context/base/lpdf-epd.lua | 308 ++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 Master/texmf-dist/tex/context/base/lpdf-epd.lua (limited to 'Master/texmf-dist/tex/context/base/lpdf-epd.lua') diff --git a/Master/texmf-dist/tex/context/base/lpdf-epd.lua b/Master/texmf-dist/tex/context/base/lpdf-epd.lua new file mode 100644 index 00000000000..19c1f9bd8d9 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/lpdf-epd.lua @@ -0,0 +1,308 @@ +if not modules then modules = { } end modules ['lpdf-epd'] = { + version = 1.001, + comment = "companion to lpdf-epa.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is an experimental layer around the epdf library. The reason for +-- this layer is that I want to be independent of the library (which +-- implements a selection of what a file provides) and also because I +-- want an interface closer to Lua's table model while the API stays +-- close to the original xpdf library. Of course, after prototyping a +-- solution, we can optimize it using the low level epdf accessors. + +-- It will be handy when we have a __length and __next that can trigger +-- the resolve till then we will provide .n as #. + +-- As there can be references to the parent we cannot expand a tree. I +-- played with some expansion variants but it does to pay off. + +-- Maybe we need a close(). +-- We cannot access all destinations in one run. + +local setmetatable, rawset, rawget, tostring, tonumber = setmetatable, rawset, rawget, tostring, tonumber +local lower, match, char = string.lower, string.match, string.char +local concat = table.concat + +function epdf.type(o) + local t = lower(match(tostring(o),"[^ :]+")) + return t or "?" +end + +lpdf = lpdf or { } +local lpdf = lpdf + +lpdf.epdf = { } + +local checked_access + +local function prepare(document,d,t,n,k) + for i=1,n do + local v = d:getVal(i) + local r = d:getValNF(i) + if r:getTypeName() ~= "ref" then + t[d:getKey(i)] = checked_access[v:getTypeName()](v,document) + else + r = r:getRef().num + local c = document.cache[r] + if c then + -- + else + c = checked_access[v:getTypeName()](v,document,r) + document.cache[r] = c + document.xrefs[c] = r + end + t[d:getKey(i)] = c + end + end + getmetatable(t).__index = nil + return t[k] +end + +local function some_dictionary(d,document,r) + local n = d and d:getLength() or 0 + if n > 0 then + local t = { } + setmetatable(t, { __index = function(t,k) return prepare(document,d,t,n,k) end } ) + return t + end +end + +local done = { } + +local function prepare(document,a,t,n,k) + for i=1,n do + local v = a:get(i) + local r = a:getNF(i) + if r:getTypeName() ~= "ref" then + t[i] = checked_access[v:getTypeName()](v,document) + else + r = r:getRef().num + local c = document.cache[r] + if c then + -- + else + c = checked_access[v:getTypeName()](v,document,r) + document.cache[r] = c + document.xrefs[c] = r + end + t[i] = c + end + end + getmetatable(t).__index = nil + return t[k] +end + +local function some_array(a,document,r) + local n = a and a:getLength() or 0 + if n > 0 then + local t = { n = n } + setmetatable(t, { __index = function(t,k) return prepare(document,a,t,n,k) end } ) + return t + end +end + +local function streamaccess(s,_,what) + if not what or what == "all" or what == "*all" then + local t, n = { }, 0 + s:streamReset() + while true do + local c = s:streamGetChar() + if c < 0 then + break + else + n = n + 1 + t[n] = char(c) + end + end + return concat(t) + end +end + +local function some_stream(d,document,r) + if d then + d:streamReset() + local s = some_dictionary(d:streamGetDict(),document,r) + getmetatable(s).__call = function(...) return streamaccess(d,...) end + return s + end +end + +-- we need epdf.getBool + +checked_access = { + dictionary = function(d,document,r) + return some_dictionary(d:getDict(),document,r) + end, + array = function(a,document,r) + return some_array(a:getArray(),document,r) + end, + stream = function(v,document,r) + return some_stream(v,document,r) + end, + real = function(v) + return v:getReal() + end, + integer = function(v) + return v:getNum() + end, + string = function(v) + return v:getString() + end, + boolean = function(v) + return v:getBool() + end, + name = function(v) + return v:getName() + end, + ref = function(v) + return v:getRef() + end, +} + +--~ checked_access.real = epdf.real +--~ checked_access.integer = epdf.integer +--~ checked_access.string = epdf.string +--~ checked_access.boolean = epdf.boolean +--~ checked_access.name = epdf.name +--~ checked_access.ref = epdf.ref + +local function getnames(document,n,target) -- direct + if n then + local Names = n.Names + if Names then + if not target then + target = { } + end + for i=1,Names.n,2 do + target[Names[i]] = Names[i+1] + end + else + local Kids = n.Kids + if Kids then + for i=1,Kids.n do + target = getnames(document,Kids[i],target) + end + end + end + return target + end +end + +local function getkids(document,n,target) -- direct + if n then + local Kids = n.Kids + if Kids then + for i=1,Kids.n do + target = getkids(document,Kids[i],target) + end + elseif target then + target[#target+1] = n + else + target = { n } + end + return target + end +end + +-- /OCProperties << +-- /OCGs [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ] +-- /D << +-- /Order [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ] +-- /ON [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ] +-- /OFF [ ] +-- >> +-- >> + +local function getlayers(document) + local properties = document.Catalog.OCProperties + if properties then + local layers = properties.OCGs + if layers then + local t = { } + local n = layers.n + for i=1,n do + local layer = layers[i] +--~ print(document.xrefs[layer]) + t[i] = layer.Name + end + t.n = n + return t + end + end +end + +local function getpages(document) + local data = document.data + local xrefs = document.xrefs + local cache = document.cache + local cata = data:getCatalog() + local xref = data:getXRef() + local pages = { } + for pagenumber=1,cata:getNumPages() do + local pagereference = cata:getPageRef(pagenumber).num + local pagedata = some_dictionary(xref:fetch(pagereference,0):getDict(),document,pagereference) + pagedata.number = pagenumber + pages[pagenumber] = pagedata + xrefs[pagedata] = pagereference + cache[pagereference] = pagedata + end + return pages +end + +-- loader + +local function delayed(document,tag,f) + local t = { } + setmetatable(t, { __index = function(t,k) + local result = f() + if result then + document[tag] = result + return result[k] + end + end } ) + return t +end + +local loaded = { } + +function lpdf.epdf.load(filename) + local document = loaded[filename] + if not document then + statistics.starttiming(lpdf.epdf) + local data = epdf.open(filename) -- maybe resolvers.find_file + if data then + document = { + filename = filename, + cache = { }, + xrefs = { }, + data = data, + } + local Catalog = some_dictionary(data:getXRef():getCatalog():getDict(),document) + document.Catalog = Catalog + -- document.catalog = Catalog + -- a few handy helper tables + document.pages = delayed(document,"pages", function() return getpages(document) end) + document.destinations = delayed(document,"destinations", function() return getnames(document,Catalog.Names.Dests) end) + document.javascripts = delayed(document,"javascripts", function() return getnames(document,Catalog.Names.JS) end) + document.widgets = delayed(document,"widgets", function() return getnames(document,Catalog.Names.AcroForm) end) + document.embeddedfiles = delayed(document,"embeddedfiles",function() return getnames(document,Catalog.Names.EmbeddedFiles) end) + document.layers = delayed(document,"layers", function() return getlayers(document) end) + else + document = false + end + loaded[filename] = document + statistics.stoptiming(lpdf.epdf) + -- print(statistics.elapsedtime(lpdf.epdf)) + end + return document +end + +-- helpers + +-- function lpdf.epdf.getdestinationpage(document,name) +-- local destination = document.data:findDest(name) +-- return destination and destination.number +-- end -- cgit v1.2.3