summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mlib-pps.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mlib-pps.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/mlib-pps.lua832
1 files changed, 832 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mlib-pps.lua b/Master/texmf-dist/tex/context/base/mlib-pps.lua
new file mode 100644
index 00000000000..0e3d2e3ecea
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mlib-pps.lua
@@ -0,0 +1,832 @@
+if not modules then modules = { } end modules ['mlib-pps'] = { -- prescript, postscripts and specials
+ version = 1.001,
+ comment = "companion to mlib-ctx.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local format, concat, round = string.format, table.concat, math.round
+local sprint = tex.sprint
+
+colors = colors or { }
+
+local rgbtocmyk = colors.rgbtocmyk or function() return 0,0,0,1 end
+local cmyktorgb = colors.cmyktorgb or function() return 0,0,0 end
+local rgbtogray = colors.rgbtogray or function() return 0 end
+local cmyktogray = colors.cmyktogray or function() return 0 end
+
+metapost = metapost or { }
+metapost.specials = metapost.specials or { }
+metapost.specials.data = metapost.specials.data or { }
+
+local data = metapost.specials.data
+
+local colordata = { {}, {}, {}, {}, {} }
+
+--~ (r,g,b) => cmyk : r=123 g= 1 b=hash
+--~ => spot : r=123 g= 2 b=hash
+--~ => transparent rgb : r=123 g= 3 b=hash
+--~ => transparent cmyk : r=123 g= 4 b=hash
+--~ => transparent spot : r=123 g= 5 b=hash
+--~ => rest : r=123 g=n>10 b=whatever
+
+function metapost.specials.register(str) -- only colors
+ local size, content, n, class = str:match("^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$")
+ if class then
+ local data = { }
+ for s in content:gmatch("[^ ]+") 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
+ else
+ colordata[class][tonumber(data[1])] = data
+ end
+ end
+end
+
+function metapost.colorhandler(cs, object, result, colorconverter)
+ local cr = "0 g 0 G"
+ local what = round(cs[2]*10000)
+ local data = colordata[what][round(cs[3]*10000)]
+ 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]))
+ 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]))
+ end
+ object.prescript = "tr"
+ object.postscript = data[1] .. "," .. data[2]
+ end
+ object.color = nil
+ return object, cr
+end
+
+function metapost.colorspec(cs)
+ 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] }
+ 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]))
+ elseif what == 3 then
+ return { data[3], data[4], data[5] }
+ elseif what == 4 then
+ return { data[3], data[4], data[5], 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]))
+ end
+end
+
+function metapost.specials.tr(specification,object,result)
+ local a, t = specification:match("^(.+),(.+)$")
+ local before = a and t and function()
+ result[#result+1] = format("/Tr%s gs",transparencies.register('mp',a,t))
+ return object, result
+ end
+ local after = before and function()
+ result[#result+1] = "/Tr0 gs"
+ 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
+
+-- Unfortunately we cannot use cmyk colors natively because there is no
+-- generic color allocation primitive ... it's just an rgbcolor color.. This
+-- means that we cannot pass colors in either cmyk or rgb form.
+--
+-- def cmyk(expr c,m,y,k) =
+-- 1 withprescript "cc" withpostscript ddddecimal (c,m,y,k)
+-- enddef ;
+--
+-- This is also an example of a simple plugin.
+
+--~ function metapost.specials.cc(specification,object,result)
+--~ object.color = specification:split(" ")
+--~ return object, nil, nil, nil
+--~ end
+--~ function metapost.specials.cc(specification,object,result)
+--~ local c = specification:split(" ")
+--~ 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
+--~ end
+
+-- thanks to taco's reading of the postscript manual:
+--
+-- x' = sx * x + ry * y + tx
+-- y' = rx * x + sy * y + ty
+
+function metapost.specials.fg(specification,object,result,flusher)
+ 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 = 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))
+ return object, { }
+ end
+ return { } , before, nil, nil -- replace { } by object for tracing
+end
+
+local nofshades = 0 -- todo: hash resources, start at 1000 in order not to clash with older
+
+local function normalize(ca,cb)
+ if #cb == 1 then
+ if #ca == 4 then
+ cb[1], cb[2], cb[3], cb[4] = 0, 0, 0, 1-cb[1]
+ else
+ cb[1], cb[2], cb[3] = cb[1], cb[1], cb[1]
+ end
+ elseif #cb == 3 then
+ if #ca == 4 then
+ cb[1], cb[2], cb[3], cb[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ else
+ cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
+ end
+ end
+end
+
+function metapost.specials.cs(specification,object,result,flusher) -- spot colors?
+ nofshades = nofshades + 1
+ flusher.flushfigure(result)
+ result = { }
+ local t = specification:split(" ")
+ -- we need a way to move/scale
+ local ca = t[4]:split(":")
+ local cb = t[8]:split(":")
+ if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
+ if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
+ 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]))
+ else
+ if #ca > #cb then
+ normalize(ca,cb)
+ elseif #ca < #cb then
+ normalize(cb,ca)
+ end
+ local model = colors.model
+ if model == "all" then
+ model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
+ end
+ if model == "rgb" then
+ 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])
+ 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]))
+ elseif model == "cmyk" then
+ if #ca == 3 then
+ ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3])
+ cb[1], cb[2], cb[3], ca[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ elseif #ca == 1 then
+ 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]))
+ else
+ if #ca == 4 then
+ ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4])
+ cb[1] = cmyktogray(cb[1],cb[2],cb[3],cb[4])
+ elseif #ca == 3 then
+ 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]))
+ end
+ end
+ local before = function()
+ result[#result+1] = "q /Pattern cs"
+ return object, result
+ end
+ local after = function()
+ result[#result+1] = format("W n /MpSh%s sh Q", nofshades)
+ return object, result
+ end
+ object.color, object.type = nil, nil
+ return object, before, nil, after
+end
+
+function metapost.specials.ls(specification,object,result,flusher)
+ nofshades = nofshades + 1
+ flusher.flushfigure(result)
+ result = { }
+ local t = specification:split(" ")
+ -- we need a way to move/scale
+ local ca = t[4]:split(":")
+ local cb = t[7]:split(":")
+ if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
+ if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
+ 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]))
+ else
+ if #ca > #cb then
+ normalize(ca,cb)
+ elseif #ca < #cb then
+ normalize(cb,ca)
+ end
+ local model = colors.model
+ if model == "all" then
+ model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
+ end
+ if model == "rgb" then
+ 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])
+ 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("\\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]))
+ elseif model == "cmyk" then
+ if #ca == 3 then
+ ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3])
+ cb[1], cb[2], cb[3], ca[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ elseif #ca == 1 then
+ 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]))
+ else
+ if #ca == 4 then
+ ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4])
+ cb[1] = cmyktogray(cb[1],cb[2],cb[3],cb[4])
+ elseif #ca == 3 then
+ 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]))
+ end
+ end
+ local before = function()
+ result[#result+1] = "q /Pattern cs"
+ return object, result
+ end
+ local after = function()
+ result[#result+1] = format("W n /MpSh%s sh Q", nofshades)
+ return object, result
+ end
+ object.color, object.type = nil, nil
+ return object, before, nil, after
+end
+
+-- no need for a before here
+
+local current_format, current_graphic
+
+--~ metapost.first_box, metapost.last_box = 1000, 1100
+
+metapost.textext_current = metapost.first_box
+metapost.trace_texttexts = false
+metapost.multipass = false
+
+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))
+ 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
+ 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
+ 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"
+ 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"
+ 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
+ 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
+ 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"
+ end
+ local c, m, y, k
+ if n == 4 then
+ c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ else
+ c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3])
+ 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
+ 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"
+ end
+ 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"
+ 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"
+ 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
+ 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"
+ end
+ end
+ 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"
+ end
+ end
+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 found = false
+
+ local function convert(str)
+ found = true
+ return "textext(\"" .. str .. "\")"
+ end
+ local function ditto(str)
+ return "\" & ditto & \""
+ end
+ local function register()
+ found = true
+ end
+
+ local parser = P {
+ [1] = Cs((V(2)/register + V(3)/convert + 1)^0),
+ [2] = ttex + gtex,
+ [3] = (btex + vtex) * spacing * Cs((dquote/ditto + (1 - etex))^0) * etex,
+ }
+
+ -- currently a a one-liner produces less code
+
+ 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
+ end
+
+end
+
+local factor = 65536*(7200/7227)
+
+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)
+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
+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))
+ 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)
+ else
+ break
+ end
+ end
+ return t
+end
+
+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)
+ if preamble then
+ preamble, done_2 = metapost.check_texts(preamble)
+ else
+ preamble, done_2 = "", 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
+ local flushed = metapost.process(mpsformat, {
+ preamble,
+ "beginfig(1); ",
+ "_trial_run_ := true ;",
+--~ "resettextexts;",
+ str,
+ "endfig ;"
+ }, true, nil, true ) -- true means: trialrun, true means: avoid extra run if no multipass
+ 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()}")
+ end
+ else
+ metapost.process(mpsformat, {
+ preamble or "",
+ "beginfig(1); ",
+ "_trial_run_ := false ;",
+--~ "resettextexts;",
+ str,
+ "endfig ;"
+ } )
+ end
+end
+
+function metapost.graphic_extra_pass()
+ metapost.textext_current = metapost.first_box
+ metapost.process(current_format, {
+ "beginfig(0); ",
+ "_trial_run_ := false ;",
+--~ "resettextexts;",
+ concat(metapost.text_texts_data()," ;\n"),
+ current_graphic,
+ "endfig ;"
+ })
+end
+
+function metapost.getclippath(data)
+ local mpx = metapost.format("metafun")
+ if mpx and data then
+ input.starttiming(metapost)
+ input.starttiming(metapost.exectime)
+ local result = mpx:execute(format("beginfig(1);%s;endfig;",data))
+ input.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)
+ sprint(result)
+ end
+end
+
+metapost.tex = metapost.tex or { }
+
+do -- only used in graphictexts
+
+ local environments = { }
+
+ function metapost.tex.set(str)
+ environments[#environments+1] = str
+ end
+ function metapost.tex.reset()
+ environments = { }
+ end
+ function metapost.tex.get()
+ return concat(environments,"\n")
+ end
+
+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]]
+
+ 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,""))
+ end
+ end
+ graphics = { }
+ end
+ end
+
+end