summaryrefslogtreecommitdiff
path: root/tex/context/base/mlib-pdf.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
commit8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch)
tree94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mlib-pdf.lua
parentf5aed2e51223c36c84c5f25a6cad238b2af59087 (diff)
downloadcontext-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mlib-pdf.lua')
-rw-r--r--tex/context/base/mlib-pdf.lua698
1 files changed, 0 insertions, 698 deletions
diff --git a/tex/context/base/mlib-pdf.lua b/tex/context/base/mlib-pdf.lua
deleted file mode 100644
index fb76a52e3..000000000
--- a/tex/context/base/mlib-pdf.lua
+++ /dev/null
@@ -1,698 +0,0 @@
-if not modules then modules = { } end modules ['mlib-pdf'] = {
- version = 1.001,
- comment = "companion to mlib-ctx.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
-}
-
--- maybe %s is better than %f
-
-local format, concat, gsub = string.format, table.concat, string.gsub
-local abs, sqrt, round = math.abs, math.sqrt, math.round
-local setmetatable, rawset, tostring, tonumber, type = setmetatable, rawset, tostring, tonumber, type
-local P, S, C, Ct, Cc, Cg, Cf, Carg = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cf, lpeg.Carg
-local lpegmatch = lpeg.match
-local formatters = string.formatters
-
-local report_metapost = logs.reporter("metapost")
-
-local trace_variables = false trackers.register("metapost.variables",function(v) trace_variables = v end)
-
-local mplib = mplib
-local context = context
-
-local allocate = utilities.storage.allocate
-
-local copy_node = node.copy
-local write_node = node.write
-
-local pen_info = mplib.pen_info
-local object_fields = mplib.fields
-
-local save_table = false
-
-metapost = metapost or { }
-local metapost = metapost
-
-metapost.flushers = metapost.flushers or { }
-local pdfflusher = { }
-metapost.flushers.pdf = pdfflusher
-
-metapost.n = 0
-metapost.optimize = true -- false
-
-local experiment = true -- uses context(node) that already does delayed nodes
-local savedliterals = nil -- needs checking
-local mpsliteral = nodes.pool.register(node.new("whatsit",nodes.whatsitcodes.pdfliteral)) -- pdfliteral.mode = 1
-
-local f_f = formatters["%F"]
-
-local f_m = formatters["%F %F m"]
-local f_c = formatters["%F %F %F %F %F %F c"]
-local f_l = formatters["%F %F l"]
-local f_cm = formatters["%F %F %F %F %F %F cm"]
-local f_M = formatters["%F M"]
-local f_j = formatters["%i j"]
-local f_J = formatters["%i J"]
-local f_d = formatters["[%s] %F d"]
-local f_w = formatters["%F w"]
-
-directives.register("metapost.savetable",function(v)
- if type(v) == "string" then
- save_table = file.addsuffix(v,"mpl")
- elseif v then
- save_table = file.addsuffix(environment.jobname .. "-graphic","mpl")
- else
- save_table = false
- end
-end)
-
-local pdfliteral = function(pdfcode)
- local literal = copy_node(mpsliteral)
- literal.data = pdfcode
- return literal
-end
-
--- Because in MKiV we always have two passes, we save the objects. When an extra
--- mp run is done (due to for instance texts identifier in the parse pass), we
--- get a new result table and the stored objects are forgotten. Otherwise they
--- are reused.
-
-local function getobjects(result,figure,index)
- if metapost.optimize then
- local robjects = result.objects
- if not robjects then
- robjects = { }
- result.objects = robjects
- end
- local fobjects = robjects[index or 1]
- if not fobjects then
- fobjects = figure:objects()
- robjects[index] = fobjects
- end
- return fobjects
- else
- return figure:objects()
- end
-end
-
-function metapost.convert(result, trialrun, flusher, multipass, askedfig)
- if trialrun then
- local multipassindeed = metapost.parse(result,askedfig)
- if multipass and not multipassindeed and metapost.optimize then
- if save_table then
- table.save(save_table,metapost.totable(result,1)) -- direct
- end
- metapost.flush(result,flusher,askedfig) -- saves a run
- else
- return false
- end
- else
- if save_table then
- table.save(save_table,metapost.totable(result,1)) -- direct
- end
- metapost.flush(result,flusher,askedfig)
- end
- return true -- done
-end
-
-function metapost.flushliteral(d)
- if savedliterals then
- local literal = copy_node(mpsliteral)
- literal.data = savedliterals[d]
- write_node(literal)
- else
- report_metapost("problem flushing literal %a",d)
- end
-end
-
-function metapost.flushreset() -- will become obsolete and internal
- savedliterals = nil
-end
-
-function pdfflusher.comment(message)
- if message then
- message = formatters["%% mps graphic %s: %s"](metapost.n,message)
- if experiment then
- context(pdfliteral(message))
- else
- if savedliterals then
- local last = #savedliterals + 1
- savedliterals[last] = message
- context.MPLIBtoPDF(last)
- else
- savedliterals = { message }
- context.MPLIBtoPDF(1)
- end
- end
- end
-end
-
-function pdfflusher.startfigure(n,llx,lly,urx,ury,message)
- savedliterals = nil
- metapost.n = metapost.n + 1
- context.startMPLIBtoPDF(f_f(llx),f_f(lly),f_f(urx),f_f(ury))
- if message then pdfflusher.comment(message) end
-end
-
-function pdfflusher.stopfigure(message)
- if message then pdfflusher.comment(message) end
- context.stopMPLIBtoPDF()
- context.MPLIBflushreset() -- maybe just at the beginning
-end
-
-function pdfflusher.flushfigure(pdfliterals) -- table
- if #pdfliterals > 0 then
- pdfliterals = concat(pdfliterals,"\n")
- if experiment then
- context(pdfliteral(pdfliterals))
- else
- if savedliterals then
- local last = #savedliterals + 1
- savedliterals[last] = pdfliterals
- context.MPLIBtoPDF(last)
- else
- savedliterals = { pdfliterals }
- context.MPLIBtoPDF(1)
- end
- end
- end
-end
-
-function pdfflusher.textfigure(font,size,text,width,height,depth) -- we could save the factor
- text = gsub(text,".","\\hbox{%1}") -- kerning happens in metapost (i have to check if this is true for mplib)
- context.MPtextext(font,size,text,0,-number.dimenfactors.bp*depth)
-end
-
-local bend_tolerance = 131/65536
-
-local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
-
-local function pen_characteristics(object)
- local t = pen_info(object)
- rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
- divider = sx*sy - rx*ry
- return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
-end
-
-local function mpconcat(px, py) -- no tx, ty here / we can move this one inline if needed
- return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
-end
-
-local function curved(ith,pth)
- local d = pth.left_x - ith.right_x
- if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
- d = pth.left_y - ith.right_y
- if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
- return false
- end
- end
- return true
-end
-
-local function flushnormalpath(path, t, open)
- local pth, ith, nt
- if t then
- nt = #t
- else
- t = { }
- nt = 0
- end
- for i=1,#path do
- nt = nt + 1
- pth = path[i]
- if not ith then
- t[nt] = f_m(pth.x_coord,pth.y_coord)
- elseif curved(ith,pth) then
- t[nt] = f_c(ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
- else
- t[nt] = f_l(pth.x_coord,pth.y_coord)
- end
- ith = pth
- end
- if not open then
- nt = nt + 1
- local one = path[1]
- if curved(pth,one) then
- t[nt] = f_c(pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
- else
- t[nt] = f_l(one.x_coord,one.y_coord)
- end
- elseif #path == 1 then
- -- special case .. draw point
- local one = path[1]
- nt = nt + 1
- t[nt] = f_l(one.x_coord,one.y_coord)
- end
- return t
-end
-
-local function flushconcatpath(path, t, open)
- local pth, ith, nt
- if t then
- nt = #t
- else
- t = { }
- nt = 0
- end
- nt = nt + 1
- t[nt] = f_cm(sx,rx,ry,sy,tx,ty)
- for i=1,#path do
- nt = nt + 1
- pth = path[i]
- if not ith then
- t[nt] = f_m(mpconcat(pth.x_coord,pth.y_coord))
- elseif curved(ith,pth) then
- local a, b = mpconcat(ith.right_x,ith.right_y)
- local c, d = mpconcat(pth.left_x,pth.left_y)
- t[nt] = f_c(a,b,c,d,mpconcat(pth.x_coord,pth.y_coord))
- else
- t[nt] = f_l(mpconcat(pth.x_coord, pth.y_coord))
- end
- ith = pth
- end
- if not open then
- nt = nt + 1
- local one = path[1]
- if curved(pth,one) then
- local a, b = mpconcat(pth.right_x,pth.right_y)
- local c, d = mpconcat(one.left_x,one.left_y)
- t[nt] = f_c(a,b,c,d,mpconcat(one.x_coord, one.y_coord))
- else
- t[nt] = f_l(mpconcat(one.x_coord,one.y_coord))
- end
- elseif #path == 1 then
- -- special case .. draw point
- nt = nt + 1
- local one = path[1]
- t[nt] = f_l(mpconcat(one.x_coord,one.y_coord))
- end
- return t
-end
-
-metapost.flushnormalpath = flushnormalpath
-
--- The flusher is pdf based, if another backend is used, we need to overload the
--- flusher; this is beta code, the organization will change (already upgraded in
--- sync with mplib)
---
--- We can avoid the before table but I like symmetry. There is of course a small
--- performance penalty, but so is passing extra arguments (result, flusher, after)
--- and returning stuff.
-
-local ignore = function () end
-
-local space = P(" ")
-local equal = P("=")
-local key = C((1-equal)^1) * equal
-local newline = S("\n\r")^1
-local number = (((1-space-newline)^1) / tonumber) * (space^0)
-
-local p_number = number
-local p_string = C((1-newline)^0)
-local p_boolean = P("false") * Cc(false) + P("true") * Cc(true)
-local p_set = Ct(number^1)
-local p_path = Ct(Ct(number * number^-5)^1)
-
--- local variable =
--- P("1:") * key * p_number
--- + P("2:") * key * p_string
--- + P("3:") * key * p_boolean
--- + S("4568") * P(":") * key * p_set
--- + P("7:") * key * p_path
---
--- local pattern_key = Cf ( Carg(1) * (Cg(variable * newline^0)^0), rawset)
-
-local variable =
- P("1:") * p_number
- + P("2:") * p_string
- + P("3:") * p_boolean
- + S("4568") * P(":") * p_set
- + P("7:") * p_path
-
-local pattern_tab = Cf ( Carg(1) * (Cg(variable * newline^0)^0), rawset)
-
-local variable =
- P("1:") * p_number
- + P("2:") * p_string
- + P("3:") * p_boolean
- + S("4568") * P(":") * number^1
- + P("7:") * (number * number^-5)^1
-
-local pattern_lst = (variable * newline^0)^0
-
-metapost.variables = { } -- to be stacked
-metapost.properties = { } -- to be stacked
-
-function metapost.untagvariable(str,variables) -- will be redone
- if variables == false then
- return lpegmatch(pattern_lst,str)
- else
- return lpegmatch(pattern_tab,str,1,variables or { })
- end
-end
-
--- function metapost.processspecial(str)
--- lpegmatch(pattern_key,object.prescript,1,variables)
--- end
-
-function metapost.processspecial(str)
- local code = loadstring(str)
- if code then
- if trace_variables then
- report_metapost("executing special code: %s",str)
- end
- code()
- else
- report_metapost("invalid special code: %s",str)
- end
-end
-
-local function setproperties(figure)
- local boundingbox = figure:boundingbox()
- local properties = {
- llx = boundingbox[1],
- lly = boundingbox[2],
- urx = boundingbox[3],
- ury = boundingbox[4],
- slot = figure:charcode(),
- width = figure:width(),
- height = figure:height(),
- depth = figure:depth(),
- italic = figure:italcorr(),
- number = figure:charcode() or 0,
- }
- metapost.properties = properties
- return properties
-end
-
-local function setvariables(figure)
- local variables = { }
- metapost.variables = variables
- return variables
-end
-
-function metapost.flush(result,flusher,askedfig)
- if result then
- local figures = result.fig
- if figures then
- flusher = flusher or pdfflusher
- local resetplugins = metapost.resetplugins or ignore -- before figure
- local processplugins = metapost.processplugins or ignore -- each object
- local synchronizeplugins = metapost.synchronizeplugins or ignore
- local pluginactions = metapost.pluginactions or ignore -- before / after
- local startfigure = flusher.startfigure
- local stopfigure = flusher.stopfigure
- local flushfigure = flusher.flushfigure
- local textfigure = flusher.textfigure
- local processspecial = flusher.processspecial or metapost.processspecial
- local variables = setvariables(figure) -- also resets then in case of not found
- for index=1,#figures do
- local figure = figures[index]
- local properties = setproperties(figure)
- if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
- local objects = getobjects(result,figure,index)
- local result = { }
- local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- local llx = properties.llx
- local lly = properties.lly
- local urx = properties.urx
- local ury = properties.ury
- if urx < llx then
- -- invalid
- startfigure(properties.number,0,0,0,0,"invalid",figure)
- stopfigure()
- else
- startfigure(properties.number,llx,lly,urx,ury,"begin",figure)
- result[#result+1] = "q"
- if objects then
- resetplugins(result) -- we should move the colorinitializer here
-local savedpath = nil
-local savedhtap = nil
- for o=1,#objects do
- local object = objects[o]
- local objecttype = object.type
- if objecttype == "start_bounds" or objecttype == "stop_bounds" then
- -- skip
- elseif objecttype == "special" then
- if processspecial then
- processspecial(object.prescript)
- end
- elseif objecttype == "start_clip" then
- local evenodd = not object.istext and object.postscript == "evenodd"
- result[#result+1] = "q"
- flushnormalpath(object.path,result,false)
- result[#result+1] = evenodd and "W* n" or "W n"
- elseif objecttype == "stop_clip" then
- result[#result+1] = "Q"
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
- elseif objecttype == "text" then
- result[#result+1] = "q"
- local ot = object.transform -- 3,4,5,6,1,2
- result[#result+1] = f_cm(ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: formatters["%F %F m %F %F %F %F 0 0 cm"](unpack(ot))
- flushfigure(result) -- flush accumulated literals
- result = { }
- textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
- result[#result+1] = "Q"
- else
- -- we use an indirect table as we want to overload
- -- entries but this is not possible in userdata
- --
- -- can be optimized if no path
- --
- local original = object
- local object = { }
- setmetatable(object, {
- __index = original
- })
- -- first we analyze
- local before, after = processplugins(object)
- local evenodd = not object.istext and object.postscript == "evenodd"
- local collect = not object.istext and object.postscript == "collect"
- if collect then
- if not savedpath then
- savedpath = { object.path or false }
- savedhtap = { object.htap or false }
- else
- savedpath[#savedpath+1] = object.path or false
- savedhtap[#savedhtap+1] = object.htap or false
- end
- else
- local objecttype = object.type -- can have changed
- if before then
- result = pluginactions(before,result,flushfigure)
- end
- local ml = object.miterlimit
- if ml and ml ~= miterlimit then
- miterlimit = ml
- result[#result+1] = f_M(ml)
- end
- local lj = object.linejoin
- if lj and lj ~= linejoin then
- linejoin = lj
- result[#result+1] = f_j(lj)
- end
- local lc = object.linecap
- if lc and lc ~= linecap then
- linecap = lc
- result[#result+1] = f_J(lc)
- end
- local dl = object.dash
- if dl then
- local d = f_d(concat(dl.dashes or {}," "),dl.offset)
- if d ~= dashed then
- dashed = d
- result[#result+1] = d
- end
- elseif dashed ~= false then -- was just dashed test
- result[#result+1] = "[] 0 d"
- dashed = false
- end
- local path = object.path -- newpath
- local transformed, penwidth = false, 1
- local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point"
- local pen = object.pen
- if pen then
- if pen.type == 'elliptical' then
- transformed, penwidth = pen_characteristics(original) -- boolean, value
- result[#result+1] = f_w(penwidth) -- todo: only if changed
- if objecttype == 'fill' then
- objecttype = 'both'
- end
- else -- calculated by mplib itself
- objecttype = 'fill'
- end
- end
- if transformed then
- result[#result+1] = "q"
- end
- if path then
- if savedpath then
- for i=1,#savedpath do
- local path = savedpath[i]
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- end
- savedpath = nil
- end
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- if objecttype == "fill" then
- result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
- elseif objecttype == "outline" then
- result[#result+1] = open and "S" or "h S"
- elseif objecttype == "both" then
- result[#result+1] = evenodd and "h B*" or "h B"-- B* = eo -- b includes closepath
- end
- end
- if transformed then
- result[#result+1] = "Q"
- end
- local path = object.htap
- if path then
- if transformed then
- result[#result+1] = "q"
- end
- if savedhtap then
- for i=1,#savedhtap do
- local path = savedhtap[i]
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- end
- savedhtap = nil
- evenodd = true
- end
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- if objecttype == "fill" then
- result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
- elseif objecttype == "outline" then
- result[#result+1] = open and "S" or "h S"
- elseif objecttype == "both" then
- result[#result+1] = evenodd and "h B*" or "h B"-- B* = eo -- b includes closepath
- end
- if transformed then
- result[#result+1] = "Q"
- end
- end
- if after then
- result = pluginactions(after,result,flushfigure)
- end
- end
- if object.grouped then
- -- can be qQ'd so changes can end up in groups
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
- end
- end
- end
- end
- result[#result+1] = "Q"
- flushfigure(result)
- stopfigure("end")
- end
- if askedfig ~= "all" then
- break
- end
- end
- end
- end
- end
-end
-
-function metapost.parse(result,askedfig)
- if result then
- local figures = result.fig
- if figures then
- local multipass = false
- local analyzeplugins = metapost.analyzeplugins -- each object
- for index=1,#figures do
- local figure = figures[index]
- local properties = setproperties(figure)
- if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
- local objects = getobjects(result,figure,index)
- if objects then
- for o=1,#objects do
- if analyzeplugins(objects[o]) then
- multipass = true
- end
- end
- end
- if askedfig ~= "all" then
- break
- end
- end
- end
- return multipass
- end
- end
-end
-
--- tracing:
-
-local result = { }
-
-local flusher = {
- startfigure = function()
- result = { }
- context.startnointerference()
- end,
- flushfigure = function(literals)
- local n = #result
- for i=1,#literals do
- result[n+i] = literals[i]
- end
- end,
- stopfigure = function()
- context.stopnointerference()
- end
-}
-
-function metapost.pdfliterals(result)
- metapost.flush(result,flusher)
- return result
-end
-
-function metapost.totable(result,askedfig)
- local askedfig = askedfig or 1
- local figure = result and result.fig and result.fig[1]
- if figure then
- local results = { }
- -- local objects = figure:objects()
- local objects = getobjects(result,figure,askedfig)
- for o=1,#objects do
- local object = objects[o]
- local result = { }
- local fields = object_fields(object) -- hm, is this the whole list, if so, we can get it once
- for f=1,#fields do
- local field = fields[f]
- result[field] = object[field]
- end
- results[o] = result
- end
- local boundingbox = figure:boundingbox()
- return {
- boundingbox = {
- llx = boundingbox[1],
- lly = boundingbox[2],
- urx = boundingbox[3],
- ury = boundingbox[4],
- },
- objects = results
- }
- else
- return nil
- end
-end