diff options
Diffstat (limited to 'tex/context/base/attr-col.lua')
-rw-r--r-- | tex/context/base/attr-col.lua | 1076 |
1 files changed, 538 insertions, 538 deletions
diff --git a/tex/context/base/attr-col.lua b/tex/context/base/attr-col.lua index 7c6b7909b..473bf8a74 100644 --- a/tex/context/base/attr-col.lua +++ b/tex/context/base/attr-col.lua @@ -1,538 +1,538 @@ -if not modules then modules = { } end modules ['attr-col'] = { - version = 1.001, - comment = "companion to attr-col.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- this module is being reconstructed and code will move to other places --- we can also do the nsnone via a metatable and then also se index 0 - --- list could as well refer to the tables (instead of numbers that --- index into another table) .. depends on what we need - -local type = type -local format = string.format -local concat = table.concat -local min, max, floor = math.min, math.max, math.floor - -local attributes, nodes, utilities, logs, backends, storage = attributes, nodes, utilities, logs, backends, storage -local commands, context, interfaces = commands, context, interfaces -local tex = tex - -local allocate = utilities.storage.allocate -local setmetatableindex = table.setmetatableindex - -local report_attributes = logs.reporter("attributes","colors") -local report_colors = logs.reporter("colors","support") -local report_transparencies = logs.reporter("transparencies","support") - --- todo: document this but first reimplement this as it reflects the early --- days of luatex / mkiv and we have better ways now - --- nb: attributes: color etc is much slower than normal (marks + literals) but ... --- nb. too many "0 g"s - -local states = attributes.states -local tasks = nodes.tasks -local nodeinjections = backends.nodeinjections -local registrations = backends.registrations -local unsetvalue = attributes.unsetvalue - -local registerstorage = storage.register -local formatters = string.formatters - --- We can distinguish between rules and glyphs but it's not worth the trouble. A --- first implementation did that and while it saves a bit for glyphs and rules, it --- costs more resourses for transparencies. So why bother. - --- --- colors --- - --- we can also collapse the two attributes: n, n+1, n+2 and then --- at the tex end add 0, 1, 2, but this is not faster and less --- flexible (since sometimes we freeze color attribute values at --- the lua end of the game) --- --- we also need to store the colorvalues because we need then in mp --- --- This is a compromis between speed and simplicity. We used to store the --- values and data in one array, which made in neccessary to store the --- converters that need node constructor into strings and evaluate them --- at runtime (after reading from storage). Think of: --- --- colors.strings = colors.strings or { } --- --- if environment.initex then --- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")" --- end --- --- registerstorage("attributes/colors/data", colors.strings, "attributes.colors.data") -- evaluated --- --- We assume that only processcolors are defined in the format. - -attributes.colors = attributes.colors or { } -local colors = attributes.colors - -local a_color = attributes.private('color') -local a_selector = attributes.private('colormodel') - -colors.data = allocate() -colors.values = colors.values or { } -colors.registered = colors.registered or { } -colors.weightgray = true -colors.attribute = a_color -colors.selector = a_selector -colors.default = 1 -colors.main = nil -colors.triggering = true -colors.supported = true -colors.model = "all" - -local data = colors.data -local values = colors.values -local registered = colors.registered - -local numbers = attributes.numbers -local list = attributes.list - -registerstorage("attributes/colors/values", values, "attributes.colors.values") -registerstorage("attributes/colors/registered", registered, "attributes.colors.registered") - -local f_colors = { - rgb = formatters["r:%s:%s:%s"], - cmyk = formatters["c:%s:%s:%s:%s"], - gray = formatters["s:%s"], - spot = formatters["p:%s:%s:%s:%s"], -} - -local models = { - [interfaces.variables.none] = unsetvalue, - black = unsetvalue, - bw = unsetvalue, - all = 1, - gray = 2, - rgb = 3, - cmyk = 4, -} - -local function rgbtocmyk(r,g,b) -- we could reduce - return 1-r, 1-g, 1-b, 0 -end - -local function cmyktorgb(c,m,y,k) - return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k) -end - -local function rgbtogray(r,g,b) - if colors.weightgray then - return .30*r + .59*g + .11*b - else - return r/3 + g/3 + b/3 - end -end - -local function cmyktogray(c,m,y,k) - return rgbtogray(cmyktorgb(c,m,y,k)) -end - --- not critical so not needed: --- --- local function cmyktogray(c,m,y,k) --- local r, g, b = 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k) --- if colors.weightgray then --- return .30*r + .59*g + .11*b --- else --- return r/3 + g/3 + b/3 --- end --- end - --- http://en.wikipedia.org/wiki/HSI_color_space --- http://nl.wikipedia.org/wiki/HSV_(kleurruimte) - -local function hsvtorgb(h,s,v) - -- h = h % 360 - local hd = h/60 - local hf = floor(hd) - local hi = hf % 6 - -- local f = hd - hi - local f = hd - hf - local p = v * (1 - s) - local q = v * (1 - f * s) - local t = v * (1 - (1 - f) * s) - if hi == 0 then - return v, t, p - elseif hi == 1 then - return q, v, p - elseif hi == 2 then - return p, v, t - elseif hi == 3 then - return p, q, v - elseif hi == 4 then - return t, p, v - elseif hi == 5 then - return v, p, q - else - print("error in hsv -> rgb",hi,h,s,v) - end -end - -local function rgbtohsv(r,g,b) - local offset, maximum, other_1, other_2 - if r >= g and r >= b then - offset, maximum, other_1, other_2 = 0, r, g, b - elseif g >= r and g >= b then - offset, maximum, other_1, other_2 = 2, g, b, r - else - offset, maximum, other_1, other_2 = 4, b, r, g - end - if maximum == 0 then - return 0, 0, 0 - end - local minimum = other_1 < other_2 and other_1 or other_2 - if maximum == minimum then - return 0, 0, maximum - end - local delta = maximum - minimum - return (offset + (other_1-other_2)/delta)*60, delta/maximum, maximum -end - -local function graytorgb(s) -- unweighted - return 1-s, 1-s, 1-s -end - -local function hsvtogray(h,s,v) - return rgb_to_gray(hsv_to_rgb(h,s,v)) -end - -local function graytohsv(s) - return 0, 0, s -end - -colors.rgbtocmyk = rgbtocmyk -colors.rgbtogray = rgbtogray -colors.cmyktorgb = cmyktorgb -colors.cmyktogray = cmyktogray -colors.rgbtohsv = rgbtohsv -colors.hsvtorgb = hsvtorgb -colors.hsvtogray = hsvtogray -colors.graytohsv = graytohsv - --- we can share some *data by using s, rgb and cmyk hashes, but --- normally the amount of colors is not that large; storing the --- components costs a bit of extra runtime, but we expect to gain --- some back because we have them at hand; the number indicates the --- default color space - -function colors.gray(s) - return { 2, s, s, s, s, 0, 0, 0, 1-s } -end - -function colors.rgb(r,g,b) - local s = rgbtogray(r,g,b) - local c, m, y, k = rgbtocmyk(r,g,b) - return { 3, s, r, g, b, c, m, y, k } -end - -function colors.cmyk(c,m,y,k) - local s = cmyktogray(c,m,y,k) - local r, g, b = cmyktorgb(c,m,y,k) - return { 4, s, r, g, b, c, m, y, k } -end - ---~ function colors.spot(parent,f,d,p) ---~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p } ---~ end - -function colors.spot(parent,f,d,p) - if type(p) == "number" then - local n = list[numbers.color][parent] -- hard coded ref to color number - if n then - local v = values[n] - if v then - -- the via cmyk hack is dirty, but it scales better - local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8] - local r, g, b = cmyktorgb(c,m,y,k) - local s = cmyktogray(c,m,y,k) - return { 5, s, r, g, b, c, m, y, k, parent, f, d, p } - end - end - else - -- todo, multitone (maybe p should be a table) - end - return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p } -end - -local function graycolor(...) graycolor = nodeinjections.graycolor return graycolor(...) end -local function rgbcolor (...) rgbcolor = nodeinjections.rgbcolor return rgbcolor (...) end -local function cmykcolor(...) cmykcolor = nodeinjections.cmykcolor return cmykcolor(...) end -local function spotcolor(...) spotcolor = nodeinjections.spotcolor return spotcolor(...) end - -local function extender(colors,key) - if colors.supported and key == "none" then - local d = graycolor(0) - colors.none = d - return d - end -end - -local function reviver(data,n) - if colors.supported then - local v = values[n] - local d - if not v then - local gray = graycolor(0) - d = { gray, gray, gray, gray } - report_attributes("unable to revive color %a",n) - else - local model = colors.forcedmodel(v[1]) - if model == 2 then - local gray= graycolor(v[2]) - d = { gray, gray, gray, gray } - elseif model == 3 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) - d = { rgb, gray, rgb, cmyk } - elseif model == 4 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) - d = { cmyk, gray, rgb, cmyk } - elseif model == 5 then - local spot = spotcolor(v[10],v[11],v[12],v[13]) - -- d = { spot, gray, rgb, cmyk } - d = { spot, spot, spot, spot } - end - end - data[n] = d - return d - end -end - -setmetatableindex(colors, extender) -setmetatableindex(colors.data, reviver) - -function colors.filter(n) - return concat(data[n],":",5) -end - -function colors.setmodel(name,weightgray) - colors.model = name - colors.default = models[name] or 1 - colors.weightgray = weightgray ~= false - return colors.default -end - -function colors.register(name, colorspace, ...) -- passing 9 vars is faster (but not called that often) - local stamp = f_colors[colorspace](...) - local color = registered[stamp] - if not color then - color = #values + 1 - values[color] = colors[colorspace](...) - registered[stamp] = color - -- colors.reviver(color) - end - if name then - list[a_color][name] = color -- not grouped, so only global colors - end - return registered[stamp] -end - -function colors.value(id) - return values[id] -end - -attributes.colors.handler = nodes.installattributehandler { - name = "color", - namespace = colors, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.selective, - resolver = function() return colors.main end, -} - -function colors.enable(value) - if value == false or not colors.supported then - tasks.disableaction("shipouts","attributes.colors.handler") - else - tasks.enableaction("shipouts","attributes.colors.handler") - end -end - -function colors.forcesupport(value) -- can move to attr-div - colors.supported = value - report_colors("color is %ssupported",value and "" or "not ") - colors.enable(value) -end - --- transparencies - -local a_transparency = attributes.private('transparency') - -attributes.transparencies = attributes.transparencies or { } -local transparencies = attributes.transparencies -transparencies.registered = transparencies.registered or { } -transparencies.data = allocate() -transparencies.values = transparencies.values or { } -transparencies.triggering = true -transparencies.attribute = a_transparency -transparencies.supported = true - -local registered = transparencies.registered -- we could use a 2 dimensional table instead -local data = transparencies.data -local values = transparencies.values -local f_transparency = formatters["%s:%s"] - -registerstorage("attributes/transparencies/registered", registered, "attributes.transparencies.registered") -registerstorage("attributes/transparencies/values", values, "attributes.transparencies.values") - -local function inject_transparency(...) - inject_transparency = nodeinjections.transparency - return inject_transparency(...) -end - -local function register_transparency(...) - register_transparency = registrations.transparency - return register_transparency(...) -end - -function transparencies.register(name,a,t,force) -- name is irrelevant here (can even be nil) - -- Force needed here for metapost converter. We could always force - -- but then we'd end up with transparencies resources even if we - -- would not use transparencies (but define them only). This is - -- somewhat messy. - local stamp = f_transparency(a,t) - local n = registered[stamp] - if not n then - n = #values + 1 - values[n] = { a, t } - registered[stamp] = n - if force then - register_transparency(n,a,t) - end - elseif force and not data[n] then - register_transparency(n,a,t) - end - if name then - list[a_transparency][name] = n -- not grouped, so only global transparencies - end - return registered[stamp] -end - -local function extender(transparencies,key) - if colors.supported and key == "none" then - local d = inject_transparency(0) - transparencies.none = d - return d - end -end - -local function reviver(data,n) - if transparencies.supported then - local v = values[n] - local d - if not v then - d = inject_transparency(0) - else - d = inject_transparency(n) - register_transparency(n,v[1],v[2]) - end - data[n] = d - return d - else - return "" - end -end - -setmetatableindex(transparencies, extender) -setmetatableindex(transparencies.data, reviver) -- register if used - --- check if there is an identity - -function transparencies.value(id) - return values[id] -end - -attributes.transparencies.handler = nodes.installattributehandler { - name = "transparency", - namespace = transparencies, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function transparencies.enable(value) -- nil is enable - if value == false or not transparencies.supported then - tasks.disableaction("shipouts","attributes.transparencies.handler") - else - tasks.enableaction("shipouts","attributes.transparencies.handler") - end -end - -function transparencies.forcesupport(value) -- can move to attr-div - transparencies.supported = value - report_transparencies("transparency is %ssupported",value and "" or "not ") - transparencies.enable(value) -end - ---- colorintents: overprint / knockout - -attributes.colorintents = attributes.colorintents or { } -local colorintents = attributes.colorintents -colorintents.data = allocate() -- colorintents.data or { } -colorintents.attribute = attributes.private('colorintent') - -colorintents.registered = allocate { - overprint = 1, - knockout = 2, -} - -local data, registered = colorintents.data, colorintents.registered - -local function extender(colorintents,key) - if key == "none" then - local d = data[2] - colorintents.none = d - return d - end -end - -local function reviver(data,n) - if n == 1 then - local d = nodeinjections.overprint() -- called once - data[1] = d - return d - elseif n == 2 then - local d = nodeinjections.knockout() -- called once - data[2] = d - return d - end -end - -setmetatableindex(colorintents, extender) -setmetatableindex(colorintents.data, reviver) - -function colorintents.register(stamp) - return registered[stamp] or registered.overprint -end - -colorintents.handler = nodes.installattributehandler { - name = "colorintent", - namespace = colorintents, - initializer = states.initialize, - finalizer = states.finalize, - processor = states.process, -} - -function colorintents.enable() - tasks.enableaction("shipouts","attributes.colorintents.handler") -end - --- interface - -commands.enablecolor = colors.enable -commands.enabletransparency = transparencies.enable -commands.enablecolorintents = colorintents.enable - -function commands.registercolor (...) context(colors .register(...)) end -function commands.registertransparency(...) context(transparencies.register(...)) end -function commands.registercolorintent (...) context(colorintents .register(...)) end +if not modules then modules = { } end modules ['attr-col'] = {
+ version = 1.001,
+ comment = "companion to attr-col.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this module is being reconstructed and code will move to other places
+-- we can also do the nsnone via a metatable and then also se index 0
+
+-- list could as well refer to the tables (instead of numbers that
+-- index into another table) .. depends on what we need
+
+local type = type
+local format = string.format
+local concat = table.concat
+local min, max, floor = math.min, math.max, math.floor
+
+local attributes, nodes, utilities, logs, backends, storage = attributes, nodes, utilities, logs, backends, storage
+local commands, context, interfaces = commands, context, interfaces
+local tex = tex
+
+local allocate = utilities.storage.allocate
+local setmetatableindex = table.setmetatableindex
+
+local report_attributes = logs.reporter("attributes","colors")
+local report_colors = logs.reporter("colors","support")
+local report_transparencies = logs.reporter("transparencies","support")
+
+-- todo: document this but first reimplement this as it reflects the early
+-- days of luatex / mkiv and we have better ways now
+
+-- nb: attributes: color etc is much slower than normal (marks + literals) but ...
+-- nb. too many "0 g"s
+
+local states = attributes.states
+local tasks = nodes.tasks
+local nodeinjections = backends.nodeinjections
+local registrations = backends.registrations
+local unsetvalue = attributes.unsetvalue
+
+local registerstorage = storage.register
+local formatters = string.formatters
+
+-- We can distinguish between rules and glyphs but it's not worth the trouble. A
+-- first implementation did that and while it saves a bit for glyphs and rules, it
+-- costs more resourses for transparencies. So why bother.
+
+--
+-- colors
+--
+
+-- we can also collapse the two attributes: n, n+1, n+2 and then
+-- at the tex end add 0, 1, 2, but this is not faster and less
+-- flexible (since sometimes we freeze color attribute values at
+-- the lua end of the game)
+--
+-- we also need to store the colorvalues because we need then in mp
+--
+-- This is a compromis between speed and simplicity. We used to store the
+-- values and data in one array, which made in neccessary to store the
+-- converters that need node constructor into strings and evaluate them
+-- at runtime (after reading from storage). Think of:
+--
+-- colors.strings = colors.strings or { }
+--
+-- if environment.initex then
+-- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")"
+-- end
+--
+-- registerstorage("attributes/colors/data", colors.strings, "attributes.colors.data") -- evaluated
+--
+-- We assume that only processcolors are defined in the format.
+
+attributes.colors = attributes.colors or { }
+local colors = attributes.colors
+
+local a_color = attributes.private('color')
+local a_selector = attributes.private('colormodel')
+
+colors.data = allocate()
+colors.values = colors.values or { }
+colors.registered = colors.registered or { }
+colors.weightgray = true
+colors.attribute = a_color
+colors.selector = a_selector
+colors.default = 1
+colors.main = nil
+colors.triggering = true
+colors.supported = true
+colors.model = "all"
+
+local data = colors.data
+local values = colors.values
+local registered = colors.registered
+
+local numbers = attributes.numbers
+local list = attributes.list
+
+registerstorage("attributes/colors/values", values, "attributes.colors.values")
+registerstorage("attributes/colors/registered", registered, "attributes.colors.registered")
+
+local f_colors = {
+ rgb = formatters["r:%s:%s:%s"],
+ cmyk = formatters["c:%s:%s:%s:%s"],
+ gray = formatters["s:%s"],
+ spot = formatters["p:%s:%s:%s:%s"],
+}
+
+local models = {
+ [interfaces.variables.none] = unsetvalue,
+ black = unsetvalue,
+ bw = unsetvalue,
+ all = 1,
+ gray = 2,
+ rgb = 3,
+ cmyk = 4,
+}
+
+local function rgbtocmyk(r,g,b) -- we could reduce
+ return 1-r, 1-g, 1-b, 0
+end
+
+local function cmyktorgb(c,m,y,k)
+ return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+end
+
+local function rgbtogray(r,g,b)
+ if colors.weightgray then
+ return .30*r + .59*g + .11*b
+ else
+ return r/3 + g/3 + b/3
+ end
+end
+
+local function cmyktogray(c,m,y,k)
+ return rgbtogray(cmyktorgb(c,m,y,k))
+end
+
+-- not critical so not needed:
+--
+-- local function cmyktogray(c,m,y,k)
+-- local r, g, b = 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+-- if colors.weightgray then
+-- return .30*r + .59*g + .11*b
+-- else
+-- return r/3 + g/3 + b/3
+-- end
+-- end
+
+-- http://en.wikipedia.org/wiki/HSI_color_space
+-- http://nl.wikipedia.org/wiki/HSV_(kleurruimte)
+
+local function hsvtorgb(h,s,v)
+ -- h = h % 360
+ local hd = h/60
+ local hf = floor(hd)
+ local hi = hf % 6
+ -- local f = hd - hi
+ local f = hd - hf
+ local p = v * (1 - s)
+ local q = v * (1 - f * s)
+ local t = v * (1 - (1 - f) * s)
+ if hi == 0 then
+ return v, t, p
+ elseif hi == 1 then
+ return q, v, p
+ elseif hi == 2 then
+ return p, v, t
+ elseif hi == 3 then
+ return p, q, v
+ elseif hi == 4 then
+ return t, p, v
+ elseif hi == 5 then
+ return v, p, q
+ else
+ print("error in hsv -> rgb",hi,h,s,v)
+ end
+end
+
+local function rgbtohsv(r,g,b)
+ local offset, maximum, other_1, other_2
+ if r >= g and r >= b then
+ offset, maximum, other_1, other_2 = 0, r, g, b
+ elseif g >= r and g >= b then
+ offset, maximum, other_1, other_2 = 2, g, b, r
+ else
+ offset, maximum, other_1, other_2 = 4, b, r, g
+ end
+ if maximum == 0 then
+ return 0, 0, 0
+ end
+ local minimum = other_1 < other_2 and other_1 or other_2
+ if maximum == minimum then
+ return 0, 0, maximum
+ end
+ local delta = maximum - minimum
+ return (offset + (other_1-other_2)/delta)*60, delta/maximum, maximum
+end
+
+local function graytorgb(s) -- unweighted
+ return 1-s, 1-s, 1-s
+end
+
+local function hsvtogray(h,s,v)
+ return rgb_to_gray(hsv_to_rgb(h,s,v))
+end
+
+local function graytohsv(s)
+ return 0, 0, s
+end
+
+colors.rgbtocmyk = rgbtocmyk
+colors.rgbtogray = rgbtogray
+colors.cmyktorgb = cmyktorgb
+colors.cmyktogray = cmyktogray
+colors.rgbtohsv = rgbtohsv
+colors.hsvtorgb = hsvtorgb
+colors.hsvtogray = hsvtogray
+colors.graytohsv = graytohsv
+
+-- we can share some *data by using s, rgb and cmyk hashes, but
+-- normally the amount of colors is not that large; storing the
+-- components costs a bit of extra runtime, but we expect to gain
+-- some back because we have them at hand; the number indicates the
+-- default color space
+
+function colors.gray(s)
+ return { 2, s, s, s, s, 0, 0, 0, 1-s }
+end
+
+function colors.rgb(r,g,b)
+ local s = rgbtogray(r,g,b)
+ local c, m, y, k = rgbtocmyk(r,g,b)
+ return { 3, s, r, g, b, c, m, y, k }
+end
+
+function colors.cmyk(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ local r, g, b = cmyktorgb(c,m,y,k)
+ return { 4, s, r, g, b, c, m, y, k }
+end
+
+--~ function colors.spot(parent,f,d,p)
+--~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+--~ end
+
+function colors.spot(parent,f,d,p)
+ if type(p) == "number" then
+ local n = list[numbers.color][parent] -- hard coded ref to color number
+ if n then
+ local v = values[n]
+ if v then
+ -- the via cmyk hack is dirty, but it scales better
+ local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8]
+ local r, g, b = cmyktorgb(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ return { 5, s, r, g, b, c, m, y, k, parent, f, d, p }
+ end
+ end
+ else
+ -- todo, multitone (maybe p should be a table)
+ end
+ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+end
+
+local function graycolor(...) graycolor = nodeinjections.graycolor return graycolor(...) end
+local function rgbcolor (...) rgbcolor = nodeinjections.rgbcolor return rgbcolor (...) end
+local function cmykcolor(...) cmykcolor = nodeinjections.cmykcolor return cmykcolor(...) end
+local function spotcolor(...) spotcolor = nodeinjections.spotcolor return spotcolor(...) end
+
+local function extender(colors,key)
+ if colors.supported and key == "none" then
+ local d = graycolor(0)
+ colors.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if colors.supported then
+ local v = values[n]
+ local d
+ if not v then
+ local gray = graycolor(0)
+ d = { gray, gray, gray, gray }
+ report_attributes("unable to revive color %a",n)
+ else
+ local model = colors.forcedmodel(v[1])
+ if model == 2 then
+ local gray= graycolor(v[2])
+ d = { gray, gray, gray, gray }
+ elseif model == 3 then
+ local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
+ d = { rgb, gray, rgb, cmyk }
+ elseif model == 4 then
+ local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
+ d = { cmyk, gray, rgb, cmyk }
+ elseif model == 5 then
+ local spot = spotcolor(v[10],v[11],v[12],v[13])
+ -- d = { spot, gray, rgb, cmyk }
+ d = { spot, spot, spot, spot }
+ end
+ end
+ data[n] = d
+ return d
+ end
+end
+
+setmetatableindex(colors, extender)
+setmetatableindex(colors.data, reviver)
+
+function colors.filter(n)
+ return concat(data[n],":",5)
+end
+
+function colors.setmodel(name,weightgray)
+ colors.model = name
+ colors.default = models[name] or 1
+ colors.weightgray = weightgray ~= false
+ return colors.default
+end
+
+function colors.register(name, colorspace, ...) -- passing 9 vars is faster (but not called that often)
+ local stamp = f_colors[colorspace](...)
+ local color = registered[stamp]
+ if not color then
+ color = #values + 1
+ values[color] = colors[colorspace](...)
+ registered[stamp] = color
+ -- colors.reviver(color)
+ end
+ if name then
+ list[a_color][name] = color -- not grouped, so only global colors
+ end
+ return registered[stamp]
+end
+
+function colors.value(id)
+ return values[id]
+end
+
+attributes.colors.handler = nodes.installattributehandler {
+ name = "color",
+ namespace = colors,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.selective,
+ resolver = function() return colors.main end,
+}
+
+function colors.enable(value)
+ if value == false or not colors.supported then
+ tasks.disableaction("shipouts","attributes.colors.handler")
+ else
+ tasks.enableaction("shipouts","attributes.colors.handler")
+ end
+end
+
+function colors.forcesupport(value) -- can move to attr-div
+ colors.supported = value
+ report_colors("color is %ssupported",value and "" or "not ")
+ colors.enable(value)
+end
+
+-- transparencies
+
+local a_transparency = attributes.private('transparency')
+
+attributes.transparencies = attributes.transparencies or { }
+local transparencies = attributes.transparencies
+transparencies.registered = transparencies.registered or { }
+transparencies.data = allocate()
+transparencies.values = transparencies.values or { }
+transparencies.triggering = true
+transparencies.attribute = a_transparency
+transparencies.supported = true
+
+local registered = transparencies.registered -- we could use a 2 dimensional table instead
+local data = transparencies.data
+local values = transparencies.values
+local f_transparency = formatters["%s:%s"]
+
+registerstorage("attributes/transparencies/registered", registered, "attributes.transparencies.registered")
+registerstorage("attributes/transparencies/values", values, "attributes.transparencies.values")
+
+local function inject_transparency(...)
+ inject_transparency = nodeinjections.transparency
+ return inject_transparency(...)
+end
+
+local function register_transparency(...)
+ register_transparency = registrations.transparency
+ return register_transparency(...)
+end
+
+function transparencies.register(name,a,t,force) -- name is irrelevant here (can even be nil)
+ -- Force needed here for metapost converter. We could always force
+ -- but then we'd end up with transparencies resources even if we
+ -- would not use transparencies (but define them only). This is
+ -- somewhat messy.
+ local stamp = f_transparency(a,t)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = { a, t }
+ registered[stamp] = n
+ if force then
+ register_transparency(n,a,t)
+ end
+ elseif force and not data[n] then
+ register_transparency(n,a,t)
+ end
+ if name then
+ list[a_transparency][name] = n -- not grouped, so only global transparencies
+ end
+ return registered[stamp]
+end
+
+local function extender(transparencies,key)
+ if colors.supported and key == "none" then
+ local d = inject_transparency(0)
+ transparencies.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if transparencies.supported then
+ local v = values[n]
+ local d
+ if not v then
+ d = inject_transparency(0)
+ else
+ d = inject_transparency(n)
+ register_transparency(n,v[1],v[2])
+ end
+ data[n] = d
+ return d
+ else
+ return ""
+ end
+end
+
+setmetatableindex(transparencies, extender)
+setmetatableindex(transparencies.data, reviver) -- register if used
+
+-- check if there is an identity
+
+function transparencies.value(id)
+ return values[id]
+end
+
+attributes.transparencies.handler = nodes.installattributehandler {
+ name = "transparency",
+ namespace = transparencies,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function transparencies.enable(value) -- nil is enable
+ if value == false or not transparencies.supported then
+ tasks.disableaction("shipouts","attributes.transparencies.handler")
+ else
+ tasks.enableaction("shipouts","attributes.transparencies.handler")
+ end
+end
+
+function transparencies.forcesupport(value) -- can move to attr-div
+ transparencies.supported = value
+ report_transparencies("transparency is %ssupported",value and "" or "not ")
+ transparencies.enable(value)
+end
+
+--- colorintents: overprint / knockout
+
+attributes.colorintents = attributes.colorintents or { }
+local colorintents = attributes.colorintents
+colorintents.data = allocate() -- colorintents.data or { }
+colorintents.attribute = attributes.private('colorintent')
+
+colorintents.registered = allocate {
+ overprint = 1,
+ knockout = 2,
+}
+
+local data, registered = colorintents.data, colorintents.registered
+
+local function extender(colorintents,key)
+ if key == "none" then
+ local d = data[2]
+ colorintents.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.overprint() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.knockout() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatableindex(colorintents, extender)
+setmetatableindex(colorintents.data, reviver)
+
+function colorintents.register(stamp)
+ return registered[stamp] or registered.overprint
+end
+
+colorintents.handler = nodes.installattributehandler {
+ name = "colorintent",
+ namespace = colorintents,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function colorintents.enable()
+ tasks.enableaction("shipouts","attributes.colorintents.handler")
+end
+
+-- interface
+
+commands.enablecolor = colors.enable
+commands.enabletransparency = transparencies.enable
+commands.enablecolorintents = colorintents.enable
+
+function commands.registercolor (...) context(colors .register(...)) end
+function commands.registertransparency(...) context(transparencies.register(...)) end
+function commands.registercolorintent (...) context(colorintents .register(...)) end
|