if not modules then modules = { } end modules ['colo-ini'] = { version = 1.000, comment = "companion to colo-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local type = type local concat = table.concat local format, gmatch, gsub, lower, match, find = string.format, string.gmatch, string.gsub, string.lower, string.match, string.find local texsprint = tex.sprint local ctxcatcodes = tex.ctxcatcodes local trace_define = false trackers.register("colors.define",function(v) trace_define = v end) local settings_to_hash_strict = aux.settings_to_hash_strict colors = colors or { } transparencies = transparencies or { } local registrations = backends.registrations local a_color = attributes.private('color') local a_transparency = attributes.private('transparency') local a_colorspace = attributes.private('colormodel') local a_background = attributes.private('background') local register_color = colors.register local attributes_list = attributes.list local function definecolor(name, ca, global) if ca and ca > 0 then if global then if trace_define then commands.writestatus("color","define global color '%s' with attribute: %s",name,ca) end context.colordefagc(name,ca) else if trace_define then commands.writestatus("color","define local color '%s' with attribute: %s",name,ca) end context.colordefalc(name,ca) end else if global then context.colordefrgc(name) else context.colordefrlc(name) end end end local function inheritcolor(name, ca, global) if ca and ca ~= "" then if global then if trace_define then commands.writestatus("color","inherit global color '%s' with attribute: %s",name,ca) end context.colordeffgc(name,ca) else if trace_define then commands.writestatus("color","inherit local color '%s' with attribute: %s",name,ca) end context.colordefflc(name,ca) end else if global then context.colordefrgc(name) else context.colordefrlc(name) end end end local function definetransparent(name, ta, global) if ta and ta > 0 then if global then if trace_define then commands.writestatus("color","define global transparency '%s' with attribute: %s",name,ta) end context.colordefagt(name,ta) else if trace_define then commands.writestatus("color","define local transparency '%s' with attribute: %s",name,ta) end context.colordefalt(name,ta) end else if global then context.colordefrgt(name) else context.colordefrlt(name) end end end local function inherittransparent(name, ta, global) if ta and ta ~= "" then if global then if trace_define then commands.writestatus("color","inherit global transparency '%s' with attribute: %s",name,ta) end context.colordeffgt(name,ta) else if trace_define then commands.writestatus("color","inherit local transparency '%s' with attribute: %s",name,ta) end context.colordefflt(name,ta) end else if global then context.colordefrgt(name) else context.colordefrlt(name) end end end local transparent = { none = 0, normal = 1, multiply = 2, screen = 3, overlay = 4, softlight = 5, hardlight = 6, colordodge = 7, colorburn = 8, darken = 9, lighten = 10, difference = 11, exclusion = 12, } -- By coupling we are downward compatible. When we decouple we need to do more tricky -- housekeeping (e.g. persist color independent transparencies when color bound ones -- are nil.) colors.couple = true function colors.definetransparency(name,n) transparent[name] = n end local registered = { } local function do_registerspotcolor(parent,name,parentnumber,e,f,d,p) if not registered[parentnumber] then local v = colors.values[parentnumber] if v then local kind = colors.default -- else problems with shading etc if kind == 1 then kind = v[1] end if e and e ~= "" then registrations.spotcolorname(parent,e) -- before registration of the color end if kind == 2 then -- name noffractions names p's r g b registrations.grayspotcolor(parent,f,d,p,v[2]) elseif kind == 3 then registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5]) elseif kind == 4 then registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9]) end end registered[parentnumber] = true end end local function do_registermultitonecolor(parent,name,parentnumber,e,f,d,p) -- same as spot but different template if not registered[parentnumber] then local v = colors.values[parentnumber] if v then local kind = colors.default -- else problems with shading etc if kind == 1 then kind = v[1] end if kind == 2 then registrations.grayindexcolor(parent,f,d,p,v[2]) elseif kind == 3 then registrations.rgbindexcolor (parent,f,d,p,v[3],v[4],v[5]) elseif kind == 4 then registrations.cmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9]) end end registered[parentnumber] = true end end function colors.definesimplegray(name,s) return register_color(name,'gray',s) -- we still need to get rid of 'color' end function colors.defineprocesscolor(name,str,global,freeze) -- still inconsistent color vs transparent local x = match(str,"^#(.+)$") -- for old times sake (if we need to feed from xml or so) if x then local r, g, b = match(x .. "000000","(..)(..)(..)") -- watch the 255 definecolor(name, register_color(name,'rgb',(tonumber(r,16) or 0)/255,(tonumber(g,16) or 0)/255,(tonumber(b,16) or 0)/255), global) else local settings = settings_to_hash_strict(str) if settings then local r, g, b = settings.r, settings.g, settings.b if r or g or b then definecolor(name, register_color(name,'rgb', tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0), global) else local c, m, y, k = settings.c, settings.m, settings.y, settings.k if c or m or y or b then definecolor(name, register_color(name,'cmyk',tonumber(c) or 0, tonumber(m) or 0, tonumber(y) or 0, tonumber(k) or 0), global) else local h, s, v = settings.h, settings.s, settings.v if v then r, g, b = colors.hsvtorgb(tonumber(h) or 0, tonumber(s) or 1, tonumber(v) or 1) -- maybe later native definecolor(name, register_color(name,'rgb',r,g,b), global) else local x = settings.x or h if x then r, g, b = match(x .. "000000","(..)(..)(..)") -- watch the 255 definecolor(name, register_color(name,'rgb',(tonumber(r,16) or 0)/255,(tonumber(g,16) or 0)/255,(tonumber(b,16) or 0)/255), global) else definecolor(name, register_color(name,'gray',tonumber(s) or 0), global) end end end end local a, t = settings.a, settings.t if a and t then definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global) elseif colors.couple then -- definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up definetransparent(name, 0, global) -- can be sped up end elseif freeze then local ca = attributes_list[a_color] [str] local ta = attributes_list[a_transparency][str] if ca then definecolor(name, ca, global) end if ta then definetransparent(name, ta, global) end else inheritcolor(name, str, global) inherittransparent(name, str, global) -- if global and str ~= "" then -- For Peter Rolf who wants access to the numbers in Lua. (Currently only global is supported.) -- attributes_list[a_color] [name] = attributes_list[a_color] [str] or attributes.unsetvalue -- reset -- attributes_list[a_transparency][name] = attributes_list[a_transparency][str] or attributes.unsetvalue -- end end end end function colors.isblack(ca) -- maybe commands local cv = ca > 0 and colors.value(ca) return (cv and cv[2] == 0) or false end function colors.definespotcolor(name,parent,str,global) if parent == "" or find(parent,"=") then colors.registerspotcolor(name, parent) elseif name ~= parent then local cp = attributes_list[a_color][parent] if cp then local t = settings_to_hash_strict(str) if t then local tp = tonumber(t.p) or 1 do_registerspotcolor(parent, name, cp, t.e, 1, "", tp) -- p not really needed, only diagnostics if name and name ~= "" then definecolor(name, register_color(name,'spot', parent, 1, "", tp), true) local ta, tt = t.a, t.t if ta and tt then definetransparent(name, transparencies.register(name,transparent[ta] or tonumber(ta) or 1,tonumber(tt) or 1), global) elseif colors.couple then --~ definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up definetransparent(name, 0, global) -- can be sped up end end end end end end function colors.registerspotcolor(parent, str) local cp = attributes_list[a_color][parent] if cp then local e = "" if str then local t = settings_to_hash_strict(str) e = (t and t.e) or "" end do_registerspotcolor(parent, "dummy", cp, e, 1, "", 1) -- p not really needed, only diagnostics end end function colors.definemultitonecolor(name,multispec,colorspec,selfspec) local dd, pp, nn = { }, { }, { } for k,v in gmatch(multispec,"(%a+)=([^%,]*)") do dd[#dd+1] = k pp[#pp+1] = v nn[#nn+1] = k nn[#nn+1] = format("%1.3g",tonumber(v) or 0) -- 0 can't happen end --~ v = tonumber(v) * p local nof = #dd if nof > 0 then dd, pp, nn = concat(dd,','), concat(pp,','), concat(nn,'_') local parent = gsub(lower(nn),"[^%d%a%.]+","_") colors.defineprocesscolor(parent,colorspec..","..selfspec,true,true) local cp = attributes_list[a_color][parent] if cp then do_registerspotcolor(parent, name, cp, "", nof, dd, pp) do_registermultitonecolor(parent, name, cp, "", nof, dd, pp) definecolor(name, register_color(name, 'spot', parent, nof, dd, pp), true) local t = settings_to_hash_strict(selfspec) if t and t.a and t.t then definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global) elseif colors.couple then -- definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up definetransparent(name, 0, global) -- can be sped up end end end end function colors.mp(model,ca,ta,default) local cv = colors.value(ca) -- faster when direct colors.values[ca] if cv then local tv = transparencies.value(ta) if model == 1 then model = cv[1] end if tv then if model == 2 then return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5]) elseif model == 3 then return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5]) elseif model == 4 then return format("transparent(%s,%s,cmyk(%s,%s,%s,%s))",tv[1],tv[2],cv[6],cv[7],cv[8],cv[9]) else return format("transparent(%s,%s,multitonecolor(\"%s\",%s,\"%s\",\"%s\"))",tv[1],tv[2],cv[10],cv[11],cv[12],cv[13]) end else if model == 2 then return format("(%s,%s,%s)",cv[3],cv[4],cv[5]) elseif model == 3 then return format("(%s,%s,%s)",cv[3],cv[4],cv[5]) elseif model == 4 then return format("cmyk(%s,%s,%s,%s)",cv[6],cv[7],cv[8],cv[9]) else return format("multitonecolor(\"%s\",%s,\"%s\",\"%s\")",cv[10],cv[11],cv[12],cv[13]) end end else default = default or 0 -- rgb ! return format("(%s,%s,%s)",default,default,default) end end function colors.formatcolor(ca,separator) local cv = colors.value(ca) if cv then local c, f, t, model = { }, 13, 13, cv[1] if model == 2 then f, t = 2, 2 elseif model == 3 then f, t = 3, 5 elseif model == 4 then f, t = 6, 9 end for i=f,t do c[#c+1] = format("%0.3f",cv[i]) end return concat(c,separator) else return format("%0.3f",0) end end function colors.formatgray(ca,separator) local cv = colors.value(ca) return format("%0.3f",(cv and cv[2]) or 0) end function colors.colorcomponents(ca) -- return list local cv = colors.value(ca) if cv then local model = cv[1] if model == 2 then return format("s=%1.3f",cv[2]) elseif model == 3 then return format("r=%1.3f g=%1.3f b=%1.3f",cv[3],cv[4],cv[5]) elseif model == 4 then return format("c=%1.3f m=%1.3f y=%1.3f k=%1.3f",cv[6],cv[7],cv[8],cv[9]) elseif type(cv[13]) == "string" then return format("p=%s",cv[13]) else return format("p=%1.3f",cv[13]) end else return "" end end function colors.transparencycomponents(ta) local tv = transparencies.value(ta) if tv then return format("a=%1.3f t=%1.3f",tv[1],tv[2]) else return "" end end function colors.spotcolorname(ca,default) local cv, v = colors.value(ca), "unknown" if cv and cv[1] == 5 then v = cv[10] end return tostring(v) end function colors.spotcolorparent(ca,default) local cv, v = colors.value(ca), "unknown" if cv and cv[1] == 5 then v = cv[12] if v == "" then v = cv[10] end end return tostring(v) end function colors.spotcolorvalue(ca,default) local cv, v = colors.value(ca), 0 if cv and cv[1] == 5 then v = cv[13] end return tostring(v) end -- experiment (a bit of a hack, as we need to get the attribute number) local min = math.min -- a[b,c] -> b+a*(c-b) local function f(one,two,i,fraction) local o, t = one[i], two[i] local otf = o + fraction * (t - o) if otf > 1 then otf = 1 end return otf end function colors.defineintermediatecolor(name,fraction,c_one,c_two,a_one,a_two,specs,global,freeze) fraction = tonumber(fraction) or 1 local one, two = colors.value(c_one), colors.value(c_two) if one and two then local csone, cstwo = one[1], two[1] if csone == cstwo then -- actually we can set all 8 values at once here but this is cleaner as we avoid -- problems with weighted gray conversions and work with original values local ca if csone == 2 then ca = register_color(name,'gray',f(one,two,2,fraction)) elseif csone == 3 then ca = register_color(name,'rgb',f(one,two,3,fraction),f(one,two,4,fraction),f(one,two,5,fraction)) elseif csone == 4 then ca = register_color(name,'cmyk',f(one,two,6,fraction),f(one,two,7,fraction),f(one,two,8,fraction),f(one,two,9,fraction)) else ca = register_color(name,'gray',f(one,two,2,fraction)) end definecolor(name,ca,global,freeze) end end local one, two = transparencies.value(a_one), transparencies.value(a_two) local t = settings_to_hash_strict(specs) local ta = tonumber((t and t.a) or (one and one[1]) or (two and two[1])) local tt = tonumber((t and t.t) or (one and two and f(one,two,2,fraction))) if ta and tt then --~ print(ta,tt) definetransparent(name,transparencies.register(name,ta,tt),global) end end