Last active
September 25, 2015 10:03
-
-
Save dohyunkim/29a64ba3570750e464f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- | |
| -- 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.11.1", | |
| date = "2015/09/17", | |
| 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 textprint = tex.tprint | |
| local texget = tex.get | |
| local texset = tex.set | |
| local texgettoks = tex.gettoks | |
| local texgetbox = tex.getbox | |
| local mplib = require ('mplib') | |
| local kpse = require ('kpse') | |
| local file = file or { } | |
| local replacesuffix = file.replacesuffix or function (filename, suffix) | |
| return (stringgsub(filename,"%.[%a%d]+$","")) .. "." .. suffix | |
| end | |
| local stripsuffix = file.stripsuffix or function (filename) | |
| return (stringgsub(filename,"%.[%a%d]+$","")) | |
| end | |
| local randomseed = nil | |
| local mpkpse = kpse.new("luatex", "mpost") | |
| local special_ftype = { | |
| pfb = "type1 fonts", | |
| enc = "enc files", | |
| } | |
| local function finder(name, mode, ftype) | |
| if mode == "w" then | |
| return name | |
| else | |
| ftype = special_ftype[ftype] or ftype | |
| local file = mpkpse:find_file(name,ftype) | |
| if file then return file end | |
| return mpkpse:find_file(name,stringmatch(name,"[a-zA-Z]+$")) | |
| end | |
| end | |
| luamplib.finder = finder | |
| function luamplib.resetlastlog() | |
| luamplib.lastlog = "" | |
| end | |
| do | |
| 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,verbatim,firstpass) | |
| local mpx = mplib.new { | |
| ini_version = true, | |
| find_file = luamplib.finder, | |
| math_mode = luamplib.numbersystem, | |
| random_seed = randomseed, | |
| make_text = function(...) return luamplib.maketext(firstpass,...) end, | |
| run_script = function(...) return luamplib.runscript(firstpass,...) end, | |
| extensions = 1, | |
| } | |
| local preamble = preamble .. (verbatim and "" or luamplib.mplibcodepreamble) | |
| if luamplib.textextlabel then | |
| preamble = preamble .. (verbatim and "" or luamplib.textextlabelpreamble) | |
| end | |
| local result | |
| if not mpx then | |
| result = { status = 99, error = "out of memory"} | |
| else | |
| result = mpx:execute(format(preamble, 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") | |
| else | |
| local t, e, l = result.term, result.error, result.log | |
| local log = stringgsub(t or l or "no-term","^%s+","\n") | |
| luamplib.lastlog = luamplib.lastlog .. "\n " .. (l or t or "no-log") | |
| if result.status > 0 then | |
| warn("%s",log) | |
| if result.status > 1 then | |
| err("%s",e or "see above messages") | |
| end | |
| end | |
| return log | |
| end | |
| end | |
| local function process_indeed (mpx, data, indeed) | |
| local converted, result = false, {} | |
| if mpx and data then | |
| result = mpx:execute(data) | |
| local log = luamplib.reporterror(result) | |
| if indeed and log then | |
| if luamplib.showlog then | |
| info("%s",luamplib.lastlog) | |
| luamplib.resetlastlog() | |
| elseif result.fig then | |
| if stringfind(log,"\n>>") then info("%s",log) end | |
| converted = luamplib.convert(result) | |
| else | |
| info("%s",log) | |
| warn("No figure output. Maybe no beginfig/endfig") | |
| end | |
| end | |
| else | |
| err("Mem file unloadable. Maybe generated with a different version of mplib?") | |
| end | |
| return converted, result | |
| end | |
| luamplib.codeinherit = false | |
| local mplibinstances = {} | |
| local process = function (data,indeed,verbatim) | |
| local standalone, firstpass = not luamplib.codeinherit, not indeed | |
| local currfmt = currentformat .. (luamplib.numbersystem or "scaled") | |
| currfmt = firstpass and currfmt or (currfmt.."2") | |
| local mpx = mplibinstances[currfmt] | |
| if standalone or not mpx then | |
| randomseed = firstpass and math.random(65535) or randomseed | |
| mpx = luamplib.load(currentformat,verbatim,firstpass) | |
| mplibinstances[currfmt] = mpx | |
| end | |
| return process_indeed(mpx, data, indeed) | |
| end | |
| luamplib.process = process | |
| local esctex = "!!!T!!!E!!!X!!!" | |
| local esclbr = "!!!!!LEFTBRCE!!!!!" | |
| local escrbr = "!!!!!RGHTBRCE!!!!!" | |
| local escpcnt = "!!!!!PERCENT!!!!!" | |
| local eschash = "!!!!!HASH!!!!!" | |
| local begname = "%f[A-Z_a-z]" | |
| local endname = "%f[^A-Z_a-z]" | |
| luamplib.maketext = function(firstpass, str, what) | |
| str = str:gsub('"', '"&ditto&"') | |
| if what == 0 then | |
| return format("rawtextext(\"%s\")", str) | |
| else | |
| return format("VerbatimTeX(\"%s\")", str) | |
| end | |
| end | |
| local TeXcode_t = { } | |
| luamplib.TeXcode_t = TeXcode_t | |
| luamplib.runscript = function(firstpass, code) | |
| local script = assert(load(code)) | |
| if type(script) == "function" then -- any case of non-function? | |
| script() | |
| end | |
| return "" | |
| end | |
| 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 | |
| textprint({"\\mplibtoPDF{"},{-2,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_: | |
| _TEXBOX := _TEXBOX + 1; | |
| runscript("tex.sprint[===[\setbox"&decimal _TEXBOX&"\hbox{"&t&"}]===]"); | |
| image( | |
| addto currentpicture doublepath unitsquare; ) | |
| 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; | |
| LUAMPLIB_FIGID := 1; | |
| def specialVerbatimTeX (text t) = runscript("luamplib.TeXcode_t["&decimal LUAMPLIB_FIGID&"]=[==["&t&"]==]"); enddef; | |
| def normalVerbatimTeX (text t) = runscript("tex.sprint[===["&t&"]===]"); enddef; | |
| let VerbatimTeX = specialVerbatimTeX; | |
| extra_beginfig := extra_beginfig & " let VerbatimTeX = normalVerbatimTeX; "; | |
| extra_endfig := extra_endfig & " let VerbatimTeX = specialVerbatimTeX; LUAMPLIB_FIGID := LUAMPLIB_FIGID + 1; "; | |
| ]] | |
| luamplib.mplibcodepreamble = mplibcodepreamble | |
| local textextlabelpreamble = [[ | |
| primarydef s infont f = rawtextext(s) enddef; | |
| 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; | |
| ]] | |
| luamplib.textextlabelpreamble = textextlabelpreamble | |
| local boxbasenum = 1000 | |
| local btex_etex = begname.."btex"..endname.."%s*(.-)%s*"..begname.."etex"..endname | |
| local verbatimtex_etex = begname.."verbatimtex"..endname.."%s*(.-)%s*"..begname.."etex"..endname | |
| local function protect_tex_contents (str) | |
| return str:gsub("\\%%", "\\"..escpcnt) | |
| :gsub("%%.-\n", "") | |
| :gsub("%%.-$", "") | |
| :gsub("\n%s*", " ") | |
| :gsub(escpcnt, "%%") | |
| end | |
| local function protect_tex_text_common (data) | |
| local everymplib = texgettoks('everymplibtoks') or '' | |
| local everyendmplib = texgettoks('everyendmplibtoks') or '' | |
| data = format("\n%s\n%s\n%s",everymplib, data, everyendmplib) | |
| data = data:gsub("\r","\n") | |
| data = data:gsub("\"[^\n]-\"", function(str) | |
| return str:gsub("([bem])tex"..endname,"%1"..esctex) | |
| end) | |
| data = data:gsub(btex_etex, function(str) | |
| return format("btex %s etex", protect_tex_contents(str)) | |
| end) | |
| data = data:gsub(verbatimtex_etex, function(str) | |
| return format("verbatimtex %s etex;", protect_tex_contents(str)) | |
| end) | |
| local prepreamble = format("_TEXBOX:=%i;\n", boxbasenum) | |
| return prepreamble .. data | |
| end | |
| local function protecttextextVerbatim(data) | |
| data = protect_tex_text_common(data) | |
| data = data:gsub("\"[^\n]-\"", function(str) -- restore string btex .. etex | |
| return str:gsub("([bem])"..esctex, "%1tex") | |
| end) | |
| local _,result = process(data, false) | |
| return data | |
| end | |
| luamplib.protecttextextVerbatim = protecttextextVerbatim | |
| local function protecttextext(data) | |
| data = protect_tex_text_common(data) | |
| data = data:gsub("\"[^\n]-\"", function(str) | |
| str = str:gsub("([bem])"..esctex, "%1tex") | |
| :gsub("%%", escpcnt) | |
| :gsub("{", esclbr) | |
| :gsub("}", escrbr) | |
| :gsub("#", eschash) | |
| return format("\\detokenize{%s}",str) | |
| end) | |
| data = data:gsub("%%.-\n", "") | |
| luamplib.mpxcolors = {} | |
| data = data:gsub("\\mpcolor"..endname.."(.-){(.-)}", function(opt,str) | |
| local cnt = #luamplib.mpxcolors + 1 | |
| luamplib.mpxcolors[cnt] = format( | |
| "\\expandafter\\mplibcolor\\csname mpxcolor%i\\endcsname%s{%s}", | |
| cnt,opt,str) | |
| return format("\\csname mpxcolor%i\\endcsname",cnt) | |
| end) | |
| data = data:gsub("([^`\\])#","%1##") | |
| texsprint(data) | |
| end | |
| luamplib.protecttextext = protecttextext | |
| local function makeTEXboxes (data) | |
| data = data:gsub("##","#") | |
| :gsub(escpcnt,"%%") | |
| :gsub(esclbr,"{") | |
| :gsub(escrbr,"}") | |
| :gsub(eschash,"#") | |
| local _,result = process(data, false) | |
| return data | |
| end | |
| luamplib.makeTEXboxes = makeTEXboxes | |
| local factor = 65536*(7227/7200) | |
| local function processwithTEXboxes (data) | |
| if not data then return end | |
| local num = boxbasenum | |
| local prepreamble = format("TEXBOX_:=%i;\n",num) | |
| while true do | |
| num = num + 1 | |
| local box = texgetbox(num) | |
| if not box then break end | |
| prepreamble = format( | |
| "%sTEXBOX_wd_[%i]:=%f;\nTEXBOX_ht_[%i]:=%f;\nTEXBOX_dp_[%i]:=%f;\n", | |
| prepreamble, | |
| num, box.width /factor, | |
| num, box.height/factor, | |
| num, box.depth /factor) | |
| end | |
| process(prepreamble .. data, true) | |
| end | |
| luamplib.processwithTEXboxes = processwithTEXboxes | |
| local pdfmode = texget("pdfoutput") > 0 and true or false | |
| local function start_pdf_code() | |
| if pdfmode then | |
| pdf_literalcode("q") | |
| else | |
| texsprint("\\special{pdf:bcontent}") -- dvipdfmx | |
| end | |
| end | |
| local function stop_pdf_code() | |
| if pdfmode then | |
| pdf_literalcode("Q") | |
| else | |
| texsprint("\\special{pdf:econtent}") -- dvipdfmx | |
| end | |
| end | |
| local function putTEXboxes (object,prescript) | |
| local box = prescript.MPlibTEXboxID | |
| local n,tw,th = box[1],tonumber(box[2]),tonumber(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, rx, ry, sy = 1, 0, 0, 1 | |
| if tw ~= 0 then | |
| sx = (second.x_coord - tx)/tw | |
| rx = (second.y_coord - ty)/tw | |
| if sx == 0 then sx = 0.00001 end | |
| end | |
| if th ~= 0 then | |
| sy = (fourth.y_coord - ty)/th | |
| ry = (fourth.x_coord - tx)/th | |
| if sy == 0 then sy = 0.00001 end | |
| end | |
| start_pdf_code() | |
| pdf_literalcode("%f %f %f %f %f %f cm",sx,rx,ry,sy,tx,ty) | |
| texsprint(format("\\mplibputtextbox{%i}",n)) | |
| stop_pdf_code() | |
| end | |
| end | |
| local pdf_objs = {} | |
| if not pdfmode then | |
| texsprint("\\special{pdf:obj @MPlibTr<<>>}", | |
| "\\special{pdf:obj @MPlibSh<<>>}") | |
| end | |
| -- objstr <string> => obj <number>, new <boolean> | |
| local function update_pdfobjs (os) | |
| local on = pdf_objs[os] | |
| if on then | |
| return on,false | |
| end | |
| if pdfmode then | |
| on = pdf.immediateobj(os) | |
| else | |
| on = pdf_objs.cnt or 0 | |
| pdf_objs.cnt = on + 1 | |
| end | |
| 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 pgf_loaded | |
| local function update_tr_res(res,mode,opaq) | |
| local os = format("<</BM /%s/ca %.3f/CA %.3f/AIS false>>",mode,opaq,opaq) | |
| local on, new = update_pdfobjs(os) | |
| if new then | |
| if pdfmode then | |
| res = format("%s/MPlibTr%i %i 0 R",res,on,on) | |
| else | |
| if pgf_loaded then | |
| texsprint(format("\\csname pgf@sys@addpdfresource@extgs@plain\\endcsname{/MPlibTr%i%s}",on,os)) | |
| else | |
| texsprint(format("\\special{pdf:put @MPlibTr<</MPlibTr%i%s>>}",on,os)) | |
| end | |
| end | |
| end | |
| return res,on | |
| end | |
| local function tr_pdf_pageresources(mode,opaq) | |
| pgf_loaded = pgf_loaded or (newtoken and newtoken.create("pgfutil@everybye").cmdname == "assign_toks") | |
| local res, on_on, off_on = "", nil, nil | |
| res, off_on = update_tr_res(res, "Normal", 1) | |
| res, on_on = update_tr_res(res, mode, opaq) | |
| if pdfmode then | |
| if res ~= "" then | |
| local tpr = texget("pdfpageresources") -- respect luaotfload-colors | |
| local no_extgs = not stringfind(tpr,"/ExtGState<<.*>>") | |
| local pgf_pdf_loaded = no_extgs and pgf_loaded | |
| if pgf_pdf_loaded then | |
| texsprint(format("\\csname pgf@sys@addpdfresource@extgs@plain\\endcsname{%s}",res)) | |
| else | |
| if no_extgs then | |
| tpr = tpr.."/ExtGState<<>>" | |
| end | |
| tpr = tpr:gsub("/ExtGState<<","%1"..res) | |
| texset("global","pdfpageresources",tpr) | |
| end | |
| end | |
| else | |
| if not pgf_loaded then | |
| texsprint(format("\\special{pdf:put @resources<</ExtGState @MPlibTr>>}")) | |
| end | |
| end | |
| return on_on, off_on | |
| end | |
| local shading_res | |
| local getpageres = pdf.getpageresources or function() return pdf.pageresources end | |
| local setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end | |
| local function shading_initialize () | |
| shading_res = {} | |
| if pdfmode and luatexbase.is_active_callback then -- luatexbase 0.7+ | |
| local shading_obj = pdf.reserveobj() | |
| setpageres(format("%s/Shading %i 0 R",getpageres() or "",shading_obj)) | |
| luatexbase.add_to_callback("finish_pdffile", function() | |
| pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(shading_res))) | |
| end, "luamplib.finish_pdffile") | |
| pdf_objs.finishpdf = true | |
| end | |
| end | |
| local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordinates) | |
| if not shading_res then shading_initialize() end | |
| local os = format("<</FunctionType 2/Domain [ %s ]/C0 [ %s ]/C1 [ %s ]/N 1>>", | |
| domain, colora, colorb) | |
| local funcobj = pdfmode and format("%i 0 R",update_pdfobjs(os)) or os | |
| os = format("<</ShadingType %i/ColorSpace /%s/Function %s/Coords [ %s ]/Extend [ true true ]/AntiAlias true>>", | |
| shtype, colorspace, funcobj, coordinates) | |
| local on, new = update_pdfobjs(os) | |
| if pdfmode then | |
| if new then | |
| local res = format("/MPlibSh%i %i 0 R", on, on) | |
| if pdf_objs.finishpdf then | |
| shading_res[#shading_res+1] = res | |
| else | |
| local pageres = getpageres() or "" | |
| if not stringfind(pageres,"/Shading<<.*>>") then | |
| pageres = pageres.."/Shading<<>>" | |
| end | |
| pageres = pageres:gsub("/Shading<<","%1"..res) | |
| setpageres(pageres) | |
| end | |
| end | |
| else | |
| if new then | |
| texsprint(format("\\special{pdf:put @MPlibSh<</MPlibSh%i%s>>}",on,os)) | |
| end | |
| texsprint(format("\\special{pdf:put @resources<</Shading @MPlibSh>>}")) | |
| end | |
| 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 prev_override_color | |
| local function do_preobj_color(object,prescript) | |
| -- transparency | |
| local opaq = prescript and prescript.tr_transparency | |
| local tron_no, troff_no | |
| if opaq then | |
| local mode = prescript.tr_alternative or 1 | |
| mode = transparancy_modes[tonumber(mode)] | |
| tron_no, troff_no = tr_pdf_pageresources(mode,opaq) | |
| pdf_literalcode("/MPlibTr%i gs",tron_no) | |
| end | |
| -- color | |
| local override = prescript and prescript.MPlibOverrideColor | |
| if override then | |
| if pdfmode then | |
| pdf_literalcode(override) | |
| override = nil | |
| else | |
| texsprint(format("\\special{color push %s}",override)) | |
| prev_override_color = override | |
| end | |
| else | |
| local cs = object.color | |
| if cs and #cs > 0 then | |
| pdf_literalcode(luamplib.colorconverter(cs)) | |
| prev_override_color = nil | |
| elseif not pdfmode then | |
| override = prev_override_color | |
| if override then | |
| texsprint(format("\\special{color push %s}",override)) | |
| end | |
| end | |
| end | |
| -- shading | |
| local sh_type = prescript and prescript.sh_type | |
| if sh_type then | |
| local domain = prescript.sh_domain | |
| local centera = stringexplode(prescript.sh_center_a) | |
| local centerb = stringexplode(prescript.sh_center_b) | |
| for _,t in pairs({centera,centerb}) do | |
| for i,v in ipairs(t) do | |
| t[i] = format("%f",v) | |
| end | |
| end | |
| centera = tableconcat(centera," ") | |
| centerb = tableconcat(centerb," ") | |
| local colora = prescript.sh_color_a or {0}; | |
| local colorb = prescript.sh_color_b or {1}; | |
| for _,t in pairs({colora,colorb}) do | |
| for i,v in ipairs(t) do | |
| t[i] = format("%.3f",v) | |
| end | |
| end | |
| 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 troff_no,override | |
| end | |
| colora = tableconcat(colora, " ") | |
| colorb = tableconcat(colorb, " ") | |
| local shade_no | |
| if sh_type == "linear" then | |
| local coordinates = tableconcat({centera,centerb}," ") | |
| shade_no = sh_pdfpageresources(2,domain,colorspace,colora,colorb,coordinates) | |
| elseif sh_type == "circular" then | |
| local radiusa = format("%f",prescript.sh_radius_a) | |
| local radiusb = format("%f",prescript.sh_radius_b) | |
| local coordinates = tableconcat({centera,radiusa,centerb,radiusb}," ") | |
| shade_no = sh_pdfpageresources(3,domain,colorspace,colora,colorb,coordinates) | |
| end | |
| pdf_literalcode("q /Pattern cs") | |
| return troff_no,override,shade_no | |
| end | |
| return troff_no,override | |
| end | |
| local function do_postobj_color(tr,over,sh) | |
| if sh then | |
| pdf_literalcode("W n /MPlibSh%s sh Q",sh) | |
| end | |
| if over then | |
| texsprint("\\special{color pop}") | |
| end | |
| if tr then | |
| pdf_literalcode("/MPlibTr%i gs",tr) | |
| 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 TeXcode_t[f] then | |
| texsprint(TeXcode_t[f]) | |
| end | |
| pdf_startfigure(fignum,llx,lly,urx,ury) | |
| start_pdf_code() | |
| 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,cr_over,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 | |
| start_pdf_code() | |
| flushnormalpath(object.path,t,false) | |
| pdf_literalcode("W n") | |
| elseif objecttype == "stop_clip" then | |
| stop_pdf_code() | |
| 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 | |
| start_pdf_code() | |
| pdf_literalcode("%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) | |
| stop_pdf_code() | |
| 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 | |
| start_pdf_code() | |
| 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 | |
| stop_pdf_code() | |
| end | |
| local path = object.htap | |
| if path then | |
| if transformed then | |
| start_pdf_code() | |
| 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 | |
| stop_pdf_code() | |
| end | |
| end | |
| -- if cr then | |
| -- pdf_literalcode(cr) | |
| -- end | |
| end | |
| do_postobj_color(tr_opaq,cr_over,shade_no) | |
| end | |
| end | |
| stop_pdf_code() | |
| 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("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f 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("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" | |
| else | |
| local s = cr[1] | |
| return format("%.3f g %.3f G",s,s), "0 g 0 G" | |
| end | |
| end | |
| luamplib.colorconverter = colorconverter | |
| -- | |
| -- End of File `luamplib.lua'. |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
texnum.mp
format.mp