diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mlib-pps.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mlib-pps.lua | 829 |
1 files changed, 422 insertions, 407 deletions
diff --git a/Master/texmf-dist/tex/context/base/mlib-pps.lua b/Master/texmf-dist/tex/context/base/mlib-pps.lua index 0e3d2e3ecea..cf4fe69bedf 100644 --- a/Master/texmf-dist/tex/context/base/mlib-pps.lua +++ b/Master/texmf-dist/tex/context/base/mlib-pps.lua @@ -6,8 +6,18 @@ if not modules then modules = { } end modules ['mlib-pps'] = { -- prescript, pos license = "see context related readme files", } -local format, concat, round = string.format, table.concat, math.round +-- current limitation: if we have textext as well as a special color then due to +-- prescript/postscript overload we can have problems + +local format, gmatch, concat, round, match = string.format, string.gmatch, table.concat, math.round, string.match local sprint = tex.sprint +local tonumber, type = tonumber, type + +local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming + +local ctxcatcodes = tex.ctxcatcodes + +local trace_textexts = false trackers.register("metapost.textexts", function(v) trace_textexts = v end) colors = colors or { } @@ -19,6 +29,7 @@ local cmyktogray = colors.cmyktogray or function() return 0 end metapost = metapost or { } metapost.specials = metapost.specials or { } metapost.specials.data = metapost.specials.data or { } +metapost.externals = metapost.externals or { n = 0 } local data = metapost.specials.data @@ -31,41 +42,113 @@ local colordata = { {}, {}, {}, {}, {} } --~ => transparent spot : r=123 g= 5 b=hash --~ => rest : r=123 g=n>10 b=whatever +local nooutercolor = "0 g 0 G" +local nooutertransparency = "/Tr0 gs" -- only when set +local outercolormode = 0 +local outercolor = nooutercolor +local outertransparency = nooutertransparency +local innercolor = nooutercolor +local innertransparency = nooutertransparency + +local pdfcolor, pdftransparency = lpdf.color, lpdf.transparency +local registercolor, registerspotcolor = colors.register, colors.registerspotcolor +local registertransparency = transparencies.register + +function metapost.set_outer_color(mode,colormodel,colorattribute,transparencyattribute) + -- has always to be called before conversion + -- todo: transparency (not in the mood now) + outercolormode = mode + if mode == 1 or mode == 3 then + -- inherit from outer (registered color) + outercolor = pdfcolor(colormodel,colorattribute) or nooutercolor + outertransparency = pdftransparency(transparencyattribute) or nooutertransparency + elseif mode == 2 then + -- stand alone (see m-punk.tex) + outercolor = "" + outertransparency = "" + else -- 0 + outercolor = nooutercolor + outertransparency = nooutertransparency + end + innercolor = outercolor + innertransparency = outertransparency -- not yet used +end + +local function checked_color_pair(color) + if not color then + return innercolor, outercolor + elseif outercolormode == 3 then + innercolor = color + return innercolor, innercolor + else + return color, outercolor + end +end + +metapost.checked_color_pair = checked_color_pair + +function metapost.colorinitializer() + innercolor = outercolor + innertransparency = outertransparency + return outercolor, outertransparency +end + function metapost.specials.register(str) -- only colors - local size, content, n, class = str:match("^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$") + local size, content, n, class = match(str,"^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$") if class then + -- use lpeg splitter local data = { } - for s in content:gmatch("[^ ]+") do + for s in gmatch(content,"[^ ]+") do data[#data+1] = s end class, n = tonumber(class), tonumber(n) - if class == 3 or class == 4 or class == 5 then -- weird - colordata[class][n] = data + if class == 3 or class == 4 or class == 5 then + -- hm, weird + else + n = tonumber(data[1]) + end + if n then + local cc = colordata[class] + if cc then + cc[n] = data + else + logs.report("mplib","problematic special: %s (no colordata class %s)", str or "?",class) + end else - colordata[class][tonumber(data[1])] = data + -- there is some bug to be solved, so we issue a message + logs.report("mplib","problematic special: %s", str or "?") end end +--~ if str:match("^%%%%MetaPostOption: multipass") then +--~ metapost.multipass = true +--~ end end -function metapost.colorhandler(cs, object, result, colorconverter) - local cr = "0 g 0 G" +local function spotcolorconverter(parent, n, d, p) + registerspotcolor(parent) + return pdfcolor(colors.model,registercolor(nil,'spot',parent,n,d,p)) +end + +function metapost.colorhandler(cs, object, result, colorconverter) -- handles specials + local cr = outercolor local what = round(cs[2]*10000) - local data = colordata[what][round(cs[3]*10000)] + local data = colordata[what] + if data then + data = data[round(cs[3]*10000)] + end if not data then -- elseif what == 1 then result[#result+1], cr = colorconverter({ data[2], data[3], data[4], data[5] }) elseif what == 2 then - ctx.registerspotcolor(data[2]) - result[#result+1] = ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',data[2],data[3],data[4],data[5])) + result[#result+1] = spotcolorconverter(data[2],data[3],data[4],data[5]) else if what == 3 then result[#result+1], cr = colorconverter({ data[3], data[4], data[5]}) elseif what == 4 then result[#result+1], cr = colorconverter({ data[3], data[4], data[5], data[6]}) elseif what == 5 then - ctx.registerspotcolor(data[3]) - result[#result+1] = ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',data[3],data[4],data[5],data[6])) + result[#result+1] = spotcolorconverter(data[3],data[4],data[5],data[6]) end object.prescript = "tr" object.postscript = data[1] .. "," .. data[2] @@ -74,56 +157,40 @@ function metapost.colorhandler(cs, object, result, colorconverter) return object, cr end -function metapost.colorspec(cs) +function metapost.colorspec(cs) -- used for shades ... returns table (for checking) or string (spot) local what = round(cs[2]*10000) local data = colordata[what][round(cs[3]*10000)] if not data then return { 0 } elseif what == 1 then - return { data[2], data[3], data[4], data[5] } + return { tonumber(data[2]), tonumber(data[3]), tonumber(data[4]), tonumber(data[5]) } elseif what == 2 then - ctx.registerspotcolor(data[2]) - return ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',data[2],data[3],data[4],data[5])) + return spotcolorconverter(data[2],data[3],data[4],data[5]) elseif what == 3 then - return { data[3], data[4], data[5] } + return { tonumber(data[3]), tonumber(data[4]), tonumber(data[5]) } elseif what == 4 then - return { data[3], data[4], data[5], data[6] } + return { tonumber(data[3]), tonumber(data[4]), tonumber(data[5]), tonumber(data[6]) } elseif what == 5 then - ctx.registerspotcolor(data[3]) - return ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',data[3],data[4],data[5],data[6])) + return spotcolorconverter(data[3],data[4],data[5],data[6]) end end function metapost.specials.tr(specification,object,result) - local a, t = specification:match("^(.+),(.+)$") + local a, t = match(specification,"^(.+),(.+)$") local before = a and t and function() - result[#result+1] = format("/Tr%s gs",transparencies.register('mp',a,t)) + result[#result+1] = format("/Tr%s gs",registertransparency(nil,a,t,true)) -- maybe nil instead of 'mp' return object, result end local after = before and function() - result[#result+1] = "/Tr0 gs" + result[#result+1] = outertransparency -- here we could revert to the outer color return object, result end return object, before, nil, after end ---~ -- possible speedup: hash registered colors ---~ ---~ function metapost.specials.sp(specification,object,result) -- todo: color conversion ---~ local s = object.color[1] ---~ object.color = nil ---~ local before = function() ---~ local spec = specification:split(" ") ---~ ctx.registerspotcolor(spec[1]) ---~ result[#result+1] = ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',spec[1],spec[2],spec[3],s)) ---~ return object, result ---~ end ---~ local after = function() ---~ result[#result+1] = "0 g 0 G" ---~ return object, result ---~ end ---~ return object, before, nil, nil ---~ end +local specificationsplitter = lpeg.Ct(lpeg.splitat(" ")) +local colorsplitter = lpeg.Ct(lpeg.splitat(":")) +local colorsplitter = lpeg.Ct(lpeg.splitter(":",tonumber)) -- Unfortunately we cannot use cmyk colors natively because there is no -- generic color allocation primitive ... it's just an rgbcolor color.. This @@ -136,11 +203,11 @@ end -- This is also an example of a simple plugin. --~ function metapost.specials.cc(specification,object,result) ---~ object.color = specification:split(" ") +--~ object.color = specificationsplitter:match(specification) --~ return object, nil, nil, nil --~ end --~ function metapost.specials.cc(specification,object,result) ---~ local c = specification:split(" ") +--~ local c = specificationsplitter:match(specification) --~ local o = object.color[1] --~ c[1],c[2],c[3],c[4] = o*c[1],o*c[2],o*c[3],o*c[4] --~ return object, nil, nil, nil @@ -151,7 +218,7 @@ end -- x' = sx * x + ry * y + tx -- y' = rx * x + sy * y + ty -function metapost.specials.fg(specification,object,result,flusher) +function metapost.specials.fg(specification,object,result,flusher) -- graphics local op = object.path local first, second, fourth = op[1], op[2], op[4] local tx, ty = first.x_coord , first.y_coord @@ -161,12 +228,26 @@ function metapost.specials.fg(specification,object,result,flusher) if sy == 0 then sy = 0.00001 end local before = specification and function() flusher.flushfigure(result) - sprint(tex.ctxcatcodes,format("\\MPLIBfigure{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,specification)) + sprint(ctxcatcodes,format("\\MPLIBfigure{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,specification)) + object.path = nil return object, { } end return { } , before, nil, nil -- replace { } by object for tracing end +function metapost.specials.ps(specification,object,result) -- positions + local op = object.path + local first, third = op[1], op[3] + local x, y = first.x_coord, first.y_coord + local w, h = third.x_coord - x, third.y_coord - y + local label = specification + x = x - metapost.llx + y = metapost.ury - y + -- logs.report("mplib", "todo: position '%s' at (%s,%s) with (%s,%s)",label,x,y,w,h) + sprint(ctxcatcodes,format("\\dosavepositionwhd{%s}{0}{%sbp}{%sbp}{%sbp}{%sbp}{0pt}",label,x,y,w,h)) + return { }, nil, nil, nil +end + local nofshades = 0 -- todo: hash resources, start at 1000 in order not to clash with older local function normalize(ca,cb) @@ -185,22 +266,28 @@ local function normalize(ca,cb) end end +-- todo: check for the same colorspace (actually a backend issue), now we can +-- have several similar resources +-- +-- normalize(ca,cb) fails for spotcolors + function metapost.specials.cs(specification,object,result,flusher) -- spot colors? + -- a mess, not dynamic anyway nofshades = nofshades + 1 flusher.flushfigure(result) result = { } - local t = specification:split(" ") + local t = specificationsplitter:match(specification) -- we need a way to move/scale - local ca = t[4]:split(":") - local cb = t[8]:split(":") + local ca = colorsplitter:match(t[4]) + local cb = colorsplitter:match(t[8]) if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end + local name = format("MplSh%s",nofshades) + local domain = { tonumber(t[1]), tonumber(t[2]) } + local coordinates = { tonumber(t[5]), tonumber(t[6]), tonumber(t[7]), tonumber(t[9]), tonumber(t[10]), tonumber(t[11]) } if type(ca) == "string" then - -- spot color, not supported, maybe at some point use the fallbacks - sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}", - nofshades, - t[1], t[2], 0, 1, 1, "DeviceGray", - t[5], t[6], t[7], t[9], t[10], t[11])) + -- backend specific (will be renamed) + lpdf.circularshade(name,domain,{ 0 },{ 1 },1,"DeviceGray",coordinates) else if #ca > #cb then normalize(ca,cb) @@ -215,15 +302,14 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color if #ca == 4 then ca[1], ca[2], ca[3] = cmyktorgb(ca[1],ca[2],ca[3],ca[4]) cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4]) + ca[4], cb[4] = nil, nil elseif #ca == 1 then local a, b = 1-ca[1], 1-cb[1] ca[1], ca[2], ca[3] = a, a, a cb[1], cb[2], cb[3] = b, b, b end - sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}", - nofshades, - t[1], t[2], ca[1], ca[2], ca[3], cb[1], cb[2], cb[3], 1, "DeviceRGB", - t[5], t[6], t[7], t[9], t[10], t[11])) + -- backend specific (will be renamed) + lpdf.circularshade(name,domain,ca,cb,1,"DeviceRGB",coordinates) elseif model == "cmyk" then if #ca == 3 then ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3]) @@ -232,10 +318,8 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1] cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1] end - sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}", - nofshades, - t[1], t[2], ca[1], ca[2], ca[3], ca[4], cb[1], cb[2], cb[3], cb[4], 1, "DeviceCMYK", - t[5], t[6], t[7], t[9], t[10], t[11])) + -- backend specific (will be renamed) + lpdf.circularshade(name,domain,ca,cb,1,"DeviceCMYK",coordinates) else if #ca == 4 then ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4]) @@ -244,10 +328,8 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color ca[1] = rgbtogray(ca[1],ca[2],ca[3]) cb[1] = rgbtogray(cb[1],cb[2],cb[3]) end - sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}", - nofshades, - t[1], t[2], ca[1], cb[1], 1, "DeviceGray", - t[5], t[6], t[7], t[9], t[10], t[11])) + -- backend specific (will be renamed) + lpdf.circularshade(name,domain,ca,cb,1,"DeviceGRAY",coordinates) end end local before = function() @@ -255,7 +337,7 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color return object, result end local after = function() - result[#result+1] = format("W n /MpSh%s sh Q", nofshades) + result[#result+1] = format("W n /%s sh Q", name) return object, result end object.color, object.type = nil, nil @@ -266,18 +348,18 @@ function metapost.specials.ls(specification,object,result,flusher) nofshades = nofshades + 1 flusher.flushfigure(result) result = { } - local t = specification:split(" ") + local t = specificationsplitter:match(specification) -- we need a way to move/scale - local ca = t[4]:split(":") - local cb = t[7]:split(":") + local ca = colorsplitter:match(t[4]) + local cb = colorsplitter:match(t[7]) if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end + local name = format("MpSh%s",nofshades) + local domain = { tonumber(t[1]), tonumber(t[2]) } + local coordinates = { tonumber(t[5]), tonumber(t[6]), tonumber(t[8]), tonumber(t[9]) } if type(ca) == "string" then - -- spot color, not supported, maybe at some point use the fallbacks - sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}", - nofshades, - t[1], t[2], 0, 1, 1, "DeviceGray", - t[5], t[6], t[8], t[9])) + -- backend specific (will be renamed) + lpdf.linearshade(name,domain,{ 0 },{ 1 },1,"DeviceGray",coordinates) else if #ca > #cb then normalize(ca,cb) @@ -297,10 +379,8 @@ function metapost.specials.ls(specification,object,result,flusher) ca[1], ca[2], ca[3] = a, a, a cb[1], cb[2], cb[3] = b, b, b end - sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}", - nofshades, - t[1], t[2], ca[1], ca[2], ca[3], cb[1], cb[2], cb[3], 1, "DeviceRGB", - t[5], t[6], t[8], t[9])) + -- backend specific (will be renamed) + lpdf.linearshade(name,domain,ca,cb,1,"DeviceRGB",coordinates) elseif model == "cmyk" then if #ca == 3 then ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3]) @@ -309,10 +389,8 @@ function metapost.specials.ls(specification,object,result,flusher) ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1] cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1] end - sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}", - nofshades, - t[1], t[2], ca[1], ca[2], ca[3], ca[4], cb[1], cb[2], cb[3], cb[4], 1, "DeviceCMYK", - t[5], t[6], t[8], t[9])) + -- backend specific (will be renamed) + lpdf.linearshade(name,domain,ca,cb,1,"DeviceCMYK",coordinates) else if #ca == 4 then ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4]) @@ -321,10 +399,8 @@ function metapost.specials.ls(specification,object,result,flusher) ca[1] = rgbtogray(ca[1],ca[2],ca[3]) cb[1] = rgbtogray(cb[1],cb[2],cb[3]) end - sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}", - nofshades, - t[1], t[2], ca[1], cb[1], 1, "DeviceGray", - t[5], t[6], t[8], t[9])) + -- backend specific (will be renamed) + lpdf.linearshade(name,domain,ca,cb,1,"DeviceGRAY",coordinates) end end local before = function() @@ -332,7 +408,7 @@ function metapost.specials.ls(specification,object,result,flusher) return object, result end local after = function() - result[#result+1] = format("W n /MpSh%s sh Q", nofshades) + result[#result+1] = format("W n /%s sh Q", name) return object, result end object.color, object.type = nil, nil @@ -343,273 +419,230 @@ end local current_format, current_graphic ---~ metapost.first_box, metapost.last_box = 1000, 1100 - +metapost.first_box = metapost.first_box or 1000 +metapost.last_box = metapost.last_box or 1100 metapost.textext_current = metapost.first_box -metapost.trace_texttexts = false metapost.multipass = false +function metapost.free_boxes() + local tb = tex.box + for i = metapost.first_box,metapost.last_box do + local b = tb[i] + if b then + tb[i] = nil -- no node.flush_list(b) needed, else double free error + else + break + end + end +end + function metapost.specials.tf(specification,object) --~ print("setting", metapost.textext_current) - local n, str = specification:match("^(%d+):(.+)$") - if metapost.textext_current < metapost.last_box then - metapost.textext_current = metapost.first_box + n - 1 - end - if metapost.trace_texttexts then - print("metapost", format("first pass: order %s, box %s",n,metapost.textext_current)) + local n, str = match(specification,"^(%d+):(.+)$") + if n and str then + if metapost.textext_current < metapost.last_box then + metapost.textext_current = metapost.first_box + n - 1 + end + if trace_textexts then + logs.report("metapost","first pass: order %s, box %s",n,metapost.textext_current) + end + sprint(ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",metapost.textext_current,str)) + metapost.multipass = true end - sprint(tex.ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",metapost.textext_current,str)) - metapost.multipass = true return { }, nil, nil, nil end function metapost.specials.ts(specification,object,result,flusher) -- print("getting", metapost.textext_current) - local n, str = specification:match("^(%d+):(.+)$") - if metapost.trace_texttexts then - print("metapost", format("second pass: order %s, box %s",n,metapost.textext_current)) - end - local op = object.path - local first, second, fourth = op[1], op[2], op[4] - local tx, ty = first.x_coord , first.y_coord - local sx, sy = second.x_coord - tx, fourth.y_coord - ty - local rx, ry = second.y_coord - ty, fourth.x_coord - tx - if sx == 0 then sx = 0.00001 end - if sy == 0 then sy = 0.00001 end - local before = function() -- no need for function - --~ flusher.flushfigure(result) - --~ sprint(tex.ctxcatcodes,format("\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,metapost.textext_current)) - --~ result = { } - result[#result+1] = format("q %f %f %f %f %f %f cm", sx,rx,ry,sy,tx,ty) - flusher.flushfigure(result) - if metapost.textext_current < metapost.last_box then - metapost.textext_current = metapost.first_box + n - 1 + local n, str = match(specification,"^(%d+):(.+)$") + if n and str then + if trace_textexts then + logs.report("metapost","second pass: order %s, box %s",n,metapost.textext_current) end - local b = metapost.textext_current - sprint(tex.ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",b, metapost.sxsy(tex.wd[b],tex.ht[b],tex.dp[b]))) - result = { "Q" } - return object, result + local op = object.path + local first, second, fourth = op[1], op[2], op[4] + local tx, ty = first.x_coord , first.y_coord + local sx, sy = second.x_coord - tx, fourth.y_coord - ty + local rx, ry = second.y_coord - ty, fourth.x_coord - tx + if sx == 0 then sx = 0.00001 end + if sy == 0 then sy = 0.00001 end + if not trace_textexts then + object.path = nil + end + local before = function() -- no need for function + --~ flusher.flushfigure(result) + --~ sprint(ctxcatcodes,format("\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,metapost.textext_current)) + --~ result = { } + result[#result+1] = format("q %f %f %f %f %f %f cm", sx,rx,ry,sy,tx,ty) + flusher.flushfigure(result) + if metapost.textext_current < metapost.last_box then + metapost.textext_current = metapost.first_box + n - 1 + end + local b = metapost.textext_current + sprint(ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",b, metapost.sxsy(tex.wd[b],tex.ht[b],tex.dp[b]))) + result = { "Q" } + return object, result + end + return { }, before, nil, nil -- replace { } by object for tracing + else + return { }, nil, nil, nil -- replace { } by object for tracing end - return { }, before, nil, nil -- replace { } by object for tracing end -function metapost.colorconverter() - -- it no longer pays off to distinguish between outline and fill - -- (we now have both too, e.g. in arrows) - local model = colors.model - if model == "all" then - return function(cr) - local n = #cr - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - elseif n == 4 then - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" +-- rather generic pdf, so use this elsewhere too it no longer pays +-- off to distinguish between outline and fill (we now have both +-- too, e.g. in arrows) + +metapost.reducetogray = true + +local models = { } + +function models.all(cr) + local n = #cr + if n == 0 then + return checked_color_pair() + elseif metapost.reducetogray then + if n == 1 then + local s = cr[1] + return checked_color_pair(format("%.3f g %.3f G",s,s)) + elseif n == 3 then + local r, g, b = cr[1], cr[2], cr[3] + if r == g and g == b then + return checked_color_pair(format("%.3f g %.3f G",r,r)) else - local r, g, b = cr[1], cr[2], cr[3] - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" + return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b)) end - end - elseif model == "rgb" then - return function(cr) - local n = #cr - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - end - local r, g, b - if n == 4 then - r, g, b = cmyktorgb(cr[1],cr[2],cr[3],cr[4]) + else + local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + if c == m and m == y and y == 0 then + k = 1 - k + return checked_color_pair(format("%.3f g %.3f G",k,k)) else - r, g, b = cr[1],cr[2],cr[3] + return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k)) end - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" end - elseif model == "cmyk" then - return function(cr) - local n = #cr - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" + elseif n == 1 then + local s = cr[1] + return checked_color_pair(format("%.3f g %.3f G",s,s)) + elseif n == 3 then + local r, g, b = cr[1], cr[2], cr[3] + return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b)) + else + local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k)) + end +end + +function models.rgb(cr) + local n = #cr + if n == 0 then + return checked_color_pair() + elseif metapost.reducetogray then + if n == 1 then + local s = cr[1] + checked_color_pair(format("%.3f g %.3f G",s,s)) + elseif n == 3 then + local r, g, b = cr[1], cr[2], cr[3] + if r == g and g == b then + return checked_color_pair(format("%.3f g %.3f G",r,r)) + else + return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b)) end - local c, m, y, k - if n == 4 then - c, m, y, k = cr[1], cr[2], cr[3], cr[4] + else + local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + if c == m and m == y and y == 0 then + k = 1 - k + return checked_color_pair(format("%.3f g %.3f G",k,k)) else - c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3]) + local r, g, b = cmyktorgb(c,m,y,k) + return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b)) end - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" end + elseif n == 1 then + local s = cr[1] + return checked_color_pair(format("%.3f g %.3f G",s,s)) else - return function(cr) - local s - local n = #cr - if n == 4 then - s = cmyktogray(cr[1],cr[2],cr[3],cr[4]) - elseif n == 3 then - s = rgbtogray(cr[1],cr[2],cr[3]) - else - s = cr[1] - end - return format("%.3f g %.3f G",s,s), "0 g 0 G" + local r, g, b + if n == 3 then + r, g, b = cmyktorgb(cr[1],cr[2],cr[3],cr[4]) + else + r, g, b = cr[1], cr[2], cr[3] end + return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b)) end end ---~ local cmyk_fill = "%.3f %.3f %.3f %.3f k" ---~ local rgb_fill = "%.3f %.3f %.3f rg" ---~ local gray_fill = "%.3f g" ---~ local reset_fill = "0 g" - ---~ local cmyk_stroke = "%.3f %.3f %.3f %.3f K" ---~ local rgb_stroke = "%.3f %.3f %.3f RG" ---~ local gray_stroke = "%.3f G" ---~ local reset_stroke = "0 G" - -metapost.reducetogray = true - -function metapost.colorconverter() -- rather generic pdf, so use this elsewhere too - -- it no longer pays off to distinguish between outline and fill - -- (we now have both too, e.g. in arrows) - local model = colors.model - local reduce = metapost.reducetogray - if model == "all" then - return function(cr) - local n = #cr - if reduce then - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] - if r == g and g == b then - return format("%.3f g %.3f G",r,r), "0 g 0 G" - else - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" - end - else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] - if c == m and m == y and y == 0 then - k = 1 - k - return format("%.3f g %.3f G",k,k), "0 g 0 G" - else - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" - end - end - elseif n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" +function models.cmyk(cr) + local n = #cr + if n == 0 then + return checked_color_pair() + elseif metapost.reducetogray then + if n == 1 then + local s = cr[1] + return checked_color_pair(format("%.3f g %.3f G",s,s)) + elseif n == 3 then + local r, g, b = cr[1], cr[2], cr[3] + if r == g and g == b then + return checked_color_pair(format("%.3f g %.3f G",r,r)) else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" + local c, m, y, k = rgbtocmyk(r,g,b) + return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k)) end - end - elseif model == "rgb" then - return function(cr) - local n = #cr - if reduce then - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] - if r == g and g == b then - return format("%.3f g %.3f G",r,r), "0 g 0 G" - else - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" - end - else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] - if c == m and m == y and y == 0 then - k = 1 - k - return format("%.3f g %.3f G",k,k), "0 g 0 G" - else - local r, g, b = cmyktorgb(c,m,y,k) - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" - end - end - elseif n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - else - local r, g, b - if n == 3 then - r, g, b = cmyktorgb(cr[1],cr[2],cr[3],cr[4]) - else - r, g, b = cr[1], cr[2], cr[3] - end - return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G" - end - end - elseif model == "cmyk" then - return function(cr) - local n = #cr - if reduce then - if n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" - elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] - if r == g and g == b then - return format("%.3f g %.3f G",r,r), "0 g 0 G" - else - local c, m, y, k = rgbtocmyk(r,g,b) - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" - end - else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] - if c == m and m == y and y == 0 then - k = 1 - k - return format("%.3f g %.3f G",k,k), "0 g 0 G" - else - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" - end - end - elseif n == 1 then - local s = cr[1] - return format("%.3f g %.3f G",s,s), "0 g 0 G" + else + local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + if c == m and m == y and y == 0 then + k = 1 - k + return checked_color_pair(format("%.3f g %.3f G",k,k)) else - local c, m, y, k - if n == 3 then - c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3]) - else - c, m, y, k = cr[1], cr[2], cr[3], cr[4] - end - return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G" + return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k)) end end + elseif n == 1 then + local s = cr[1] + return checked_color_pair(format("%.3f g %.3f G",s,s)) else - return function(cr) - local n, s = #cr, 0 - if n == 4 then - s = cmyktogray(cr[1],cr[2],cr[3],cr[4]) - elseif n == 3 then - s = rgbtogray(cr[1],cr[2],cr[3]) - else - s = cr[1] - end - return format("%.3f g %.3f G",s,s), "0 g 0 G" + local c, m, y, k + if n == 3 then + c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3]) + else + c, m, y, k = cr[1], cr[2], cr[3], cr[4] end + return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k)) end end +function models.gray(cr) + local n, s = #cr, 0 + if n == 0 then + return checked_color_pair() + elseif n == 4 then + s = cmyktogray(cr[1],cr[2],cr[3],cr[4]) + elseif n == 3 then + s = rgbtogray(cr[1],cr[2],cr[3]) + else + s = cr[1] + end + return checked_color_pair(format("%.3f g %.3f G",s,s)) +end + +function metapost.colorconverter() + return models[colors.model] or gray +end + do local P, S, V, Cs = lpeg.P, lpeg.S, lpeg.V, lpeg.Cs - local btex = P("btex") - local etex = P(" etex") - local vtex = P("verbatimtex") - local ttex = P("textext") - local gtex = P("graphictext") - local spacing = S(" \n\r\t\v")^0 - local dquote = P('"') + local btex = P("btex") + local etex = P(" etex") + local vtex = P("verbatimtex") + local ttex = P("textext") + local gtex = P("graphictext") + local multipass = P("forcemultipass") + local spacing = S(" \n\r\t\v")^0 + local dquote = P('"') - local found = false + local found, forced = false, false local function convert(str) found = true @@ -621,11 +654,15 @@ do local function register() found = true end + local function force() + forced = true + end local parser = P { - [1] = Cs((V(2)/register + V(3)/convert + 1)^0), + [1] = Cs((V(2)/register + V(3)/convert + V(4)/force + 1)^0), [2] = ttex + gtex, [3] = (btex + vtex) * spacing * Cs((dquote/ditto + (1 - etex))^0) * etex, + [4] = multipass, -- experimental, only for testing } -- currently a a one-liner produces less code @@ -633,29 +670,31 @@ do local parser = Cs(((ttex + gtex)/register + ((btex + vtex) * spacing * Cs((dquote/ditto + (1 - etex))^0) * etex)/convert + 1)^0) function metapost.check_texts(str) - found = false - return parser:match(str), found + found, forced = false, false + return parser:match(str), found, forced end end -local factor = 65536*(7200/7227) +local factor = 65536*(7227/7200) -function metapost.edefsxsy(wd,ht,dp) -- helper for text - commands.edef("sx",(wd ~= 0 and 1/( wd /(factor))) or 0) - commands.edef("sy",(wd ~= 0 and 1/((ht+dp)/(factor))) or 0) +function metapost.edefsxsy(wd,ht,dp) -- helper for figure + local hd = ht + dp + commands.edef("sx",(wd ~= 0 and factor/wd) or 0) + commands.edef("sy",(hd ~= 0 and factor/hd) or 0) end function metapost.sxsy(wd,ht,dp) -- helper for text - return (wd ~= 0 and 1/(wd/(factor))) or 0, (wd ~= 0 and 1/((ht+dp)/(factor))) or 0 + local hd = ht + dp + return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0 end function metapost.text_texts_data() local t, n = { }, 0 for i = metapost.first_box, metapost.last_box do n = n + 1 - if metapost.trace_texttexts then - print("metapost", format("passed data: order %s, box %s",n,i)) + if trace_textexts then + logs.report("metapost","passed data: order %s, box %s",n,i) end if tex.box[i] then t[#t+1] = format("_tt_w_[%i]:=%f;_tt_h_[%i]:=%f;_tt_d_[%i]:=%f;", n,tex.wd[i]/factor, n,tex.ht[i]/factor, n,tex.dp[i]/factor) @@ -670,106 +709,80 @@ metapost.intermediate = metapost.intermediate or {} metapost.intermediate.actions = metapost.intermediate.actions or {} metapost.intermediate.needed = false ---~ function metapost.graphic_base_pass(mpsformat,str,preamble) ---~ local prepared, done = metapost.check_texts(str) ---~ metapost.textext_current = metapost.first_box ---~ metapost.intermediate.needed = false ---~ if done then ---~ current_format, current_graphic = mpsformat, prepared ---~ metapost.process(mpsformat, { ---~ preamble or "", ---~ "beginfig(1); ", ---~ "_trial_run_ := true ;", ---~ prepared, ---~ "endfig ;" ---~ }, true ) -- true means: trialrun ---~ if metapost.intermediate.needed then ---~ for _, action in pairs(metapost.intermediate.actions) do ---~ action() ---~ end ---~ end ---~ sprint(tex.ctxcatcodes,"\\ctxlua{metapost.graphic_extra_pass()}") ---~ else ---~ metapost.process(mpsformat, { ---~ preamble or "", ---~ "beginfig(1); ", ---~ "_trial_run_ := false ;", ---~ "resettextexts;", ---~ str, ---~ "endfig ;" ---~ } ) ---~ end ---~ end - metapost.method = 1 -- 1:dumb 2:clever -function metapost.graphic_base_pass(mpsformat,str,preamble) - local done_1, done_2 - str, done_1 = metapost.check_texts(str) +function metapost.graphic_base_pass(mpsformat,str,preamble,askedfig) + local nofig = (askedfig and "") or false + local done_1, done_2, forced_1, forced_2 + str, done_1, forced_1 = metapost.check_texts(str) if preamble then - preamble, done_2 = metapost.check_texts(preamble) + preamble, done_2, forced_2 = metapost.check_texts(preamble) else - preamble, done_2 = "", false + preamble, done_2, forced_2 = "", false, false end metapost.textext_current = metapost.first_box metapost.intermediate.needed = false metapost.multipass = false -- no needed here current_format, current_graphic = mpsformat, str if metapost.method == 1 or (metapost.method == 2 and (done_1 or done_2)) then + -- first true means: trialrun, second true means: avoid extra run if no multipass local flushed = metapost.process(mpsformat, { preamble, - "beginfig(1); ", - "_trial_run_ := true ;", ---~ "resettextexts;", + nofig or "beginfig(1); ", + "if unknown _trial_run_ : boolean _trial_run_ fi ; _trial_run_ := true ;", str, - "endfig ;" - }, true, nil, true ) -- true means: trialrun, true means: avoid extra run if no multipass + nofig or "endfig ;" + -- }, true, nil, true ) + }, true, nil, not (forced_1 or forced_2), false, askedfig) if metapost.intermediate.needed then for _, action in pairs(metapost.intermediate.actions) do action() end end - if not flushed then - sprint(tex.ctxcatcodes,"\\ctxlua{metapost.graphic_extra_pass()}") + if not flushed or not metapost.optimize then + -- tricky, we can only ask once for objects and therefore + -- we really need a second run when not optimized + sprint(ctxcatcodes,format("\\ctxlua{metapost.graphic_extra_pass(%s)}",askedfig or "false")) end else metapost.process(mpsformat, { preamble or "", - "beginfig(1); ", + nofig or "beginfig(1); ", "_trial_run_ := false ;", ---~ "resettextexts;", str, - "endfig ;" - } ) + nofig or "endfig ;" + }, false, nil, false, false, askedfig ) end + -- here we could free the textext boxes + metapost.free_boxes() end -function metapost.graphic_extra_pass() +function metapost.graphic_extra_pass(askedfig) + local nofig = (askedfig and "") or false metapost.textext_current = metapost.first_box metapost.process(current_format, { - "beginfig(0); ", + nofig or "beginfig(1); ", "_trial_run_ := false ;", ---~ "resettextexts;", concat(metapost.text_texts_data()," ;\n"), current_graphic, - "endfig ;" - }) + nofig or "endfig ;" + }, false, nil, false, true, askedfig ) end function metapost.getclippath(data) local mpx = metapost.format("metafun") if mpx and data then - input.starttiming(metapost) - input.starttiming(metapost.exectime) + starttiming(metapost) + starttiming(metapost.exectime) local result = mpx:execute(format("beginfig(1);%s;endfig;",data)) - input.stoptiming(metapost.exectime) + stoptiming(metapost.exectime) if result.status > 0 then print("error", result.status, result.error or result.term or result.log) result = "" else result = metapost.filterclippath(result) end - input.stoptiming(metapost) + stoptiming(metapost) sprint(result) end end @@ -792,41 +805,43 @@ do -- only used in graphictexts end -do -- not that beautiful but ok, we could save a md5 hash in the tui file ! +local graphics = { } +local start = [[\starttext]] +local preamble = [[\long\def\MPLIBgraphictext#1{\startTEXpage[scale=10000]#1\stopTEXpage}]] +local stop = [[\stoptext]] - local graphics = { } - local start = [[\starttext]] - local preamble = [[\long\def\MPLIBgraphictext#1{\startTEXpage[scale=10000]#1\stopTEXpage}]] - local stop = [[\stoptext]] +function metapost.specials.gt(specification,object) -- number, so that we can reorder + graphics[#graphics+1] = format("\\MPLIBgraphictext{%s}",specification) + metapost.intermediate.needed = true + metapost.multipass = true + return { }, nil, nil, nil +end - function metapost.specials.gt(specification,object) -- number, so that we can reorder - graphics[#graphics+1] = format("\\MPLIBgraphictext{%s}",specification) - metapost.intermediate.needed = true - metapost.multipass = true - return { }, nil, nil, nil - end - - function metapost.intermediate.actions.makempy() - if #graphics > 0 then - local mpofile = tex.jobname .. "-mp" - local mpyfile = file.replacesuffix(mpofile,"mpy") - local pdffile = file.replacesuffix(mpofile,"pdf") - local texfile = file.replacesuffix(mpofile,"tex") - io.savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") - os.execute(format("context --once %s", texfile)) - if io.exists(pdffile) then - os.execute(format("pstoedit -ssp -dt -f mpost %s %s", pdffile, mpyfile)) - local result = { } - if io.exists(mpyfile) then - local data = io.loaddata(mpyfile) - for figure in data:gmatch("beginfig(.-)endfig") do - result[#result+1] = format("begingraphictextfig%sendgraphictextfig ;\n", figure) - end - io.savedata(mpyfile,concat(result,"")) +function metapost.intermediate.actions.makempy() + if #graphics > 0 then + local externals = metapost.externals + externals.n = externals.n + 1 + starttiming(externals) + local mpofile = tex.jobname .. "-mpgraph" + local mpyfile = file.replacesuffix(mpofile,"mpy") + local pdffile = file.replacesuffix(mpofile,"pdf") + local texfile = file.replacesuffix(mpofile,"tex") + io.savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") + local command = format("context --once %s %s", (tex.interactionmode == 0 and "--batchmode") or "", texfile) + os.execute(command) + if io.exists(pdffile) then + command = format("pstoedit -ssp -dt -f mpost %s %s", pdffile, mpyfile) + os.execute(command) + local result = { } + if io.exists(mpyfile) then + local data = io.loaddata(mpyfile) + for figure in gmatch(data,"beginfig(.-)endfig") do + result[#result+1] = format("begingraphictextfig%sendgraphictextfig ;\n", figure) end + io.savedata(mpyfile,concat(result,"")) end - graphics = { } end + stoptiming(externals) + graphics = { } -- ? end - end |