diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luamplib/luamplib.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luamplib/luamplib.lua | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua new file mode 100644 index 00000000000..632c4140c45 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua @@ -0,0 +1,446 @@ +-- +-- This is file `luamplib.lua', +-- generated with the docstrip utility. +-- +-- The original source files were: +-- +-- luamplib.dtx (with options: `lua') +-- This is a generated file. +-- +-- Copyright (C) 2008-2009 by Hans Hagen, Taco Hoekwater and Elie Roux +-- <elie.roux@telecom-bretagne.eu>. +-- +-- This work is under the CC0 license. +-- +-- This Current Maintainer of this work is Elie Roux. +-- +-- This work consists of the main source file luamplib.dtx +-- and the derived files +-- luamplib.sty, luamplib.lua, luamplib-createmem.lua and luamplib.pdf. +-- + +luamplib = { } + +luamplib.module = { + name = "luamplib", + version = 1.01, + date = "2009/03/09", + description = "Lua functions to typeset Metapost directly with MPLib.", + author = "Hans Hagen, Taco Hoekwater & Elie Roux", + copyright = "ConTeXt Development Team & Elie Roux", + license = "CC0", +} + +luatextra.provides_module(luamplib.module) + + +local format, concat, abs = string.format, table.concat, math.abs + + +luamplib.currentformat = "plain" +luamplib.currentmem = "luatex-plain.mem" + +local currentformat = luamplib.currentformat +local currentmem = luamplib.currentmem + +function luamplib.setformat (name) + luamplib.currentformat = name +end + +function luamplib.setmemfile(name) + luamplib.currentmem = name +end + + +luamplib.finder = luamplib.finder or function(name, mode, ftype) + if mode == "w" then + return name + else + local result + if ftype == 'mem' then + local envsave = os.getenv('engine') + os.setenv('engine', 'metapost') + result = kpse.find_file(name,ftype) + os.setenv('engine', envsave) + else + result = kpse.find_file(name,ftype) + end + return result + end +end + +function luamplib.info (...) + luatextra.module_info('luamplib', format(...)) +end + +function luamplib.log (...) + luatextra.module_log('luamplib', format(...)) +end + +function luamplib.term (...) + luatextra.module_term('luamplib', format(...)) +end + +function luamplib.warning (...) + luatextra.module_warning('luamplib', format(...)) +end + +function luamplib.error (...) + luatextra.module_error('luamplib', format(...)) +end + + +luamplib.data = "" + +function luamplib.resetdata() + luamplib.data = "" +end + +function luamplib.addline(line) + luamplib.data = luamplib.data .. '\n' .. line +end + +function luamplib.processlines() + luamplib.process(luamplib.data) + luamplib.resetdata() +end + + +function luamplib.load() + local mpx = mplib.new { + ini_version = false, + mem_name = currentmem, + find_file = luamplib.finder + } + if mpx then + luamplib.log("using mem file %s", luamplib.finder(currentmem, 'r', 'mem')) + return mpx, nil + else + return nil, { status = 99, error = "out of memory or invalid format" } + end +end + + +function luamplib.report(result) + if not result then + luamplib.error("no result object") + elseif result.status > 0 then + local t, e, l, f = result.term, result.error, result.log + if l then + luamplib.log(l) + end + if t then + luamplib.term(t) + end + if e then + if result.status == 1 then + luamplib.warning(e) + else + luamplib.error(e) + end + end + if not t and not e and not l then + if result.status == 1 then + luamplib.warning("unknown error, no error, terminal or log messages, maybe missing beginfig/endfig") + else + luamplib.error("unknown error, no error, terminal or log messages, maybe missing beginfig/endfig") + end + end + else + return true + end + return false +end + +function luamplib.process(data) + local converted, result = false, {} + local mpx = luamplib.load() + if mpx and data then + local result = mpx:execute(data) + if luamplib.report(result) then + if result.fig then + converted = luamplib.convert(result) + else + luamplib.warning("no figure output") + end + end + else + luamplib.error("Mem file unloadable. Maybe generated with a different version of mplib?") + end + return converted, result +end + +local function getobjects(result,figure,f) + return figure:objects() +end + +function luamplib.convert(result, flusher) + luamplib.flush(result, flusher) + return true -- done +end + +local function pdf_startfigure(n,llx,lly,urx,ury) + tex.sprint(format("\\mplibstarttoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury)) +end + +local function pdf_stopfigure() + tex.sprint("\\mplibstoptoPDF") +end + +function pdf_literalcode(fmt,...) -- table + tex.sprint(format("\\mplibtoPDF{%s}",format(fmt,...))) +end + +function pdf_textfigure(font,size,text,width,height,depth) + text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost + tex.sprint(format("\\mplibtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-( 7200/ 7227)/65536*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) + if luamplib.pen_info then + local t = luamplib.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 + else + rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1 + return false, 1 + end +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 + + +function luamplib.flush(result,flusher) + if result then + local figures = result.fig + if figures then + for f=1, #figures do + luamplib.info("flushing figure %s",f) + local figure = figures[f] + local objects = getobjects(result,figure,f) + local fignum = tonumber((figure:filename()):match("([%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 + 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 + if 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 + 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 cs = object.color + if cs and #cs > 0 then + pdf_literalcode(luamplib.colorconverter(cs)) + end + 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",concat(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 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 + 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 + end + end + pdf_literalcode("Q") + pdf_stopfigure() + end + end + end + end +end + +function luamplib.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 +-- +-- End of File `luamplib.lua'. |