-- -- This is file `luamplib.lua', -- generated with the docstrip utility. -- -- The original source files were: -- -- luamplib.dtx (with options: `lua') -- -- See source file 'luamplib.dtx' for licencing and contact information. -- luamplib = luamplib or { } local luamplib = luamplib luamplib.showlog = luamplib.showlog or false luamplib.lastlog = "" local err, warn, info, log = luatexbase.provides_module({ name = "luamplib", version = "2.6.0", date = "2014/03/08", description = "Lua package to typeset Metapost with LuaTeX's MPLib.", }) local format, abs = string.format, math.abs local stringgsub = string.gsub local stringfind = string.find local stringmatch = string.match local stringgmatch = string.gmatch local stringexplode = string.explode local tableconcat = table.concat local texsprint = tex.sprint local mplib = require ('mplib') local kpse = require ('kpse') local lfs = require ('lfs') local lfsattributes = lfs.attributes local lfsisdir = lfs.isdir local lfstouch = lfs.touch local ioopen = io.open local file = file if not file then file = { } function file.replacesuffix(filename, suffix) return (stringgsub(filename,"%.[%a%d]+$","")) .. "." .. suffix end function file.stripsuffix(filename) return (stringgsub(filename,"%.[%a%d]+$","")) end end local luamplibtime = kpse.find_file("luamplib.lua") luamplibtime = luamplibtime and lfsattributes(luamplibtime,"modification") local currenttime = os.time() local outputdir = "." for _,v in ipairs(arg) do local t = stringmatch(v,"%-output%-directory=(.+)") if t then outputdir = t break end end function luamplib.getcachedir(dir) dir = stringgsub(dir,"##","#") dir = stringgsub(dir,"^~", os.type == "windows" and os.getenv("UserProfile") or os.getenv("HOME")) if lfstouch and dir then if lfsisdir(dir) then local tmp = dir.."/_luam_plib_temp_file_" local fh = ioopen(tmp,"w") if fh then fh:close(fh) os.remove(tmp) luamplib.cachedir = dir else warn("Directory '"..dir.."' is not writable!") end else warn("Directory '"..dir.."' does not exist!") end end end local noneedtoreplace = { ["boxes.mp"] = true, -- ["format.mp"] = true, ["graph.mp"] = true, ["marith.mp"] = true, ["mfplain.mp"] = true, ["mpost.mp"] = true, ["plain.mp"] = true, ["rboxes.mp"] = true, ["sarith.mp"] = true, ["string.mp"] = true, ["TEX.mp"] = true, ["metafun.mp"] = true, ["metafun.mpiv"] = true, ["mp-abck.mpiv"] = true, ["mp-apos.mpiv"] = true, ["mp-asnc.mpiv"] = true, ["mp-base.mpiv"] = true, ["mp-butt.mpiv"] = true, ["mp-char.mpiv"] = true, ["mp-chem.mpiv"] = true, ["mp-core.mpiv"] = true, ["mp-crop.mpiv"] = true, ["mp-figs.mpiv"] = true, ["mp-form.mpiv"] = true, ["mp-func.mpiv"] = true, ["mp-grap.mpiv"] = true, ["mp-grid.mpiv"] = true, ["mp-grph.mpiv"] = true, ["mp-idea.mpiv"] = true, ["mp-mlib.mpiv"] = true, ["mp-page.mpiv"] = true, ["mp-shap.mpiv"] = true, ["mp-step.mpiv"] = true, ["mp-text.mpiv"] = true, ["mp-tool.mpiv"] = true, } luamplib.noneedtoreplace = noneedtoreplace local function replaceformatmp(file,newfile,ofmodify) local fh = ioopen(file,"r") if not fh then return file end local data = fh:read("*all"); fh:close() fh = ioopen(newfile,"w") if not fh then return file end fh:write( "let normalinfont = infont;\n", "primarydef str infont name = rawtextext(str) enddef;\n", data, "vardef Fmant_(expr x) = rawtextext(decimal abs x) enddef;\n", "vardef Fexp_(expr x) = rawtextext(\"$^{\"&decimal x&\"}$\") enddef;\n", "let infont = normalinfont;\n" ); fh:close() lfstouch(newfile,currenttime,ofmodify) return newfile end local function replaceinputmpfile (name,file) local ofmodify = lfsattributes(file,"modification") if not ofmodify then return file end local cachedir = luamplib.cachedir or outputdir local newfile = stringgsub(name,"%W","_") newfile = cachedir .."/luamplib_input_"..newfile if newfile and luamplibtime then local nf = lfsattributes(newfile) if nf and nf.mode == "file" and ofmodify == nf.modification and luamplibtime < nf.access then return nf.size == 0 and file or newfile end end if name == "format.mp" then return replaceformatmp(file,newfile,ofmodify) end local fh = ioopen(file,"r") if not fh then return file end local data = fh:read("*all"); fh:close() data = stringgsub(data, "\"[^\n]-\"", function(str) str = stringgsub(str,"%%","!!!!!PERCENT!!!!!") str = stringgsub(str,"([bem])tex%f[^A-Z_a-z]","%1!!!T!!!E!!!X!!!") return str end) data = stringgsub(data,"%%.-\n","") local count,cnt = 0,0 data,cnt = stringgsub(data, "%f[A-Z_a-z]btex%f[^A-Z_a-z]%s*(.-)%s*%f[A-Z_a-z]etex%f[^A-Z_a-z]", function(str) str = stringgsub(str,"[\n\r]%s*"," ") str = stringgsub(str,'"','"&ditto&"') return format("rawtextext(\"%s\")",str) end) count = count + cnt data,cnt = stringgsub(data, "%f[A-Z_a-z]verbatimtex%f[^A-Z_a-z]%s*.-%s*%f[A-Z_a-z]etex%f[^A-Z_a-z]", "") count = count + cnt if count == 0 then noneedtoreplace[name] = true fh = ioopen(newfile,"w"); if fh then fh:close() lfstouch(newfile,currenttime,ofmodify) end return file end data = stringgsub(data,"([bem])!!!T!!!E!!!X!!!","%1tex") data = stringgsub(data,"!!!!!PERCENT!!!!!","%%") fh = ioopen(newfile,"w") if not fh then return file end fh:write(data); fh:close() lfstouch(newfile,currenttime,ofmodify) return newfile end local randomseed = nil local mpkpse = kpse.new("luatex", "mpost") local function finder(name, mode, ftype) if mode == "w" then return name else local file = mpkpse:find_file(name,ftype) if file then if not lfstouch or ftype ~= "mp" or noneedtoreplace[name] then return file end return replaceinputmpfile(name,file) end return mpkpse:find_file(name,stringmatch(name,"[a-zA-Z]+$")) end end luamplib.finder = finder function luamplib.resetlastlog() luamplib.lastlog = "" end local mplibone = tonumber(mplib.version()) <= 1.50 if mplibone then luamplib.make = luamplib.make or function(name,mem_name,dump) local t = os.clock() local mpx = mplib.new { ini_version = true, find_file = luamplib.finder, job_name = file.stripsuffix(name) } mpx:execute(format("input %s ;",name)) if dump then mpx:execute("dump ;") info("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t) else info("%s read in %0.3f seconds",name,os.clock()-t) end return mpx end function luamplib.load(name) local mem_name = file.replacesuffix(name,"mem") local mpx = mplib.new { ini_version = false, mem_name = mem_name, find_file = luamplib.finder } if not mpx and type(luamplib.make) == "function" then -- when i have time i'll locate the format and dump mpx = luamplib.make(name,mem_name) end if mpx then info("using format %s",mem_name,false) return mpx, nil else return nil, { status = 99, error = "out of memory or invalid format" } end end else local preamble = [[ boolean mplib ; mplib := true ; let dump = endinput ; let normalfontsize = fontsize; input %s ; ]] luamplib.make = luamplib.make or function() end function luamplib.load(name) local mpx = mplib.new { ini_version = true, find_file = luamplib.finder, math_mode = luamplib.numbersystem, random_seed = randomseed, } local result if not mpx then result = { status = 99, error = "out of memory"} else result = mpx:execute(format(preamble, file.replacesuffix(name,"mp"))) end luamplib.reporterror(result) return mpx, result end end local currentformat = "plain" local function setformat (name) --- used in .sty currentformat = name end luamplib.setformat = setformat luamplib.reporterror = function (result) if not result then err("no result object returned") elseif result.status > 0 then local t, e, l = result.term, result.error, result.log if t then info(t) end if e then err(e) end if not t and not e and l then luamplib.lastlog = luamplib.lastlog .. "\n " .. l log(l) else err("unknown, no error, terminal or log messages") end else return false end return true end local function process_indeed (mpx, data) local converted, result = false, {} local mpx = luamplib.load(mpx) if mpx and data then local result = mpx:execute(data) if not result then err("no result object returned") elseif result.status > 0 then err("%s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) elseif luamplib.showlog then luamplib.lastlog = luamplib.lastlog .. "\n" .. result.term info("%s",result.term or "no-term") elseif result.fig then converted = luamplib.convert(result) else err("unknown error, maybe no beginfig/endfig") end else err("Mem file unloadable. Maybe generated with a different version of mplib?") end return converted, result end local process = function (data) return process_indeed(currentformat, data) end luamplib.process = process local function getobjects(result,figure,f) return figure:objects() end local function convert(result, flusher) luamplib.flush(result, flusher) return true -- done end luamplib.convert = convert local function pdf_startfigure(n,llx,lly,urx,ury) texsprint(format("\\mplibstarttoPDF{%f}{%f}{%f}{%f}",llx,lly,urx,ury)) end local function pdf_stopfigure() texsprint("\\mplibstoptoPDF") end local function pdf_literalcode(fmt,...) -- table texsprint(format("\\mplibtoPDF{%s}",format(fmt,...))) end luamplib.pdf_literalcode = pdf_literalcode local function pdf_textfigure(font,size,text,width,height,depth) -- if text == "" then text = "\0" end -- char(0) has gone text = text:gsub(".",function(c) return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost end) texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth)) end luamplib.pdf_textfigure = pdf_textfigure 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 = mplib.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 concat(px, py) -- no tx, ty here 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,open) local pth, ith for i=1,#path do pth = path[i] if not ith then pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord) elseif curved(ith,pth) then pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord) else pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord) end ith = pth end if not open then local one = path[1] if curved(pth,one) then pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord ) else pdf_literalcode("%f %f l",one.x_coord,one.y_coord) end elseif #path == 1 then -- special case .. draw point local one = path[1] pdf_literalcode("%f %f l",one.x_coord,one.y_coord) end return t end local function flushconcatpath(path,open) pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty) local pth, ith for i=1,#path do pth = path[i] if not ith then pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord)) elseif curved(ith,pth) then local a, b = concat(ith.right_x,ith.right_y) local c, d = concat(pth.left_x,pth.left_y) pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord)) else pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord)) end ith = pth end if not open then local one = path[1] if curved(pth,one) then local a, b = concat(pth.right_x,pth.right_y) local c, d = concat(one.left_x,one.left_y) pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord)) else pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) end elseif #path == 1 then -- special case .. draw point local one = path[1] pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) end return t end local further_split_keys = { ["MPlibTEXboxID"] = true, ["sh_color_a"] = true, ["sh_color_b"] = true, } local function script2table(s) local t = {} for _,i in ipairs(stringexplode(s,"\13+")) do local k,v = stringmatch(i,"(.-)=(.*)") -- v may contain = or empty. if k and v and k ~= "" then if further_split_keys[k] then t[k] = stringexplode(v,":") else t[k] = v end end end return t end local mplibcodepreamble = [[ vardef rawtextext (expr t) = if unknown TEXBOX_: image( special "MPlibmkTEXbox="&t; ) else: TEXBOX_ := TEXBOX_ + 1; if known TEXBOX_wd_[TEXBOX_]: image ( addto currentpicture doublepath unitsquare xscaled TEXBOX_wd_[TEXBOX_] yscaled (TEXBOX_ht_[TEXBOX_] + TEXBOX_dp_[TEXBOX_]) shifted (0, -TEXBOX_dp_[TEXBOX_]) withprescript "MPlibTEXboxID=" & decimal TEXBOX_ & ":" & decimal TEXBOX_wd_[TEXBOX_] & ":" & decimal(TEXBOX_ht_[TEXBOX_]+TEXBOX_dp_[TEXBOX_]); ) else: image( special "MPlibTEXError=1"; ) fi fi enddef; if known context_mlib: defaultfont := "cmtt10"; let infont = normalinfont; let fontsize = normalfontsize; vardef thelabel@#(expr p,z) = if string p : thelabel@#(p infont defaultfont scaled defaultscale,z) else : p shifted (z + labeloffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p)) fi enddef; def graphictext primary filename = if (readfrom filename = EOF): errmessage "Please prepare '"&filename&"' in advance with"& " 'pstoedit -ssp -dt -f mpost yourfile.ps "&filename&"'"; fi closefrom filename; def data_mpy_file = filename enddef; mfun_do_graphic_text (filename) enddef; if unknown TEXBOX_: def mfun_do_graphic_text text t = enddef; fi else: vardef textext@# (text t) = rawtextext (t) enddef; fi def externalfigure primary filename = draw rawtextext("\includegraphics{"& filename &"}") enddef; def TEX = textext enddef; def fontmapfile primary filename = enddef; def specialVerbatimTeX (text t) = special "MPlibVerbTeX="&t; enddef; def ignoreVerbatimTeX (text t) = enddef; let VerbatimTeX = specialVerbatimTeX; extra_beginfig := extra_beginfig & " let VerbatimTeX = ignoreVerbatimTeX;" ; extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX;" ; ]] local textextlabelpreamble = [[ primarydef s infont f = rawtextext(s) enddef; let normalinfont = infont; def fontsize expr f = begingroup save size,pic; numeric size; picture pic; pic := rawtextext("\hskip\pdffontsize\font"); size := xpart urcorner pic - xpart llcorner pic; if size = 0: 10pt else: size fi endgroup enddef; let normalfontsize = fontsize; ]] local function protecttextext(data) local everymplib = tex.toks['everymplibtoks'] or '' local everyendmplib = tex.toks['everyendmplibtoks'] or '' data = "\n" .. everymplib .."\n".. data .."\n".. everyendmplib data = stringgsub(data,"\r","\n") data = stringgsub(data, "\"[^\n]-\"", function(str) str = stringgsub(str,"%%","!!!!!PERCENT!!!!!") str = stringgsub(str,"([bem])tex%f[^A-Z_a-z]","%1!!!T!!!E!!!X!!!") return str end) data = stringgsub(data,"%%.-\n","") data = stringgsub(data, "%f[A-Z_a-z]btex%f[^A-Z_a-z]%s*(.-)%s*%f[A-Z_a-z]etex%f[^A-Z_a-z]", function(str) str = stringgsub(str,'"','"&ditto&"') str = stringgsub(str,"\n%s*"," ") return format("rawtextext(\"%s\")",str) end) data = stringgsub(data, "%f[A-Z_a-z]verbatimtex%f[^A-Z_a-z]%s*(.-)%s*%f[A-Z_a-z]etex%f[^A-Z_a-z]", function(str) str = stringgsub(str,'"','"&ditto&"') str = stringgsub(str,"\n%s*"," ") return format("VerbatimTeX(\"%s\")",str) end) data = stringgsub(data, "\"[^\n]-\"", function(str) str = stringgsub(str,"([bem])!!!T!!!E!!!X!!!","%1tex") str = stringgsub(str,"{", "!!!!!LEFTBRCE!!!!!") str = stringgsub(str,"}", "!!!!!RGHTBRCE!!!!!") str = stringgsub(str,"#", "!!!!!SHARPE!!!!!") return format("\\detokenize{%s}",str) end) texsprint(data) end luamplib.protecttextext = protecttextext local TeX_code_t = {} local function domakeTEXboxes (data) local num = 255 -- output box if data and data.fig then local figures = data.fig for f=1, #figures do TeX_code_t[f] = nil local figure = figures[f] local objects = getobjects(data,figure,f) if objects then for o=1,#objects do local object = objects[o] local prescript = object.prescript prescript = prescript and script2table(prescript) local str = prescript and prescript.MPlibmkTEXbox if str then num = num + 1 texsprint(format("\\setbox%i\\hbox{%s}",num,str)) end local texcode = prescript and prescript.MPlibVerbTeX if texcode and texcode ~= "" then TeX_code_t[f] = texcode end end end end end end local function makeTEXboxes (data) data = stringgsub(data, "##", "#") -- restore # doubled in input string data = stringgsub(data, "!!!!!PERCENT!!!!!", "%%") data = stringgsub(data, "!!!!!LEFTBRCE!!!!!","{") data = stringgsub(data, "!!!!!RGHTBRCE!!!!!","}") data = stringgsub(data, "!!!!!SHARPE!!!!!", "#" ) local preamble = mplibcodepreamble if luamplib.textextlabel then preamble = textextlabelpreamble .. preamble end randomseed = math.random(65535) local mpx = luamplib.load(currentformat) if mpx and data then local result = mpx:execute(preamble .. data) domakeTEXboxes(result) end return data end luamplib.makeTEXboxes = makeTEXboxes local factor = 65536*(7227/7200) local function processwithTEXboxes (data) local num = 255 -- output box local prepreamble = "TEXBOX_ := "..num..";\n" while true do num = num + 1 local box = tex.box[num] if not box then break end prepreamble = prepreamble .. "TEXBOX_wd_["..num.."] := "..box.width /factor..";\n".. "TEXBOX_ht_["..num.."] := "..box.height/factor..";\n".. "TEXBOX_dp_["..num.."] := "..box.depth /factor..";\n" end local preamble = prepreamble .. mplibcodepreamble if luamplib.textextlabel then preamble = textextlabelpreamble .. preamble end process(preamble .. data) end luamplib.processwithTEXboxes = processwithTEXboxes local function putTEXboxes (object,prescript) local box = prescript.MPlibTEXboxID local n,tw,th = box[1],box[2],box[3] if n and tw and th then local op = object.path local first, second, fourth = op[1], op[2], op[4] local tx, ty = first.x_coord, first.y_coord local sx, sy = (second.x_coord - tx)/tw, (fourth.y_coord - ty)/th local rx, ry = (second.y_coord - ty)/tw, (fourth.x_coord - tx)/th if sx == 0 then sx = 0.00001 end if sy == 0 then sy = 0.00001 end pdf_literalcode("q %f %f %f %f %f %f cm",sx,rx,ry,sy,tx,ty) texsprint(format("\\mplibputtextbox{%i}",n)) pdf_literalcode("Q") end end local pdf_objs = {} -- objstr => obj , new local function update_pdfobjs (os) local on = pdf_objs[os] if on then return on,false end on = pdf.immediateobj(os) pdf_objs[os] = on return on,true end local transparancy_modes = { [0] = "Normal", "Normal", "Multiply", "Screen", "Overlay", "SoftLight", "HardLight", "ColorDodge", "ColorBurn", "Darken", "Lighten", "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity", "Compatible", } local function update_tr_res(res,mode,opaq) local os = format("<>",mode,opaq,opaq) local on, new = update_pdfobjs(os) if new then res = res .. format("/MPlibTr%s%g %i 0 R",mode,opaq,on) end return res end local function tr_pdf_pageresources(mode,opaq) local res = "" res = update_tr_res(res, "Normal", 1) res = update_tr_res(res, mode, opaq) if res ~= "" then local tpr = tex.pdfpageresources -- respect luaotfload-colors if not stringfind(tpr,"/ExtGState<<.*>>") then tpr = tpr.."/ExtGState<<>>" end tpr = stringgsub(tpr,"/ExtGState<<","%1"..res) tex.set("global","pdfpageresources",tpr) end end -- luatexbase.mcb is not yet updated: "finish_pdffile" callback is missing local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordinates) local os, on, new os = format("<>", domain, colora, colorb) on = update_pdfobjs(os) os = format("<>", shtype, colorspace, on, coordinates) on, new = update_pdfobjs(os) if not new then return on end local res = format("/MPlibSh%i %i 0 R", on, on) local ppr = pdf.pageresources or "" if not stringfind(ppr,"/Shading<<.*>>") then ppr = ppr.."/Shading<<>>" end pdf.pageresources = stringgsub(ppr,"/Shading<<","%1"..res) return on end local function color_normalize(ca,cb) if #cb == 1 then if #ca == 4 then cb[1], cb[2], cb[3], cb[4] = 0, 0, 0, 1-cb[1] else -- #ca = 3 cb[1], cb[2], cb[3] = cb[1], cb[1], cb[1] end elseif #cb == 3 then -- #ca == 4 cb[1], cb[2], cb[3], cb[4] = 1-cb[1], 1-cb[2], 1-cb[3], 0 end end local function do_preobj_color(object,prescript) -- transparency local opaq = prescript and prescript.tr_transparency if opaq then local mode = prescript.tr_alternative or 1 mode = transparancy_modes[tonumber(mode)] tr_pdf_pageresources(mode,opaq) pdf_literalcode("/MPlibTr%s%g gs",mode,opaq) end -- color local cs = object.color if cs and #cs > 0 then pdf_literalcode(luamplib.colorconverter(cs)) end -- shading local sh_type = prescript and prescript.sh_type if sh_type then local domain = prescript.sh_domain local centera = prescript.sh_center_a local centerb = prescript.sh_center_b local colora = prescript.sh_color_a or {0}; local colorb = prescript.sh_color_b or {1}; if #colora > #colorb then color_normalize(colora,colorb) elseif #colorb > #colora then color_normalize(colorb,colora) end local colorspace if #colorb == 1 then colorspace = "DeviceGray" elseif #colorb == 3 then colorspace = "DeviceRGB" elseif #colorb == 4 then colorspace = "DeviceCMYK" else return opaq end colora = tableconcat(colora, " ") colorb = tableconcat(colorb, " ") local shade_no if sh_type == "linear" then local coordinates = format("%s %s",centera,centerb) shade_no = sh_pdfpageresources(2,domain,colorspace,colora,colorb,coordinates) elseif sh_type == "circular" then local radiusa = prescript.sh_radius_a local radiusb = prescript.sh_radius_b local coordinates = format("%s %s %s %s",centera,radiusa,centerb,radiusb) shade_no = sh_pdfpageresources(3,domain,colorspace,colora,colorb,coordinates) end pdf_literalcode("q /Pattern cs") return opaq,shade_no end return opaq end local function do_postobj_color(tr,sh) if sh then pdf_literalcode("W n /MPlibSh%s sh Q",sh) end if tr then pdf_literalcode("/MPlibTrNormal1 gs") end end local function flush(result,flusher) if result then local figures = result.fig if figures then for f=1, #figures do info("flushing figure %s",f) local figure = figures[f] local objects = getobjects(result,figure,f) local fignum = tonumber(stringmatch(figure:filename(),"([%d]+)$") or figure:charcode() or 0) local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false local bbox = figure:boundingbox() local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack if urx < llx then -- invalid pdf_startfigure(fignum,0,0,0,0) pdf_stopfigure() else if TeX_code_t[f] then texsprint(TeX_code_t[f]) end pdf_startfigure(fignum,llx,lly,urx,ury) pdf_literalcode("q") if objects then for o=1,#objects do local object = objects[o] local objecttype = object.type local prescript = object.prescript prescript = prescript and script2table(prescript) -- prescript is now a table local tr_opaq,shade_no = do_preobj_color(object,prescript) if prescript and prescript.MPlibTEXboxID then putTEXboxes(object,prescript) elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then -- skip elseif objecttype == "start_clip" then pdf_literalcode("q") flushnormalpath(object.path,t,false) pdf_literalcode("W n") elseif objecttype == "stop_clip" then pdf_literalcode("Q") miterlimit, linecap, linejoin, dashed = -1, -1, -1, false elseif objecttype == "special" then -- not supported if prescript and prescript.MPlibTEXError then warn("textext() anomaly. Try disabling \\mplibtextextlabel.") end elseif objecttype == "text" then local ot = object.transform -- 3,4,5,6,1,2 pdf_literalcode("q %f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth) pdf_literalcode("Q") else local ml = object.miterlimit if ml and ml ~= miterlimit then miterlimit = ml pdf_literalcode("%f M",ml) end local lj = object.linejoin if lj and lj ~= linejoin then linejoin = lj pdf_literalcode("%i j",lj) end local lc = object.linecap if lc and lc ~= linecap then linecap = lc pdf_literalcode("%i J",lc) end local dl = object.dash if dl then local d = format("[%s] %i d",tableconcat(dl.dashes or {}," "),dl.offset) if d ~= dashed then dashed = d pdf_literalcode(dashed) end elseif dashed then pdf_literalcode("[] 0 d") dashed = false end local path = object.path local transformed, penwidth = false, 1 local open = path and path[1].left_type and path[#path].right_type local pen = object.pen if pen then if pen.type == 'elliptical' then transformed, penwidth = pen_characteristics(object) -- boolean, value pdf_literalcode("%f w",penwidth) if objecttype == 'fill' then objecttype = 'both' end else -- calculated by mplib itself objecttype = 'fill' end end if transformed then pdf_literalcode("q") end if path then if transformed then flushconcatpath(path,open) else flushnormalpath(path,open) end if not shade_no then ----- conflict with shading if objecttype == "fill" then pdf_literalcode("h f") elseif objecttype == "outline" then pdf_literalcode((open and "S") or "h S") elseif objecttype == "both" then pdf_literalcode("h B") end end end if transformed then pdf_literalcode("Q") end local path = object.htap if path then if transformed then pdf_literalcode("q") end if transformed then flushconcatpath(path,open) else flushnormalpath(path,open) end if objecttype == "fill" then pdf_literalcode("h f") elseif objecttype == "outline" then pdf_literalcode((open and "S") or "h S") elseif objecttype == "both" then pdf_literalcode("h B") end if transformed then pdf_literalcode("Q") end end -- if cr then -- pdf_literalcode(cr) -- end end do_postobj_color(tr_opaq,shade_no) end end pdf_literalcode("Q") pdf_stopfigure() end end end end end luamplib.flush = flush local function colorconverter(cr) local n = #cr if n == 4 then local c, m, y, k = cr[1], cr[2], cr[3], cr[4] return format("%.3g %.3g %.3g %.3g k %.3g %.3g %.3g %.3g K",c,m,y,k,c,m,y,k), "0 g 0 G" elseif n == 3 then local r, g, b = cr[1], cr[2], cr[3] return format("%.3g %.3g %.3g rg %.3g %.3g %.3g RG",r,g,b,r,g,b), "0 g 0 G" else local s = cr[1] return format("%.3g g %.3g G",s,s), "0 g 0 G" end end luamplib.colorconverter = colorconverter -- -- End of File `luamplib.lua'.