summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/lpdf-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/lpdf-ini.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/lpdf-ini.lua519
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
+