summaryrefslogtreecommitdiff
path: root/tex/context/base/lpdf-ini.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/lpdf-ini.lua')
-rw-r--r--tex/context/base/lpdf-ini.lua349
1 files changed, 206 insertions, 143 deletions
diff --git a/tex/context/base/lpdf-ini.lua b/tex/context/base/lpdf-ini.lua
index 23fe6c177..34825698c 100644
--- a/tex/context/base/lpdf-ini.lua
+++ b/tex/context/base/lpdf-ini.lua
@@ -9,15 +9,28 @@ if not modules then modules = { } end modules ['lpdf-ini'] = {
local setmetatable, getmetatable, type, next, tostring, tonumber, rawset = setmetatable, getmetatable, type, next, tostring, tonumber, rawset
local char, byte, format, gsub, concat, match, sub, gmatch = string.char, string.byte, string.format, string.gsub, table.concat, string.match, string.sub, string.gmatch
local utfchar, utfvalues = utf.char, utf.values
-local sind, cosd, floor = math.sind, math.cosd, math.floor
+local sind, cosd, floor, max, min = math.sind, math.cosd, math.floor, math.max, math.min
local lpegmatch, P, C, R, S, Cc, Cs = lpeg.match, lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Cs
local formatters = string.formatters
+-- pdf.mapfile pdf.mapline (todo: used in font-ctx.lua)
+-- pdf.getpos pdf.gethpos pdf.getvpos
+-- pdf.reserveobj pdf.immediateobj pdf.obj pdf.refobj
+-- pdf.pageref
+-- pdf.catalog pdf.info pdf.names pdf.trailer
+
+local backends = backends
+local pdf = pdf
+lpdf = lpdf or { }
+local lpdf = lpdf
+
local pdfreserveobject = pdf.reserveobj
local pdfimmediateobject = pdf.immediateobj
local pdfdeferredobject = pdf.obj
local pdfreferenceobject = pdf.refobj
+local factor = number.dimenfactors.bp
+
local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end)
local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end)
local trace_objects = false trackers.register("backend.objects", function(v) trace_objects = v end)
@@ -26,8 +39,6 @@ local trace_detail = false trackers.register("backend.detail", function
local report_objects = logs.reporter("backend","objects")
local report_finalizing = logs.reporter("backend","finalizing")
-local backends = backends
-
backends.pdf = backends.pdf or {
comment = "backend for directly generating pdf output",
nodeinjections = { },
@@ -36,8 +47,76 @@ backends.pdf = backends.pdf or {
tables = { },
}
-lpdf = lpdf or { }
-local lpdf = lpdf
+-- first some helpers
+
+local codeinjections = backends.pdf.codeinjections
+
+local pdfgetpos, pdfgethpos, pdfgetvpos, pdfhasmatrix, pdfgetmatrix
+
+if pdf.getpos then
+ pdfgetpos = pdf.getpos
+ pdfgethpos = pdf.gethpos
+ pdfgetvpos = pdf.getvpos
+ pdfgetmatrix = pdf.getmatrix
+ pdfhasmatrix = pdf.hasmatrix
+else
+ if pdf.h then
+ function pdfgetpos () return pdf.h, pdf.v end
+ function pdfgethpos() return pdf.h end
+ function pdfgetvpos() return pdf.v end
+ end
+ function pdfhasmatrix() return false end
+ function pdfgetmatrix() return 1, 0, 0, 1, 0, 0 end
+end
+
+codeinjections.getpos = pdfgetpos lpdf.getpos = pdfgetpos
+codeinjections.gethpos = pdfgethpos lpdf.gethpos = pdfgethpos
+codeinjections.getvpos = pdfgetvpos lpdf.getvpos = pdfgetvpos
+codeinjections.hasmatrix = pdfhasmatrix lpdf.hasmatrix = pdfhasmatrix
+codeinjections.getmatrix = pdfgetmatrix lpdf.getmatrix = pdfgetmatrix
+
+function lpdf.transform(llx,lly,urx,ury)
+ if pdfhasmatrix() then
+ local sx, rx, ry, sy = pdfgetmatrix()
+ local w, h = urx - llx, ury - lly
+ return llx, lly, llx + sy*w - ry*h, lly + sx*h - rx*w
+ else
+ return llx, lly, urx, ury
+ end
+end
+
+-- function lpdf.rectangle(width,height,depth)
+-- local h, v = pdfgetpos()
+-- local llx, lly, urx, ury
+-- if pdfhasmatrix() then
+-- local sx, rx, ry, sy = pdfgetmatrix()
+-- llx = 0
+-- lly = -depth
+-- -- llx = ry * depth
+-- -- lly = -sx * depth
+-- urx = sy * width - ry * height
+-- ury = sx * height - rx * width
+-- else
+-- llx = 0
+-- lly = -depth
+-- urx = width
+-- ury = height
+-- return (h+llx)*factor, (v+lly)*factor, (h+urx)*factor, (v+ury)*factor
+-- end
+-- end
+
+function lpdf.rectangle(width,height,depth)
+ local h, v = pdfgetpos()
+ if pdfhasmatrix() then
+ local sx, rx, ry, sy = pdfgetmatrix()
+ -- return (h+ry*depth)*factor, (v-sx*depth)*factor, (h+sy*width-ry*height)*factor, (v+sx*height-rx*width)*factor
+ return h *factor, (v- depth)*factor, (h+sy*width-ry*height)*factor, (v+sx*height-rx*width)*factor
+ else
+ return h *factor, (v- depth)*factor, (h+ width )*factor, (v+ height )*factor
+ end
+end
+
+--
local function tosixteen(str) -- an lpeg might be faster (no table)
if not str or str == "" then
@@ -91,13 +170,13 @@ end
lpdf.toeight = toeight
---~ local escaped = lpeg.Cs((lpeg.S("\0\t\n\r\f ()[]{}/%")/function(s) return format("#%02X",byte(s)) end + lpeg.P(1))^0)
-
---~ local function cleaned(str)
---~ return (str and str ~= "" and lpegmatch(escaped,str)) or ""
---~ end
-
---~ lpdf.cleaned = cleaned -- not public yet
+-- local escaped = lpeg.Cs((lpeg.S("\0\t\n\r\f ()[]{}/%")/function(s) return format("#%02X",byte(s)) end + lpeg.P(1))^0)
+--
+-- local function cleaned(str)
+-- return (str and str ~= "" and lpegmatch(escaped,str)) or ""
+-- end
+--
+-- lpdf.cleaned = cleaned -- not public yet
local function merge_t(a,b)
local t = { }
@@ -112,16 +191,16 @@ local f_dictionary = formatters["<< % t >>"]
local f_key_array = formatters["/%s [ % t ]"]
local f_array = formatters["[ % t ]"]
+-- local f_key_value = formatters["/%s %s"]
+-- local f_key_dictionary = formatters["/%s <<% t>>"]
+-- local f_dictionary = formatters["<<% t>>"]
+-- local f_key_array = formatters["/%s [% t]"]
+-- local f_array = formatters["[% t]"]
+
local tostring_a, tostring_d
tostring_d = function(t,contentonly,key)
- if not next(t) then
- if contentonly then
- return ""
- else
- return "<< >>"
- end
- else
+ if next(t) then
local r, rn = { }, 0
for k, v in next, t do
rn = rn + 1
@@ -150,18 +229,16 @@ tostring_d = function(t,contentonly,key)
else
return f_dictionary(r)
end
+ elseif contentonly then
+ return ""
+ else
+ return "<< >>"
end
end
tostring_a = function(t,contentonly,key)
local tn = #t
- if tn == 0 then
- if contentonly then
- return ""
- else
- return "[ ]"
- end
- else
+ if tn ~= 0 then
local r = { }
for k=1,tn do
local v = t[k]
@@ -191,10 +268,14 @@ tostring_a = function(t,contentonly,key)
else
return f_array(r)
end
+ elseif contentonly then
+ return ""
+ else
+ return "[ ]"
end
end
-local tostring_x = function(t) return concat(t, " ") 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
@@ -207,7 +288,7 @@ local tostring_r = function(t) local n = t[1] return n and n > 0 and (n .. " 0 R
local tostring_v = function(t)
local s = t[1]
if type(s) == "table" then
- return concat(s,"")
+ return concat(s)
else
return s
end
@@ -325,12 +406,27 @@ local function pdfboolean(b,default)
end
end
-local function pdfreference(r)
- return setmetatable({ r or 0 },mt_r)
+local r_zero = setmetatable({ 0 },mt_r)
+
+local function pdfreference(r) -- maybe make a weak table
+ if r and r ~= 0 then
+ return setmetatable({ r },mt_r)
+ else
+ return r_zero
+ end
end
+local v_zero = setmetatable({ 0 },mt_v)
+local v_empty = setmetatable({ "" },mt_v)
+
local function pdfverbose(t) -- maybe check for type
- return setmetatable({ t or "" },mt_v)
+ if t == 0 then
+ return v_zero
+ elseif t == "" then
+ return v_empty
+ else
+ return setmetatable({ t },mt_v)
+ end
end
lpdf.stream = pdfstream -- THIS WILL PROBABLY CHANGE
@@ -345,37 +441,19 @@ lpdf.boolean = pdfboolean
lpdf.reference = pdfreference
lpdf.verbose = pdfverbose
--- n = pdf.obj(n, str)
--- n = pdf.obj(n, "file", filename)
--- n = pdf.obj(n, "stream", streamtext, attrtext)
--- n = pdf.obj(n, "streamfile", filename, attrtext)
-
--- we only use immediate objects
-
--- todo: tracing
-
local names, cache = { }, { }
function lpdf.reserveobject(name)
- if name == "annot" then
- -- catch misuse
- return pdfreserveobject("annot")
- else
- local r = pdfreserveobject()
- if name then
- names[name] = r
- if trace_objects then
- report_objects("reserving number %a under name %a",r,name)
- end
- elseif trace_objects then
- report_objects("reserving number %a",r)
+ local r = pdfreserveobject() -- we don't support "annot"
+ if name then
+ names[name] = r
+ if trace_objects then
+ report_objects("reserving number %a under name %a",r,name)
end
- return r
+ elseif trace_objects then
+ report_objects("reserving number %a",r)
end
-end
-
-function lpdf.reserveannotation()
- return pdfreserveobject("annot")
+ return r
end
-- lpdf.immediateobject = pdfimmediateobject
@@ -383,11 +461,29 @@ end
-- lpdf.object = pdfdeferredobject
-- lpdf.referenceobject = pdfreferenceobject
-lpdf.pagereference = pdf.pageref or tex.pdfpageref
-lpdf.registerannotation = pdf.registerannot
+local pagereference = pdf.pageref or tex.pdfpageref
+local nofpages = 0
+
+function lpdf.pagereference(n)
+ if nofpages == 0 then
+ nofpages = structures.pages.nofpages
+ if nofpages == 0 then
+ nofpages = 1
+ end
+ end
+ if n > nofpages then
+ return pagereference(nofpages) -- or 1, could be configureable
+ else
+ return pagereference(n)
+ end
+end
-function lpdf.delayedobject(data) -- we will get rid of this one
- local n = pdfdeferredobject(data)
+function lpdf.delayedobject(data,n)
+ if n then
+ pdfdeferredobject(n,data)
+ else
+ n = pdfdeferredobject(data)
+ end
pdfreferenceobject(n)
return n
end
@@ -484,57 +580,6 @@ function lpdf.shareobjectreference(content)
end
end
---~ local d = lpdf.dictionary()
---~ local e = lpdf.dictionary { ["e"] = "abc", x = lpdf.dictionary { ["f"] = "ABC" } }
---~ local f = lpdf.dictionary { ["f"] = "ABC" }
---~ local a = lpdf.array { lpdf.array { lpdf.string("xxx") } }
-
---~ print(a)
---~ os.exit()
-
---~ 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(e)
-
---~ local d = lpdf.dictionary()
---~ d["abcd"] = { 1, 2, 3, "test" }
---~ print(d)
---~ print(d())
-
---~ local d = lpdf.array()
---~ d[#d+1] = 1
---~ d[#d+1] = 2
---~ d[#d+1] = 3
---~ d[#d+1] = "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.constant("xx")
---~ print(s) -- fails somehow
---~ print(s()) -- fails somehow
-
---~ local s = lpdf.boolean(false)
---~ s.value = true
---~ print(s)
---~ print(s())
-
-- three priority levels, default=2
local pagefinalizers, documentfinalizers = { { }, { }, { } }, { { }, { }, { } }
@@ -606,8 +651,8 @@ end
lpdf.registerpagefinalizer = registerpagefinalizer
lpdf.registerdocumentfinalizer = registerdocumentfinalizer
-function lpdf.finalizepage()
- if not environment.initex then
+function lpdf.finalizepage(shipout)
+ if shipout and not environment.initex then
-- resetpageproperties() -- maybe better before
run(pagefinalizers,"page")
setpageproperties()
@@ -625,9 +670,27 @@ function lpdf.finalizedocument()
end
end
-backends.pdf.codeinjections.finalizepage = lpdf.finalizepage -- will go when we have hook
+-- backends.pdf.codeinjections.finalizepage = lpdf.finalizepage -- no longer triggered at the tex end
+
+if not callbacks.register("finish_pdfpage", lpdf.finalizepage) then
+
+ local find_tail = nodes.tail
+ local latelua_node = nodes.pool.latelua
+
+ function backends.pdf.nodeinjections.finalizepage(head)
+ local t = find_tail(head.list)
+ if t then
+ local n = latelua_node("lpdf.finalizepage(true)") -- last in the shipout
+ t.next = n
+ n.prev = t
+ end
+ return head, true
+ end
+
+ nodes.tasks.appendaction("shipouts","normalizers","backends.pdf.nodeinjections.finalizepage")
+
+end
---~ callbacks.register("finish_pdfpage", lpdf.finalizepage)
callbacks.register("finish_pdffile", lpdf.finalizedocument)
-- some minimal tracing, handy for checking the order
@@ -718,7 +781,7 @@ registerpagefinalizer(checkshades,3,"shades")
function lpdf.rotationcm(a)
local s, c = sind(a), cosd(a)
- return format("%0.6f %0.6f %0.6f %0.6f 0 0 cm",c,s,-s,c)
+ return format("%0.6F %0.6F %0.6F %0.6F 0 0 cm",c,s,-s,c)
end
-- ! -> universaltime
@@ -795,29 +858,29 @@ end
-- lpdf.addtoinfo("ConTeXt.Jobname", environment.jobname)
-- lpdf.addtoinfo("ConTeXt.Url", "www.pragma-ade.com")
-if not pdfreferenceobject then
-
- local delayed = { }
-
- local function flush()
- local n = 0
- for k,v in next, delayed do
- pdfimmediateobject(k,v)
- n = n + 1
- end
- if trace_objects then
- report_objects("%s objects flushed",n)
- end
- delayed = { }
- end
-
- lpdf.registerdocumentfinalizer(flush,3,"objects") -- so we need a final flush too
- lpdf.registerpagefinalizer (flush,3,"objects") -- somehow this lags behind .. I need to look into that some day
-
- function lpdf.delayedobject(data)
- local n = pdfreserveobject()
- delayed[n] = data
- return n
- end
-
-end
+-- if not pdfreferenceobject then
+--
+-- local delayed = { }
+--
+-- local function flush()
+-- local n = 0
+-- for k,v in next, delayed do
+-- pdfimmediateobject(k,v)
+-- n = n + 1
+-- end
+-- if trace_objects then
+-- report_objects("%s objects flushed",n)
+-- end
+-- delayed = { }
+-- end
+--
+-- lpdf.registerdocumentfinalizer(flush,3,"objects") -- so we need a final flush too
+-- lpdf.registerpagefinalizer (flush,3,"objects") -- somehow this lags behind .. I need to look into that some day
+--
+-- function lpdf.delayedobject(data)
+-- local n = pdfreserveobject()
+-- delayed[n] = data
+-- return n
+-- end
+--
+-- end