Skip to content

Instantly share code, notes, and snippets.

@phi-gamma
Created May 3, 2013 13:30
Show Gist options
  • Save phi-gamma/5509115 to your computer and use it in GitHub Desktop.
Save phi-gamma/5509115 to your computer and use it in GitHub Desktop.
luamplib import from Context 2013-05-03
--
-- 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 { } --- HH has: metapost
local luamplib = luamplib
luamplib.showlog = luamplib.showlog or false
luamplib.lastlog = ""
local err, warn, info, log = luatexbase.provides_module({
name = "luamplib",
version = 2.00,
date = "2013/05/03",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
})
local function term(...)
texio.write_nl('term', 'luamplib: ' .. string.format(...))
end
local format, concat, abs, match = string.format, table.concat, math.abs, string.match
local mplib = require ('mplib')
local kpse = require ('kpse')
local file = file
if not file then
--[[doc--
<p>A few helpers, taken from <t>l-file.lua</t>.</p>
--doc]]--
file = { }
function file.replacesuffix(filename, suffix)
return (string.gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
end
function file.stripsuffix(filename)
return (string.gsub(filename,"%.[%a%d]+$",""))
end
end
local data = ""
local function resetdata()
data = ""
end
luamplib.resetdata = resetdata
local function addline(line)
data = data .. '\n' .. line
end
luamplib.addline = addline
local function processlines()
luamplib.process(data)
resetdata()
end
luamplib.processlines = processlines
local mpkpse = kpse.new("luatex", "mpost")
local function finder(name, mode, ftype)
if mode == "w" then
return name
else
return mpkpse:find_file(name,ftype)
end
end
luamplib.finder = finder
luamplib.report = info --- <- metapost.report
--[[doc
<p>The rest of this module is not documented. More info can be found in the
<l n='luatex'/> manual, articles in user group journals and the files that
ship with <l n='context'/>.</p>
--doc]]--
function luamplib.resetlastlog()
luamplib.lastlog = ""
end
--[[doc--
Below included is section that defines fallbacks for older
versions of mplib.
--doc]]--
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(string.format("input %s ;",name))
if dump then
mpx:execute("dump ;")
luamplib.report("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t)
else
luamplib.report("%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
luamplib.report("using format %s",mem_name,false)
return mpx, nil
else
return nil, { status = 99, error = "out of memory or invalid format" }
end
end
else
--[[doc--
These are the versions called with sufficiently recent mplib.
--doc]]--
local preamble = [[
boolean mplib ; mplib := true ;
let dump = endinput ;
input %s ;
]]
luamplib.make = luamplib.make or function()
end
function luamplib.load(name)
local mpx = mplib.new {
ini_version = true,
find_file = luamplib.finder,
}
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
luamplib.report("luamplib error: no result object returned")
elseif result.status > 0 then
local t, e, l = result.term, result.error, result.log
if t then
luamplib.report("luamplib terminal: %s",t)
end
if e then
luamplib.report("luamplib error: %s", e)
end
if not t and not e and l then
luamplib.lastlog = luamplib.lastlog .. "\n " .. l
luamplib.report("luamplib log: %s",l)
else
luamplib.report("luamplib error: 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
luamplib.report("mp error: no result object returned")
elseif result.status > 0 then
luamplib.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
elseif luamplib.showlog then
luamplib.lastlog = luamplib.lastlog .. "\n" .. result.term
luamplib.report("mp info: %s",result.term or "no-term")
elseif result.fig then
converted = luamplib.convert(result)
else
luamplib.report("mp error: unknown error, maybe no beginfig/endfig")
end
else
luamplib.report("luamplib error: 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)
tex.sprint(format("\\mplibstarttoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
end
local function pdf_stopfigure()
tex.sprint("\\mplibstoptoPDF")
end
local function pdf_literalcode(fmt,...) -- table
tex.sprint(format("\\mplibtoPDF{%s}",format(fmt,...)))
end
luamplib.pdf_literalcode = pdf_literalcode
local 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
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 function flush(result,flusher)
if result then
local figures = result.fig
if figures then
for f=1, #figures do
luamplib.report("flushing figure %s",f)
local figure = figures[f]
local objects = getobjects(result,figure,f)
local fignum = tonumber(match(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
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
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'.
--- vim:ts=4:sw=4:expandtab
%%
%% This is file `luamplib.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% luamplib.dtx (with options: `package')
%%
%% See source file 'luamplib.dtx' for licencing and contact information.
%%
\bgroup\expandafter\expandafter\expandafter\egroup
\expandafter\ifx\csname ProvidesPackage\endcsname\relax
\input luatexbase-modutils.sty
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
[2011/12/09 v1.09 mplib package for LuaTeX]
\RequirePackage{luatexbase-modutils}
\RequirePackage{fancyvrb}
\fi
\RequireLuaModule{luamplib}
\def\mplibsetformat#1{%
\directlua{luamplib.setformat("\luatexluaescapestring{#1}")}}
\ifnum\pdfoutput>0
\let\mplibtoPDF\pdfliteral
\else
%\def\MPLIBtoPDF#1{\special{pdf:literal direct #1}} % not ok yet
\def\mplibtoPDF#1{}
\expandafter\ifx\csname PackageWarning\endcsname\relax
\write16{}
\write16{Warning: MPLib only works in PDF mode, no figure will be output.}
\write16{}
\else
\PackageWarning{mplib}{MPLib only works in PDF mode, no figure will be output.}
\fi
\fi
\bgroup\expandafter\expandafter\expandafter\egroup
\expandafter\ifx\csname ProvidesPackage\endcsname\relax
\def\mplibsetupcatcodes{%
\catcode`\{=12 % could be optional .. not really needed
\catcode`\}=12 % could be optional .. not really needed
\catcode`\#=12
\catcode`\^=12
\catcode`\~=12
\catcode`\_=12
%\catcode`\%=12 %% please look into this! /phg
\catcode`\&=12
\catcode`\$=12
}
\def\mplibcode{%
\bgroup %
\mplibsetupcatcodes %
\mplibdocode %
}
\long\def\mplibdocode#1\endmplibcode{%
\egroup %
\mplibprocess{#1}%
}
\long\def\mplibprocess#1{%
\directlua{luamplib.process("\luatexluaescapestring{#1}")}%
}
\else
\begingroup
\catcode`\,=13
\catcode`\-=13
\catcode`\<=13
\catcode`\>=13
\catcode`\^^I=13
\catcode`\`=13 % must be last...
\gdef\FV@hack{%
\def,{\string,}%
\def-{\string-}%
\def<{\string<}%
\def>{\string>}%
\def`{\string`}%
\def^^I{\string^^I}%
}
\endgroup
\newcommand\mplibaddlines[1]{%
\begingroup %
\FV@hack %
\def\FV@ProcessLine##1{%
\directlua{luamplib.addline("\luatexluaescapestring{##1}")}%
}%
\csname FV@SV@#1\endcsname %
\endgroup %
}
\newenvironment{mplibcode}{%
\VerbatimEnvironment %
\begin{SaveVerbatim}{memoire}%
}{%
\end{SaveVerbatim}%
\mplibaddlines{memoire}%
\directlua{luamplib.processlines()}%
}
\fi
\ifx\mplibscratchbox\undefined \newbox\mplibscratchbox \fi
\def\mplibstarttoPDF#1#2#3#4{%
\hbox\bgroup
\xdef\MPllx{#1}\xdef\MPlly{#2}%
\xdef\MPurx{#3}\xdef\MPury{#4}%
\xdef\MPwidth{\the\dimexpr#3bp-#1bp\relax}%
\xdef\MPheight{\the\dimexpr#4bp-#2bp\relax}%
\parskip0pt%
\leftskip0pt%
\parindent0pt%
\everypar{}%
\setbox\mplibscratchbox\vbox\bgroup
\noindent
}
\def\mplibstoptoPDF{%
\egroup %
\setbox\mplibscratchbox\hbox %
{\hskip-\MPllx bp%
\raise-\MPlly bp%
\box\mplibscratchbox}%
\setbox\mplibscratchbox\vbox to \MPheight
{\vfill
\hsize\MPwidth
\wd\mplibscratchbox0pt%
\ht\mplibscratchbox0pt%
\dp\mplibscratchbox0pt%
\box\mplibscratchbox}%
\wd\mplibscratchbox\MPwidth
\ht\mplibscratchbox\MPheight
\box\mplibscratchbox
\egroup
}
\def\mplibtextext#1#2#3#4#5{%
\begingroup
\setbox\mplibscratchbox\hbox
{\font\temp=#1 at #2bp%
\temp
#3}%
\setbox\mplibscratchbox\hbox
{\hskip#4 bp%
\raise#5 bp%
\box\mplibscratchbox}%
\wd\mplibscratchbox0pt%
\ht\mplibscratchbox0pt%
\dp\mplibscratchbox0pt%
\box\mplibscratchbox
\endgroup
}
\endinput
%%
%% End of file `luamplib.sty'.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment