texlive[70930] Master/texmf-dist: luamplib (12apr24)
commits+karl at tug.org
commits+karl at tug.org
Fri Apr 12 23:45:57 CEST 2024
Revision: 70930
https://tug.org/svn/texlive?view=revision&revision=70930
Author: karl
Date: 2024-04-12 23:45:57 +0200 (Fri, 12 Apr 2024)
Log Message:
-----------
luamplib (12apr24)
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/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-04-12 21:45:49 UTC (rev 70929)
+++ trunk/Master/texmf-dist/doc/luatex/luamplib/NEWS 2024-04-12 21:45:57 UTC (rev 70930)
@@ -1,5 +1,31 @@
History of the luamplib package
+2024/04/12 2.28.0
+ * provide a new metapost operator 'mplibgraphictext', which is similar
+ to ConTeXt's 'graphictext'. But the syntax is not the same:
+
+ mplibgraphictext "Text" fakebold 2 scale 3
+ fillcolor red drawcolor blue
+
+ where 'fakebold' and 'scale' are fontspec's font options.
+ 'fakebold', 'scale', 'drawcolor' and 'fillcolor' are optional and
+ default values are '2', '1', "black" and "white" respectively.
+ When color expressions are given as string, they are regarded as
+ xcolor's or l3color's expressions. The operator generates a metapost
+ picture, which can be drawn or assigned to a variable. For compatibilty
+ with 'graphictext', 'withdrawcolor' and 'withfillcolor' are synonyms of
+ 'drawcolor' and 'fillcolor'. Because the implementation is quite
+ different from the \ConTeXt's, there are some limitations such that
+ we can't apply shading (gradient colors) to the text.
+
+ * support metafun's new shading method. Color expressions given as string
+ are regarded as xcolor's or l3color's expressions. Spot colors defined
+ by the color commands of l3color package are also acceptable
+ (currently '\DocumentMetadata{ }' is needed for spot colors).
+
+ * fix the y-position of text figures, which means the result of 'infont'
+ operator, not of the 'textext' operator.
+
2024/04/04 2.27.2
* for warning/info/error messages we now use our own lua function,
instead of ltluatex's. As a result, mplib's multi-line messages are
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-04-12 21:45:49 UTC (rev 70929)
+++ trunk/Master/texmf-dist/doc/luatex/luamplib/test-luamplib-latex.tex 2024-04-12 21:45:57 UTC (rev 70930)
@@ -1,5 +1,7 @@
\DocumentMetadata{ uncompress }
\documentclass{article}
+\usepackage{fontspec}
+\setmainfont{latin modern roman}
\usepackage{luamplib}
\usepackage{xcolor}
\everymplib{ beginfig(0); }
@@ -166,6 +168,35 @@
rotatedlabel.top(textext("Rotated!"), origin, 45);
endfig;
\end{mplibcode}%
+\par
+\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 ;
+picture p;
+p:=mplibgraphictext "\bfseries\itshape xyz";
+draw p scaled 3 shifted (40,0);
+endfig;
+\end{mplibcode}%
+\mplibsetformat{metafun}%
+\begin{mplibcode}
+beginfig(1)
+fill unitsquare xyscaled (\mpdim\textwidth,1cm)
+ withshademethod "linear"
+ withshadevector (0,1)
+ withshadestep (
+ withshadefraction .5
+ withshadecolors (red,"blue!50")
+ )
+ withshadestep (
+ withshadefraction 1
+ withshadecolors ("blue!50",green)
+ )
+ ;
+endfig;
+\end{mplibcode}%
\tracingcommands0
\vskip 2\baselineskip
Modified: trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx
===================================================================
--- trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx 2024-04-12 21:45:49 UTC (rev 70929)
+++ trunk/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx 2024-04-12 21:45:57 UTC (rev 70930)
@@ -85,7 +85,7 @@
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{luamplib.drv}%
- [2024/04/04 v2.27.2 Interface for using the mplib library]%
+ [2024/04/12 v2.28.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/04/04 v2.27.2}
+% \date{2024/04/12 v2.28.0}
%
% \maketitle
%
@@ -423,6 +423,27 @@
% As backslashes (|\|) should be escaped by users, it would be easier to use
% slashes (|/|) instead.
%
+% \paragraph{\texttt{mplibgraphictext}}
+% For some amusement, luamplib provides its own metapost operator
+% |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
+% \end{verbatim}
+% |fakebold|, |scale|, |drawcolor| and |fillcolor| are optional;
+% default values are |2|, |1|, |"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).
+% 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
+% |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.
+%
% \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.
@@ -455,8 +476,8 @@
luatexbase.provides_module {
name = "luamplib",
- version = "2.27.2",
- date = "2024/04/04",
+ version = "2.28.0",
+ date = "2024/04/12",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -531,6 +552,7 @@
end
local is_defined = token.is_defined
+local get_macro = token.get_macro
local mplib = require ('mplib')
local kpse = require ('kpse')
@@ -1062,7 +1084,7 @@
local ccexplat = luatexbase.registernumber"luamplibcctabexplat"
-local function process_color (str)
+local function process_color (str, filldraw)
if str then
if not str:find("%b{}") then
str = format("{%s}",str)
@@ -1074,7 +1096,7 @@
else
for _,v in ipairs(str:match"{(.+)}":explode"!") do
if not v:find("^%s*%d+%s*$") then
- local pp = token.get_macro(format("l__color_named_%s_prop",v))
+ local pp = get_macro(format("l__color_named_%s_prop",v))
if not pp or pp == "" then
myfmt = mplibcolorfmt.xcolor
break
@@ -1083,14 +1105,105 @@
end
end
end
+ if filldraw and filldraw ~= "shade" and myfmt == mplibcolorfmt.l3color then
+ return str
+ end
run_tex_code(myfmt:format(str), ccexplat or catat11)
local t = texgettoks"mplibtmptoks"
+ if filldraw then return t end
return format('1 withprescript "MPlibOverrideColor=%s"', t)
end
return ""
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 tt, t = res:explode(), { }
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ table.insert(t, tt[i])
+ end
+ 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.shadecolor = function (str)
+ local res = process_color(str, "shade")
+ if res:find" cs" then -- spot color shade: l3 only
% \end{macrocode}
+% An example of spot color shading:
+% \begin{verbatim}
+% \DocumentMetadata{ }
+% \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 value = res:explode()[3]
+ return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,str,name)
+ end
+ local tt, t = res:explode(), { }
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ table.insert(t, tt[i])
+ end
+ return t
+end
+
+% \end{macrocode}
%
% for \cs{mpdim} or |mplibdimen|
% \begin{macrocode}
@@ -1217,13 +1330,13 @@
function mp.print(...)
mpprint(buffer,...)
end
- f()
+ local res = {f()}
buffer = tableconcat(buffer)
if buffer and buffer ~= "" then
return buffer
end
buffer = {}
- mpprint(buffer, f())
+ mpprint(buffer, table.unpack(res))
return tableconcat(buffer)
end
return ""
@@ -1291,15 +1404,20 @@
(1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
fi
enddef;
- def graphictext primary filename =
- if (readfrom filename = EOF):
- errmessage "Please prepare '"&filename&"' in advance with"&
- " 'pstoedit -ssp -dt -f mpost yourfile.ps "&filename&"'";
+ 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
- closefrom filename;
- def data_mpy_file = filename enddef;
- mfun_do_graphic_text (filename)
enddef;
+ def resolvedcolor(expr s) =
+ runscript("return luamplib.shadecolor('"& s &"')")
+ enddef;
else:
vardef textext@# (text t) = rawtextext (t) enddef;
fi
@@ -1307,6 +1425,57 @@
draw rawtextext("\includegraphics{"& filename &"}")
enddef;
def TEX = textext enddef;
+def mplibgraphictext primary t =
+ begingroup;
+ mplibgraphictext_ (t)
+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";
+ 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;
+ let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
+ addto tpic doublepath origin rest; tpic:=nullpicture;
+ def fakebold primary c = enddef;
+ def scale primary c = enddef;
+ def fillcolor primary c = enddef;
+ def drawcolor primary c = enddef;
+ 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;)
+ 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
+enddef;
]]
luamplib.mplibcodepreamble = mplibcodepreamble
@@ -1447,13 +1616,12 @@
sh_color_a = true,
sh_color_b = true,
}
-
local function script2table(s)
local t = {}
for _,i in ipairs(s:explode("\13+")) do
local k,v = i:match("(.-)=(.*)") -- v may contain = or empty.
- if k and v and k ~= "" then
- if further_split_keys[k] then
+ if k and v and k ~= "" and not t[k] then
+ if further_split_keys[k] or further_split_keys[k:sub(1,10)] then
t[k] = v:explode(":")
else
t[k] = v
@@ -1499,7 +1667,7 @@
text = text:gsub(".",function(c)
return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost
end)
- texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth))
+ texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,0))
end
local bend_tolerance = 131/65536
@@ -1642,17 +1810,14 @@
% Colors and Transparency
% \begin{macrocode}
local pdfmanagement = is_defined'pdfmanagement_add:nnn'
-
local pdf_objs = {}
-local getpageres, setpageres
-local pgf = { extgs = "pgf at sys@addpdfresource at extgs@plain" }
+pdf_objs.pgfextgs = "pgf at sys@addpdfresource at extgs@plain"
if pdfmode then
- getpageres = pdf.getpageresources or function() return pdf.pageresources end
- setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
+ pdf_objs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
+ pdf_objs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
else
- texsprint("\\special{pdf:obj @MPlibTr<<>>}",
- "\\special{pdf:obj @MPlibSh<<>>}")
+ texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
end
local function update_pdfobjs (os)
@@ -1685,12 +1850,14 @@
if new then
if pdfmode then
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}{MPlibTr%s}{%s 0 R}]], on,on))
+ texsprint(ccexplat,{
+ [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
+ format("{MPlibTr%s}{%s 0 R}", on, on),
+ })
else
local tr = format("/MPlibTr%s %s 0 R",on,on)
- if pgf.loaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pgf.extgs,tr))
+ if pdf_objs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdf_objs.pgfextgs,tr))
elseif is_defined"TRP at list" then
texsprint(catat11,{
[[\if at filesw\immediate\write\@auxout{]],
@@ -1698,7 +1865,7 @@
tr,
[[}}\fi]],
})
- if not token.get_macro"TRP at list":find(tr) then
+ if not get_macro"TRP at list":find(tr) then
texsprint(catat11,[[\global\TRP at reruntrue]])
end
else
@@ -1707,12 +1874,14 @@
end
else
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}{MPlibTr%s}{@mplibpdfobj%s}]], on,on))
+ 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 pgf.loaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pgf.extgs,tr))
+ if pdf_objs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdf_objs.pgfextgs,tr))
else
texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
end
@@ -1723,26 +1892,26 @@
end
local function tr_pdf_pageresources(mode,opaq)
- if pgf.loaded == nil then
- pgf.loaded = is_defined(pgf.extgs)
+ if pdf_objs.pgfloaded == nil then
+ pdf_objs.pgfloaded = is_defined(pdf_objs.pgfextgs)
end
local res, on_on, off_on = "", nil, nil
res, off_on = update_tr_res(res, "Normal", 1)
res, on_on = update_tr_res(res, mode, opaq)
- if pdfmanagement or pgf.loaded or is_defined"TRP at list" then
+ if pdfmanagement or pdf_objs.pgfloaded or is_defined"TRP at list" then
return on_on, off_on
end
if pdfmode then
if res ~= "" then
- local tpr, n = getpageres() or "", 0
+ local tpr, n = pdf_objs.getpageres() or "", 0
tpr, n = tpr:gsub("/ExtGState<<", "%1"..res)
if n == 0 then
tpr = format("%s/ExtGState<<%s>>", tpr, res)
end
- setpageres(tpr)
+ pdf_objs.setpageres(tpr)
end
else
- texsprint(format("\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"))
+ texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
end
return on_on, off_on
end
@@ -1749,47 +1918,78 @@
% \end{macrocode}
%
-% Shading with |metafun| format. (maybe legacy way)
+% Shading with |metafun| format.
% \begin{macrocode}
-local shading_res
-
local function shading_initialize ()
- shading_res = {}
+ pdf_objs.shading_res = {}
if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
local shading_obj = pdf.reserveobj()
- setpageres(format("%s/Shading %i 0 R",getpageres() or "",shading_obj))
+ pdf_objs.setpageres(format("%s/Shading %i 0 R",pdf_objs.getpageres() or "",shading_obj))
luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(shading_res)))
- end, "luamplib.finish_pdffile")
- pdf_objs.finishpdf = true
+ pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(pdf_objs.shading_res)))
+ end, "luamplib.finish_pdffile")
end
end
-local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordinates)
- if not pdfmanagement and not shading_res then shading_initialize() end
- local os = format("<</FunctionType 2/Domain [ %s ]/C0 [ %s ]/C1 [ %s ]/N 1>>",
- domain, colora, colorb)
- local funcobj = pdfmode and format("%s 0 R",update_pdfobjs(os))
- or format("@mplibpdfobj%s",update_pdfobjs(os))
- os = format("<</ShadingType %i/ColorSpace /%s/Function %s/Coords [ %s ]/Extend [ true true ]/AntiAlias true>>",
- shtype, colorspace, funcobj, coordinates)
- local on, new = update_pdfobjs(os)
+local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions)
+ if not pdfmanagement and not pdf_objs.shading_res then
+ shading_initialize()
+ end
+ local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>"
+ if steps > 1 then
+ local list,bounds,encode = { },{ },{ }
+ for i=1,steps do
+ if i < steps then
+ bounds[i] = fractions[i] or 1
+ end
+ encode[2*i-1] = 0
+ encode[2*i] = 1
+ os = fun2fmt:format(domain,tableconcat(ca[i],' '),tableconcat(cb[i],' '))
+ list[i] = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ end
+ os = tableconcat {
+ "<</FunctionType 3",
+ format("/Bounds [%s]", tableconcat(bounds,' ')),
+ format("/Encode [%s]", tableconcat(encode,' ')),
+ format("/Functions [%s]", tableconcat(list, ' ')),
+ format("/Domain [%s]>>", domain),
+ }
+ else
+ os = fun2fmt:format(domain,tableconcat(ca[1],' '),tableconcat(cb[1],' '))
+ end
+ local objref = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ os = tableconcat {
+ format("<</ShadingType %i", shtype),
+ format("/ColorSpace %s", colorspace),
+ format("/Function %s", objref),
+ format("/Coords [%s]", coordinates),
+ "/Extend [true true]/AntiAlias true>>",
+ }
+ local on, new
+ if colorspace == [[\pdffeedback lastobj 0 R]] then
+ on, new = pdf.reserveobj(), true
+ texsprint(format([[\immediate\pdfextension obj useobjnum %s{%s}]],on,os))
+ else
+ on, new = update_pdfobjs(os)
+ end
if pdfmode then
if new then
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}{MPlibSh%s}{%s 0 R}]], on,on))
+ 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 pdf_objs.finishpdf then
- shading_res[#shading_res+1] = res
+ if luatexbase.callbacktypes.finish_pdffile then
+ pdf_objs.shading_res[#pdf_objs.shading_res+1] = res
else
- local pageres = getpageres() or ""
+ local pageres = pdf_objs.getpageres() or ""
if not pageres:find("/Shading<<.*>>") then
pageres = pageres.."/Shading<<>>"
end
pageres = pageres:gsub("/Shading<<","%1"..res)
- setpageres(pageres)
+ pdf_objs.setpageres(pageres)
end
end
end
@@ -1796,14 +1996,19 @@
else
if pdfmanagement then
if new then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}{MPlibSh%s}{@mplibpdfobj%s}]], on,on))
+ texsprint(ccexplat,{
+ [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
+ format("{MPlibSh%s}{@mplibpdfobj%s}", on, on),
+ })
end
else
if new then
- texsprint(format("\\special{pdf:put @MPlibSh<</MPlibSh%s @mplibpdfobj%s>>}",on,on))
+ texsprint{
+ "\\special{pdf:put @MPlibSh",
+ format("<</MPlibSh%s @mplibpdfobj%s>>}",on, on),
+ }
end
- texsprint(format("\\special{pdf:put @resources<</Shading @MPlibSh>>}"))
+ texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}"
end
end
return on
@@ -1821,13 +2026,11 @@
end
end
-local prev_override_color
-
-local function do_preobj_color(object,prescript)
% \end{macrocode}
%
% transparency
% \begin{macrocode}
+local function do_preobj_TR(prescript)
local opaq = prescript and prescript.tr_transparency
local tron_no, troff_no
if opaq then
@@ -1836,10 +2039,15 @@
tron_no, troff_no = tr_pdf_pageresources(mode,opaq)
pdf_literalcode("/MPlibTr%i gs",tron_no)
end
+ return troff_no
+end
+
% \end{macrocode}
%
% color
% \begin{macrocode}
+local prev_override_color
+local function do_preobj_CR(object,prescript)
local override = prescript and prescript.MPlibOverrideColor
if override then
if pdfmode then
@@ -1869,56 +2077,118 @@
end
end
end
+ return override
+end
+
% \end{macrocode}
%
% shading
% \begin{macrocode}
+local function do_preobj_SH(object,prescript)
+ local shade_no
local sh_type = prescript and prescript.sh_type
if sh_type then
- local domain = prescript.sh_domain
- local centera = prescript.sh_center_a:explode()
- local centerb = prescript.sh_center_b:explode()
- for _,t in pairs({centera,centerb}) do
- for i,v in ipairs(t) do
- t[i] = format("%f",v)
+ local domain = prescript.sh_domain or "0 1"
+ local centera = prescript.sh_center_a or "0 0"; centera = centera:explode()
+ local centerb = prescript.sh_center_b or "0 0"; centerb = centerb:explode()
+ local transform = prescript.sh_transform == "yes"
+ local sx,sy,sr,dx,dy = 1,1,1,0,0
+ if transform then
+ local first = prescript.sh_first or "0 0"; first = first:explode()
+ local setx = prescript.sh_set_x or "0 0"; setx = setx:explode()
+ local sety = prescript.sh_set_y or "0 0"; sety = sety:explode()
+ local x,y = tonumber(setx[1]) or 0, tonumber(sety[1]) or 0
+ if x ~= 0 and y ~= 0 then
+ local path = object.path
+ local path1x = path[1].x_coord
+ local path1y = path[1].y_coord
+ local path2x = path[x].x_coord
+ local path2y = path[y].y_coord
+ local dxa = path2x - path1x
+ local dya = path2y - path1y
+ local dxb = setx[2] - first[1]
+ local dyb = sety[2] - first[2]
+ if dxa ~= 0 and dya ~= 0 and dxb ~= 0 and dyb ~= 0 then
+ sx = dxa / dxb ; if sx < 0 then sx = - sx end
+ sy = dya / dyb ; if sy < 0 then sy = - sy end
+ sr = math.sqrt(sx^2 + sy^2)
+ dx = path1x - sx*first[1]
+ dy = path1y - sy*first[2]
+ end
end
end
- centera = tableconcat(centera," ")
- centerb = tableconcat(centerb," ")
- local colora = prescript.sh_color_a or {0};
- local colorb = prescript.sh_color_b or {1};
- for _,t in pairs({colora,colorb}) do
- for i,v in ipairs(t) do
- t[i] = format("%.3f",v)
+ local model, ca, cb, colorspace, steps, fractions = 0
+ ca = { prescript.sh_color_a_1 or prescript.sh_color_a or {0} }
+ cb = { prescript.sh_color_b_1 or prescript.sh_color_b or {1} }
+ steps = tonumber(prescript.sh_step) or 1
+ if steps > 1 then
+ fractions = { prescript.sh_fraction_1 or 0 }
+ for i=2,steps do
+ fractions[i] = prescript[format("sh_fraction_%i",i)] or (i/steps)
+ ca[i] = prescript[format("sh_color_a_%i",i)] or {0}
+ cb[i] = prescript[format("sh_color_b_%i",i)] or {1}
end
end
- if #colora > #colorb then
- color_normalize(colora,colorb)
- elseif #colorb > #colora then
- color_normalize(colorb,colora)
+ if prescript.mplib_spotcolor then
+ local names, last = { }, ""
+ local script = object.prescript:explode"\13+"
+ for i=#script,1,-1 do
+ if script[i]:find"mplib_spotcolor" then
+ local str, name = script[i]:match"mplib_spotcolor=(.-):(.+)"
+ if str ~= last then
+ names[#names+1] = name
+ end
+ last = str
+ end
+ end
+ texsprint(ccexplat,{
+ [[\color_model_new:nnn{]], tableconcat(names),
+ [[}{DeviceN}{names={]], tableconcat(names,","), [[}}]]
+ })
+ colorspace = [[\pdffeedback lastobj 0 R]]
+ for n,t in ipairs{ca,cb} do
+ for i=1,#t do
+ for j=1, i+n-2 do table.insert(t[i], j, 0) end
+ for j=i+n, #t+1 do table.insert(t[i], j, 0) end
+ end
+ end
+ else
+ for _,t in ipairs{ca,cb} do
+ for _,tt in ipairs(t) do
+ model = model > #tt and model or #tt
+ end
+ end
+ for _,t in ipairs{ca,cb} do
+ for _,tt in ipairs(t) do
+ if #tt < model then
+ color_normalize(model == 4 and {1,1,1,1} or {1,1,1},tt)
+ end
+ end
+ end
+ colorspace = model == 4 and "/DeviceCMYK"
+ or model == 3 and "/DeviceRGB"
+ or model == 1 and "/DeviceGray"
+ or err"unknown color model"
end
- local colorspace
- if #colorb == 1 then colorspace = "DeviceGray"
- elseif #colorb == 3 then colorspace = "DeviceRGB"
- elseif #colorb == 4 then colorspace = "DeviceCMYK"
- else return troff_no,override
- end
- colora = tableconcat(colora, " ")
- colorb = tableconcat(colorb, " ")
- local shade_no
if sh_type == "linear" then
- local coordinates = tableconcat({centera,centerb}," ")
- shade_no = sh_pdfpageresources(2,domain,colorspace,colora,colorb,coordinates)
+ local coordinates = format("%f %f %f %f",
+ dx + sx*centera[1], dy + sy*centera[2],
+ dx + sx*centerb[1], dy + sy*centerb[2])
+ shade_no = sh_pdfpageresources(2,domain,colorspace,ca,cb,coordinates,steps,fractions)
elseif sh_type == "circular" then
- local radiusa = format("%f",prescript.sh_radius_a)
- local radiusb = format("%f",prescript.sh_radius_b)
- local coordinates = tableconcat({centera,radiusa,centerb,radiusb}," ")
- shade_no = sh_pdfpageresources(3,domain,colorspace,colora,colorb,coordinates)
+ local factor = prescript.sh_factor or 1
+ local radiusa = factor * prescript.sh_radius_a
+ local radiusb = factor * prescript.sh_radius_b
+ local coordinates = format("%f %f %f %f %f %f",
+ dx + sx*centera[1], dy + sy*centera[2], sr*radiusa,
+ dx + sx*centerb[1], dy + sy*centerb[2], sr*radiusb)
+ shade_no = sh_pdfpageresources(3,domain,colorspace,ca,cb,coordinates,steps,fractions)
+ else
+ err"unknown shading type"
end
pdf_literalcode("q /Pattern cs")
- return troff_no,override,shade_no
end
- return troff_no,override
+ return shade_no
end
local function do_postobj_color(tr,over,sh)
@@ -1981,12 +2251,14 @@
local objecttype = object.type
% \end{macrocode}
%
-% The following 5 lines are part of |btex...etex| patch.
+% The following 7 lines are part of |btex...etex| patch.
% Again, colors are processed at this stage.
% \begin{macrocode}
local prescript = object.prescript
prescript = prescript and script2table(prescript) -- prescript is now a table
- local tr_opaq,cr_over,shade_no = do_preobj_color(object,prescript)
+ local tr_opaq = do_preobj_TR(prescript)
+ local cr_over = do_preobj_CR(object,prescript)
+ local shade_no = do_preobj_SH(object,prescript)
if prescript and prescript.mplibtexboxid then
put_tex_boxes(object,prescript)
elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip
@@ -2208,7 +2480,7 @@
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/04/04 v2.27.2 mplib package for LuaTeX]
+ [2024/04/12 v2.28.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-04-12 21:45:49 UTC (rev 70929)
+++ trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua 2024-04-12 21:45:57 UTC (rev 70930)
@@ -11,8 +11,8 @@
luatexbase.provides_module {
name = "luamplib",
- version = "2.27.2",
- date = "2024/04/04",
+ version = "2.28.0",
+ date = "2024/04/12",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -66,6 +66,7 @@
end
local is_defined = token.is_defined
+local get_macro = token.get_macro
local mplib = require ('mplib')
local kpse = require ('kpse')
@@ -466,7 +467,7 @@
local ccexplat = luatexbase.registernumber"luamplibcctabexplat"
-local function process_color (str)
+local function process_color (str, filldraw)
if str then
if not str:find("%b{}") then
str = format("{%s}",str)
@@ -478,7 +479,7 @@
else
for _,v in ipairs(str:match"{(.+)}":explode"!") do
if not v:find("^%s*%d+%s*$") then
- local pp = token.get_macro(format("l__color_named_%s_prop",v))
+ local pp = get_macro(format("l__color_named_%s_prop",v))
if not pp or pp == "" then
myfmt = mplibcolorfmt.xcolor
break
@@ -487,13 +488,53 @@
end
end
end
+ if filldraw and filldraw ~= "shade" and myfmt == mplibcolorfmt.l3color then
+ return str
+ end
run_tex_code(myfmt:format(str), ccexplat or catat11)
local t = texgettoks"mplibtmptoks"
+ if filldraw then return t end
return format('1 withprescript "MPlibOverrideColor=%s"', t)
end
return ""
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 tt, t = res:explode(), { }
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ table.insert(t, tt[i])
+ end
+ 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.shadecolor = function (str)
+ local res = process_color(str, "shade")
+ if res:find" cs" 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 value = res:explode()[3]
+ return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,str,name)
+ end
+ local tt, t = res:explode(), { }
+ local be = tt[1]:find"^%d" and 1 or 2
+ for i=be, #tt do
+ if tt[i]:find"^%a" then break end
+ table.insert(t, tt[i])
+ end
+ return t
+end
+
local function process_dimen (str)
if str then
str = str:gsub("{(.+)}","%1")
@@ -592,13 +633,13 @@
function mp.print(...)
mpprint(buffer,...)
end
- f()
+ local res = {f()}
buffer = tableconcat(buffer)
if buffer and buffer ~= "" then
return buffer
end
buffer = {}
- mpprint(buffer, f())
+ mpprint(buffer, table.unpack(res))
return tableconcat(buffer)
end
return ""
@@ -658,15 +699,20 @@
(1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
fi
enddef;
- def graphictext primary filename =
- if (readfrom filename = EOF):
- errmessage "Please prepare '"&filename&"' in advance with"&
- " 'pstoedit -ssp -dt -f mpost yourfile.ps "&filename&"'";
+ 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
- closefrom filename;
- def data_mpy_file = filename enddef;
- mfun_do_graphic_text (filename)
enddef;
+ def resolvedcolor(expr s) =
+ runscript("return luamplib.shadecolor('"& s &"')")
+ enddef;
else:
vardef textext@# (text t) = rawtextext (t) enddef;
fi
@@ -674,6 +720,57 @@
draw rawtextext("\includegraphics{"& filename &"}")
enddef;
def TEX = textext enddef;
+def mplibgraphictext primary t =
+ begingroup;
+ mplibgraphictext_ (t)
+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";
+ 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;
+ let withfillcolor = fillcolor; let withdrawcolor = drawcolor;
+ addto tpic doublepath origin rest; tpic:=nullpicture;
+ def fakebold primary c = enddef;
+ def scale primary c = enddef;
+ def fillcolor primary c = enddef;
+ def drawcolor primary c = enddef;
+ 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;)
+ 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
+enddef;
]]
luamplib.mplibcodepreamble = mplibcodepreamble
@@ -784,13 +881,12 @@
sh_color_a = true,
sh_color_b = true,
}
-
local function script2table(s)
local t = {}
for _,i in ipairs(s:explode("\13+")) do
local k,v = i:match("(.-)=(.*)") -- v may contain = or empty.
- if k and v and k ~= "" then
- if further_split_keys[k] then
+ if k and v and k ~= "" and not t[k] then
+ if further_split_keys[k] or further_split_keys[k:sub(1,10)] then
t[k] = v:explode(":")
else
t[k] = v
@@ -826,7 +922,7 @@
text = text:gsub(".",function(c)
return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost
end)
- texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,-( 7200/ 7227)/65536*depth))
+ texsprint(format("\\mplibtextext{%s}{%f}{%s}{%s}{%f}",font,size,text,0,0))
end
local bend_tolerance = 131/65536
@@ -956,17 +1052,14 @@
end
local pdfmanagement = is_defined'pdfmanagement_add:nnn'
-
local pdf_objs = {}
-local getpageres, setpageres
-local pgf = { extgs = "pgf at sys@addpdfresource at extgs@plain" }
+pdf_objs.pgfextgs = "pgf at sys@addpdfresource at extgs@plain"
if pdfmode then
- getpageres = pdf.getpageresources or function() return pdf.pageresources end
- setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
+ pdf_objs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
+ pdf_objs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
else
- texsprint("\\special{pdf:obj @MPlibTr<<>>}",
- "\\special{pdf:obj @MPlibSh<<>>}")
+ texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
end
local function update_pdfobjs (os)
@@ -999,12 +1092,14 @@
if new then
if pdfmode then
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}{MPlibTr%s}{%s 0 R}]], on,on))
+ texsprint(ccexplat,{
+ [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}]],
+ format("{MPlibTr%s}{%s 0 R}", on, on),
+ })
else
local tr = format("/MPlibTr%s %s 0 R",on,on)
- if pgf.loaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pgf.extgs,tr))
+ if pdf_objs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdf_objs.pgfextgs,tr))
elseif is_defined"TRP at list" then
texsprint(catat11,{
[[\if at filesw\immediate\write\@auxout{]],
@@ -1012,7 +1107,7 @@
tr,
[[}}\fi]],
})
- if not token.get_macro"TRP at list":find(tr) then
+ if not get_macro"TRP at list":find(tr) then
texsprint(catat11,[[\global\TRP at reruntrue]])
end
else
@@ -1021,12 +1116,14 @@
end
else
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/ExtGState}{MPlibTr%s}{@mplibpdfobj%s}]], on,on))
+ 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 pgf.loaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pgf.extgs,tr))
+ if pdf_objs.pgfloaded then
+ texsprint(format("\\csname %s\\endcsname{%s}", pdf_objs.pgfextgs,tr))
else
texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
end
@@ -1037,69 +1134,100 @@
end
local function tr_pdf_pageresources(mode,opaq)
- if pgf.loaded == nil then
- pgf.loaded = is_defined(pgf.extgs)
+ if pdf_objs.pgfloaded == nil then
+ pdf_objs.pgfloaded = is_defined(pdf_objs.pgfextgs)
end
local res, on_on, off_on = "", nil, nil
res, off_on = update_tr_res(res, "Normal", 1)
res, on_on = update_tr_res(res, mode, opaq)
- if pdfmanagement or pgf.loaded or is_defined"TRP at list" then
+ if pdfmanagement or pdf_objs.pgfloaded or is_defined"TRP at list" then
return on_on, off_on
end
if pdfmode then
if res ~= "" then
- local tpr, n = getpageres() or "", 0
+ local tpr, n = pdf_objs.getpageres() or "", 0
tpr, n = tpr:gsub("/ExtGState<<", "%1"..res)
if n == 0 then
tpr = format("%s/ExtGState<<%s>>", tpr, res)
end
- setpageres(tpr)
+ pdf_objs.setpageres(tpr)
end
else
- texsprint(format("\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"))
+ texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
end
return on_on, off_on
end
-local shading_res
-
local function shading_initialize ()
- shading_res = {}
+ pdf_objs.shading_res = {}
if pdfmode and luatexbase.callbacktypes.finish_pdffile then -- ltluatex
local shading_obj = pdf.reserveobj()
- setpageres(format("%s/Shading %i 0 R",getpageres() or "",shading_obj))
+ pdf_objs.setpageres(format("%s/Shading %i 0 R",pdf_objs.getpageres() or "",shading_obj))
luatexbase.add_to_callback("finish_pdffile", function()
- pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(shading_res)))
- end, "luamplib.finish_pdffile")
- pdf_objs.finishpdf = true
+ pdf.immediateobj(shading_obj,format("<<%s>>",tableconcat(pdf_objs.shading_res)))
+ end, "luamplib.finish_pdffile")
end
end
-local function sh_pdfpageresources(shtype,domain,colorspace,colora,colorb,coordinates)
- if not pdfmanagement and not shading_res then shading_initialize() end
- local os = format("<</FunctionType 2/Domain [ %s ]/C0 [ %s ]/C1 [ %s ]/N 1>>",
- domain, colora, colorb)
- local funcobj = pdfmode and format("%s 0 R",update_pdfobjs(os))
- or format("@mplibpdfobj%s",update_pdfobjs(os))
- os = format("<</ShadingType %i/ColorSpace /%s/Function %s/Coords [ %s ]/Extend [ true true ]/AntiAlias true>>",
- shtype, colorspace, funcobj, coordinates)
- local on, new = update_pdfobjs(os)
+local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions)
+ if not pdfmanagement and not pdf_objs.shading_res then
+ shading_initialize()
+ end
+ local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>"
+ if steps > 1 then
+ local list,bounds,encode = { },{ },{ }
+ for i=1,steps do
+ if i < steps then
+ bounds[i] = fractions[i] or 1
+ end
+ encode[2*i-1] = 0
+ encode[2*i] = 1
+ os = fun2fmt:format(domain,tableconcat(ca[i],' '),tableconcat(cb[i],' '))
+ list[i] = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ end
+ os = tableconcat {
+ "<</FunctionType 3",
+ format("/Bounds [%s]", tableconcat(bounds,' ')),
+ format("/Encode [%s]", tableconcat(encode,' ')),
+ format("/Functions [%s]", tableconcat(list, ' ')),
+ format("/Domain [%s]>>", domain),
+ }
+ else
+ os = fun2fmt:format(domain,tableconcat(ca[1],' '),tableconcat(cb[1],' '))
+ end
+ local objref = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ os = tableconcat {
+ format("<</ShadingType %i", shtype),
+ format("/ColorSpace %s", colorspace),
+ format("/Function %s", objref),
+ format("/Coords [%s]", coordinates),
+ "/Extend [true true]/AntiAlias true>>",
+ }
+ local on, new
+ if colorspace == [[\pdffeedback lastobj 0 R]] then
+ on, new = pdf.reserveobj(), true
+ texsprint(format([[\immediate\pdfextension obj useobjnum %s{%s}]],on,os))
+ else
+ on, new = update_pdfobjs(os)
+ end
if pdfmode then
if new then
if pdfmanagement then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}{MPlibSh%s}{%s 0 R}]], on,on))
+ 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 pdf_objs.finishpdf then
- shading_res[#shading_res+1] = res
+ if luatexbase.callbacktypes.finish_pdffile then
+ pdf_objs.shading_res[#pdf_objs.shading_res+1] = res
else
- local pageres = getpageres() or ""
+ local pageres = pdf_objs.getpageres() or ""
if not pageres:find("/Shading<<.*>>") then
pageres = pageres.."/Shading<<>>"
end
pageres = pageres:gsub("/Shading<<","%1"..res)
- setpageres(pageres)
+ pdf_objs.setpageres(pageres)
end
end
end
@@ -1106,14 +1234,19 @@
else
if pdfmanagement then
if new then
- texsprint(ccexplat,format(
- [[\pdfmanagement_add:nnn{Page/Resources/Shading}{MPlibSh%s}{@mplibpdfobj%s}]], on,on))
+ texsprint(ccexplat,{
+ [[\pdfmanagement_add:nnn{Page/Resources/Shading}]],
+ format("{MPlibSh%s}{@mplibpdfobj%s}", on, on),
+ })
end
else
if new then
- texsprint(format("\\special{pdf:put @MPlibSh<</MPlibSh%s @mplibpdfobj%s>>}",on,on))
+ texsprint{
+ "\\special{pdf:put @MPlibSh",
+ format("<</MPlibSh%s @mplibpdfobj%s>>}",on, on),
+ }
end
- texsprint(format("\\special{pdf:put @resources<</Shading @MPlibSh>>}"))
+ texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}"
end
end
return on
@@ -1131,9 +1264,7 @@
end
end
-local prev_override_color
-
-local function do_preobj_color(object,prescript)
+local function do_preobj_TR(prescript)
local opaq = prescript and prescript.tr_transparency
local tron_no, troff_no
if opaq then
@@ -1142,6 +1273,11 @@
tron_no, troff_no = tr_pdf_pageresources(mode,opaq)
pdf_literalcode("/MPlibTr%i gs",tron_no)
end
+ return troff_no
+end
+
+local prev_override_color
+local function do_preobj_CR(object,prescript)
local override = prescript and prescript.MPlibOverrideColor
if override then
if pdfmode then
@@ -1171,52 +1307,114 @@
end
end
end
+ return override
+end
+
+local function do_preobj_SH(object,prescript)
+ local shade_no
local sh_type = prescript and prescript.sh_type
if sh_type then
- local domain = prescript.sh_domain
- local centera = prescript.sh_center_a:explode()
- local centerb = prescript.sh_center_b:explode()
- for _,t in pairs({centera,centerb}) do
- for i,v in ipairs(t) do
- t[i] = format("%f",v)
+ local domain = prescript.sh_domain or "0 1"
+ local centera = prescript.sh_center_a or "0 0"; centera = centera:explode()
+ local centerb = prescript.sh_center_b or "0 0"; centerb = centerb:explode()
+ local transform = prescript.sh_transform == "yes"
+ local sx,sy,sr,dx,dy = 1,1,1,0,0
+ if transform then
+ local first = prescript.sh_first or "0 0"; first = first:explode()
+ local setx = prescript.sh_set_x or "0 0"; setx = setx:explode()
+ local sety = prescript.sh_set_y or "0 0"; sety = sety:explode()
+ local x,y = tonumber(setx[1]) or 0, tonumber(sety[1]) or 0
+ if x ~= 0 and y ~= 0 then
+ local path = object.path
+ local path1x = path[1].x_coord
+ local path1y = path[1].y_coord
+ local path2x = path[x].x_coord
+ local path2y = path[y].y_coord
+ local dxa = path2x - path1x
+ local dya = path2y - path1y
+ local dxb = setx[2] - first[1]
+ local dyb = sety[2] - first[2]
+ if dxa ~= 0 and dya ~= 0 and dxb ~= 0 and dyb ~= 0 then
+ sx = dxa / dxb ; if sx < 0 then sx = - sx end
+ sy = dya / dyb ; if sy < 0 then sy = - sy end
+ sr = math.sqrt(sx^2 + sy^2)
+ dx = path1x - sx*first[1]
+ dy = path1y - sy*first[2]
+ end
end
end
- centera = tableconcat(centera," ")
- centerb = tableconcat(centerb," ")
- local colora = prescript.sh_color_a or {0};
- local colorb = prescript.sh_color_b or {1};
- for _,t in pairs({colora,colorb}) do
- for i,v in ipairs(t) do
- t[i] = format("%.3f",v)
+ local model, ca, cb, colorspace, steps, fractions = 0
+ ca = { prescript.sh_color_a_1 or prescript.sh_color_a or {0} }
+ cb = { prescript.sh_color_b_1 or prescript.sh_color_b or {1} }
+ steps = tonumber(prescript.sh_step) or 1
+ if steps > 1 then
+ fractions = { prescript.sh_fraction_1 or 0 }
+ for i=2,steps do
+ fractions[i] = prescript[format("sh_fraction_%i",i)] or (i/steps)
+ ca[i] = prescript[format("sh_color_a_%i",i)] or {0}
+ cb[i] = prescript[format("sh_color_b_%i",i)] or {1}
end
end
- if #colora > #colorb then
- color_normalize(colora,colorb)
- elseif #colorb > #colora then
- color_normalize(colorb,colora)
+ if prescript.mplib_spotcolor then
+ local names, last = { }, ""
+ local script = object.prescript:explode"\13+"
+ for i=#script,1,-1 do
+ if script[i]:find"mplib_spotcolor" then
+ local str, name = script[i]:match"mplib_spotcolor=(.-):(.+)"
+ if str ~= last then
+ names[#names+1] = name
+ end
+ last = str
+ end
+ end
+ texsprint(ccexplat,{
+ [[\color_model_new:nnn{]], tableconcat(names),
+ [[}{DeviceN}{names={]], tableconcat(names,","), [[}}]]
+ })
+ colorspace = [[\pdffeedback lastobj 0 R]]
+ for n,t in ipairs{ca,cb} do
+ for i=1,#t do
+ for j=1, i+n-2 do table.insert(t[i], j, 0) end
+ for j=i+n, #t+1 do table.insert(t[i], j, 0) end
+ end
+ end
+ else
+ for _,t in ipairs{ca,cb} do
+ for _,tt in ipairs(t) do
+ model = model > #tt and model or #tt
+ end
+ end
+ for _,t in ipairs{ca,cb} do
+ for _,tt in ipairs(t) do
+ if #tt < model then
+ color_normalize(model == 4 and {1,1,1,1} or {1,1,1},tt)
+ end
+ end
+ end
+ colorspace = model == 4 and "/DeviceCMYK"
+ or model == 3 and "/DeviceRGB"
+ or model == 1 and "/DeviceGray"
+ or err"unknown color model"
end
- local colorspace
- if #colorb == 1 then colorspace = "DeviceGray"
- elseif #colorb == 3 then colorspace = "DeviceRGB"
- elseif #colorb == 4 then colorspace = "DeviceCMYK"
- else return troff_no,override
- end
- colora = tableconcat(colora, " ")
- colorb = tableconcat(colorb, " ")
- local shade_no
if sh_type == "linear" then
- local coordinates = tableconcat({centera,centerb}," ")
- shade_no = sh_pdfpageresources(2,domain,colorspace,colora,colorb,coordinates)
+ local coordinates = format("%f %f %f %f",
+ dx + sx*centera[1], dy + sy*centera[2],
+ dx + sx*centerb[1], dy + sy*centerb[2])
+ shade_no = sh_pdfpageresources(2,domain,colorspace,ca,cb,coordinates,steps,fractions)
elseif sh_type == "circular" then
- local radiusa = format("%f",prescript.sh_radius_a)
- local radiusb = format("%f",prescript.sh_radius_b)
- local coordinates = tableconcat({centera,radiusa,centerb,radiusb}," ")
- shade_no = sh_pdfpageresources(3,domain,colorspace,colora,colorb,coordinates)
+ local factor = prescript.sh_factor or 1
+ local radiusa = factor * prescript.sh_radius_a
+ local radiusb = factor * prescript.sh_radius_b
+ local coordinates = format("%f %f %f %f %f %f",
+ dx + sx*centera[1], dy + sy*centera[2], sr*radiusa,
+ dx + sx*centerb[1], dy + sy*centerb[2], sr*radiusb)
+ shade_no = sh_pdfpageresources(3,domain,colorspace,ca,cb,coordinates,steps,fractions)
+ else
+ err"unknown shading type"
end
pdf_literalcode("q /Pattern cs")
- return troff_no,override,shade_no
end
- return troff_no,override
+ return shade_no
end
local function do_postobj_color(tr,over,sh)
@@ -1259,7 +1457,9 @@
local objecttype = object.type
local prescript = object.prescript
prescript = prescript and script2table(prescript) -- prescript is now a table
- local tr_opaq,cr_over,shade_no = do_preobj_color(object,prescript)
+ local tr_opaq = do_preobj_TR(prescript)
+ local cr_over = do_preobj_CR(object,prescript)
+ local shade_no = do_preobj_SH(object,prescript)
if prescript and prescript.mplibtexboxid then
put_tex_boxes(object,prescript)
elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip
Modified: trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty 2024-04-12 21:45:49 UTC (rev 70929)
+++ trunk/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty 2024-04-12 21:45:57 UTC (rev 70930)
@@ -14,7 +14,7 @@
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/04/04 v2.27.2 mplib package for LuaTeX]
+ [2024/04/12 v2.28.0 mplib package for LuaTeX]
\ifx\newluafunction\@undefined
\input ltluatex
\fi
More information about the tex-live-commits
mailing list.