diff options
Diffstat (limited to 'Master/texmf-dist/source/luatex/luamplib/luamplib.dtx')
-rw-r--r-- | Master/texmf-dist/source/luatex/luamplib/luamplib.dtx | 542 |
1 files changed, 399 insertions, 143 deletions
diff --git a/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx b/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx index edae80ada69..f40d1add132 100644 --- a/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx +++ b/Master/texmf-dist/source/luatex/luamplib/luamplib.dtx @@ -85,7 +85,7 @@ See source file '\inFileName' for licencing and contact information. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{luamplib.drv}% - [2024/06/14 v2.32.2 Interface for using the mplib library]% + [2024/07/08 v2.33.0 Interface for using the mplib library]% \documentclass{ltxdoc} \usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -153,7 +153,7 @@ See source file '\inFileName' for licencing and contact information. % \author{Hans Hagen, Taco Hoekwater, Elie Roux, Philipp Gesang and Kim Dohyun\\ % Maintainer: LuaLaTeX Maintainers --- % Support: \email{lualatex-dev@tug.org}} -% \date{2024/06/14 v2.32.2} +% \date{2024/07/08 v2.33.0} % % \maketitle % @@ -431,7 +431,7 @@ See source file '\inFileName' for licencing and contact information. % |\mplibshowlog{disable}| will revert this functionality. % This is a \TeX{} side interface for |luamplib.showlog|. (v2.20.8) % -% \paragraph{Settings regarding cache files} +% \paragraph{About cache files} % To support |btex ... etex| in external |.mp| files, \textsf{luamplib} % inspects the content of each and every |.mp| input files and makes caches % if nececcsary, before returning their paths to \LuaTeX's mplib library. @@ -562,7 +562,8 @@ See source file '\inFileName' for licencing and contact information. % \endmppattern % or \end{mppattern} % % \mpfig -% fill fullcircle scaled 100 withpostscript "collect"; +% fill fullcircle scaled 100 +% withpostscript "collect" ; % draw unitsquare shifted - center unitsquare scaled 45 % withpattern "mypatt" % withpostscript "evenodd" ; @@ -576,10 +577,10 @@ See source file '\inFileName' for licencing and contact information. % |ystep| &\textit{number} & vertical spacing between pattern cells\\ % |xshift| &\textit{number} & horizontal shifting of pattern cells\\ % |yshift| &\textit{number} & vertical shifting of pattern cells\\ -% |matrix| &\textit{table} or \textit{string} & |xx|, |yx|, |xy|, |yy| values\kern1pt* or MP transformation code\\ +% |matrix| &\textit{table} or \textit{string} & |xx|, |yx|, |xy|, |yy| values\kern1pt* or MP transform code\\ % |bbox| &\textit{table} or \textit{string} & |llx|, |lly|, |urx|, |ury| values\kern1pt*\\ % |resources|&\textit{string} & PDF resources if needed\\ -% |colored| &\textit{boolean}& |false| for uncolored pattern. default: |true|\\\hline +% |colored| or |coloured| &\textit{boolean}& |false| for uncolored pattern. default: |true|\\\hline % & & \small *\,in string type, numbers are separated by spaces\\ % \end{tabular} % \end{center} @@ -597,39 +598,111 @@ See source file '\inFileName' for licencing and contact information. % However, as luamplib automatically includes the resources of the current page, this option % is not needed in most cases. % -% Option |colored=false| will generate an uncolored pattern which shall have no color at all. +% Option |colored=false| (|coloured| is a synonym of |colored|) will generate an uncolored pattern which shall have no color at all. % Uncolored pattern will be painted later by the color of a metapost object. % An example: % \begin{verbatim} % \begin{mppattern}{pattuncolored} % [ % colored = false, -% matrix = "rotated 30", +% matrix = "slanted .3 rotated 30", % ] % \tiny\TeX % \end{mppattern} % % \begin{mplibcode} % beginfig(1) -% picture tex; tex := mpliboutlinetext.p ("\bfseries \TeX"); -% i:=0; -% for item within tex: -% i:=i+1; -% if i < length tex: -% fill pathpart item scaled 10 -% withpostscript "collect"; -% else: +% picture tex; +% tex = mpliboutlinetext.p ("\bfseries \TeX"); +% for i=1 upto mpliboutlinenum: +% j:=0; +% for item within mpliboutlinepic[i]: +% j:=j+1; % draw pathpart item scaled 10 -% withpattern "pattuncolored" -% withpen pencircle scaled 0.5 -% withcolor 0.7 blue % paints the pattern -% ; -% fi +% if j < length mpliboutlinepic[i]: +% withpostscript "collect" +% else: +% withpattern "pattuncolored" +% withpen pencircle scaled 1/2 +% withcolor (i/4)[red,blue] % paints the pattern +% fi; +% endfor % endfor % endfig; % \end{mplibcode} % \end{verbatim} % +% \paragraph{\texttt{withfademethod} and related macros} +% |withfademethod| is a metapost operator which makes the color of an object gradiently transparent. +% The syntax is \textit{<path>}\texttt{\char"7C}\textit{<picture>} |withfademethod| \textit{<string>}, +% the latter being either |"linear"| or |"circular"|. +% Though it is similar to the |withshademethod| provided by metafun, +% the differences are: (1) the operand of |withfademethod| can be a picture as well as a path; +% (2) you cannot make gradient colors, but can only make gradient opacity. +% +% Related macros to control optional values are: +% \begin{description} +% \item [|withfadeopacity (|\textit{\mdseries number, number}|)|] +% sets the starting opacity and the ending opacity, default value being |(1,0)|. +% `|1|' denotes full color; `|0|' full transparency. +% \item [|withfadevector (|\textit{\mdseries pair, pair}|)|] +% sets the starting and ending points. Default value in the linear mode is +% |(llcorner p, lrcorner p)|, where |p| is the operand, +% meaning that fading starts from the left edge and ends at the right edge. +% Default value in the circular mode is |(center p, center p)|, which means +% centers of both starting and ending circles are the center of the bounding box. +% \item [|withfadecenter|] is a synonym of |withfadevector|. +% \item [|withfaderadius (|\textit{\mdseries number, number}|)|] +% sets the radii of starting and ending circles. This is no-op in the linear mode. +% Default value is |(0, abs(center p - urcorner p))|, meaning that fading starts from the +% center and ends at the four corners of the bounding box. +% \item [|withfadebbox (|\textit{\mdseries pair, pair}|)|] +% sets the bounding box of the fading area, default value being |(llcorner p, urcorner p)|. +% Though this option is not needed in most cases, there could be cases when users want to +% explicitly control the bounding box. +% \end{description} +% An example: +% \begin{verbatim} +% \mpfig +% picture mill; +% mill = btex \includegraphics[width=100bp]{mill} etex; +% draw mill +% withfademethod "circular" +% withfadecenter (center mill, center mill) +% withfaderadius (20, 50) +% withfadeopacity (1, 0) +% ; +% \endmpfig +% \end{verbatim} +% +% \paragraph{Lua table \texttt{luamplib.instances}} +% Users can access the Lua table containing mplib instances, |luamplib.instances|, +% through which metapost variables are also easily accessible +% as documented in Lua\TeX{} manual \textsection\,11.2.8.4 (|texdoc luatex|). +% The following will print |false|, |3.0|, |MetaPost| and +% the points and the cyclicity of the path |unitsquare|, consecutively. +% \begin{verbatim} +% \begin{mplibcode}[instance1] +% boolean b; b = 1 > 2; +% numeric n; n = 3; +% string s; s = "MetaPost"; +% path p; p = unitsquare; +% \end{mplibcode} +% +% \directlua{ +% local instance1 = luamplib.instances.instance1 +% print( instance1:get_boolean"b" ) +% print( instance1:get_number"n" ) +% print( instance1:get_string"s" ) +% local t = instance1:get_path"p" +% for k,v in pairs(t) do +% print(k, type(v)=='table' and table.concat(v,' ') or v) +% end +% } +% \end{verbatim} +% In this way, it would not be difficult to define a paragraph shape +% (using \cs{parshape} \TeX\ primitive) which follows an arbitrary metapost path. +% % \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. @@ -662,8 +735,8 @@ See source file '\inFileName' for licencing and contact information. luatexbase.provides_module { name = "luamplib", - version = "2.32.2", - date = "2024/06/14", + version = "2.33.0", + date = "2024/07/08", description = "Lua package to typeset Metapost with LuaTeX's MPLib.", } @@ -725,6 +798,7 @@ luamplib.showlog = luamplib.showlog or false % \begin{macrocode} local tableconcat = table.concat local tableinsert = table.insert +local tableunpack = table.unpack local texsprint = tex.sprint local texgettoks = tex.gettoks local texgetbox = tex.getbox @@ -1004,6 +1078,7 @@ end % \begin{macrocode} luamplib.codeinherit = false local mplibinstances = {} +luamplib.instances = mplibinstances local has_instancename = false local function reporterror (result, prevlog) @@ -1047,6 +1122,12 @@ local function reporterror (result, prevlog) end end +% \end{macrocode} +% +% |lualibs-os.lua| installs a randomseed. When this file is not loaded, +% we should explicitly seed a unique interger to get random randomseed for each run. +% \begin{macrocode} +if not math.initialseed then math.randomseed(currenttime) end local function luamplibload (name) local mpx = mplib.new { ini_version = true, @@ -1200,8 +1281,7 @@ local function process_tex_text (str) else local boxid = texboxes.globalid + 1 texboxes.globalid = boxid - run_tex_code(format( - [[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid)) + run_tex_code(format([[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid)) tex_box_id = tex.getcount'allocationnumber' end run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str)) @@ -1408,7 +1488,7 @@ function luamplib.runscript (code) return buffer end buffer = {} - mpprint(buffer, table.unpack(res)) + mpprint(buffer, tableunpack(res)) return tableconcat(buffer) end return "" @@ -1542,27 +1622,48 @@ luamplib.shadecolor = function (str) % \end{mplibcode} % \end{document} % \end{verbatim} +% another one: user-defined DeviceN colorspace +% \begin{verbatim} +% \DocumentMetadata{ } +% \documentclass{article} +% \usepackage{luamplib} +% \mplibsetformat{metafun} +% \ExplSyntaxOn +% \color_model_new:nnn { pantone1215 } +% { Separation } +% { name = PANTONE~1215~U , +% alternative-model = cmyk , +% alternative-values = {0, 0.15, 0.51, 0} +% } +% \color_model_new:nnn { pantone+black } +% { DeviceN } +% { +% names = {pantone1215,black} +% } +% \color_set:nnn{purepantone}{pantone+black}{1,0} +% \color_set:nnn{pureblack} {pantone+black}{0,1} +% \ExplSyntaxOff +% \begin{document} +% \mpfig +% fill unitsquare xscaled \mpdim{\textwidth} yscaled 30 +% withshademethod "linear" +% withshadecolors ("purepantone","pureblack") +% ; +% \endmpfig +% \end{document} +% \end{verbatim} % \begin{macrocode} run_tex_code({ [[\color_export:nnN{]], str, [[}{backend}\mplib_@tempa]], },ccexplat) - local name = get_macro'mplib_@tempa':match'{(.-)}{.+}' + local name, value = get_macro'mplib_@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_@tempa{\pdf_object_ref:n{]], obj, "}}", - },ccexplat) - obj = get_macro'mplib_@tempa' - end + obj = format("%s 0 R", ltx.pdf.object_id( t[1]:sub(2,-1) )) else obj = t[2] end - local value = t[3]:match"%[(.-)%]" or t[3] - return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name) + return format('(1) withprescript"mplib_spotcolor=%s:%s:%s"', value,obj,name) end return colorsplit(res) end @@ -1868,7 +1969,7 @@ function luamplib.glyph (f, c) 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 "image(fill fullcircle scaled 0;)" end + if not t then return "image()" end for i,v in ipairs(t) do if type(v) == "table" then for ii,vv in ipairs(v) do @@ -2122,7 +2223,7 @@ function luamplib.outlinetext (text) local id = tonumber(fmt:match"mplibtexboxid=(%d+):") local box = texgetbox(id) local res = outline_horz({ }, box, box.head, 0, 0) - if #res == 0 then res = { "mpliboutlinepic[1]:=image(fill fullcircle scaled 0;);" } end + if #res == 0 then res = { "mpliboutlinepic[1]:=image();" } end return tableconcat(res) .. format("mpliboutlinenum:=%i;", #res) end @@ -2327,6 +2428,39 @@ vardef mplibtransformmatrix (text e) = & decimal ypart t & "," & "}"); enddef; +primarydef p withfademethod s = + p withprescript "mplibfadetype=" & s + withprescript "mplibfadebbox=" & + decimal xpart llcorner p & ":" & + decimal ypart llcorner p & ":" & + decimal xpart urcorner p & ":" & + decimal ypart urcorner p +enddef; +def withfadeopacity (expr a,b) = + withprescript "mplibfadeopacity=" & + decimal a & ":" & + decimal b +enddef; +def withfadevector (expr a,b) = + withprescript "mplibfadevector=" & + decimal xpart a & ":" & + decimal ypart a & ":" & + decimal xpart b & ":" & + decimal ypart b +enddef; +let withfadecenter = withfadevector; +def withfaderadius (expr a,b) = + withprescript "mplibfaderadius=" & + decimal a & ":" & + decimal b +enddef; +def withfadebbox (expr a,b) = + withprescript "mplibfadebbox=" & + decimal xpart a & ":" & + decimal ypart a & ":" & + decimal xpart b & ":" & + decimal ypart b +enddef; ]], legacyverbatimtex = [[ def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef; @@ -2680,31 +2814,42 @@ pdfetcs.pgfextgs = "pgf@sys@addpdfresource@extgs@plain" pdfetcs.pgfpattern = "pgf@sys@addpdfresource@patterns@plain" pdfetcs.pgfcolorspace = "pgf@sys@addpdfresource@colorspaces@plain" -local function update_pdfobjs (os) - local on = pdfobjs[os] +local function update_pdfobjs (os, stream) + local key = os + if stream then key = key..stream end + local on = pdfobjs[key] if on then return on,false end if pdfmode then - on = pdf.immediateobj(os) + if stream then + on = pdf.immediateobj("stream",stream,os) + else + on = pdf.immediateobj(os) + end else on = pdfetcs.cnt or 1 - texsprint(format("\\special{pdf:obj @mplibpdfobj%s %s}",on,os)) + if stream then + texsprint(format("\\special{pdf:stream @mplibpdfobj%s (%s) <<%s>>}",on,stream,os)) + else + texsprint(format("\\special{pdf:obj @mplibpdfobj%s %s}",on,os)) + end pdfetcs.cnt = on + 1 end - pdfobjs[os] = on + pdfobjs[key] = on 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 getpageres = pdfetcs.getpageres + local setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end + local 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)) + setpageres(format("%s/%s %i 0 R", getpageres() or "", name, obj)) luatexbase.add_to_callback("finish_pdffile", function() pdf.immediateobj(obj, format("<<%s>>", tableconcat(pdfetcs[tabname]))) end, @@ -2712,21 +2857,29 @@ if pdfmode then end end pdfetcs.fallback_update_resources = function (name, res) + local tabname = format("%s_res",name) + if not pdfetcs[tabname] then + initialize_resources(name) + end if luatexbase.callbacktypes.finish_pdffile then - local t = pdfetcs[format("%s_res",name)] + local t = pdfetcs[tabname] t[#t+1] = res else - local tpr, n = pdfetcs.getpageres() or "", 0 + local tpr, n = 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) + setpageres(tpr) end end else - texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}", - "\\special{pdf:obj @MPlibCS<<>>}","\\special{pdf:obj @MPlibPt<<>>}") + texsprint { + "\\special{pdf:obj @MPlibTr<<>>}", + "\\special{pdf:obj @MPlibSh<<>>}", + "\\special{pdf:obj @MPlibCS<<>>}", + "\\special{pdf:obj @MPlibPt<<>>}", + } end % \end{macrocode} @@ -2740,57 +2893,56 @@ local transparancy_modes = { [0] = "Normal", "Hue", "Saturation", "Color", "Luminosity", "Compatible", } - -local function update_tr_res(mode,opaq) - local os = format("<</BM /%s/ca %.3f/CA %.3f/AIS false>>",mode,opaq,opaq) - local on, new = update_pdfobjs(os) - if not new then return on end +local function add_extgs_resources (on, new) 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 is_defined(pdfetcs.pgfextgs) then - texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr)) - elseif pdfmode then - if is_defined"TRP@list" then - texsprint(catat11,{ - [[\if@filesw\immediate\write\@auxout{]], - [[\string\g@addto@macro\string\TRP@list{]], - tr, - [[}}\fi]], - }) - if not get_macro"TRP@list":find(tr) then - texsprint(catat11,[[\global\TRP@reruntrue]]) + if new then + local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on) + if pdfmanagement then + texsprint { + "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/ExtGState}{", key, "}{", val, "}" + } + else + local tr = format("/%s %s", key, val) + if is_defined(pdfetcs.pgfextgs) then + texsprint { "\\csname ", pdfetcs.pgfextgs, "\\endcsname{", tr, "}" } + elseif pdfmode then + if is_defined"TRP@list" then + texsprint(catat11,{ + [[\if@filesw\immediate\write\@auxout{]], + [[\string\g@addto@macro\string\TRP@list{]], + tr, + [[}}\fi]], + }) + if not get_macro"TRP@list":find(tr) then + texsprint(catat11,[[\global\TRP@reruntrue]]) + end + else + pdfetcs.fallback_update_resources("ExtGState", tr) end else - if not pdfetcs.ExtGState_res then - pdfetcs.initialize_resources"ExtGState" - end - pdfetcs.fallback_update_resources("ExtGState", tr) + texsprint { "\\special{pdf:put @MPlibTr<<", tr, ">>}" } end - else - texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr)) - texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}" end end - return on + if not pdfmode and not pdfmanagement and not is_defined(pdfetcs.pgfextgs) then + texsprint"\\special{pdf:put @resources <</ExtGState @MPlibTr>>}" + end + return key end - local function do_preobj_TR(object,prescript) if object.postscript == "collect" then return end local opaq = prescript and prescript.tr_transparency - local tron_no + local on if opaq then local mode = prescript.tr_alternative or 1 mode = transparancy_modes[tonumber(mode)] - tron_no = update_tr_res(mode, opaq) + local os, new = format("<</BM /%s/ca %.3f/CA %.3f/AIS false>>",mode,opaq,opaq) + on, new = update_pdfobjs(os) + local key = add_extgs_resources(on,new) start_pdf_code() - pdf_literalcode("/MPlibTr%i gs",tron_no) + pdf_literalcode("/%s gs",key) end - return tron_no + return on end % \end{macrocode} @@ -2829,24 +2981,25 @@ local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,st "/Extend [true true]/AntiAlias true>>", } local on, new = update_pdfobjs(os) - 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 - local res = format("/%s %s", key, val) - if pdfmode then - if not pdfetcs.Shading_res then - pdfetcs.initialize_resources"Shading" - end - pdfetcs.fallback_update_resources("Shading", res) + if new then + local key = format("MPlibSh%s", on) + local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on) + if pdfmanagement then + texsprint { + "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/Shading}{", key, "}{", val, "}" + } else - texsprint(format("\\special{pdf:put @MPlibSh<<%s>>}", res)) - texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}" + local res = format("/%s %s", key, val) + if pdfmode then + pdfetcs.fallback_update_resources("Shading", res) + else + texsprint { "\\special{pdf:put @MPlibSh<<", res, ">>}" } + end end end + if not pdfmode and not pdfmanagement then + texsprint"\\special{pdf:put @resources <</Shading @MPlibSh>>}" + end return on end @@ -2927,15 +3080,14 @@ local function do_preobj_SH(object,prescript) local script = object.prescript:explode"\13+" for i=#script,1,-1 do if script[i]:find"mplib_spotcolor" then - local name, value - objref, name = script[i]:match"=(.-):(.+)" - value = script[i+1]:match"=(.+)" + local t, name, value = script[i]:explode"="[2]:explode":" + value, objref, name = t[1], t[2], t[3] if not names[name] then pos = pos+1 names[name] = pos names[#names+1] = name end - local t = { } + t = { } for j=1,names[name] do t[#t+1] = 0 end t[#t+1] = value tableinsert(#ca == #cb and ca or cb, t) @@ -2995,7 +3147,8 @@ end % % Patterns % \begin{macrocode} -patterns = { } +pdfetcs.patterns = { } +local patterns = pdfetcs.patterns function luamplib.registerpattern ( boxid, name, opts ) local box = texgetbox(boxid) local wd = format("%.3f",box.width/factor) @@ -3003,7 +3156,12 @@ function luamplib.registerpattern ( boxid, name, opts ) info("w/h/d of '%s': %s %s 0.0", name, wd, hd) if opts.xstep == 0 then opts.xstep = nil end if opts.ystep == 0 then opts.ystep = nil end - if opts.colored == nil then opts.colored = true end + if opts.colored == nil then + opts.colored = opts.coloured + if opts.colored == nil then + opts.colored = true + end + end if type(opts.matrix) == "table" then opts.matrix = tableconcat(opts.matrix," ") end if type(opts.bbox) == "table" then opts.bbox = tableconcat(opts.bbox," ") end if opts.matrix and opts.matrix:find"%a" then @@ -3029,7 +3187,7 @@ function luamplib.registerpattern ( boxid, name, opts ) for _,v in ipairs{"ExtGState","ColorSpace","Shading"} do local pp = get_macro(format("g__pdfdict_/g__pdf_Core/Page/Resources/%s_prop",v)) if pp and pp:find"__prop_pair" then - t[#t+1] = format("/%s %s", v, ltx.__pdf.object["__pdf/Page/Resources/"..v]) + t[#t+1] = format("/%s %s 0 R", v, ltx.pdf.object_id("__pdf/Page/Resources/"..v)) end end else @@ -3055,17 +3213,24 @@ function luamplib.registerpattern ( boxid, name, opts ) local optres, t = opts.resources or "", { } if pdfmanagement then for _,v in ipairs{"ExtGState","ColorSpace","Shading"} do - run_tex_code(format( - [[\mplibtmptoks\expanded{{/%s \pdf_object_ref:n{__pdf/Page/Resources/%s}}}]],v,v),ccexplat) - t[#t+1] = texgettoks'mplibtmptoks' + local pp = get_macro(format("g__pdfdict_/g__pdf_Core/Page/Resources/%s_prop",v)) + if pp and pp:find"__prop_pair" then + run_tex_code { + "\\mplibtmptoks\\expanded{{", + format("/%s \\csname pdf_object_ref:n\\endcsname{__pdf/Page/Resources/%s}",v,v), + "}}", + } + t[#t+1] = texgettoks'mplibtmptoks' + end end elseif is_defined(pdfetcs.pgfextgs) then - run_tex_code("\\mplibtmptoks\\expanded{{\z - \\ifpgf@sys@pdf@extgs@exists /ExtGState @pgfextgs\\fi\z - \\ifpgf@sys@pdf@colorspaces@exists /ColorSpace @pgfcolorspaces\\fi}}",catat11) + run_tex_code ({ + "\\mplibtmptoks\\expanded{{", + "\\ifpgf@sys@pdf@extgs@exists /ExtGState @pgfextgs\\fi", + "\\ifpgf@sys@pdf@colorspaces@exists /ColorSpace @pgfcolorspaces\\fi", + "}}", + }, catat11) t[#t+1] = texgettoks'mplibtmptoks' - else - t[#t+1] = "/ExtGState @MPlibTr/Shading @MPlibSh/ColorSpace @MPlibCS" end optres = optres .. tableconcat(t) texsprint { @@ -3089,22 +3254,23 @@ local function pattern_colorspace (cs) local key = format("MPlibCS%i",on) local val = pdfmode and format("%i 0 R",on) or format("@mplibpdfobj%i",on) if pdfmanagement then - texsprint(ccexplat,format("\\pdfmanagement_add:nnn{Page/Resources/ColorSpace}{%s}{%s}",key,val)) + texsprint { + "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/ColorSpace}{", key, "}{", val, "}" + } else local res = format("/%s %s", key, val) if is_defined(pdfetcs.pgfcolorspace) then - texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfcolorspace, res)) + texsprint { "\\csname ", pdfetcs.pgfcolorspace, "\\endcsname{", res, "}" } elseif pdfmode then - if not pdfetcs.ColorSpace_res then - pdfetcs.initialize_resources"ColorSpace" - end pdfetcs.fallback_update_resources("ColorSpace", res) else - texsprint(format("\\special{pdf:put @MPlibCS<<%s>>}", res)) - texsprint"\\special{pdf:put @resources<</ColorSpace @MPlibCS>>}" + texsprint { "\\special{pdf:put @MPlibCS<<", res, ">>}" } end end end + if not pdfmode and not pdfmanagement and not is_defined(pdfetcs.pgfcolorspace) then + texsprint"\\special{pdf:put @resources <</ColorSpace @MPlibCS>>}" + end return on end local function do_preobj_PAT(object, prescript) @@ -3139,29 +3305,115 @@ local function do_preobj_PAT(object, prescript) end pdf_literalcode("/MPlibCS%i cs %s /%s scn", pattern_colorspace(cs), color, key) end - if patt.done then return end - local val = pdfmode and format("%s 0 R",index) or patterns[index] - if pdfmanagement then - texsprint(ccexplat, format("\\pdfmanagement_add:nnn{Page/Resources/Pattern}{%s}{%s}",key,val)) - else - local res = format("/%s %s", key, val) - if is_defined(pdfetcs.pgfpattern) then - texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfpattern, res)) - elseif pdfmode then - if not pdfetcs.Pattern_res then - pdfetcs.initialize_resources"Pattern" - end - pdfetcs.fallback_update_resources("Pattern", res) + if not patt.done then + local val = pdfmode and format("%s 0 R",index) or patterns[index] + if pdfmanagement then + texsprint { + "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/Pattern}{", key, "}{", val, "}" + } else - texsprint(format("\\special{pdf:put @MPlibPt<<%s>>}", res)) - texsprint"\\special{pdf:put @resources<</Pattern @MPlibPt>>}" + local res = format("/%s %s", key, val) + if is_defined(pdfetcs.pgfpattern) then + texsprint { "\\csname ", pdfetcs.pgfpattern, "\\endcsname{", res, "}" } + elseif pdfmode then + pdfetcs.fallback_update_resources("Pattern", res) + else + texsprint { "\\special{pdf:put @MPlibPt<<", res, ">>}" } + end end end + if not pdfmode and not pdfmanagement and not is_defined(pdfetcs.pgfpattern) then + texsprint"\\special{pdf:put @resources <</Pattern @MPlibPt>>}" + end patt.done = true end % \end{macrocode} % +% Fading +% \begin{macrocode} +local function do_preobj_FADE (object, prescript) + if object.postscript == "collect" then return end + local fd_type = prescript and prescript.mplibfadetype + if not fd_type then return end + local dx, dy = 0, 0 + local bbox = prescript.mplibfadebbox:explode":" + if tonumber(bbox[1]) < 0 then + dx = -bbox[1] + bbox[1], bbox[3] = 0, bbox[3] + dx + end + if tonumber(bbox[2]) < 0 then + dy = -bbox[2] + bbox[2], bbox[4] = 0, bbox[4] + dy + end + local vec, coords = prescript.mplibfadevector, { } + if vec then + vec = vec:explode":" + for i=1,4 do + coords[#coords+1] = vec[i] + (i % 2 == 0 and dy or dx) + end + end + if fd_type == "linear" then + if not vec then + coords = { bbox[1], bbox[2], bbox[3], bbox[2] } -- left to right + end + coords = format("%f %f %f %f", tableunpack(coords)) + elseif fd_type == "circular" then + local width, height = bbox[3]-bbox[1], bbox[4]-bbox[2] + if not vec then + coords = { width/2, height/2, width/2, height/2 } -- center for both circle + end + local radius = prescript.mplibfaderadius or format("0:%f",math.sqrt(width^2+height^2)/2); + radius = radius:explode":" + tableinsert(coords, 3, radius[1]) + tableinsert(coords, radius[2]) + coords = format("%f %f %f %f %f %f", tableunpack(coords)) + else + err("unknown fading method '%s'", fd_type) + end + fd_type = fd_type == "linear" and 2 or 3 + bbox = format("%f %f %f %f", tableunpack(bbox)) + local opaq = (prescript.mplibfadeopacity or "1:0"):explode":" + local ca, cb = {{ opaq[1] }}, {{ opaq[2] }} + local on, os, new + on = sh_pdfpageresources(fd_type, "0 1", "/DeviceGray", ca, cb, coords, 1) + if pdfmode then + os = format("<</PatternType 2/Shading %s 0 R>>", on) + else + os = format("<</PatternType 2/Shading @mplibpdfobj%s>>", on) + end + on = update_pdfobjs(os) + local streamtext = format("q /Pattern cs/MPlibFd%s scn %s re f Q", on, bbox) + if pdfmode then + os = format("<</Pattern<</MPlibFd%s %s 0 R>>>>", on, on) + else + os = format("<</Pattern<</MPlibFd%s @mplibpdfobj%s>>>>", on, on) + end + on = update_pdfobjs(os) + local resources = "/Resources "..format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on) + on = update_pdfobjs"<</S/Transparency/CS/DeviceGray>>" + local attr = tableconcat{ + "/Subtype/Form", + format("/BBox[%s]", bbox), + format("/Matrix[1 0 0 1 %f %f]", -dx, -dy), + resources, + "/Group ", format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on), + } + on = update_pdfobjs(attr, streamtext) + os = tableconcat { + "<</SMask<</S/Luminosity/G ", + format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on), + ">>>>", + } + on, new = update_pdfobjs(os) + local key = add_extgs_resources(on,new) + start_pdf_code() + pdf_literalcode("/%s gs", key) + return on +end + +% \end{macrocode} +% % Finally, flush figures by inserting PDF literals. % \begin{macrocode} function luamplib.flush (result,flusher) @@ -3203,13 +3455,14 @@ function luamplib.flush (result,flusher) local object = objects[o] local objecttype = object.type % \end{macrocode} -% The following 6 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 cr_over = do_preobj_CR(object,prescript) -- color local tr_opaq = do_preobj_TR(object,prescript) -- opacity + local fading_ = do_preobj_FADE(object,prescript) -- fading if prescript and prescript.mplibtexboxid then put_tex_boxes(object,prescript) elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip @@ -3387,6 +3640,9 @@ function luamplib.flush (result,flusher) end end end + if fading_ then -- fading + stop_pdf_code() + end if tr_opaq then -- opacity stop_pdf_code() end @@ -3450,7 +3706,7 @@ end \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luamplib} - [2024/06/14 v2.32.2 mplib package for LuaTeX] + [2024/07/08 v2.33.0 mplib package for LuaTeX] \ifx\newluafunction\@undefined \input ltluatex \fi |