Created
May 3, 2013 13:30
-
-
Save phi-gamma/5509115 to your computer and use it in GitHub Desktop.
luamplib import from Context 2013-05-03
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 { } --- 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 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.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