if not modules then modules = { } end modules ['mlib-run'] = { 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", } --~ cmyk -> done, native --~ spot -> done, but needs reworking (simpler) --~ multitone -> --~ shade -> partly done, todo: cm --~ figure -> done --~ hyperlink -> low priority, easy -- new * run -- or -- new * execute^1 * finish -- a*[b,c] == b + a * (c-b) --[[ldx--

The directional helpers and pen analysis are more or less translated from the code. It really helps that Taco know that source so well. Taco and I spent quite some time on speeding up the and code. There is not much to gain, especially if one keeps in mind that when integrated in only a part of the time is spent in . Of course an integrated approach is way faster than an external and processing time nears zero.

--ldx]]-- local trace_graphics = false trackers.register("metapost.graphics", function(v) trace_graphics = v end) local format, gsub, match = string.format, string.gsub, string.match local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming metapost = metapost or { } metapost.showlog = false metapost.lastlog = "" function metapost.resetlastlog() metapost.lastlog = "" end local function finder(name, mode, ftype) if mode=="w" then return name elseif file.is_qualified_path(name) then return name else return resolvers.find_file(name,ftype) end end metapost.finder = finder metapost.parameters = { hash_size = 100000, main_memory = 4000000, max_in_open = 50, param_size = 100000, } metapost.exectime = metapost.exectime or { } -- hack local preamble = [[ boolean mplib; string mp_parent_version; mplib := true; mp_parent_version := "%s"; input %s ; dump ; ]] function metapost.make(name, target, version) starttiming(mplib) target = file.replacesuffix(target or name, "mem") local mpx = mplib.new ( table.merged ( metapost.parameters, { ini_version = true, find_file = finder, job_name = file.removesuffix(target), } ) ) if mpx then starttiming(metapost.exectime) local result = mpx:execute(format(preamble,version or "unknown",name)) stoptiming(metapost.exectime) mpx:finish() end stoptiming(mplib) end function metapost.load(name) starttiming(mplib) local mpx = mplib.new ( table.merged ( metapost.parameters, { ini_version = false, mem_name = file.replacesuffix(name,"mem"), find_file = finder, -- job_name = "mplib", } ) ) local result if not mpx then result = { status = 99, error = "out of memory"} end stoptiming(mplib) return mpx, result end function metapost.unload(mpx) starttiming(mplib) if mpx then mpx:finish() end stoptiming(mplib) end function metapost.reporterror(result) if not result then metapost.report("mp error: no result object returned") elseif result.status > 0 then local t, e, l = result.term, result.error, result.log if t and t ~= "" then metapost.report("mp terminal: %s",t) end if e then metapost.report("mp error: %s",(e=="" and "?") or e) end if not t and not e and l then metapost.lastlog = metapost.lastlog .. "\n" .. l metapost.report("mp log: %s",l) else metapost.report("mp error: unknown, no error, terminal or log messages") end else return false end return true end function metapost.checkformat(mpsinput, mpsformat, dirname) mpsinput = file.addsuffix(mpsinput or "metafun", "mp") mpsformat = file.removesuffix(file.basename(mpsformat or texconfig.formatname or (tex and tex.formatname) or mpsinput)) local mpsbase = file.removesuffix(file.basename(mpsinput)) if mpsbase ~= mpsformat then mpsformat = mpsformat .. "-" .. mpsbase end mpsformat = file.addsuffix(mpsformat, "mem") local pth = dirname or file.dirname(texconfig.formatname or "") if pth ~= "" then mpsformat = file.join(pth,mpsformat) end local the_version = environment.version or "unset version" if lfs.isfile(mpsformat) then commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat) local mpx, result = metapost.load(mpsformat) if mpx then local result = mpx:execute("show mp_parent_version ;") if not result.log then metapost.reporterror(result) else local version = match(result.log,">> *(.-)[\n\r]") or "unknown" version = gsub(version,"[\'\"]","") if version ~= the_version then commands.writestatus("mplib","version mismatch: %s <> %s", version or "unknown", the_version) else return mpx end end else commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformat) metapost.reporterror(result) end end commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformat) metapost.make(mpsinput,mpsformat,the_version) -- somehow return ... fails here if lfs.isfile(mpsformat) then commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat) return metapost.load(mpsformat) else commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformat) end end local mpxformats = { } function metapost.format(instance,name) name = name or instance local mpx = mpxformats[instance] if not mpx then commands.writestatus("mplib","initializing instance '%s' using format '%s'",instance,name) mpx = metapost.checkformat(name) mpxformats[instance] = mpx end return mpx end function metapost.reset(mpx) if not mpx then -- nothing elseif type(mpx) == "string" then if mpxformats[mpx] then mpxformats[mpx]:finish() mpxformats[mpx] = nil end else for name, instance in next, mpxformats do if instance == mpx then mpx:finish() mpxformats[name] = nil break end end end end local mp_inp, mp_log, mp_tag = { }, { }, 0 function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass, askedfig) local converted, result = false, {} if type(mpx) == "string" then mpx = metapost.format(mpx) -- goody end if mpx and data then starttiming(metapost) if trace_graphics then if not mp_inp[mpx] then mp_tag = mp_tag + 1 mp_inp[mpx] = io.open(format("%s-mplib-run-%03i.mp", tex.jobname,mp_tag),"w") mp_log[mpx] = io.open(format("%s-mplib-run-%03i.log",tex.jobname,mp_tag),"w") end local banner = format("%% begin graphic: n=%s, trialrun=%s, multipass=%s, isextrapass=%s\n\n", metapost.n, tostring(trialrun), tostring(multipass), tostring(isextrapass)) mp_inp[mpx]:write(banner) mp_log[mpx]:write(banner) end if type(data) == "table" then for i=1,#data do local d = data[i] if d then if trace_graphics then mp_inp[mpx]:write(d) end starttiming(metapost.exectime) result = mpx:execute(d) stoptiming(metapost.exectime) if trace_graphics and result then local str = result.log or result.error if str and str ~= "" then mp_log[mpx]:write(str) end end if not metapost.reporterror(result) then if metapost.showlog then local str = (result.term ~= "" and result.term) or "no terminal output" if not str:is_empty() then metapost.lastlog = metapost.lastlog .. "\n" .. str metapost.report("mp log: %s",str) end end if result.fig then converted = metapost.convert(result, trialrun, flusher, multipass, askedfig) end end else metapost.report("mp error: invalid graphic component %s",i) end end else if trace_graphics then mp_inp:write(data) end starttiming(metapost.exectime) result = mpx[mpx]:execute(data) stoptiming(metapost.exectime) if trace_graphics and result then local str = result.log or result.error if str and str ~= "" then mp_log[mpx]:write(str) end end -- todo: error message if not result then metapost.report("mp error: no result object returned") elseif result.status > 0 then metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) else if metapost.showlog then metapost.lastlog = metapost.lastlog .. "\n" .. result.term metapost.report("mp info: %s",result.term or "no-term") end if result.fig then converted = metapost.convert(result, trialrun, flusher, multipass, askedfig) end end end if trace_graphics then local banner = "\n% end graphic\n\n" mp_inp[mpx]:write(banner) mp_log[mpx]:write(banner) end stoptiming(metapost) end return converted, result end function metapost.convert() metapost.report('mp warning: no converter set') end function metapost.report(...) logs.report("mplib",...) end -- handy function metapost.directrun(formatname,filename,outputformat,astable,mpdata) local fullname = file.addsuffix(filename,"mp") local data = mpdata or io.loaddata(fullname) if outputformat ~= "svg" then outputformat = "mps" end if not data then logs.simple("unknown file '%s'",filename or "?") else local mpx = metapost.checkformat(formatname,formatname,caches.setpath("formats")) if not mpx then logs.simple("unknown format '%s'",formatname or "?") else logs.simple("processing '%s'",(mpdata and (filename or "data")) or fullname) local result = mpx:execute(data) if not result then logs.simple("error: no result object returned") elseif result.status > 0 then logs.simple("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) else if metapost.showlog then metapost.lastlog = metapost.lastlog .. "\n" .. result.term logs.simple("info: %s",result.term or "no-term") end local figures = result.fig if figures then local sorted = table.sortedkeys(figures) if astable then local result = { } logs.simple("storing %s figures in table",#sorted) for k=1,#sorted do local v = sorted[k] if outputformat == "mps" then result[v] = figures[v]:postscript() else result[v] = figures[v]:svg() -- (3) for prologues end end return result else local basename = file.removesuffix(file.basename(filename)) for k=1,#sorted do local v = sorted[k] local output if outputformat == "mps" then output = figures[v]:postscript() else output = figures[v]:svg() -- (3) for prologues end local outname = format("%s-%s.%s",basename,v,outputformat) logs.simple("saving %s bytes in '%s'",#output,outname) io.savedata(outname,output) end return #sorted end end end end end end