diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2009-08-23 11:11:32 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2009-08-23 11:11:32 +0000 |
commit | 8fc3039c82d48605b5ca8b2eda3f4fdd755681e1 (patch) | |
tree | 3cd9bbdd599bc4d1ac0409e167fee2136e4c0ec9 /Master/texmf-dist/tex/context/base/lpdf-ini.lua | |
parent | 850fc99b7cd3ae7a20065531fe866ff7bae642ec (diff) |
this is context 2009.08.19 17:10
git-svn-id: svn://tug.org/texlive/trunk@14827 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/lpdf-ini.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/lpdf-ini.lua | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/lpdf-ini.lua b/Master/texmf-dist/tex/context/base/lpdf-ini.lua new file mode 100644 index 00000000000..3335c623756 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/lpdf-ini.lua @@ -0,0 +1,519 @@ +if not modules then modules = { } end modules ['back-pdf'] = { + version = 1.001, + comment = "companion to lpdf-ini.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This code is very experimental ! + +local setmetatable, getmetatable, type, next, tostring, tonumber, rawset = setmetatable, getmetatable, type, next, tostring, tonumber, rawset +local char, byte, format, gsub, concat = string.char, string.byte, string.format, string.gsub, table.concat +local utfvalues = string.utfvalues +local texwrite = tex.write +local sind, cosd = math.sind, math.cosd + +local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end) + +lpdf = lpdf or { } + +local function tosixteen(str) + if not str or str == "" then + return "()" + else + local r = { "<feff" } + for b in utfvalues(str) do + if b < 0x10000 then + r[#r+1] = format("%04x",b) + else + r[#r+1] = format("%04x%04x",b/1024+0xD800,b%1024+0xDC00) + end + end + r[#r+1] = ">" + return concat(r) + end +end + +lpdf.tosixteen = tosixteen + +-- lpeg is some 5 times faster than gsub (in test) on escaping + +local escapes = { + ["\\"] = "\\\\", + ["/"] = "\\/", ["#"] = "\\#", + ["<"] = "\\<", [">"] = "\\>", + ["["] = "\\[", ["]"] = "\\]", + ["("] = "\\(", [")"] = "\\)", +} + +local escaped = lpeg.Cs(lpeg.Cc("(") * (lpeg.S("\\/#<>[]()")/escapes + lpeg.P(1))^0 * lpeg.Cc(")")) + +local function toeight(str) + -- if not str or str == "" then + -- return "()" + -- else + -- return escaped:match(str) + -- end + -- + -- no need for escaping .. just use unicode instead + return "(" .. str .. ")" +end + +lpdf.toeight = toeight + +local escapes = "-" + +local escaped = lpeg.Cs(lpeg.Cc("(") * (lpeg.S("\\/#<>[]()")/escapes + lpeg.P(1))^0 * lpeg.Cc(")")) + +local function cleaned(str) + if not str or str == "" then + return "()" + else + return escaped:match(str) + end +end + +lpdf.cleaned = cleaned + +local function merge_t(a,b) + local t = { } + for k,v in next, a do t[k] = v end + for k,v in next, b do t[k] = v end + return setmetatable(t,getmetatable(a)) +end + +local tostring_a, tostring_d + +tostring_d = function(t,contentonly,key) + if not next(t) then + if contentonly then + return "" + else + return "<< >>" + end + else + local r = { } + for k, v in next, t do + local tv = type(v) + if tv == "string" then + r[#r+1] = format("/%s %s",k,toeight(v)) + elseif tv == "unicode" then + r[#r+1] = format("/%s %s",k,tosixteen(v)) + elseif tv == "table" then + local mv = getmetatable(v) + if mv and mv.__lpdftype then + r[#r+1] = format("/%s %s",k,tostring(v)) + elseif v[1] then + r[#r+1] = format("/%s %s",k,tostring_a(v)) + else + r[#r+1] = format("/%s %s",k,tostring_d(v)) + end + else + r[#r+1] = format("/%s %s",k,tostring(v)) + end + end + if contentonly then + return concat(r, " ") + elseif key then + return format("/%s << %s >>", key, concat(r, " ")) + else + return format("<< %s >>", concat(r, " ")) + end + end +end + +tostring_a = function(t,contentonly,key) + if #t == 0 then + if contentonly then + return "" + else + return "[ ]" + end + else + local r = { } + for k, v in next, t do + local tv = type(v) + if tv == "string" then + r[#r+1] = toeight(v) + elseif tv == "unicode" then + r[#r+1] = tosixteen(v) + elseif tv == "table" then + local mv = getmetatable(v) + if mv and mv.__lpdftype then + r[#r+1] = tostring(v) + elseif v[1] then + r[#r+1] = tostring_a(v) + else + r[#r+1] = tostring_d(v) + end + else + r[#r+1] = tostring(v) + end + end + if contentonly then + return concat(r, " ") + elseif key then + return format("/%s [ %s ]", key, concat(r, " ")) + else + return format("[ %s ]", concat(r, " ")) + end + end +end + +local tostring_x = function(t) return concat(t, " ") end +local tostring_s = function(t) return toeight(t[1]) end +local tostring_u = function(t) return tosixteen(t[1]) end +local tostring_n = function(t) return tostring(t[1]) end -- tostring not needed +local tostring_c = function(t) return t[1] end -- already prefixed (hashed) +local tostring_z = function() return "null" end +local tostring_t = function() return "true" end +local tostring_f = function() return "false" end +local tostring_r = function(t) return t[1] .. " 0 R" end +local tostring_v = function(t) return concat(t[1],"") end + +local function value_x(t) return t end -- the call is experimental +local function value_s(t,key) return t[1] end -- the call is experimental +local function value_u(t,key) return t[1] end -- the call is experimental +local function value_n(t,key) return t[1] end -- the call is experimental +local function value_c(t) return sub(t[1],2) end -- the call is experimental +local function value_d(t) return tostring_d(t,true,key) end -- the call is experimental +local function value_a(t) return tostring_a(t,true,key) end -- the call is experimental +local function value_z() return nil end -- the call is experimental +local function value_t() return true end -- the call is experimental +local function value_b() return false end -- the call is experimental +local function value_r() return t[1] end -- the call is experimental +local function value_v() return t[1] end -- the call is experimental + +local function add_x(t,k,v) rawset(t,k,tostring(v)) end + +local mt_x = { __lpdftype = "stream", __tostring = tostring_x, __call = value_x, __newindex = add_x } +local mt_d = { __lpdftype = "dictionary", __tostring = tostring_d, __call = value_d } +local mt_a = { __lpdftype = "array", __tostring = tostring_a, __call = value_a } +local mt_u = { __lpdftype = "unicode", __tostring = tostring_u, __call = value_u } +local mt_s = { __lpdftype = "string", __tostring = tostring_s, __call = value_s } +local mt_n = { __lpdftype = "number", __tostring = tostring_n, __call = value_n } +local mt_c = { __lpdftype = "constant", __tostring = tostring_c, __call = value_c } +local mt_z = { __lpdftype = "null", __tostring = tostring_z, __call = value_z } +local mt_t = { __lpdftype = "true", __tostring = tostring_t, __call = value_t } +local mt_f = { __lpdftype = "false", __tostring = tostring_f, __call = value_f } +local mt_r = { __lpdftype = "reference", __tostring = tostring_r, __call = value_r } +local mt_v = { __lpdftype = "verbose", __tostring = tostring_v, __call = value_v } + +function lpdf.stream(t) + if t then + for i=1,#t do + t[i] = tostring(t[i]) + end + end + return setmetatable(t or { },mt_x) +end + +function lpdf.dictionary(t) + return setmetatable(t or { },mt_d) +end + +function lpdf.array(t) + if type(t) == "string"then + return setmetatable({ t },mt_a) + else + return setmetatable(t or { },mt_a) + end +end + +function lpdf.string(str,default) + return setmetatable({ str or default or "" },mt_s) +end + +function lpdf.unicode(str,default) + return setmetatable({ str or default or "" },mt_u) +end + +local cache = { } -- can be weak + +function lpdf.number(n,default) -- 0-10 + n = n or default + local c = cache[n] + if not c then + c = setmetatable({ n },mt_n) + -- cache[n] = c -- too many numbers + end + return c +end + +for i=-1,9 do cache[i] = lpdf.number(i) end + +local cache = { } -- can be weak + +function lpdf.constant(str,default) + str = str or default or "" + local c = cache[str] + if not c then + c = setmetatable({ "/" .. str },mt_c) + cache[str] = c + end + return c +end + +local p_null = { } setmetatable(p_null, mt_z) +local p_true = { } setmetatable(p_true, mt_t) +local p_false = { } setmetatable(p_false,mt_f) + +function lpdf.null() + return p_null +end + +function lpdf.boolean(b,default) + if ((type(b) == boolean) and b) or default then + return p_true + else + return p_false + end +end + +function lpdf.reference(r) + return setmetatable({ r or 0 },mt_r) +end + +function lpdf.verbose(t) -- maybe check for type + return setmetatable({ t or "" },mt_v) +end + +--~ local d = lpdf.dictionary() +--~ local e = lpdf.dictionary { ["e"] = "abc" } +--~ local f = lpdf.dictionary { ["f"] = "ABC" } +--~ local a = lpdf.array() + +--~ d["test"] = lpdf.string ("test") +--~ d["more"] = "more" +--~ d["bool"] = true +--~ d["numb"] = 1234 +--~ d["oeps"] = lpdf.dictionary { ["hans"] = "ton" } +--~ d["whow"] = lpdf.array { lpdf.string("ton") } + +--~ a[#a+1] = lpdf.string("xxx") +--~ a[#a+1] = lpdf.string("yyy") + +--~ d.what = a + +--~ print(d) + +--~ local d = lpdf.dictionary() +--~ d["abcd"] = { 1, 2, 3, "test" } +--~ print(d) + +--~ local d = lpdf.array() +--~ d[#d+1] = { 1, 2, 3, "test" } +--~ print(d) + +--~ local d = lpdf.array() +--~ d[#d+1] = { a=1, b=2, c=3, d="test" } +--~ print(d) + +--~ local s = lpdf.boolean(false) +--~ print(s()) -- fails somehow + +function lpdf.checkedkey(t,key,kind) + local pn = t[key] + if pn then + local tn = type(pn) + if tn == kind then + if kind == "string" then + return pn ~= "" and pn + elseif kind == "table" then + return next(pn) and pn + else + return pn + end + elseif tn == "string" and kind == "number" then + return tonumber(pn) + end + end +end + +function lpdf.checkedvalue(value,kind) -- code not shared + if value then + local tv = type(value) + if tv == kind then + if kind == "string" then + return value ~= "" and value + elseif kind == "table" then + return next(value) and value + else + return value + end + elseif tv == "string" and kind == "number" then + return tonumber(value) + end + end +end + +function lpdf.limited(n,min,max,default) + if not n then + return default + else + n = tonumber(n) + if not n then + return default + elseif n > max then + return max + elseif n < min then + return min + else + return n + end + end +end + +-- there will be more of this + +local pdfreference = lpdf.reference +local pdfdictionary = lpdf.dictionary +local pdfreserveobj = pdf.reserveobj +local pdfimmediateobj = pdf.immediateobj + +local texset, texsprint, ctxcatcodes = tex.set, tex.sprint, tex.ctxcatcodes + +local pdfobjcache = { } + +function lpdf.sharedobj(content) + local r = pdfobjcache[content] + if not r then + r = pdfreference(pdfimmediateobj(content)) + pdfobjcache[content] = r + end + return r +end + +-- saves definitions later on + +backends = backends or { } +backends.pdf = backends.pdf or { + comment = "backend for directly generating pdf output", + nodeinjections = { }, + codeinjections = { }, + registrations = { }, + helpers = { }, +} + +-- three priority levels, default=2 + +local pagefinalizers, documentfinalizers = { { }, { }, { } }, { { }, { }, { } } + +local pageresources, pageattributes, pagesattributes + +local function resetpageproperties() + pageresources = pdfdictionary() + pageattributes = pdfdictionary() + pagesattributes = pdfdictionary() +end + +local function setpageproperties() + texset("global", "pdfpageresources", pageresources ()) + texset("global", "pdfpageattr", pageattributes ()) + texset("global", "pdfpagesattr", pagesattributes()) +end + +function lpdf.addtopageresources (k,v) pageresources [k] = v end +function lpdf.addtopageattributes (k,v) pageattributes [k] = v end +function lpdf.addtopagesattributes(k,v) pagesattributes[k] = v end + +local function set(where,f,when,what) + when = when or 2 + local w = where[when] + w[#w+1] = f + if trace_finalizers then + logs.report("backend","%s set: [%s,%s]",what,when,#w) + end +end + +local function run(where,what) + for i=1,#where do + local w = where[i] + for j=1,#w do + if trace_finalizers then + logs.report("backend","%s finalizer: [%s,%s]",what,i,j) + end + w[j]() + end + end +end + +function lpdf.registerpagefinalizer(f,when) + set(pagefinalizers,f,when,"page") +end + +function lpdf.registerdocumentfinalizer(f,when) + set(documentfinalizers,f,when,"document") +end + +function lpdf.finalizepage() + if not environment.initex then + resetpageproperties() + run(pagefinalizers,"page") + setpageproperties() + end +end + +function lpdf.finalizedocument() + if not environment.initex then + run(documentfinalizers,"document") + end +end + +local c_template = "\\normalpdfcatalog{/%s %s}" +local i_template = "\\normalpdfinfo{/%s %s}" +local n_template = "\\normalpdfnames{/%s %s}" + +function lpdf.addtocatalog(k,v) if not environment.initex then texsprint(ctxcatcodes,format(c_template,k,tostring(v))) end end +function lpdf.addtoinfo (k,v) if not environment.initex then texsprint(ctxcatcodes,format(i_template,k,tostring(v))) end end +function lpdf.addtonames (k,v) if not environment.initex then texsprint(ctxcatcodes,format(n_template,k,tostring(v))) end end + +local r_extgstates, d_extgstates = pdfreserveobj(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates) +local r_colorspaces, d_colorspaces = pdfreserveobj(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces) +local r_patterns, d_patterns = pdfreserveobj(), pdfdictionary() local p_patterns = pdfreference(r_patterns) +local r_shades, d_shades = pdfreserveobj(), pdfdictionary() local p_shades = pdfreference(r_shades) + +local function checkextgstates () if next(d_extgstates ) then lpdf.addtopageresources("ExtGState", p_extgstates ) end end +local function checkcolorspaces() if next(d_colorspaces) then lpdf.addtopageresources("ColorSpace",p_colorspaces) end end +local function checkpatterns () if next(d_patterns ) then lpdf.addtopageresources("Pattern", p_patterns ) end end +local function checkshades () if next(d_shades ) then lpdf.addtopageresources("Shading", p_shades ) end end + +local function flushextgstates () if next(d_extgstates ) then pdfimmediateobj(r_extgstates, tostring(d_extgstates )) end end +local function flushcolorspaces() if next(d_colorspaces) then pdfimmediateobj(r_colorspaces,tostring(d_colorspaces)) end end +local function flushpatterns () if next(d_patterns ) then pdfimmediateobj(r_patterns, tostring(d_patterns )) end end +local function flushshades () if next(d_shades ) then pdfimmediateobj(r_shades, tostring(d_shades )) end end + +local collected = pdfdictionary { + ExtGState = p_extgstates, + ColorSpace = p_colorspaces, + Pattern = p_patterns, + Shading = p_shades, +} ; collected = collected() + +function lpdf.collectedresources() + tex.sprint(tex.ctxcatcodes,collected) +end + +function lpdf.adddocumentextgstate (k,v) d_extgstates [k] = v end +function lpdf.adddocumentcolorspace(k,v) d_colorspaces[k] = v end +function lpdf.adddocumentpattern (k,v) d_patterns [k] = v end +function lpdf.adddocumentshade (k,v) d_shades [k] = v end + +lpdf.registerdocumentfinalizer(flushextgstates,3) +lpdf.registerdocumentfinalizer(flushcolorspaces,3) +lpdf.registerdocumentfinalizer(flushpatterns,3) +lpdf.registerdocumentfinalizer(flushshades,3) + +lpdf.registerpagefinalizer(checkextgstates,3) +lpdf.registerpagefinalizer(checkcolorspaces,3) +lpdf.registerpagefinalizer(checkpatterns,3) +lpdf.registerpagefinalizer(checkshades,3) + +-- + +function lpdf.rotationcm(a) + local s, c = sind(a), cosd(a) + texwrite(format("%s %s %s %s 0 0 cm",c,s,-s,c)) +end + |