texlive[71225] Master/texmf-dist: luamplib (10may24)
commits+karl at tug.org
commits+karl at tug.org
Fri May 10 23:15:13 CEST 2024
Revision: 71225
https://tug.org/svn/texlive?view=revision&revision=71225
Author: karl
Date: 2024-05-10 23:15:13 +0200 (Fri, 10 May 2024)
Log Message:
-----------
luamplib (10may24)
Modified Paths:
--------------
trunk/Master/texmf-dist/doc/luatex/luamplib/NEWS
trunk/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf
trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex
trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex
trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx
trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua
trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
Modified: trunk/Master/texmf-dist/doc/luatex/luamplib/NEWS
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luamplib/NEWS 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/doc/luatex/luamplib/NEWS 2024-05-10 21:15:13 UTC (rev 71225)
@@ -1,5 +1,26 @@
History of the luamplib package
+2024/05/10 2.30.0
+ * provide a new metapost operator 'mplibglyph', which returns a metapost
+ picture containing outline paths of a glyph in opentype, truetype or type1
+ fonts. When a type1 font is specified, metapost primitive 'glyph' will be
+ called. In the syntax as follows, subfont number is zero based.
+
+ mplibglyph 50 of \fontid\font % slot 50 of current font
+ mplibglyph 50 of "cmr10" % type1 font
+ mplibglyph "Q" of "TU/TeXGyrePagella(0)/m/n/10" % TeX fontname
+ mplibglyph "똠" of "NotoSansCJKkr-Regular.otf" % raw filename
+ mplibglyph "Q" of "Times.ttc(2)" % subfont number
+ mplibglyph "똠" of "SourceHanSansK-VF.otf[Regular]" % instance name
+
+ * provide a new metapost command 'mplibdrawglyph'. In contrast to metapost's
+ 'draw' command, this one fills paths of a picture according to the Nonzero
+ Winding Number Rule.
+
+ * in 'mplibgraphictext', option 'scale' is deprecated and now a synonym of
+ 'scaled'. In DVI mode, unicode-math package is needed for math formula
+ graphictext.
+
2024/05/01 2.29.0
* provide new TeX macros to reduce typing toil.
Modified: trunk/Master/texmf-dist/doc/luatex/luamplib/luamplib.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex 2024-05-10 21:15:13 UTC (rev 71225)
@@ -1,5 +1,9 @@
%\DocumentMetadata{ uncompress }
-\documentclass{article}
+\ifnum\outputmode > 0
+ \documentclass{article}
+\else
+ \documentclass[dvipdfmx]{article}
+\fi
\usepackage{fontspec}
\setmainfont{latin modern roman}
\usepackage{luamplib}
@@ -172,14 +176,15 @@
\begin{mplibcode}
beginfig(1)
draw mplibgraphictext "\bfseries Funny"
- fakebold 2 scale 2 % fontspec options
- drawcolor "blue" fillcolor "red!50" % l3color expressions
- scaled 2 rotated 30 ;
+ fakebold 2 % fontspec option
+ drawcolor blue fillcolor "red!50" % l3color expression
+ scaled 3 rotated 30 ;
picture p;
p:=mplibgraphictext "\bfseries\itshape xyz";
draw p scaled 3 shifted (40,0);
endfig;
\end{mplibcode}%
+\par
\mplibsetformat{metafun}%
\begin{mplibcode}
beginfig(1)
@@ -198,7 +203,26 @@
endfig;
\end{mplibcode}%
\leavevmode
-\everymplib[@mpfig]{ drawoptions(withcolor red); }%
+\mpfig
+picture Q, u, e;
+Q := mplibglyph "Q" of "texgyrepagella-bolditalic.otf" scaled .1;
+u := mplibglyph "u" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner Q;
+e := mplibglyph "e" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner u;
+i:=0;
+totallen := length Q + length u + length e;
+for pic=Q, u, e:
+ for item within pic:
+ i:=i+1;
+ fill pathpart item
+ if i < totallen: withpostscript "collect"; fi
+ endfor
+endfor
+ withshademethod "linear"
+ withshadedirection (0.5,2.5)
+ withshadecolors (.7red,.7yellow)
+ ;
+\endmpfig
+\everymplib[@mpfig]{ drawoptions(withcolor mplibrgbtexcolor "olive"); }%
\mpfig* input boxes \endmpfig
\mpfig circleit.a(btex\tracingcommands0 Box 1 etex); drawboxed(a); \endmpfig
\tracingcommands0
Modified: trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-plain.tex 2024-05-10 21:15:13 UTC (rev 71225)
@@ -1,6 +1,7 @@
+\input luaotfload.sty
\input miniltx
\input color
-\definecolor{orange}{rgb}{1,0.5,0}
+\definecolor{orange}{cmyk}{0,.5,1,0}
\input luamplib.sty
\mpliblegacybehavior{true}%
\everymplib{ beginfig(0); }\everyendmplib{ endfig; }
@@ -164,6 +165,19 @@
endfig;
\endmplibcode
\par
+\mplibcode
+beginfig(1) % in dvi mode, not work for type1 font
+draw mplibgraphictext "\bf Funny"
+ fakebold 2 % fontspec option
+ drawcolor blue fillcolor .5[red,white]
+ scaled 3 rotated 30 ;
+picture p;
+p:=mplibgraphictext "\it xyz"
+ fillcolor .7white;
+draw p scaled 3 shifted (40,0);
+endfig;
+\endmplibcode
+\par
\mplibsetformat{metafun}%
\mplibcode
beginfig(1)
@@ -181,7 +195,27 @@
;
endfig;
\endmplibcode
-\everymplib[@mpfig]{ drawoptions(withcolor red); }%
+\leavevmode
+\mpfig
+picture Q, u, e;
+Q := mplibglyph "Q" of "texgyrepagella-bolditalic.otf" scaled .1;
+u := mplibglyph "u" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner Q;
+e := mplibglyph "e" of "texgyrepagella-bolditalic.otf" scaled .1 shifted lrcorner u;
+i:=0;
+totallen := length Q + length u + length e;
+for pic=Q, u, e:
+ for item within pic:
+ i:=i+1;
+ fill pathpart item
+ if i < totallen: withpostscript "collect"; fi
+ endfor
+endfor
+ withshademethod "linear"
+ withshadedirection (0.5,2.5)
+ withshadecolors (.7red,.7yellow)
+ ;
+\endmpfig
+\everymplib[@mpfig]{ drawoptions(withcolor mplibrgbtexcolor"orange"); }%
\mpfig* input boxes \endmpfig
\mpfig circleit.a(btex\tracingcommands0 Box 1 etex); drawboxed(a); \endmpfig
\tracingcommands0
Modified: trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx
===================================================================
--- trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx 2024-05-10 21:15:13 UTC (rev 71225)
@@ -85,7 +85,7 @@
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{luamplib.drv}%
- [2024/05/01 v2.29.0 Interface for using the mplib library]%
+ [2024/05/10 v2.30.0 Interface for using the mplib library]%
\documentclass{ltxdoc}
\usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace}
\usepackage[x11names]{xcolor}
@@ -153,7 +153,7 @@
% \author{Hans Hagen, Taco Hoekwater, Elie Roux, Philipp Gesang and Kim Dohyun\\
% Maintainer: LuaLaTeX Maintainers ---
% Support: \email{lualatex-dev at tug.org}}
-% \date{2024/05/01 v2.29.0}
+% \date{2024/05/10 v2.30.0}
%
% \maketitle
%
@@ -415,7 +415,7 @@
% \end{verbatim}
% Generally speaking, it is recommended to turn |mplibglobaltextext|
% always on, because it has the advantage of reusing metapost pictures
-% among code chunks sharing the same mplib instance.
+% among code chunks.
% But everything has its downside: it will waste more memory resources.
%
% \paragraph{\cs{mplibverbatim}}
@@ -464,7 +464,8 @@
% |mplibtexcolor| is a metapost operator that converts a \TeX\ color expression
% to a MetaPost color expression. For instance:
% \begin{verbatim}
-% color col; col := mplibtexcolor "olive!50";
+% color col;
+% col := mplibtexcolor "olive!50";
% \end{verbatim}
% The result may vary in its color model (gray/rgb/cmyk)
% according to the given \TeX\ color. (Spot colors are forced to
@@ -478,14 +479,15 @@
% |mplibgraphictext|, the effect of which is similar to that of
% \ConTeXt's |graphictext|. However syntax is somewhat different.
% \begin{verbatim}
-% mplibgraphictext "Funny"
-% fakebold 2.3 scale 3 % fontspec options
-% drawcolor .7blue fillcolor "red!50" % color expressions
+% mplibgraphictext "Funny"
+% fakebold 2.3 % fontspec option
+% drawcolor .7blue fillcolor "red!50" % color expressions
% \end{verbatim}
-% |fakebold|, |scale|, |drawcolor| and |fillcolor| are optional;
-% default values are |2|, |1|, |"black"| and |"white"| respectively.
+% |fakebold|, |drawcolor| and |fillcolor| are optional;
+% default values are |2|, |"black"| and |"white"| respectively.
% When color expressions are given as string, they are regarded as
% xcolor's or l3color's expressions (this is the same with shading colors).
+% From v2.30, |scale| option is deprecated and is now a synonym of |scaled|.
% All from |mplibgraphictext| to the end of sentence will compose an
% anonymous |picture|, which can be drawn or assigned to a variable.
% Incidentally, |withdrawcolor| and |withfillcolor| are synonyms of
@@ -492,8 +494,61 @@
% |drawcolor| and |fillcolor|, hopefully to be compatible with |graphictext|.
% \textsc{n.b.} Because luamplib's current implementation is quite different
% from the \ConTeXt's, there are some limitations such that you can't
-% apply shading (gradient colors) to the text.
+% apply shading (gradient colors) to the text (But see below).
+% In DVI mode, |unicode-math| package is needed for math formula graphictext,
+% as we cannot embolden type1 fonts in DVI mode.
%
+% \paragraph{\texttt{mplibglyph}, \texttt{mplibdrawglyph}}
+% From v2.30, we provide a new metapost operator |mplibglyph|, which returns a metapost picture
+% containing outline paths of a glyph in opentype, truetype or type1 fonts.
+% When a type1 font is specified, metapost primitive |glyph| will be called.
+% \begin{verbatim}
+% mplibglyph 50 of \fontid\font % slot 50 of current font
+% mplibglyph "Q" of "TU/TeXGyrePagella(0)/m/n/10" % TeX fontname
+% mplibglyph "Q" of "texgyrepagella-regular.otf" % raw filename
+% mplibglyph "Q" of "Times.ttc(2)" % subfont number
+% mplibglyph "Q" of "SourceHanSansK-VF.otf[Regular]" % instance name
+% \end{verbatim}
+% Both arguments before and after of ``|of|'' can be either a number or a string.
+% Number arguments are regarded as a glyph slot (GID) and a font id number, repectively.
+% String argument at the left side is regarded as a glyph name in the font or a unicode character.
+% String argument at the right side is regarded as a \TeX\ fontname (without backslash) or
+% the raw filename of a font. When it is a font filename, a number within parentheses
+% after the filename denotes a
+% subfont number (starting from zero) of a TTC font; a string within brackets denotes
+% an instance name of a variable font.
+%
+% The returned picture will be quite similar to the result of |glyph| primitive in its structure.
+% So, metapost's |draw| command will fill the inner path of the picture with background color.
+% In contrast, |mplibdrawglyph| command fills the paths according to the Nonzero Winding
+% Number Rule. As a result, for instance, the area surrounded by inner path of ``O''
+% will remain transparent.
+%
+% We can adapt the method used in |mplibdrawglyph| to multiple pictures as if they were
+% components of one and the same picture. An example:
+% \begin{verbatim}
+% \mplibsetformat{metafun}
+% \mpfig
+% picture Q, u, e;
+% Q := mplibglyph "Q" of "Times.ttc(2)" scaled .15;
+% u := mplibglyph "u" of "Times.ttc(2)" scaled .15 shifted lrcorner Q;
+% e := mplibglyph "e" of "Times.ttc(2)" scaled .15 shifted lrcorner u;
+%
+% i:=0;
+% totallen := length Q + length u + length e;
+% for pic=Q, u, e:
+% for item within pic:
+% i:=i+1;
+% fill pathpart item
+% if i < totallen: withpostscript "collect"; fi
+% endfor
+% endfor
+% withshademethod "linear"
+% withshadedirection (0.5,2.5)
+% withshadecolors (.7red,.7yellow);
+% \endmpfig
+% \end{verbatim}
+%
% \paragraph{About figure box metrics}
% Notice that, after each figure is processed, macro \cs{MPwidth} stores
% the width value of latest figure; \cs{MPheight}, the height value.
@@ -526,8 +581,8 @@
luatexbase.provides_module {
name = "luamplib",
- version = "2.29.0",
- date = "2024/05/01",
+ version = "2.30.0",
+ date = "2024/05/10",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -588,6 +643,7 @@
% \ConTeXt. Provide a few ``shortcuts'' expected by the imported code.
% \begin{macrocode}
local tableconcat = table.concat
+local tableinsert = table.insert
local texsprint = tex.sprint
local texgettoks = tex.gettoks
local texgetbox = tex.getbox
@@ -656,7 +712,7 @@
local currenttime = os.time()
-local outputdir
+local outputdir, cachedir
if lfstouch then
for i,v in ipairs{'TEXMFVAR','TEXMF_OUTPUT_DIRECTORY','.','TEXMFOUTPUT'} do
local var = i == 3 and v or kpse.var_value(v)
@@ -676,7 +732,6 @@
end
end
outputdir = outputdir or '.'
-
function luamplib.getcachedir(dir)
dir = dir:gsub("##","#")
dir = dir:gsub("^~",
@@ -684,7 +739,7 @@
if lfstouch and dir then
if lfsisdir(dir) then
if is_writable(dir) then
- luamplib.cachedir = dir
+ cachedir = dir
else
warn("Directory '%s' is not writable!", dir)
end
@@ -751,9 +806,8 @@
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 = name:gsub("%W","_")
- newfile = cachedir .."/luamplib_input_"..newfile
+ newfile = format("%s/luamplib_input_%s", cachedir or outputdir, newfile)
if newfile and luamplibtime then
local nf = lfsattributes(newfile)
if nf and nf.mode == "file" and
@@ -817,7 +871,7 @@
enc = "enc files",
}
-local function finder(name, mode, ftype)
+function luamplib.finder (name, mode, ftype)
if mode == "w" then
if name and name ~= "mpout.log" then
kpse.record_output_file(name) -- recorder
@@ -839,7 +893,6 @@
return file
end
end
-luamplib.finder = finder
% \end{macrocode}
%
@@ -861,10 +914,9 @@
% though we cannot support |metafun| format fully.
% \begin{macrocode}
local currentformat = "plain"
-local function setformat (name)
+function luamplib.setformat (name)
currentformat = name
end
-luamplib.setformat = setformat
% \end{macrocode}
%
@@ -943,9 +995,9 @@
% \begin{macrocode}
local preamble = tableconcat{
format(preamble, replacesuffix(name,"mp")),
- luamplib.mplibcodepreamble,
- luamplib.legacy_verbatimtex and luamplib.legacyverbatimtexpreamble or "",
- luamplib.textextlabel and luamplib.textextlabelpreamble or "",
+ luamplib.preambles.mplibcode,
+ luamplib.legacy_verbatimtex and luamplib.preambles.legacyverbatimtex or "",
+ luamplib.textextlabel and luamplib.preambles.textextlabel or "",
}
local result, log
if not mpx then
@@ -1125,7 +1177,7 @@
end
local ccexplat = luatexbase.registernumber"luamplibcctabexplat"
-local function process_color (str, kind)
+local function process_color (str)
if str then
if not str:find("%b{}") then
str = format("{%s}",str)
@@ -1146,145 +1198,17 @@
end
end
end
- if myfmt == mplibcolorfmt.l3color and (kind == "fill" or kind == "draw") then return str end
run_tex_code(myfmt:format(str), ccexplat or catat11)
local t = texgettoks"mplibtmptoks"
if not pdfmode and not t:find"^pdf" then
t = t:gsub("%a+ (.+)","pdf:bc [%1]")
end
- if kind then return t end
- return format('1 withprescript "MPlibOverrideColor=%s"', t)
+ return format('1 withprescript "mpliboverridecolor=%s"', t)
end
return ""
end
-local function colorsplit (res)
- local t, tt = { }, res:gsub("[%[%]]",""):explode()
- local be = tt[1]:find"^%d" and 1 or 2
- for i=be, #tt do
- if tt[i]:find"^%a" then break end
- t[#t+1] = tt[i]
- end
- return t
-end
-
-luamplib.outlinecolor = function (str, filldraw)
- local nn = filldraw == "fill" and 'fn:=' or 'dn:='
- local cc = filldraw == "fill" and 'fc:=' or 'dc:='
- local res = process_color(str, filldraw)
- if res:match"{(.+)}" == str then
- return format('%s"n"; %s"%s";', nn,cc,str)
- end
- local t = colorsplit(res)
- local md = #t == 1 and 'gray' or #t == 3 and 'rgb' or #t == 4 and 'cmyk'
- return format('%s"nn"; %s"%s}{%s";', nn, cc, md, tableconcat(t,','))
-end
-
-luamplib.gettexcolor = function (str, rgb)
- local res = process_color(str, "metapost")
- if res:find" cs " or res:find"@pdf.obj" then
- if not rgb then
- warn("%s is a spot color. Forced to CMYK", str)
- end
- run_tex_code({
- "\\color_export:nnN{",
- str,
- "}{",
- rgb and "space-sep-rgb" or "space-sep-cmyk",
- "}\\mplib_ at tempa",
- },ccexplat)
- return get_macro"mplib_ at tempa":explode()
- end
- local t = colorsplit(res)
- if #t == 3 or not rgb then return t end
- run_tex_code({ -- force to rgb
- "\\color_export:nnnN{",
- #t == 4 and "cmyk" or "gray",
- "}{",
- tableconcat(t,","),
- "}{space-sep-rgb}\\mplib_ at tempa",
- },ccexplat)
- return get_macro"mplib_ at tempa":explode()
-end
-
-luamplib.shadecolor = function (str)
- local res = process_color(str, "shade")
- if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only
% \end{macrocode}
-% An example of spot color shading:
-% \begin{verbatim}
-% \documentclass{article}
-% \usepackage{luamplib}
-% \mplibsetformat{metafun}
-% \ExplSyntaxOn
-% \color_model_new:nnn { pantone3005 }
-% { Separation }
-% { name = PANTONE~3005~U ,
-% alternative-model = cmyk ,
-% alternative-values = {1, 0.56, 0, 0}
-% }
-% \color_set:nnn{spotA}{pantone3005}{1}
-% \color_set:nnn{spotB}{pantone3005}{0.6}
-% \color_model_new:nnn { pantone1215 }
-% { Separation }
-% { name = PANTONE~1215~U ,
-% alternative-model = cmyk ,
-% alternative-values = {0, 0.15, 0.51, 0}
-% }
-% \color_set:nnn{spotC}{pantone1215}{1}
-% \color_model_new:nnn { pantone2040 }
-% { Separation }
-% { name = PANTONE~2040~U ,
-% alternative-model = cmyk ,
-% alternative-values = {0, 0.28, 0.21, 0.04}
-% }
-% \color_set:nnn{spotD}{pantone2040}{1}
-% \ExplSyntaxOff
-% \begin{document}
-% \begin{mplibcode}
-% beginfig(1)
-% fill unitsquare xyscaled (\mpdim\textwidth,1cm)
-% withshademethod "linear"
-% withshadevector (0,1)
-% withshadestep (
-% withshadefraction .5
-% withshadecolors ("spotB","spotC")
-% )
-% withshadestep (
-% withshadefraction 1
-% withshadecolors ("spotC","spotD")
-% )
-% ;
-% endfig;
-% \end{mplibcode}
-% \end{document}
-% \end{verbatim}
-% \begin{macrocode}
- run_tex_code({
- [[\color_export:nnN{]], str, [[}{backend}\mplib_ at tempa]],
- },ccexplat)
- local name = get_macro'mplib_ at tempa':match'{(.-)}{.+}'
- local t, obj = res:explode()
- if pdfmode then
- obj = t[1]:match"^/(.+)"
- if ltx.pdf and ltx.pdf.object_id then
- obj = format("%s 0 R", ltx.pdf.object_id(obj))
- else
- run_tex_code({
- [[\edef\mplib_ at tempa{\pdf_object_ref:n{]], obj, "}}",
- },ccexplat)
- obj = get_macro'mplib_ at tempa'
- end
- else
- obj = t[2]
- end
- local value = t[3]:match"%[(.-)%]" or t[3]
- return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name)
- end
- return colorsplit(res)
-end
-
-% \end{macrocode}
%
% for \cs{mpdim} or |mplibdimen|
% \begin{macrocode}
@@ -1458,17 +1382,359 @@
% \end{macrocode}
%
+% luamplib's metapost color operators
+% \begin{macrocode}
+local function colorsplit (res)
+ local t, tt = { }, res:gsub("[%[%]]",""):explode()
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ t[#t+1] = tt[i]
+ end
+ return t
+end
+
+local min = math.min
+luamplib.gettexcolor = function (str, rgb)
+ local res = process_color(str):match'"mpliboverridecolor=(.+)"'
+ if res:find" cs " or res:find"@pdf.obj" then
+ if not rgb then
+ warn("%s is a spot color. Forced to CMYK", str)
+ end
+ run_tex_code({
+ "\\color_export:nnN{",
+ str,
+ "}{",
+ rgb and "space-sep-rgb" or "space-sep-cmyk",
+ "}\\mplib_ at tempa",
+ },ccexplat)
+ return get_macro"mplib_ at tempa":explode()
+ end
+ local t = colorsplit(res)
+ if #t == 3 or not rgb then return t end
+ if #t == 4 then
+ return { 1 - min(1,t[1]+t[4]), 1 - min(1,t[2]+t[4]), 1 - min(1,t[3]+t[4]) }
+ end
+ return { t[1], t[1], t[1] }
+end
+
+luamplib.shadecolor = function (str)
+ local res = process_color(str):match'"mpliboverridecolor=(.+)"'
+ if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only
+% \end{macrocode}
+% An example of spot color shading:
+% \begin{verbatim}
+% \documentclass{article}
+% \usepackage{luamplib}
+% \mplibsetformat{metafun}
+% \ExplSyntaxOn
+% \color_model_new:nnn { pantone3005 }
+% { Separation }
+% { name = PANTONE~3005~U ,
+% alternative-model = cmyk ,
+% alternative-values = {1, 0.56, 0, 0}
+% }
+% \color_set:nnn{spotA}{pantone3005}{1}
+% \color_set:nnn{spotB}{pantone3005}{0.6}
+% \color_model_new:nnn { pantone1215 }
+% { Separation }
+% { name = PANTONE~1215~U ,
+% alternative-model = cmyk ,
+% alternative-values = {0, 0.15, 0.51, 0}
+% }
+% \color_set:nnn{spotC}{pantone1215}{1}
+% \color_model_new:nnn { pantone2040 }
+% { Separation }
+% { name = PANTONE~2040~U ,
+% alternative-model = cmyk ,
+% alternative-values = {0, 0.28, 0.21, 0.04}
+% }
+% \color_set:nnn{spotD}{pantone2040}{1}
+% \ExplSyntaxOff
+% \begin{document}
+% \begin{mplibcode}
+% beginfig(1)
+% fill unitsquare xyscaled (\mpdim\textwidth,1cm)
+% withshademethod "linear"
+% withshadevector (0,1)
+% withshadestep (
+% withshadefraction .5
+% withshadecolors ("spotB","spotC")
+% )
+% withshadestep (
+% withshadefraction 1
+% withshadecolors ("spotC","spotD")
+% )
+% ;
+% endfig;
+% \end{mplibcode}
+% \end{document}
+% \end{verbatim}
+% \begin{macrocode}
+ run_tex_code({
+ [[\color_export:nnN{]], str, [[}{backend}\mplib_ at tempa]],
+ },ccexplat)
+ local name = get_macro'mplib_ at tempa':match'{(.-)}{.+}'
+ local t, obj = res:explode()
+ if pdfmode then
+ obj = t[1]:match"^/(.+)"
+ if ltx.pdf and ltx.pdf.object_id then
+ obj = format("%s 0 R", ltx.pdf.object_id(obj))
+ else
+ run_tex_code({
+ [[\edef\mplib_ at tempa{\pdf_object_ref:n{]], obj, "}}",
+ },ccexplat)
+ obj = get_macro'mplib_ at tempa'
+ end
+ else
+ obj = t[2]
+ end
+ local value = t[3]:match"%[(.-)%]" or t[3]
+ return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name)
+ end
+ return colorsplit(res)
+end
+
+% \end{macrocode}
+%
+% luamplib's mplibgraphictext operator
+% \begin{macrocode}
+local emboldenfonts = { }
+local function embolden (head, fakebold)
+ local curr = head
+ while curr do
+ if curr.head then
+ embolden(curr.head, fakebold)
+ elseif curr.leader and curr.leader.head then
+ embolden(curr.leader.head, fakebold)
+ elseif curr.id == node.id"glyph" and curr.font > 0 then
+ local f = curr.font
+ local i = emboldenfonts[f]
+ if not i then
+ if pdfmode then
+ local ft = font.getcopy(f)
+ ft.mode = 2
+ ft.width = ft.size * fakebold / 6578.176
+ i = font.define(ft)
+ else
+ local ft = font.getfont(f) or font.getcopy(f)
+ if ft.format ~= "opentype" and ft.format ~= "truetype" then
+ goto skip_type1
+ end
+ local name = ft.name:gsub('"',''):gsub(';$','')
+ name = format('%s;embolden=%s',name,fakebold)
+ _, i = fonts.constructors.readanddefine(name,ft.size)
+ end
+ emboldenfonts[f] = i
+ end
+ curr.font = i
+ end
+ ::skip_type1::
+ curr = node.getnext(curr)
+ end
+end
+local function graphictextcolor (col, filldraw)
+ if col:find"^[%d%.:]+$" then
+ col = col:explode":"
+ if pdfmode then
+ local op = #col == 4 and "k" or #col == 3 and "rg" or "g"
+ col[#col+1] = filldraw == "fill" and op or op:upper()
+ return tableconcat(col," ")
+ end
+ return format("[%s]", tableconcat(col," "))
+ end
+ col = process_color(col):match'"mpliboverridecolor=(.+)"'
+ if pdfmode then
+ local t, tt = col:explode(), { }
+ local b = filldraw == "fill" and 1 or #t/2+1
+ local e = b == 1 and #t/2 or #t
+ for i=b,e do
+ tt[#tt+1] = t[i]
+ end
+ return tableconcat(tt," ")
+ end
+ return col:gsub("^.- ","")
+end
+luamplib.graphictext = function (text, fakebold, fc, dc)
+ local fmt = process_tex_text(text):sub(1,-2)
+ local id = tonumber(fmt:match"mplibtexboxid=(%d+):")
+ embolden(texgetbox(id).head, fakebold)
+ local fill = graphictextcolor(fc,"fill")
+ local draw = graphictextcolor(dc,"draw")
+ local bc = pdfmode and "" or "pdf:bc "
+ return format('%s withprescript "mpliboverridecolor=%s%s %s")', fmt, bc, fill, draw)
+end
+
+% \end{macrocode}
+%
+% luamplib's mplibglyph operator
+% \begin{macrocode}
+local function mperr (str)
+ return format("hide(errmessage %q)", str)
+end
+local function getangle (a,b,c)
+ local r = math.deg(math.atan(c.y-b.y, c.x-b.x) - math.atan(b.y-a.y, b.x-a.x))
+ if r > 180 then
+ r = r - 360
+ elseif r < -180 then
+ r = r + 360
+ end
+ return r
+end
+local function turning (t)
+ local r, n = 0, #t
+ for i=1,2 do
+ tableinsert(t, t[i])
+ end
+ for i=1,n do
+ r = r + getangle(t[i], t[i+1], t[i+2])
+ end
+ return r/360
+end
+local function glyphimage(t, fmt)
+ local q,p,r = {{},{}}
+ for i,v in ipairs(t) do
+ local cmd = v[#v]
+ if cmd == "m" then
+ p = {format('(%s,%s)',v[1],v[2])}
+ r = {{x=v[1],y=v[2]}}
+ else
+ local nt = t[i+1]
+ local last = not nt or nt[#nt] == "m"
+ if cmd == "l" then
+ local pt = t[i-1]
+ local seco = pt[#pt] == "m"
+ if (last or seco) and r[1].x == v[1] and r[1].y == v[2] then
+ else
+ tableinsert(p, format('--(%s,%s)',v[1],v[2]))
+ tableinsert(r, {x=v[1],y=v[2]})
+ end
+ if last then
+ tableinsert(p, '--cycle')
+ end
+ elseif cmd == "c" then
+ tableinsert(p, format('..controls(%s,%s)and(%s,%s)',v[1],v[2],v[3],v[4]))
+ if last and r[1].x == v[5] and r[1].y == v[6] then
+ tableinsert(p, '..cycle')
+ else
+ tableinsert(p, format('..(%s,%s)',v[5],v[6]))
+ if last then
+ tableinsert(p, '--cycle')
+ end
+ tableinsert(r, {x=v[5],y=v[6]})
+ end
+ else
+ return mperr"unknown operator"
+ end
+ if last then
+ tableinsert(q[ turning(r) > 0 and 1 or 2 ], tableconcat(p))
+ end
+ end
+ end
+ r = { }
+ if fmt == "opentype" then
+ for _,v in ipairs(q[1]) do
+ tableinsert(r, format('addto currentpicture contour %s;',v))
+ end
+ for _,v in ipairs(q[2]) do
+ tableinsert(r, format('addto currentpicture contour %s withcolor background;',v))
+ end
+ else
+ for _,v in ipairs(q[2]) do
+ tableinsert(r, format('addto currentpicture contour %s;',v))
+ end
+ for _,v in ipairs(q[1]) do
+ tableinsert(r, format('addto currentpicture contour %s withcolor background;',v))
+ end
+ end
+ return format('image(%s)', tableconcat(r))
+end
+if not table.tofile then require"lualibs-lpeg"; require"lualibs-table"; end
+function luamplib.glyph (f, c)
+ local filename, subfont, instance, kind, shapedata
+ local fid = tonumber(f) or font.id(f) -- string: fontname
+ if fid > 0 then
+ local fontdata = font.getfont(fid) or font.getcopy(fid)
+ filename, subfont, kind = fontdata.filename, fontdata.subfont, fontdata.format
+ instance = fontdata.specification and fontdata.specification.instance
+ else
+ local name
+ f = f:match"^%s*(.+)%s*$"
+ name, subfont, instance = f:match"(.+)%((%d+)%)%[(.-)%]$"
+ if not name then
+ name, instance = f:match"(.+)%[(.-)%]$" -- SourceHanSansK-VF.otf[Heavy]
+ end
+ if not name then
+ name, subfont = f:match"(.+)%((%d+)%)$" -- Times.ttc(2)
+ end
+ name = name or f
+ subfont = (subfont or 0)+1
+ instance = instance and instance:lower()
+ for _,ftype in ipairs{"opentype", "truetype"} do
+ filename = kpse.find_file(name, ftype.." fonts")
+ if filename then
+ kind = ftype; break
+ end
+ end
+ end
+ if kind ~= "opentype" and kind ~= "truetype" then
+ f = fid and fid > 0 and tex.fontname(fid) or f
+ if kpse.find_file(f, "tfm") then
+ return format("glyph %s of %q", tonumber(c) or format("%q",c), f)
+ else
+ return mperr"font not found"
+ end
+ end
+ local time = lfsattributes(filename,"modification")
+ local k = format("shapes_%s(%s)[%s]", filename, subfont or "", instance or "")
+ local h = format(string.rep('%02x', 256/8), string.byte(sha2.digest256(k), 1, -1))
+ local newname = format("%s/%s.lua", cachedir or outputdir, h)
+ local newtime = lfsattributes(newname,"modification") or 0
+ if time == newtime then
+ shapedata = require(newname)
+ end
+ if not shapedata then
+ shapedata = fonts and fonts.handlers.otf.readers.loadshapes(filename,subfont,instance)
+ if not shapedata then return mperr"loadshapes() failed. luaotfload not loaded?" end
+ table.tofile(newname, shapedata, "return")
+ lfstouch(newname, time, time)
+ end
+ local gid = tonumber(c)
+ if not gid then
+ local uni = utf8.codepoint(c)
+ for i,v in pairs(shapedata.glyphs) do
+ if c == v.name or uni == v.unicode then
+ gid = i; break
+ end
+ end
+ end
+ if not gid then return mperr"cannot get GID (glyph id)" end
+ local fac = 1000 / (shapedata.units or 1000)
+ local t = shapedata.glyphs[gid].segments
+ if not t then return mperr"glyph has no contour. Maybe blank space" end
+ for i,v in ipairs(t) do
+ if type(v) == "table" then
+ for ii,vv in ipairs(v) do
+ if type(vv) == "number" then
+ t[i][ii] = format("%.0f", vv * fac)
+ end
+ end
+ end
+ end
+ return glyphimage(t, kind)
+end
+
+% \end{macrocode}
+%
% Our MetaPost preambles
% \begin{macrocode}
-local mplibcodepreamble = [[
+luamplib.preambles = {
+ mplibcode = [[
texscriptmode := 2;
def rawtextext (expr t) = runscript("luamplibtext{"&t&"}") enddef;
def mplibcolor (expr t) = runscript("luamplibcolor{"&t&"}") enddef;
def mplibdimen (expr t) = runscript("luamplibdimen{"&t&"}") enddef;
def VerbatimTeX (expr t) = runscript("luamplibverbtex{"&t&"}") enddef;
-def message expr t =
- if string t: runscript("mp.report[=["&t&"]=]") else: errmessage "Not a string" fi
-enddef;
if known context_mlib:
defaultfont := "cmtt10";
let infont = normalinfont;
@@ -1482,23 +1748,27 @@
(1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
fi
enddef;
- def colordecimals primary c =
- if cmykcolor c:
- decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c
- elseif rgbcolor c:
- decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
- elseif string c:
- colordecimals resolvedcolor(c)
- else:
- decimal c
- fi
- enddef;
- def resolvedcolor(expr s) =
- runscript("return luamplib.shadecolor('"& s &"')")
- enddef;
else:
vardef textext@# (text t) = rawtextext (t) enddef;
+ def message expr t =
+ if string t: runscript("mp.report[=["&t&"]=]") else: errmessage "Not a string" fi
+ enddef;
fi
+def resolvedcolor(expr s) =
+ runscript("return luamplib.shadecolor('"& s &"')")
+enddef;
+def colordecimals primary c =
+ if cmykcolor c:
+ decimal cyanpart c & ":" & decimal magentapart c & ":" &
+ decimal yellowpart c & ":" & decimal blackpart c
+ elseif rgbcolor c:
+ decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
+ elseif string c:
+ if known graphictextpic: c else: colordecimals resolvedcolor(c) fi
+ else:
+ decimal c
+ fi
+enddef;
def externalfigure primary filename =
draw rawtextext("\includegraphics{"& filename &"}")
enddef;
@@ -1515,55 +1785,43 @@
enddef;
def mplibgraphictext_ (expr t) text rest =
save fakebold, scale, fillcolor, drawcolor, withfillcolor, withdrawcolor,
- fb, sc, fc, dc, fn, dn, tpic;
- picture tpic; tpic := nullpicture;
- numeric fb, sc; string fc, dc, fn, dn;
- fb:=2; sc:=1; fc:="white"; dc:="black"; fn:=dn:="n";
+ fb, fc, dc, graphictextpic;
+ picture graphictextpic; graphictextpic := nullpicture;
+ numeric fb; string fc, dc; fb:=2; fc:="white"; dc:="black";
+ let scale = scaled;
def fakebold primary c = hide(fb:=c;) enddef;
- def scale primary c = hide(sc:=c;) enddef;
- def fillcolor primary c = hide(
- if string c:
- runscript("return luamplib.outlinecolor('"& c &"','fill')")
- else:
- fn:="nn"; fc:=mpliboutlinecolor_(c);
- fi
- ) enddef;
- def drawcolor primary c = hide(
- if string c:
- runscript("return luamplib.outlinecolor('"& c &"','draw')")
- else:
- dn:="nn"; dc:=mpliboutlinecolor_(c);
- fi
- ) enddef;
+ def fillcolor primary c = hide(fc:=colordecimals c;) enddef;
+ def drawcolor primary c = hide(dc:=colordecimals c;) enddef;
let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
- addto tpic doublepath origin rest; tpic:=nullpicture;
+ addto graphictextpic doublepath origin rest; graphictextpic:=nullpicture;
def fakebold primary c = enddef;
- def scale primary c = enddef;
- def fillcolor primary c = enddef;
- def drawcolor primary c = enddef;
+ let fillcolor = fakebold; let drawcolor = fakebold;
let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
- image(draw rawtextext(
- "{\addfontfeature{FakeBold="& decimal fb &",Scale="& decimal sc &
- "}\csname color_fill:"& fn &"\endcsname{"& fc &
- "}\csname color_stroke:"& dn &"\endcsname{"& dc &
- "}"& t &"}") rest;)
+ image(draw runscript("return luamplib.graphictext([===["&t&"]===],"
+ & decimal fb &",'"& fc &"','"& dc &"')") rest;)
endgroup;
enddef;
-def mpliboutlinecolor_ (expr c) =
- if color c:
- "rgb}{" & decimal redpart c & "," & decimal greenpart c
- & "," & decimal bluepart c
- elseif cmykcolor c:
- "cmyk}{" & decimal cyanpart c & "," & decimal magentapart c
- & "," & decimal yellowpart c & "," & decimal blackpart c
- else:
- "gray}{" & decimal c
- fi
+def mplibglyph expr c of f =
+ runscript (
+ "return luamplib.glyph('"
+ & if numeric f: decimal fi f
+ & "','"
+ & if numeric c: decimal fi c
+ & "')"
+ )
enddef;
-]]
-luamplib.mplibcodepreamble = mplibcodepreamble
-
-local legacyverbatimtexpreamble = [[
+def mplibdrawglyph expr g =
+ draw image(
+ save i; numeric i; i:=0;
+ for item within g:
+ i := i+1;
+ fill pathpart item
+ if i < length g: withpostscript "collect" fi;
+ endfor
+ )
+enddef;
+]],
+ legacyverbatimtex = [[
def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef;
def normalVerbatimTeX (text t) = runscript("luamplibinfig{"&t&"}") enddef;
let VerbatimTeX = specialVerbatimTeX;
@@ -1573,10 +1831,8 @@
"runscript(" &ditto&
"if luamplib.in_the_fig then luamplib.figid=luamplib.figid+1 end "&
"luamplib.in_the_fig=false" &ditto& ");";
-]]
-luamplib.legacyverbatimtexpreamble = legacyverbatimtexpreamble
-
-local textextlabelpreamble = [[
+]],
+ textextlabel = [[
primarydef s infont f = rawtextext(s) enddef;
def fontsize expr f =
begingroup
@@ -1585,8 +1841,8 @@
if size = 0: 10pt else: size fi
endgroup
enddef;
-]]
-luamplib.textextlabelpreamble = textextlabelpreamble
+]],
+}
% \end{macrocode}
%
@@ -1623,7 +1879,7 @@
luamplib.everymplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
luamplib.everyendmplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
-local function process_mplibcode (data, instancename)
+function luamplib.process_mplibcode (data, instancename)
texboxes.localid = 4096
% \end{macrocode}
@@ -1683,7 +1939,6 @@
process(data, instancename)
end
-luamplib.process_mplibcode = process_mplibcode
% \end{macrocode}
%
@@ -1718,11 +1973,10 @@
return figure:objects()
end
-local function convert(result, flusher)
+function luamplib.convert (result, flusher)
luamplib.flush(result, flusher)
return true -- done
end
-luamplib.convert = convert
local figcontents = { post = { } }
local function put2output(a,...)
@@ -1887,7 +2141,7 @@
% \begin{macrocode}
local prev_override_color
local function do_preobj_CR(object,prescript)
- local override = prescript and prescript.MPlibOverrideColor
+ local override = prescript and prescript.mpliboverridecolor
if override then
if pdfmode then
pdf_literalcode(override)
@@ -1919,13 +2173,6 @@
local pdfobjs, pdfetcs = {}, {}
pdfetcs.pgfextgs = "pgf at sys@addpdfresource at extgs@plain"
-if pdfmode then
- pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
- pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
-else
- texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
-end
-
local function update_pdfobjs (os)
local on = pdfobjs[os]
if on then
@@ -1942,6 +2189,38 @@
return on,true
end
+if pdfmode then
+ pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
+ pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
+ pdfetcs.initialize_resources = function (name)
+ local tabname = format("%s_res",name)
+ pdfetcs[tabname] = { }
+ if luatexbase.callbacktypes.finish_pdffile then -- ltluatex
+ local obj = pdf.reserveobj()
+ pdfetcs.setpageres(format("%s/%s %i 0 R", pdfetcs.getpageres() or "", name, obj))
+ luatexbase.add_to_callback("finish_pdffile", function()
+ pdf.immediateobj(obj, format("<<%s>>", tableconcat(pdfetcs[tabname])))
+ end,
+ format("luamplib.%s.finish_pdffile",name))
+ end
+ end
+ pdfetcs.fallback_update_resources = function (name, res)
+ if luatexbase.callbacktypes.finish_pdffile then
+ local t = pdfetcs[format("%s_res",name)]
+ t[#t+1] = res
+ else
+ local tpr, n = pdfetcs.getpageres() or "", 0
+ tpr, n = tpr:gsub(format("/%s<<",name), "%1"..res)
+ if n == 0 then
+ tpr = format("%s/%s<<%s>>", tpr, name, res)
+ end
+ pdfetcs.setpageres(tpr)
+ end
+ end
+else
+ texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
+end
+
% \end{macrocode}
%
% Transparency
@@ -1954,75 +2233,42 @@
"Compatible",
}
-local function opacity_initialize ()
- pdfetcs.opacity_res = {}
- if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
- local extgstate_obj = pdf.reserveobj()
- pdfetcs.setpageres(format("%s/ExtGState %i 0 R",pdfetcs.getpageres() or "",extgstate_obj))
- luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(extgstate_obj, format("<<%s>>",tableconcat(pdfetcs.opacity_res)))
- end, "luamplib.opacity.finish_pdffile")
- end
-end
-
local function update_tr_res(mode,opaq)
if pdfetcs.pgfloaded == nil then
pdfetcs.pgfloaded = is_defined(pdfetcs.pgfextgs)
- if not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP at list" then
- opacity_initialize()
+ if pdfmode and not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP at list" then
+ pdfetcs.initialize_resources"ExtGState"
end
end
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
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
- format("{MPlibTr%s}{%s 0 R}", on, on),
+ if not new then return on end
+ local key = format("MPlibTr%s", on)
+ local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
+ if pdfmanagement then
+ texsprint(ccexplat,
+ format("\\pdfmanagement_add:nnn{Page/Resources/ExtGState}{%s}{%s}", key, val))
+ else
+ local tr = format("/%s %s", key, val)
+ if pdfetcs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
+ elseif pdfmode then
+ if is_defined"TRP at list" then
+ texsprint(catat11,{
+ [[\if at filesw\immediate\write\@auxout{]],
+ [[\string\g at addto@macro\string\TRP at list{]],
+ tr,
+ [[}}\fi]],
})
+ if not get_macro"TRP at list":find(tr) then
+ texsprint(catat11,[[\global\TRP at reruntrue]])
+ end
else
- local tr = format("/MPlibTr%s %s 0 R",on,on)
- if pdfetcs.pgfloaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
- elseif is_defined"TRP at list" then
- texsprint(catat11,{
- [[\if at filesw\immediate\write\@auxout{]],
- [[\string\g at addto@macro\string\TRP at list{]],
- tr,
- [[}}\fi]],
- })
- if not get_macro"TRP at list":find(tr) then
- texsprint(catat11,[[\global\TRP at reruntrue]])
- end
- else
- if luatexbase.callbacktypes.finish_pdffile then
- pdfetcs.opacity_res[#pdfetcs.opacity_res+1] = tr
- else
- local tpr, n = pdfetcs.getpageres() or "", 0
- tpr, n = tpr:gsub("/ExtGState<<", "%1"..tr)
- if n == 0 then
- tpr = format("%s/ExtGState<<%s>>", tpr, tr)
- end
- pdfetcs.setpageres(tpr)
- end
- end
+ pdfetcs.fallback_update_resources("ExtGState", tr)
end
else
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
- format("{MPlibTr%s}{@mplibpdfobj%s}", on, on),
- })
- else
- local tr = format("/MPlibTr%s @mplibpdfobj%s",on,on)
- if pdfetcs.pgfloaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
- else
- texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
- texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
- end
- end
+ texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
+ texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
end
end
return on
@@ -2045,20 +2291,9 @@
%
% Shading with |metafun| format.
% \begin{macrocode}
-local function shading_initialize ()
- pdfetcs.shading_res = {}
- if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
- local shading_obj = pdf.reserveobj()
- pdfetcs.setpageres(format("%s/Shading %i 0 R",pdfetcs.getpageres() or "",shading_obj))
- luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(pdfetcs.shading_res)))
- end, "luamplib.shading.finish_pdffile")
- end
-end
-
local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions)
- if not pdfmanagement and not pdfetcs.shading_res then
- shading_initialize()
+ if pdfmode and not pdfmanagement and not pdfetcs.Shading_res then
+ pdfetcs.initialize_resources"Shading"
end
local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>"
if steps > 1 then
@@ -2091,42 +2326,18 @@
"/Extend [true true]/AntiAlias true>>",
}
local on, new = update_pdfobjs(os)
- if pdfmode then
- if new then
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
- format("{MPlibSh%s}{%s 0 R}", on, on),
- })
- else
- local res = format("/MPlibSh%s %s 0 R", on, on)
- if luatexbase.callbacktypes.finish_pdffile then
- pdfetcs.shading_res[#pdfetcs.shading_res+1] = res
- else
- local pageres = pdfetcs.getpageres() or ""
- if not pageres:find("/Shading<<.*>>") then
- pageres = pageres.."/Shading<<>>"
- end
- pageres = pageres:gsub("/Shading<<","%1"..res)
- pdfetcs.setpageres(pageres)
- end
- end
- end
+ if not new then return on end
+ local key = format("MPlibSh%s", on)
+ local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
+ if pdfmanagement then
+ texsprint(ccexplat,
+ format("\\pdfmanagement_add:nnn{Page/Resources/Shading}{%s}{%s}", key, val))
else
- if pdfmanagement then
- if new then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
- format("{MPlibSh%s}{@mplibpdfobj%s}", on, on),
- })
- end
+ local res = format("/%s %s", key, val)
+ if pdfmode then
+ pdfetcs.fallback_update_resources("Shading", res)
else
- if new then
- texsprint{
- "\\special{pdf:put @MPlibSh",
- format("<</MPlibSh%s @mplibpdfobj%s>>}",on, on),
- }
- end
+ texsprint(format("\\special{pdf:put @MPlibSh<<%s>>}", res))
texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}"
end
end
@@ -2145,7 +2356,18 @@
end
end
-pdfetcs.clrspcs = { }
+pdfetcs.clrspcs = setmetatable({ }, { __index = function(t,names)
+ run_tex_code({
+ [[\color_model_new:nnn]],
+ format("{mplibcolorspace_%s}", names:gsub(",","_")),
+ format("{DeviceN}{names={%s}}", names),
+ [[\edef\mplib_ at tempa{\pdf_object_ref_last:}]],
+ }, ccexplat)
+ local colorspace = get_macro'mplib_ at tempa'
+ t[names] = colorspace
+ return colorspace
+end })
+
local function do_preobj_SH(object,prescript)
local shade_no
local sh_type = prescript and prescript.sh_type
@@ -2208,7 +2430,7 @@
local t = { }
for j=1,names[name] do t[#t+1] = 0 end
t[#t+1] = value
- table.insert(#ca == #cb and ca or cb, t)
+ tableinsert(#ca == #cb and ca or cb, t)
end
end
for _,t in ipairs{ca,cb} do
@@ -2219,20 +2441,7 @@
if #names == 1 then
colorspace = objref
else
- local name = tableconcat(names,"-")
- local obj = pdfetcs.clrspcs[name]
- if obj then
- colorspace = obj
- else
- run_tex_code({
- [[\color_model_new:nnn]],
- format("{mplibcolorspace_%s}", name),
- format("{DeviceN}{names={%s}}", tableconcat(names,",")),
- [[\edef\mplib_ at tempa{\pdf_object_ref_last:}]],
- }, ccexplat)
- colorspace = get_macro'mplib_ at tempa'
- pdfetcs.clrspcs[name] = colorspace
- end
+ colorspace = pdfetcs.clrspcs[ tableconcat(names,",") ]
end
else
local model = 0
@@ -2278,7 +2487,7 @@
%
% Finally, flush figures by inserting PDF literals.
% \begin{macrocode}
-local function flush(result,flusher)
+function luamplib.flush (result,flusher)
if result then
local figures = result.fig
if figures then
@@ -2531,9 +2740,8 @@
end
end
end
-luamplib.flush = flush
-local function colorconverter(cr)
+function luamplib.colorconverter (cr)
local n = #cr
if n == 4 then
local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
@@ -2546,7 +2754,6 @@
return format("%.3f g %.3f G",s,s), "0 g 0 G"
end
end
-luamplib.colorconverter = colorconverter
% \end{macrocode}
%
% \iffalse
@@ -2569,7 +2776,7 @@
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/05/01 v2.29.0 mplib package for LuaTeX]
+ [2024/05/10 v2.30.0 mplib package for LuaTeX]
\ifx\newluafunction\@undefined
\input ltluatex
\fi
Modified: trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua 2024-05-10 21:15:13 UTC (rev 71225)
@@ -11,8 +11,8 @@
luatexbase.provides_module {
name = "luamplib",
- version = "2.29.0",
- date = "2024/05/01",
+ version = "2.30.0",
+ date = "2024/05/10",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -59,6 +59,7 @@
luamplib.showlog = luamplib.showlog or false
local tableconcat = table.concat
+local tableinsert = table.insert
local texsprint = tex.sprint
local texgettoks = tex.gettoks
local texgetbox = tex.getbox
@@ -109,7 +110,7 @@
local currenttime = os.time()
-local outputdir
+local outputdir, cachedir
if lfstouch then
for i,v in ipairs{'TEXMFVAR','TEXMF_OUTPUT_DIRECTORY','.','TEXMFOUTPUT'} do
local var = i == 3 and v or kpse.var_value(v)
@@ -129,7 +130,6 @@
end
end
outputdir = outputdir or '.'
-
function luamplib.getcachedir(dir)
dir = dir:gsub("##","#")
dir = dir:gsub("^~",
@@ -137,7 +137,7 @@
if lfstouch and dir then
if lfsisdir(dir) then
if is_writable(dir) then
- luamplib.cachedir = dir
+ cachedir = dir
else
warn("Directory '%s' is not writable!", dir)
end
@@ -191,9 +191,8 @@
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 = name:gsub("%W","_")
- newfile = cachedir .."/luamplib_input_"..newfile
+ newfile = format("%s/luamplib_input_%s", cachedir or outputdir, newfile)
if newfile and luamplibtime then
local nf = lfsattributes(newfile)
if nf and nf.mode == "file" and
@@ -245,7 +244,7 @@
enc = "enc files",
}
-local function finder(name, mode, ftype)
+function luamplib.finder (name, mode, ftype)
if mode == "w" then
if name and name ~= "mpout.log" then
kpse.record_output_file(name) -- recorder
@@ -267,7 +266,6 @@
return file
end
end
-luamplib.finder = finder
local preamble = [[
boolean mplib ; mplib := true ;
@@ -277,10 +275,9 @@
]]
local currentformat = "plain"
-local function setformat (name)
+function luamplib.setformat (name)
currentformat = name
end
-luamplib.setformat = setformat
luamplib.codeinherit = false
local mplibinstances = {}
@@ -331,9 +328,9 @@
}
local preamble = tableconcat{
format(preamble, replacesuffix(name,"mp")),
- luamplib.mplibcodepreamble,
- luamplib.legacy_verbatimtex and luamplib.legacyverbatimtexpreamble or "",
- luamplib.textextlabel and luamplib.textextlabelpreamble or "",
+ luamplib.preambles.mplibcode,
+ luamplib.legacy_verbatimtex and luamplib.preambles.legacyverbatimtex or "",
+ luamplib.textextlabel and luamplib.preambles.textextlabel or "",
}
local result, log
if not mpx then
@@ -454,7 +451,7 @@
end
local ccexplat = luatexbase.registernumber"luamplibcctabexplat"
-local function process_color (str, kind)
+local function process_color (str)
if str then
if not str:find("%b{}") then
str = format("{%s}",str)
@@ -475,94 +472,16 @@
end
end
end
- if myfmt == mplibcolorfmt.l3color and (kind == "fill" or kind == "draw") then return str end
run_tex_code(myfmt:format(str), ccexplat or catat11)
local t = texgettoks"mplibtmptoks"
if not pdfmode and not t:find"^pdf" then
t = t:gsub("%a+ (.+)","pdf:bc [%1]")
end
- if kind then return t end
- return format('1 withprescript "MPlibOverrideColor=%s"', t)
+ return format('1 withprescript "mpliboverridecolor=%s"', t)
end
return ""
end
-local function colorsplit (res)
- local t, tt = { }, res:gsub("[%[%]]",""):explode()
- local be = tt[1]:find"^%d" and 1 or 2
- for i=be, #tt do
- if tt[i]:find"^%a" then break end
- t[#t+1] = tt[i]
- end
- return t
-end
-
-luamplib.outlinecolor = function (str, filldraw)
- local nn = filldraw == "fill" and 'fn:=' or 'dn:='
- local cc = filldraw == "fill" and 'fc:=' or 'dc:='
- local res = process_color(str, filldraw)
- if res:match"{(.+)}" == str then
- return format('%s"n"; %s"%s";', nn,cc,str)
- end
- local t = colorsplit(res)
- local md = #t == 1 and 'gray' or #t == 3 and 'rgb' or #t == 4 and 'cmyk'
- return format('%s"nn"; %s"%s}{%s";', nn, cc, md, tableconcat(t,','))
-end
-
-luamplib.gettexcolor = function (str, rgb)
- local res = process_color(str, "metapost")
- if res:find" cs " or res:find"@pdf.obj" then
- if not rgb then
- warn("%s is a spot color. Forced to CMYK", str)
- end
- run_tex_code({
- "\\color_export:nnN{",
- str,
- "}{",
- rgb and "space-sep-rgb" or "space-sep-cmyk",
- "}\\mplib_ at tempa",
- },ccexplat)
- return get_macro"mplib_ at tempa":explode()
- end
- local t = colorsplit(res)
- if #t == 3 or not rgb then return t end
- run_tex_code({ -- force to rgb
- "\\color_export:nnnN{",
- #t == 4 and "cmyk" or "gray",
- "}{",
- tableconcat(t,","),
- "}{space-sep-rgb}\\mplib_ at tempa",
- },ccexplat)
- return get_macro"mplib_ at tempa":explode()
-end
-
-luamplib.shadecolor = function (str)
- local res = process_color(str, "shade")
- if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only
- run_tex_code({
- [[\color_export:nnN{]], str, [[}{backend}\mplib_ at tempa]],
- },ccexplat)
- local name = get_macro'mplib_ at tempa':match'{(.-)}{.+}'
- local t, obj = res:explode()
- if pdfmode then
- obj = t[1]:match"^/(.+)"
- if ltx.pdf and ltx.pdf.object_id then
- obj = format("%s 0 R", ltx.pdf.object_id(obj))
- else
- run_tex_code({
- [[\edef\mplib_ at tempa{\pdf_object_ref:n{]], obj, "}}",
- },ccexplat)
- obj = get_macro'mplib_ at tempa'
- end
- else
- obj = t[2]
- end
- local value = t[3]:match"%[(.-)%]" or t[3]
- return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name)
- end
- return colorsplit(res)
-end
-
local function process_dimen (str)
if str then
str = str:gsub("{(.+)}","%1")
@@ -703,15 +622,295 @@
return ""
end
-local mplibcodepreamble = [[
+local function colorsplit (res)
+ local t, tt = { }, res:gsub("[%[%]]",""):explode()
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ t[#t+1] = tt[i]
+ end
+ return t
+end
+
+local min = math.min
+luamplib.gettexcolor = function (str, rgb)
+ local res = process_color(str):match'"mpliboverridecolor=(.+)"'
+ if res:find" cs " or res:find"@pdf.obj" then
+ if not rgb then
+ warn("%s is a spot color. Forced to CMYK", str)
+ end
+ run_tex_code({
+ "\\color_export:nnN{",
+ str,
+ "}{",
+ rgb and "space-sep-rgb" or "space-sep-cmyk",
+ "}\\mplib_ at tempa",
+ },ccexplat)
+ return get_macro"mplib_ at tempa":explode()
+ end
+ local t = colorsplit(res)
+ if #t == 3 or not rgb then return t end
+ if #t == 4 then
+ return { 1 - min(1,t[1]+t[4]), 1 - min(1,t[2]+t[4]), 1 - min(1,t[3]+t[4]) }
+ end
+ return { t[1], t[1], t[1] }
+end
+
+luamplib.shadecolor = function (str)
+ local res = process_color(str):match'"mpliboverridecolor=(.+)"'
+ if res:find" cs " or res:find"@pdf.obj" then -- spot color shade: l3 only
+ run_tex_code({
+ [[\color_export:nnN{]], str, [[}{backend}\mplib_ at tempa]],
+ },ccexplat)
+ local name = get_macro'mplib_ at tempa':match'{(.-)}{.+}'
+ local t, obj = res:explode()
+ if pdfmode then
+ obj = t[1]:match"^/(.+)"
+ if ltx.pdf and ltx.pdf.object_id then
+ obj = format("%s 0 R", ltx.pdf.object_id(obj))
+ else
+ run_tex_code({
+ [[\edef\mplib_ at tempa{\pdf_object_ref:n{]], obj, "}}",
+ },ccexplat)
+ obj = get_macro'mplib_ at tempa'
+ end
+ else
+ obj = t[2]
+ end
+ local value = t[3]:match"%[(.-)%]" or t[3]
+ return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name)
+ end
+ return colorsplit(res)
+end
+
+local emboldenfonts = { }
+local function embolden (head, fakebold)
+ local curr = head
+ while curr do
+ if curr.head then
+ embolden(curr.head, fakebold)
+ elseif curr.leader and curr.leader.head then
+ embolden(curr.leader.head, fakebold)
+ elseif curr.id == node.id"glyph" and curr.font > 0 then
+ local f = curr.font
+ local i = emboldenfonts[f]
+ if not i then
+ if pdfmode then
+ local ft = font.getcopy(f)
+ ft.mode = 2
+ ft.width = ft.size * fakebold / 6578.176
+ i = font.define(ft)
+ else
+ local ft = font.getfont(f) or font.getcopy(f)
+ if ft.format ~= "opentype" and ft.format ~= "truetype" then
+ goto skip_type1
+ end
+ local name = ft.name:gsub('"',''):gsub(';$','')
+ name = format('%s;embolden=%s',name,fakebold)
+ _, i = fonts.constructors.readanddefine(name,ft.size)
+ end
+ emboldenfonts[f] = i
+ end
+ curr.font = i
+ end
+ ::skip_type1::
+ curr = node.getnext(curr)
+ end
+end
+local function graphictextcolor (col, filldraw)
+ if col:find"^[%d%.:]+$" then
+ col = col:explode":"
+ if pdfmode then
+ local op = #col == 4 and "k" or #col == 3 and "rg" or "g"
+ col[#col+1] = filldraw == "fill" and op or op:upper()
+ return tableconcat(col," ")
+ end
+ return format("[%s]", tableconcat(col," "))
+ end
+ col = process_color(col):match'"mpliboverridecolor=(.+)"'
+ if pdfmode then
+ local t, tt = col:explode(), { }
+ local b = filldraw == "fill" and 1 or #t/2+1
+ local e = b == 1 and #t/2 or #t
+ for i=b,e do
+ tt[#tt+1] = t[i]
+ end
+ return tableconcat(tt," ")
+ end
+ return col:gsub("^.- ","")
+end
+luamplib.graphictext = function (text, fakebold, fc, dc)
+ local fmt = process_tex_text(text):sub(1,-2)
+ local id = tonumber(fmt:match"mplibtexboxid=(%d+):")
+ embolden(texgetbox(id).head, fakebold)
+ local fill = graphictextcolor(fc,"fill")
+ local draw = graphictextcolor(dc,"draw")
+ local bc = pdfmode and "" or "pdf:bc "
+ return format('%s withprescript "mpliboverridecolor=%s%s %s")', fmt, bc, fill, draw)
+end
+
+local function mperr (str)
+ return format("hide(errmessage %q)", str)
+end
+local function getangle (a,b,c)
+ local r = math.deg(math.atan(c.y-b.y, c.x-b.x) - math.atan(b.y-a.y, b.x-a.x))
+ if r > 180 then
+ r = r - 360
+ elseif r < -180 then
+ r = r + 360
+ end
+ return r
+end
+local function turning (t)
+ local r, n = 0, #t
+ for i=1,2 do
+ tableinsert(t, t[i])
+ end
+ for i=1,n do
+ r = r + getangle(t[i], t[i+1], t[i+2])
+ end
+ return r/360
+end
+local function glyphimage(t, fmt)
+ local q,p,r = {{},{}}
+ for i,v in ipairs(t) do
+ local cmd = v[#v]
+ if cmd == "m" then
+ p = {format('(%s,%s)',v[1],v[2])}
+ r = {{x=v[1],y=v[2]}}
+ else
+ local nt = t[i+1]
+ local last = not nt or nt[#nt] == "m"
+ if cmd == "l" then
+ local pt = t[i-1]
+ local seco = pt[#pt] == "m"
+ if (last or seco) and r[1].x == v[1] and r[1].y == v[2] then
+ else
+ tableinsert(p, format('--(%s,%s)',v[1],v[2]))
+ tableinsert(r, {x=v[1],y=v[2]})
+ end
+ if last then
+ tableinsert(p, '--cycle')
+ end
+ elseif cmd == "c" then
+ tableinsert(p, format('..controls(%s,%s)and(%s,%s)',v[1],v[2],v[3],v[4]))
+ if last and r[1].x == v[5] and r[1].y == v[6] then
+ tableinsert(p, '..cycle')
+ else
+ tableinsert(p, format('..(%s,%s)',v[5],v[6]))
+ if last then
+ tableinsert(p, '--cycle')
+ end
+ tableinsert(r, {x=v[5],y=v[6]})
+ end
+ else
+ return mperr"unknown operator"
+ end
+ if last then
+ tableinsert(q[ turning(r) > 0 and 1 or 2 ], tableconcat(p))
+ end
+ end
+ end
+ r = { }
+ if fmt == "opentype" then
+ for _,v in ipairs(q[1]) do
+ tableinsert(r, format('addto currentpicture contour %s;',v))
+ end
+ for _,v in ipairs(q[2]) do
+ tableinsert(r, format('addto currentpicture contour %s withcolor background;',v))
+ end
+ else
+ for _,v in ipairs(q[2]) do
+ tableinsert(r, format('addto currentpicture contour %s;',v))
+ end
+ for _,v in ipairs(q[1]) do
+ tableinsert(r, format('addto currentpicture contour %s withcolor background;',v))
+ end
+ end
+ return format('image(%s)', tableconcat(r))
+end
+if not table.tofile then require"lualibs-lpeg"; require"lualibs-table"; end
+function luamplib.glyph (f, c)
+ local filename, subfont, instance, kind, shapedata
+ local fid = tonumber(f) or font.id(f) -- string: fontname
+ if fid > 0 then
+ local fontdata = font.getfont(fid) or font.getcopy(fid)
+ filename, subfont, kind = fontdata.filename, fontdata.subfont, fontdata.format
+ instance = fontdata.specification and fontdata.specification.instance
+ else
+ local name
+ f = f:match"^%s*(.+)%s*$"
+ name, subfont, instance = f:match"(.+)%((%d+)%)%[(.-)%]$"
+ if not name then
+ name, instance = f:match"(.+)%[(.-)%]$" -- SourceHanSansK-VF.otf[Heavy]
+ end
+ if not name then
+ name, subfont = f:match"(.+)%((%d+)%)$" -- Times.ttc(2)
+ end
+ name = name or f
+ subfont = (subfont or 0)+1
+ instance = instance and instance:lower()
+ for _,ftype in ipairs{"opentype", "truetype"} do
+ filename = kpse.find_file(name, ftype.." fonts")
+ if filename then
+ kind = ftype; break
+ end
+ end
+ end
+ if kind ~= "opentype" and kind ~= "truetype" then
+ f = fid and fid > 0 and tex.fontname(fid) or f
+ if kpse.find_file(f, "tfm") then
+ return format("glyph %s of %q", tonumber(c) or format("%q",c), f)
+ else
+ return mperr"font not found"
+ end
+ end
+ local time = lfsattributes(filename,"modification")
+ local k = format("shapes_%s(%s)[%s]", filename, subfont or "", instance or "")
+ local h = format(string.rep('%02x', 256/8), string.byte(sha2.digest256(k), 1, -1))
+ local newname = format("%s/%s.lua", cachedir or outputdir, h)
+ local newtime = lfsattributes(newname,"modification") or 0
+ if time == newtime then
+ shapedata = require(newname)
+ end
+ if not shapedata then
+ shapedata = fonts and fonts.handlers.otf.readers.loadshapes(filename,subfont,instance)
+ if not shapedata then return mperr"loadshapes() failed. luaotfload not loaded?" end
+ table.tofile(newname, shapedata, "return")
+ lfstouch(newname, time, time)
+ end
+ local gid = tonumber(c)
+ if not gid then
+ local uni = utf8.codepoint(c)
+ for i,v in pairs(shapedata.glyphs) do
+ if c == v.name or uni == v.unicode then
+ gid = i; break
+ end
+ end
+ end
+ if not gid then return mperr"cannot get GID (glyph id)" end
+ local fac = 1000 / (shapedata.units or 1000)
+ local t = shapedata.glyphs[gid].segments
+ if not t then return mperr"glyph has no contour. Maybe blank space" end
+ for i,v in ipairs(t) do
+ if type(v) == "table" then
+ for ii,vv in ipairs(v) do
+ if type(vv) == "number" then
+ t[i][ii] = format("%.0f", vv * fac)
+ end
+ end
+ end
+ end
+ return glyphimage(t, kind)
+end
+
+luamplib.preambles = {
+ mplibcode = [[
texscriptmode := 2;
def rawtextext (expr t) = runscript("luamplibtext{"&t&"}") enddef;
def mplibcolor (expr t) = runscript("luamplibcolor{"&t&"}") enddef;
def mplibdimen (expr t) = runscript("luamplibdimen{"&t&"}") enddef;
def VerbatimTeX (expr t) = runscript("luamplibverbtex{"&t&"}") enddef;
-def message expr t =
- if string t: runscript("mp.report[=["&t&"]=]") else: errmessage "Not a string" fi
-enddef;
if known context_mlib:
defaultfont := "cmtt10";
let infont = normalinfont;
@@ -725,23 +924,27 @@
(1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
fi
enddef;
- def colordecimals primary c =
- if cmykcolor c:
- decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c
- elseif rgbcolor c:
- decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
- elseif string c:
- colordecimals resolvedcolor(c)
- else:
- decimal c
- fi
- enddef;
- def resolvedcolor(expr s) =
- runscript("return luamplib.shadecolor('"& s &"')")
- enddef;
else:
vardef textext@# (text t) = rawtextext (t) enddef;
+ def message expr t =
+ if string t: runscript("mp.report[=["&t&"]=]") else: errmessage "Not a string" fi
+ enddef;
fi
+def resolvedcolor(expr s) =
+ runscript("return luamplib.shadecolor('"& s &"')")
+enddef;
+def colordecimals primary c =
+ if cmykcolor c:
+ decimal cyanpart c & ":" & decimal magentapart c & ":" &
+ decimal yellowpart c & ":" & decimal blackpart c
+ elseif rgbcolor c:
+ decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
+ elseif string c:
+ if known graphictextpic: c else: colordecimals resolvedcolor(c) fi
+ else:
+ decimal c
+ fi
+enddef;
def externalfigure primary filename =
draw rawtextext("\includegraphics{"& filename &"}")
enddef;
@@ -758,55 +961,43 @@
enddef;
def mplibgraphictext_ (expr t) text rest =
save fakebold, scale, fillcolor, drawcolor, withfillcolor, withdrawcolor,
- fb, sc, fc, dc, fn, dn, tpic;
- picture tpic; tpic := nullpicture;
- numeric fb, sc; string fc, dc, fn, dn;
- fb:=2; sc:=1; fc:="white"; dc:="black"; fn:=dn:="n";
+ fb, fc, dc, graphictextpic;
+ picture graphictextpic; graphictextpic := nullpicture;
+ numeric fb; string fc, dc; fb:=2; fc:="white"; dc:="black";
+ let scale = scaled;
def fakebold primary c = hide(fb:=c;) enddef;
- def scale primary c = hide(sc:=c;) enddef;
- def fillcolor primary c = hide(
- if string c:
- runscript("return luamplib.outlinecolor('"& c &"','fill')")
- else:
- fn:="nn"; fc:=mpliboutlinecolor_(c);
- fi
- ) enddef;
- def drawcolor primary c = hide(
- if string c:
- runscript("return luamplib.outlinecolor('"& c &"','draw')")
- else:
- dn:="nn"; dc:=mpliboutlinecolor_(c);
- fi
- ) enddef;
+ def fillcolor primary c = hide(fc:=colordecimals c;) enddef;
+ def drawcolor primary c = hide(dc:=colordecimals c;) enddef;
let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
- addto tpic doublepath origin rest; tpic:=nullpicture;
+ addto graphictextpic doublepath origin rest; graphictextpic:=nullpicture;
def fakebold primary c = enddef;
- def scale primary c = enddef;
- def fillcolor primary c = enddef;
- def drawcolor primary c = enddef;
+ let fillcolor = fakebold; let drawcolor = fakebold;
let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
- image(draw rawtextext(
- "{\addfontfeature{FakeBold="& decimal fb &",Scale="& decimal sc &
- "}\csname color_fill:"& fn &"\endcsname{"& fc &
- "}\csname color_stroke:"& dn &"\endcsname{"& dc &
- "}"& t &"}") rest;)
+ image(draw runscript("return luamplib.graphictext([===["&t&"]===],"
+ & decimal fb &",'"& fc &"','"& dc &"')") rest;)
endgroup;
enddef;
-def mpliboutlinecolor_ (expr c) =
- if color c:
- "rgb}{" & decimal redpart c & "," & decimal greenpart c
- & "," & decimal bluepart c
- elseif cmykcolor c:
- "cmyk}{" & decimal cyanpart c & "," & decimal magentapart c
- & "," & decimal yellowpart c & "," & decimal blackpart c
- else:
- "gray}{" & decimal c
- fi
+def mplibglyph expr c of f =
+ runscript (
+ "return luamplib.glyph('"
+ & if numeric f: decimal fi f
+ & "','"
+ & if numeric c: decimal fi c
+ & "')"
+ )
enddef;
-]]
-luamplib.mplibcodepreamble = mplibcodepreamble
-
-local legacyverbatimtexpreamble = [[
+def mplibdrawglyph expr g =
+ draw image(
+ save i; numeric i; i:=0;
+ for item within g:
+ i := i+1;
+ fill pathpart item
+ if i < length g: withpostscript "collect" fi;
+ endfor
+ )
+enddef;
+]],
+ legacyverbatimtex = [[
def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef;
def normalVerbatimTeX (text t) = runscript("luamplibinfig{"&t&"}") enddef;
let VerbatimTeX = specialVerbatimTeX;
@@ -816,10 +1007,8 @@
"runscript(" &ditto&
"if luamplib.in_the_fig then luamplib.figid=luamplib.figid+1 end "&
"luamplib.in_the_fig=false" &ditto& ");";
-]]
-luamplib.legacyverbatimtexpreamble = legacyverbatimtexpreamble
-
-local textextlabelpreamble = [[
+]],
+ textextlabel = [[
primarydef s infont f = rawtextext(s) enddef;
def fontsize expr f =
begingroup
@@ -828,8 +1017,8 @@
if size = 0: 10pt else: size fi
endgroup
enddef;
-]]
-luamplib.textextlabelpreamble = textextlabelpreamble
+]],
+}
luamplib.verbatiminput = false
@@ -857,7 +1046,7 @@
luamplib.everymplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
luamplib.everyendmplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
-local function process_mplibcode (data, instancename)
+function luamplib.process_mplibcode (data, instancename)
texboxes.localid = 4096
if luamplib.legacy_verbatimtex then
@@ -900,7 +1089,6 @@
process(data, instancename)
end
-luamplib.process_mplibcode = process_mplibcode
local further_split_keys = {
mplibtexboxid = true,
@@ -926,11 +1114,10 @@
return figure:objects()
end
-local function convert(result, flusher)
+function luamplib.convert (result, flusher)
luamplib.flush(result, flusher)
return true -- done
end
-luamplib.convert = convert
local figcontents = { post = { } }
local function put2output(a,...)
@@ -1081,7 +1268,7 @@
local prev_override_color
local function do_preobj_CR(object,prescript)
- local override = prescript and prescript.MPlibOverrideColor
+ local override = prescript and prescript.mpliboverridecolor
if override then
if pdfmode then
pdf_literalcode(override)
@@ -1109,13 +1296,6 @@
local pdfobjs, pdfetcs = {}, {}
pdfetcs.pgfextgs = "pgf at sys@addpdfresource at extgs@plain"
-if pdfmode then
- pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
- pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
-else
- texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
-end
-
local function update_pdfobjs (os)
local on = pdfobjs[os]
if on then
@@ -1132,6 +1312,38 @@
return on,true
end
+if pdfmode then
+ pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
+ pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
+ pdfetcs.initialize_resources = function (name)
+ local tabname = format("%s_res",name)
+ pdfetcs[tabname] = { }
+ if luatexbase.callbacktypes.finish_pdffile then -- ltluatex
+ local obj = pdf.reserveobj()
+ pdfetcs.setpageres(format("%s/%s %i 0 R", pdfetcs.getpageres() or "", name, obj))
+ luatexbase.add_to_callback("finish_pdffile", function()
+ pdf.immediateobj(obj, format("<<%s>>", tableconcat(pdfetcs[tabname])))
+ end,
+ format("luamplib.%s.finish_pdffile",name))
+ end
+ end
+ pdfetcs.fallback_update_resources = function (name, res)
+ if luatexbase.callbacktypes.finish_pdffile then
+ local t = pdfetcs[format("%s_res",name)]
+ t[#t+1] = res
+ else
+ local tpr, n = pdfetcs.getpageres() or "", 0
+ tpr, n = tpr:gsub(format("/%s<<",name), "%1"..res)
+ if n == 0 then
+ tpr = format("%s/%s<<%s>>", tpr, name, res)
+ end
+ pdfetcs.setpageres(tpr)
+ end
+ end
+else
+ texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
+end
+
local transparancy_modes = { [0] = "Normal",
"Normal", "Multiply", "Screen", "Overlay",
"SoftLight", "HardLight", "ColorDodge", "ColorBurn",
@@ -1140,75 +1352,42 @@
"Compatible",
}
-local function opacity_initialize ()
- pdfetcs.opacity_res = {}
- if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
- local extgstate_obj = pdf.reserveobj()
- pdfetcs.setpageres(format("%s/ExtGState %i 0 R",pdfetcs.getpageres() or "",extgstate_obj))
- luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(extgstate_obj, format("<<%s>>",tableconcat(pdfetcs.opacity_res)))
- end, "luamplib.opacity.finish_pdffile")
- end
-end
-
local function update_tr_res(mode,opaq)
if pdfetcs.pgfloaded == nil then
pdfetcs.pgfloaded = is_defined(pdfetcs.pgfextgs)
- if not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP at list" then
- opacity_initialize()
+ if pdfmode and not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP at list" then
+ pdfetcs.initialize_resources"ExtGState"
end
end
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
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
- format("{MPlibTr%s}{%s 0 R}", on, on),
+ if not new then return on end
+ local key = format("MPlibTr%s", on)
+ local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
+ if pdfmanagement then
+ texsprint(ccexplat,
+ format("\\pdfmanagement_add:nnn{Page/Resources/ExtGState}{%s}{%s}", key, val))
+ else
+ local tr = format("/%s %s", key, val)
+ if pdfetcs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
+ elseif pdfmode then
+ if is_defined"TRP at list" then
+ texsprint(catat11,{
+ [[\if at filesw\immediate\write\@auxout{]],
+ [[\string\g at addto@macro\string\TRP at list{]],
+ tr,
+ [[}}\fi]],
})
+ if not get_macro"TRP at list":find(tr) then
+ texsprint(catat11,[[\global\TRP at reruntrue]])
+ end
else
- local tr = format("/MPlibTr%s %s 0 R",on,on)
- if pdfetcs.pgfloaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
- elseif is_defined"TRP at list" then
- texsprint(catat11,{
- [[\if at filesw\immediate\write\@auxout{]],
- [[\string\g at addto@macro\string\TRP at list{]],
- tr,
- [[}}\fi]],
- })
- if not get_macro"TRP at list":find(tr) then
- texsprint(catat11,[[\global\TRP at reruntrue]])
- end
- else
- if luatexbase.callbacktypes.finish_pdffile then
- pdfetcs.opacity_res[#pdfetcs.opacity_res+1] = tr
- else
- local tpr, n = pdfetcs.getpageres() or "", 0
- tpr, n = tpr:gsub("/ExtGState<<", "%1"..tr)
- if n == 0 then
- tpr = format("%s/ExtGState<<%s>>", tpr, tr)
- end
- pdfetcs.setpageres(tpr)
- end
- end
+ pdfetcs.fallback_update_resources("ExtGState", tr)
end
else
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
- format("{MPlibTr%s}{@mplibpdfobj%s}", on, on),
- })
- else
- local tr = format("/MPlibTr%s @mplibpdfobj%s",on,on)
- if pdfetcs.pgfloaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
- else
- texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
- texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
- end
- end
+ texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
+ texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
end
end
return on
@@ -1227,20 +1406,9 @@
return tron_no
end
-local function shading_initialize ()
- pdfetcs.shading_res = {}
- if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
- local shading_obj = pdf.reserveobj()
- pdfetcs.setpageres(format("%s/Shading %i 0 R",pdfetcs.getpageres() or "",shading_obj))
- luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(pdfetcs.shading_res)))
- end, "luamplib.shading.finish_pdffile")
- end
-end
-
local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions)
- if not pdfmanagement and not pdfetcs.shading_res then
- shading_initialize()
+ if pdfmode and not pdfmanagement and not pdfetcs.Shading_res then
+ pdfetcs.initialize_resources"Shading"
end
local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>"
if steps > 1 then
@@ -1273,42 +1441,18 @@
"/Extend [true true]/AntiAlias true>>",
}
local on, new = update_pdfobjs(os)
- if pdfmode then
- if new then
- if pdfmanagement then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
- format("{MPlibSh%s}{%s 0 R}", on, on),
- })
- else
- local res = format("/MPlibSh%s %s 0 R", on, on)
- if luatexbase.callbacktypes.finish_pdffile then
- pdfetcs.shading_res[#pdfetcs.shading_res+1] = res
- else
- local pageres = pdfetcs.getpageres() or ""
- if not pageres:find("/Shading<<.*>>") then
- pageres = pageres.."/Shading<<>>"
- end
- pageres = pageres:gsub("/Shading<<","%1"..res)
- pdfetcs.setpageres(pageres)
- end
- end
- end
+ if not new then return on end
+ local key = format("MPlibSh%s", on)
+ local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
+ if pdfmanagement then
+ texsprint(ccexplat,
+ format("\\pdfmanagement_add:nnn{Page/Resources/Shading}{%s}{%s}", key, val))
else
- if pdfmanagement then
- if new then
- texsprint(ccexplat,{
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
- format("{MPlibSh%s}{@mplibpdfobj%s}", on, on),
- })
- end
+ local res = format("/%s %s", key, val)
+ if pdfmode then
+ pdfetcs.fallback_update_resources("Shading", res)
else
- if new then
- texsprint{
- "\\special{pdf:put @MPlibSh",
- format("<</MPlibSh%s @mplibpdfobj%s>>}",on, on),
- }
- end
+ texsprint(format("\\special{pdf:put @MPlibSh<<%s>>}", res))
texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}"
end
end
@@ -1327,7 +1471,18 @@
end
end
-pdfetcs.clrspcs = { }
+pdfetcs.clrspcs = setmetatable({ }, { __index = function(t,names)
+ run_tex_code({
+ [[\color_model_new:nnn]],
+ format("{mplibcolorspace_%s}", names:gsub(",","_")),
+ format("{DeviceN}{names={%s}}", names),
+ [[\edef\mplib_ at tempa{\pdf_object_ref_last:}]],
+ }, ccexplat)
+ local colorspace = get_macro'mplib_ at tempa'
+ t[names] = colorspace
+ return colorspace
+end })
+
local function do_preobj_SH(object,prescript)
local shade_no
local sh_type = prescript and prescript.sh_type
@@ -1390,7 +1545,7 @@
local t = { }
for j=1,names[name] do t[#t+1] = 0 end
t[#t+1] = value
- table.insert(#ca == #cb and ca or cb, t)
+ tableinsert(#ca == #cb and ca or cb, t)
end
end
for _,t in ipairs{ca,cb} do
@@ -1401,20 +1556,7 @@
if #names == 1 then
colorspace = objref
else
- local name = tableconcat(names,"-")
- local obj = pdfetcs.clrspcs[name]
- if obj then
- colorspace = obj
- else
- run_tex_code({
- [[\color_model_new:nnn]],
- format("{mplibcolorspace_%s}", name),
- format("{DeviceN}{names={%s}}", tableconcat(names,",")),
- [[\edef\mplib_ at tempa{\pdf_object_ref_last:}]],
- }, ccexplat)
- colorspace = get_macro'mplib_ at tempa'
- pdfetcs.clrspcs[name] = colorspace
- end
+ colorspace = pdfetcs.clrspcs[ tableconcat(names,",") ]
end
else
local model = 0
@@ -1456,7 +1598,7 @@
return shade_no
end
-local function flush(result,flusher)
+function luamplib.flush (result,flusher)
if result then
local figures = result.fig
if figures then
@@ -1671,9 +1813,8 @@
end
end
end
-luamplib.flush = flush
-local function colorconverter(cr)
+function luamplib.colorconverter (cr)
local n = #cr
if n == 4 then
local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
@@ -1686,6 +1827,5 @@
return format("%.3f g %.3f G",s,s), "0 g 0 G"
end
end
-luamplib.colorconverter = colorconverter
--
-- End of File `luamplib.lua'.
Modified: trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty 2024-05-10 21:15:04 UTC (rev 71224)
+++ trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty 2024-05-10 21:15:13 UTC (rev 71225)
@@ -14,7 +14,7 @@
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/05/01 v2.29.0 mplib package for LuaTeX]
+ [2024/05/10 v2.30.0 mplib package for LuaTeX]
\ifx\newluafunction\@undefined
\input ltluatex
\fi
More information about the tex-live-commits
mailing list.