1if not modules then modules = { } end modules ['colo-ini'] = {
2 version = 1.000,
3 comment = "companion to colo-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local type, tonumber, tostring = type, tonumber, tostring
10local concat, insert, remove = table.concat, table.insert, table.remove
11local format, gmatch, gsub, lower, match, find = string.format, string.gmatch, string.gsub, string.lower, string.match, string.find
12local P, R, C, Cc = lpeg.P, lpeg.R, lpeg.C, lpeg.Cc
13local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
14local formatters = string.formatters
15
16local trace_define = false trackers.register("colors.define",function(v) trace_define = v end)
17local trace_pgf = false trackers.register("colors.pgf", function(v) trace_pgf = v end)
18
19local report_colors = logs.reporter("colors","defining")
20local report_pgf = logs.reporter("colors","pgf")
21
22local attributes = attributes
23local backends = backends
24local storage = storage
25local context = context
26local commands = commands
27
28local implement = interfaces.implement
29local getnamespace = interfaces.getnamespace
30
31local mark = utilities.storage.mark
32
33local settings_to_hash_strict = utilities.parsers.settings_to_hash_strict
34
35local colors = attributes.colors
36local transparencies = attributes.transparencies
37local colorintents = attributes.colorintents
38local registrations = backends.registrations
39
40local v_reset = interfaces.variables.reset
41
42local texsetattribute = tex.setattribute
43local texgetattribute = tex.getattribute
44local texgetcount = tex.getcount
45local texgettoks = tex.gettoks
46local texiscount = tex.iscount
47local texgetmacro = tokens.getters.macro
48
49local a_color = attributes.private('color')
50local a_transparency = attributes.private('transparency')
51local a_colormodel = attributes.private('colormodel')
52
53local register_color = colors.register
54local attributes_list = attributes.list
55
56local colorvalues = colors.values
57local transparencyvalues = transparencies.values
58
59colors.sets = mark(colors.sets or { })
60local colorsets = colors.sets
61local colorset = { }
62colorsets.default = colorset
63local valid = mark(colors.valid or { })
64colors.valid = valid
65local counts = mark(colors.counts or { })
66colors.counts = counts
67
68storage.register("attributes/colors/sets", colorsets, "attributes.colors.sets")
69storage.register("attributes/colors/valid", valid, "attributes.colors.valid")
70storage.register("attributes/colors/counts", counts, "attributes.colors.counts")
71
72local function currentmodel()
73 return texgetattribute(a_colormodel)
74end
75
76colors.currentmodel = currentmodel
77
78local function synccolor(name)
79 valid[name] = true
80end
81
82local function synccolorclone(name,clone)
83 valid[name] = clone
84end
85
86local synccolorcount if CONTEXTLMTXMODE > 0 then
87
88
89
90
91
92 synccolorcount = function(name,n)
93 counts[name] = texiscount(n)
94 end
95else
96 synccolorcount = function(name,n)
97 counts[name] = n
98 end
99end
100
101local stack = { }
102
103local function pushset(name)
104 insert(stack,colorset)
105 colorset = colorsets[name]
106 if not colorset then
107 colorset = { }
108 colorsets[name] = colorset
109 end
110end
111
112local function popset()
113 colorset = remove(stack)
114end
115
116local function setlist(name)
117 return table.sortedkeys(name and name ~= "" and colorsets[name] or colorsets.default or {})
118end
119
120colors.pushset = pushset
121colors.popset = popset
122colors.setlist = setlist
123
124
125
126local ctx_colordefagc = context.colordefagc
127local ctx_colordefagt = context.colordefagt
128local ctx_colordefalc = context.colordefalc
129local ctx_colordefalt = context.colordefalt
130local ctx_colordeffgc = context.colordeffgc
131local ctx_colordeffgt = context.colordeffgt
132local ctx_colordefflc = context.colordefflc
133local ctx_colordefflt = context.colordefflt
134local ctx_colordefrgc = context.colordefrgc
135local ctx_colordefrgt = context.colordefrgt
136local ctx_colordefrlc = context.colordefrlc
137local ctx_colordefrlt = context.colordefrlt
138
139local function definecolor(name, ca, global)
140 if ca and ca > 0 then
141 if global then
142 if trace_define then
143 report_colors("define global color %a with attribute %a",name,ca)
144 end
145 ctx_colordefagc(name,ca)
146 else
147 if trace_define then
148 report_colors("define local color %a with attribute %a",name,ca)
149 end
150 ctx_colordefalc(name,ca)
151 end
152 else
153 if global then
154 ctx_colordefrgc(name)
155 else
156 ctx_colordefrlc(name)
157 end
158 end
159 colorset[name] = true
160end
161
162local function inheritcolor(name, ca, global)
163 if ca and ca ~= "" then
164 if global then
165 if trace_define then
166 report_colors("inherit global color %a with attribute %a",name,ca)
167 end
168 ctx_colordeffgc(name,ca)
169 else
170 if trace_define then
171 report_colors("inherit local color %a with attribute %a",name,ca)
172 end
173 ctx_colordefflc(name,ca)
174 end
175 else
176 if global then
177 ctx_colordefrgc(name)
178 else
179 ctx_colordefrlc(name)
180 end
181 end
182 colorset[name] = true
183end
184
185local function definetransparent(name, ta, global)
186 if ta and ta > 0 then
187 if global then
188 if trace_define then
189 report_colors("define global transparency %a with attribute %a",name,ta)
190 end
191 ctx_colordefagt(name,ta)
192 else
193 if trace_define then
194 report_colors("define local transparency %a with attribute %a",name,ta)
195 end
196 ctx_colordefalt(name,ta)
197 end
198 else
199 if global then
200 ctx_colordefrgt(name)
201 else
202 ctx_colordefrlt(name)
203 end
204 end
205end
206
207local function inherittransparent(name, ta, global)
208 if ta and ta ~= "" then
209 if global then
210 if trace_define then
211 report_colors("inherit global transparency %a with attribute %a",name,ta)
212 end
213 ctx_colordeffgt(name,ta)
214 else
215 if trace_define then
216 report_colors("inherit local transparency %a with attribute %a",name,ta)
217 end
218 ctx_colordefflt(name,ta)
219 end
220 else
221 if global then
222 ctx_colordefrgt(name)
223 else
224 ctx_colordefrlt(name)
225 end
226 end
227end
228
229local transparent = {
230 none = 0,
231 normal = 1,
232 multiply = 2,
233 screen = 3,
234 overlay = 4,
235 softlight = 5,
236 hardlight = 6,
237 colordodge = 7,
238 colorburn = 8,
239 darken = 9,
240 lighten = 10,
241 difference = 11,
242 exclusion = 12,
243 hue = 13,
244 saturation = 14,
245 color = 15,
246 luminosity = 16,
247}
248
249transparencies.names = transparent
250
251local gray_okay = true
252local rgb_okay = true
253local cmyk_okay = true
254local spot_okay = true
255local multi_okay = true
256local forced = false
257
258function colors.forcesupport(gray,rgb,cmyk,spot,multi)
259 gray_okay, rgb_okay, cmyk_okay, spot_okay, multi_okay, forced = gray, rgb, cmyk, spot, multi, true
260 report_colors("supported models: gray %a, rgb %a, cmyk %a, spot %a",gray,rgb,cmyk,spot)
261end
262
263local function forcedmodel(model)
264 if not forced then
265 return model
266 elseif model == 2 then
267 if gray_okay then
268
269 elseif cmyk_okay then
270 return 4
271 elseif rgb_okay then
272 return 3
273 end
274 elseif model == 3 then
275 if rgb_okay then
276
277 elseif cmyk_okay then
278 return 4
279 elseif gray_okay then
280 return 2
281 end
282 elseif model == 4 then
283 if cmyk_okay then
284
285 elseif rgb_okay then
286 return 3
287 elseif gray_okay then
288 return 2
289 end
290 elseif model == 5 then
291 if spot_okay then
292 return 5
293 elseif cmyk_okay then
294 return 4
295 elseif rgb_okay then
296 return 3
297 elseif gray_okay then
298 return 2
299 end
300 end
301 return model
302end
303
304colors.forcedmodel = forcedmodel
305
306
307
308
309
310colors.couple = true
311
312local function definetransparency(name,n,global)
313 if n == v_reset then
314 definetransparent(name, 0, global)
315 return
316 end
317 local a = tonumber(n)
318 if a then
319 transparent[name] = a
320 return
321 end
322 local a = transparent[name]
323 if a then
324 transparent[name] = a
325 return
326 end
327 local settings = settings_to_hash_strict(n)
328 if settings then
329 local a = settings.a
330 local t = settings.t
331 if a and t then
332 definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global)
333 else
334 definetransparent(name, 0, global)
335 end
336 else
337 inherittransparent(name, n, global)
338 end
339end
340
341colors.definetransparency = definetransparency
342
343local registered = { }
344
345local function do_registerspotcolor(parent,parentnumber,e,f,d,p)
346 if not registered[parent] then
347 local v = colorvalues[parentnumber]
348 if v then
349 local model = currentmodel()
350 if model == 1 then
351 model = v[1]
352 end
353 if e and e ~= "" then
354 registrations.spotcolorname(parent,e)
355 end
356 if model == 2 then
357 registrations.grayspotcolor(parent,f,d,p,v[2])
358 elseif model == 3 then
359 registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
360 elseif model == 4 then
361 registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
362 end
363 end
364 registered[parent] = true
365 end
366end
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388function colors.definesimplegray(name,s)
389 return register_color(name,'gray',s)
390end
391
392local hexdigit = R("09","AF","af")
393local hexnumber = hexdigit * hexdigit / function(s) return tonumber(s,16)/255 end
394local hexpattern = hexnumber * (P(-1) + hexnumber * hexnumber * P(-1))
395local hexcolor = Cc("H") * P("#") * hexpattern
396
397local left = P("(")
398local right = P(")")
399local comma = P(",")
400local mixnumber = lpegpatterns.number / tonumber
401 + P("-") / function() return -1 end
402local mixname = C(P(1-left-right-comma)^1)
403
404local mixcolor = Cc("M") * mixnumber * left * mixname * (comma * mixname)^0 * right * P(-1)
405
406local exclamation = P("!")
407local pgfnumber = lpegpatterns.digit^0 / function(s) return tonumber(s)/100 end
408local pgfname = C(P(1-exclamation)^1)
409local pgfcolor = Cc("P") * pgfname * exclamation * pgfnumber * (exclamation * pgfname)^-1 * P(-1)
410
411local specialcolor = hexcolor + mixcolor
412
413local l_color = attributes.list[a_color]
414local l_transparency = attributes.list[a_transparency]
415
416directives.register("colors.pgf",function(v)
417 if v then
418 specialcolor = hexcolor + mixcolor + pgfcolor
419 else
420 specialcolor = hexcolor + mixcolor
421 end
422end)
423
424local defineintermediatecolor
425
426local function resolvedname(name)
427 local color
428 if valid[name] then
429 color = counts[name]
430 if color then
431 color = texgetcount(color)
432 else
433 color = l_color[name]
434 end
435 else
436 color = l_color[name]
437 end
438 return color, l_transparency[name]
439end
440
441local function defineprocesscolor(name,str,global,freeze)
442 local what, one, two, three = lpegmatch(specialcolor,str)
443 if what == "H" then
444
445 definecolor(name, register_color(name,'rgb',one,two,three),global)
446 elseif what == "M" then
447
448
449 local c1, t1 = resolvedname(two)
450 local c2, t2 = resolvedname(three)
451 return defineintermediatecolor(name,one,c1,c2,t1,t2,"",global,freeze)
452 elseif what == "P" then
453
454
455 local c1, t1 = resolvedname(one)
456 local c2, t2 = resolvedname(three)
457 return defineintermediatecolor(name,two,c1,c2,t1,t2,"",global,freeze)
458 else
459 local settings = settings_to_hash_strict(str)
460 if settings then
461 local r = settings.r
462 local g = settings.g
463 local b = settings.b
464 local w = settings.w
465 if r or g or (b and not w) then
466
467 definecolor(name, register_color(name,'rgb', tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0), global)
468 else
469 local c = settings.c
470 local m = settings.m
471 local y = settings.y
472 local k = settings.k
473 if c or m or y or k then
474 definecolor(name, register_color(name,'cmyk',tonumber(c) or 0, tonumber(m) or 0, tonumber(y) or 0, tonumber(k) or 0), global)
475 else
476 local h = settings.h
477 local s = settings.s
478 local v = settings.v
479 if v then
480 r, g, b = colors.hsvtorgb(tonumber(h) or 0, tonumber(s) or 1, tonumber(v) or 1)
481 definecolor(name, register_color(name,'rgb',r,g,b), global)
482 else
483 if w then
484 r, g, b = colors.hwbtorgb(tonumber(h) or 0, tonumber(b) or 1, tonumber(w) or 1)
485 definecolor(name, register_color(name,'rgb',r,g,b), global)
486 else
487 local x = settings.x or h
488 if x then
489 r, g, b = lpegmatch(hexpattern,x)
490 if r and g and b then
491 definecolor(name, register_color(name,'rgb',r,g,b), global)
492 else
493 definecolor(name, register_color(name,'gray',r or 0), global)
494 end
495 else
496 definecolor(name, register_color(name,'gray',tonumber(s) or 0), global)
497 end
498 end
499 end
500 end
501 end
502 local a = settings.a
503 local t = settings.t
504 if a and t then
505 definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global)
506 elseif colors.couple then
507
508 definetransparent(name, 0, global)
509 end
510 elseif freeze then
511 local ca = attributes_list[a_color] [str]
512 local ta = attributes_list[a_transparency][str]
513 if ca then
514 definecolor(name, ca, global)
515 end
516 if ta then
517 definetransparent(name, ta, global)
518 end
519 else
520 inheritcolor(name, str, global)
521 inherittransparent(name, str, global)
522
523
524
525
526 end
527 end
528 colorset[name] = true
529end
530
531local function definelabcolor(name,str,global,freeze)
532 local settings = settings_to_hash_strict(str)
533 if settings then
534 local s
535 local a = settings.a
536 local t = settings.t
537 local l = settings.l
538 if l then
539 local c = settings.c
540 local h = settings.h
541
542 if c and h then
543 local r, g, b = colors.lchtorgb(tonumber(l) or 0, tonumber(c) or 0, tonumber(h) or 0)
544 definecolor(name, register_color(name,'rgb',r,g,b), global)
545 goto TRANSPARENCY
546 end
547
548 local b = settings.b
549 if a and b then
550 local r, g, b = colors.labtorgb(tonumber(l) or 0, tonumber(a) or 0, tonumber(b) or 0)
551 definecolor(name, register_color(name,'rgb',r,g,b), global)
552 goto TRANSPARENCY
553 end
554 else
555 local x = settings.x
556 local y = settings.z
557 local z = settings.z
558 if x and y and z then
559 local r, g, b = colors.xyztorgb(tonumber(x) or 0, tonumber(y) or 0, tonumber(z) or 0)
560 definecolor(name, register_color(name,'rgb',r,g,b), global)
561 goto TRANSPARENCY
562 end
563 end
564
565 s = settings.s
566 definecolor(name, register_color(name,'gray',tonumber(s) or 0), global)
567 ::TRANSPARENCY::
568 if a and t then
569 definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global)
570 elseif colors.couple then
571
572 definetransparent(name, 0, global)
573 end
574 elseif freeze then
575 local ca = attributes_list[a_color] [str]
576 local ta = attributes_list[a_transparency][str]
577 if ca then
578 definecolor(name, ca, global)
579 end
580 if ta then
581 definetransparent(name, ta, global)
582 end
583 else
584 inheritcolor(name, str, global)
585 inherittransparent(name, str, global)
586
587
588
589
590 end
591 colorset[name] = true
592end
593
594
595
596
597local function defineprocesscolordirect(settings)
598 if settings then
599 local name = settings.name
600 if name then
601 local r = settings.r
602 local g = settings.g
603 local b = settings.b
604 local w = settings.w
605 if r or g or (b and not w) then
606
607 register_color(name,'rgb', r or 0, g or 0, b or 0)
608 else
609 local c = settings.c
610 local m = settings.m
611 local y = settings.y
612 local k = settings.k
613 if c or m or y or k then
614 register_color(name,'cmyk',c or 0, m or 0, y or 0, k or 0)
615 else
616 local h = settings.h
617 local s = settings.s
618 local v = settings.v
619 if v then
620 r, g, b = colors.hsvtorgb(h or 0, s or 1, v or 1)
621 register_color(name,'rgb',r,g,b)
622 else
623 if w then
624 r, g, b = colors.hwbtorgb((tonumber(h) or 0) / 360, tonumber(b) or 1, tonumber(w) or 1)
625 register_color(name,'rgb',r,g,b)
626 else
627 local x = settings.x or h
628 if x then
629 r, g, b = lpegmatch(hexpattern,x)
630 if r and g and b then
631 register_color(name,'rgb',r,g,b)
632 else
633 register_color(name,'gray',r or 0)
634 end
635 else
636 register_color(name,'gray',s or 0)
637 end
638 end
639 end
640 end
641 end
642 local a = settings.a
643 local t = settings.t
644 if a and t then
645 transparencies.register(name,transparent[a] or a or 1,t or 1)
646 end
647 colorset[name] = true
648 valid[name] = true
649 end
650 end
651end
652
653local function isblack(ca)
654 local cv = ca > 0 and colorvalues[ca]
655 return (cv and cv[2] == 0) or false
656end
657
658colors.isblack = isblack
659
660
661
662
663
664local function definespotcolor(name,parent,str,global)
665 if parent == "" or find(parent,"=",1,true) then
666 colors.registerspotcolor(name, parent)
667 elseif name ~= parent then
668 local cp = attributes_list[a_color][parent]
669 if cp then
670 local t = settings_to_hash_strict(str)
671 if t then
672 local tp = tonumber(t.p) or 1
673 do_registerspotcolor(parent,cp,t.e,1,"",tp)
674 if name and name ~= "" then
675 definecolor(name,register_color(name,'spot',parent,1,"",tp),true)
676 local ta = t.a
677 local tt = t.t
678 if ta and tt then
679 definetransparent(name, transparencies.register(name,transparent[ta] or tonumber(ta) or 1,tonumber(tt) or 1), global)
680 elseif colors.couple then
681
682 definetransparent(name, 0, global)
683 end
684 end
685 end
686 end
687 end
688 colorset[name] = true
689end
690
691function colors.registerspotcolor(parent, str)
692 local cp = attributes_list[a_color][parent]
693 if cp then
694 local e = ""
695 if str then
696 local t = settings_to_hash_strict(str)
697 e = (t and t.e) or ""
698 end
699 do_registerspotcolor(parent, cp, e, 1, "", 1)
700 end
701end
702
703local function f(i,colors,fraction)
704 local otf = 0
705 if type(fraction) == "table" then
706 for c=1,#colors do
707 otf = otf + (tonumber(fraction[c]) or 1) * colors[c][i]
708 end
709 else
710 fraction = tonumber(fraction)
711 for c=1,#colors do
712 otf = otf + fraction * colors[c]
713 end
714 end
715 if otf > 1 then
716 otf = 1
717 end
718 return otf
719end
720
721local function definemixcolor(makecolor,name,fractions,cs,global,freeze)
722 local values = { }
723 for i=1,#cs do
724 local v = colorvalues[cs[i]]
725 if not v then
726 return
727 end
728 colorvalues[i] = v
729 end
730 if #values > 0 then
731 csone = values[1][1]
732 local ca
733 if csone == 2 then
734 ca = register_color(name,'gray',f(2,values,fractions))
735 elseif csone == 3 then
736 ca = register_color(name,'rgb', f(3,values,fractions),
737 f(4,values,fractions),
738 f(5,values,fractions))
739 elseif csone == 4 then
740 ca = register_color(name,'cmyk',f(6,values,fractions),
741 f(7,values,fractions),
742 f(8,values,fractions),
743 f(9,values,fractions))
744 else
745 ca = register_color(name,'gray',f(2,values,fractions))
746 end
747 definecolor(name,ca,global,freeze)
748 else
749 report_colors("invalid specification of components for color %a",makecolor)
750 end
751end
752
753local function definemultitonecolor(name,multispec,colorspec,selfspec)
754 local dd = { }
755 local pp = { }
756 local nn = { }
757 local max = 0
758 for k,v in gmatch(multispec,"([^=,]+)=([^%,]*)") do
759 max = max + 1
760 dd[max] = k
761 pp[max] = v
762 nn[max] = formatters["%s_%1.3g"](k,tonumber(v) or 0)
763 end
764 if max > 0 then
765 nn = concat(nn,'_')
766 local parent = gsub(lower(nn),"[^%d%a%.]+","_")
767 if not colorspec or colorspec == "" then
768
769 local cc = { }
770 for i=1,max do
771 cc[i] = resolvedname(dd[i])
772 end
773 definemixcolor(name,parent,pp,cc,true,true)
774 else
775 if selfspec ~= "" then
776 colorspec = colorspec .. "," .. selfspec
777 end
778 defineprocesscolor(parent,colorspec,true,true)
779 end
780 local cp = attributes_list[a_color][parent]
781 dd, pp = concat(dd,','), concat(pp,',')
782 if cp then
783 do_registerspotcolor(parent, cp, "", max, dd, pp)
784 definecolor(name, register_color(name, 'spot', parent, max, dd, pp), true)
785 local t = settings_to_hash_strict(selfspec)
786 if t and t.a and t.t then
787 definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
788 elseif colors.couple then
789
790 definetransparent(name, 0, global)
791 end
792 end
793 end
794 colorset[name] = true
795end
796
797colors.defineprocesscolor = defineprocesscolor
798colors.definespotcolor = definespotcolor
799colors.definemultitonecolor = definemultitonecolor
800
801colors.defineprocesscolordirect = defineprocesscolordirect
802
803
804
805
806
807local function mpcolor(model,ca,ta,default,name)
808 local cv = colorvalues[ca]
809 if cv then
810 local tv = transparencyvalues[ta]
811
812 local cm = cv[1]
813 if model == 1 then
814 model = cm
815 end
816 model = forcedmodel(model)
817 if cm == 5 and model == 4 then
818 model = 5
819 end
820 if tv then
821 if model == 2 then
822 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
823 elseif model == 3 then
824 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
825 elseif model == 4 then
826 return formatters["transparent(%s,%s,(%s,%s,%s,%s))"](tv[1],tv[2],cv[6],cv[7],cv[8],cv[9])
827 elseif model == 5 then
828
829 return formatters['transparent(%s,%s,namedcolor("%s"))'](tv[1],tv[2],name or cv[10])
830 else
831 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
832 end
833 else
834 if model == 2 then
835 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
836 elseif model == 3 then
837 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
838 elseif model == 4 then
839 return formatters["(%s,%s,%s,%s)"](cv[6],cv[7],cv[8],cv[9])
840 elseif model == 5 then
841 return formatters['namedcolor("%s")'](name or cv[10])
842 else
843 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
844 end
845 end
846 end
847 local tv = transparencyvalues[ta]
848 if tv then
849 return formatters["(%s,%s)"](tv[1],tv[2])
850 end
851 default = default or 0
852 return formatters["(%s,%s,%s)"](default,default,default)
853end
854
855
856
857
858
859local colornamespace = getnamespace("colornumber")
860local paletnamespace = getnamespace("colorpalet")
861
862local function namedcolorattributes(name)
863 local space = texgetattribute(a_colormodel)
864
865 local prefix = texgetmacro("currentcolorprefix")
866 local color
867 if prefix ~= "" then
868 color = valid[prefix..name]
869 if not color then
870 local n = paletnamespace .. prefix .. name
871 color = valid[n]
872 if not color then
873 color = name
874 elseif color == true then
875 color = n
876 end
877 elseif color == true then
878 color = paletnamespace .. prefix .. name
879 end
880 else
881 color = valid[name]
882 if not color then
883 return space, l_color.black
884 elseif color == true then
885 color = name
886 end
887 end
888 color = counts[color]
889 if color then
890 color = texgetcount(color)
891 else
892 color = l_color[name]
893 end
894 if color then
895 return space, color, l_transparency[name]
896 else
897 return space, l_color.black
898 end
899end
900
901colors.namedcolorattributes = namedcolorattributes
902
903local function mpnamedcolor(name)
904 local model, ca, ta = namedcolorattributes(name)
905 return mpcolor(model,ca,ta,nil,name)
906end
907
908local function mpoptions(model,ca,ta,default)
909 return formatters["withcolor %s"](mpcolor(model,ca,ta,default))
910end
911
912colors.mpcolor = mpcolor
913colors.mpnamedcolor = mpnamedcolor
914colors.mpoptions = mpoptions
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938local function formatcolor(ca,separator)
939 local cv = colorvalues[ca]
940 if cv then
941 local c, cn, f, t, model = { }, 0, 13, 13, cv[1]
942 if model == 2 then
943 f, t = 2, 2
944 elseif model == 3 then
945 f, t = 3, 5
946 elseif model == 4 then
947 f, t = 6, 9
948 end
949 for i=f,t do
950 cn = cn + 1
951 c[cn] = format("%0.3f",cv[i])
952 end
953 return concat(c,separator)
954 else
955 return "0.000"
956 end
957end
958
959local function formatgray(ca,separator)
960 local cv = colorvalues[ca]
961 return format("%0.3f",(cv and cv[2]) or 0)
962end
963
964colors.formatcolor = formatcolor
965colors.formatgray = formatgray
966
967local f_gray = formatters["s=%1.3f"]
968local f_rgb = formatters["r=%1.3f%sg=%1.3f%sb=%1.3f"]
969local f_cmyk = formatters["c=%1.3f%sm=%1.3f%sy=%1.3f%sk=%1.3f"]
970local f_spot_name = formatters["p=%s"]
971local f_spot_value = formatters["p=%1.3f"]
972local f_transparency = formatters["a=%1.3f%st=%1.3f"]
973local f_both = formatters["%s%s%s"]
974
975local function colorcomponents(ca,separator)
976 local cv = colorvalues[ca]
977 if cv then
978 local model = cv[1]
979 if model == 2 then
980 return f_gray(cv[2])
981 elseif model == 3 then
982 return f_rgb(cv[3],separator or " ",cv[4],separator or " ",cv[5])
983 elseif model == 4 then
984 return f_cmyk(cv[6],separator or " ",cv[7],separator or " ",cv[8],separator or " ",cv[9])
985 elseif type(cv[13]) == "string" then
986 return f_spot_name(cv[13])
987 else
988 return f_spot_value(cv[13])
989 end
990 else
991 return ""
992 end
993end
994
995local function transparencycomponents(ta,separator)
996 local tv = transparencyvalues[ta]
997 if tv then
998 return f_transparency(tv[1],separator or " ",tv[2])
999 else
1000 return ""
1001 end
1002end
1003
1004local function processcolorcomponents(ca,separator)
1005 local cs = colorcomponents(ca,separator)
1006 local ts = transparencycomponents(ca,separator)
1007 if cs == "" then
1008 return ts
1009 elseif ts == "" then
1010 return cs
1011 else
1012 return f_both(cs,separator or " ",ts)
1013 end
1014end
1015
1016local function spotcolorname(ca,default)
1017 local cv, v = colorvalues[ca], "unknown"
1018 if not cv and type(ca) == "string" then
1019 ca = resolvedname(ca)
1020 cv = colorvalues[ca]
1021 end
1022 if cv and cv[1] == 5 then
1023 v = cv[10]
1024 end
1025 return tostring(v)
1026end
1027
1028local function spotcolorparent(ca,default)
1029 local cv, v = colorvalues[ca], "unknown"
1030 if not cv and type(ca) == "string" then
1031 ca = resolvedname(ca)
1032 cv = colorvalues[ca]
1033 end
1034 if cv and cv[1] == 5 then
1035 v = cv[12]
1036 if v == "" then
1037 v = cv[10]
1038 end
1039 end
1040 return tostring(v)
1041end
1042
1043local function spotcolorvalue(ca,default)
1044 local cv, v = colorvalues[ca], 0
1045 if not cv and type(ca) == "string" then
1046 ca = resolvedname(ca)
1047 cv = colorvalues[ca]
1048 end
1049 if cv and cv[1] == 5 then
1050 v = cv[13]
1051 end
1052 return tostring(v)
1053end
1054
1055colors.colorcomponents = colorcomponents
1056colors.transparencycomponents = transparencycomponents
1057colors.processcolorcomponents = processcolorcomponents
1058colors.spotcolorname = spotcolorname
1059colors.spotcolorparent = spotcolorparent
1060colors.spotcolorvalue = spotcolorvalue
1061
1062
1063
1064local min = math.min
1065
1066
1067
1068local function inbetween(one,two,i,fraction)
1069 local o, t = one[i], two[i]
1070 local c = fraction < 0
1071 if c then
1072 fraction = - fraction
1073 end
1074 local otf = o + fraction * (t - o)
1075 if otf > 1 then
1076 otf = 1
1077 end
1078 if c then
1079 return 1 - otf
1080 else
1081 return otf
1082 end
1083end
1084
1085local function justone(one,fraction,i)
1086 local otf = fraction * one[i]
1087 if otf > 1 then
1088 otf = 1
1089 end
1090 return otf
1091end
1092
1093local function complement(one,fraction,i)
1094 local otf = - fraction * (1 - one[i])
1095 if otf > 1 then
1096 otf = 1
1097 end
1098 return otf
1099end
1100
1101colors.helpers = {
1102 inbetween = inbetween,
1103 justone = justone,
1104 complement = complement,
1105}
1106
1107defineintermediatecolor = function(name,fraction,c_one,c_two,a_one,a_two,specs,global,freeze)
1108 fraction = tonumber(fraction) or 1
1109 local one, two = colorvalues[c_one], colorvalues[c_two]
1110 if one then
1111 if two then
1112 local csone, cstwo = one[1], two[1]
1113
1114
1115
1116 local ca
1117 if csone == 2 then
1118 ca = register_color(name,'gray',inbetween(one,two,2,fraction))
1119 elseif csone == 3 then
1120 ca = register_color(name,'rgb', inbetween(one,two,3,fraction),
1121 inbetween(one,two,4,fraction),
1122 inbetween(one,two,5,fraction))
1123 elseif csone == 4 then
1124 ca = register_color(name,'cmyk',inbetween(one,two,6,fraction),
1125 inbetween(one,two,7,fraction),
1126 inbetween(one,two,8,fraction),
1127 inbetween(one,two,9,fraction))
1128 else
1129 ca = register_color(name,'gray',inbetween(one,two,2,fraction))
1130 end
1131 definecolor(name,ca,global,freeze)
1132
1133 else
1134 local inbetween = fraction < 0 and complement or justone
1135 local csone = one[1]
1136 local ca
1137 if csone == 2 then
1138 ca = register_color(name,'gray',inbetween(one,fraction,2))
1139 elseif csone == 3 then
1140 ca = register_color(name,'rgb', inbetween(one,fraction,3),
1141 inbetween(one,fraction,4),
1142 inbetween(one,fraction,5))
1143 elseif csone == 4 then
1144 ca = register_color(name,'cmyk',inbetween(one,fraction,6),
1145 inbetween(one,fraction,7),
1146 inbetween(one,fraction,8),
1147 inbetween(one,fraction,9))
1148 else
1149 ca = register_color(name,'gray',inbetween(one,fraction,2))
1150 end
1151 definecolor(name,ca,global,freeze)
1152 end
1153 end
1154 local one, two = transparencyvalues[a_one], transparencyvalues[a_two]
1155 local t = settings_to_hash_strict(specs)
1156 local ta = tonumber((t and t.a) or (one and one[1]) or (two and two[1]))
1157 local tt = tonumber((t and t.t) or (one and two and f(one,two,2,fraction)))
1158 if ta and tt then
1159 definetransparent(name,transparencies.register(name,ta,tt),global)
1160 end
1161end
1162
1163colors.defineintermediatecolor = defineintermediatecolor
1164
1165
1166
1167local patterns = {
1168 CONTEXTLMTXMODE > 0 and "colo-imp-%s.mkxl" or "",
1169 "colo-imp-%s.mkiv",
1170 "colo-imp-%s.tex",
1171
1172 "colo-%s.mkiv",
1173 "colo-%s.tex"
1174}
1175
1176local function action(name,foundname)
1177 context.loadfoundcolorsetfile(name,foundname)
1178end
1179
1180local function failure(name)
1181
1182 report_colors("unknown library %a",name)
1183end
1184
1185local function usecolors(name)
1186 resolvers.uselibrary {
1187 category = "color definition",
1188 name = name,
1189 patterns = patterns,
1190 action = action,
1191 failure = failure,
1192 onlyonce = true,
1193 }
1194end
1195
1196colors.usecolors = usecolors
1197
1198
1199
1200local currentpagecolormodel
1201
1202function colors.setpagecolormodel(model)
1203 currentpagecolormodel = model
1204end
1205
1206function colors.getpagecolormodel()
1207 return currentpagecolormodel
1208end
1209
1210
1211
1212local setcolormodel = colors.setmodel
1213
1214implement {
1215 name = "synccolorcount",
1216 actions = synccolorcount,
1217 arguments = { "string", CONTEXTLMTXMODE > 0 and "string" or "integer" }
1218}
1219
1220implement {
1221 name = "synccolor",
1222 actions = synccolor,
1223 arguments = "string",
1224}
1225
1226implement {
1227 name = "synccolorclone",
1228 actions = synccolorclone,
1229 arguments = "2 strings",
1230}
1231
1232implement {
1233 name = "setcolormodel",
1234 arguments = "2 strings",
1235 actions = function(model,weight)
1236 texsetattribute(a_colormodel,setcolormodel(model,weight))
1237 end
1238}
1239
1240implement {
1241 name = "setpagecolormodel",
1242 actions = colors.setpagecolormodel,
1243 arguments = "string",
1244}
1245
1246implement {
1247 name = "defineprocesscolorlocal",
1248 actions = defineprocesscolor,
1249 arguments = { "string", "string", false, "boolean" }
1250}
1251
1252implement {
1253 name = "defineprocesscolorglobal",
1254 actions = defineprocesscolor,
1255 arguments = { "string", "string", true, "boolean" }
1256}
1257
1258implement {
1259 name = "definelabcolorlocal",
1260 actions = definelabcolor,
1261 arguments = { "string", "string", false, "boolean" }
1262}
1263
1264implement {
1265 name = "definelabcolorglobal",
1266 actions = definelabcolor,
1267 arguments = { "string", "string", true, "boolean" }
1268}
1269
1270implement {
1271 name = "defineprocesscolordummy",
1272 actions = defineprocesscolor,
1273 arguments = { "'c_o_l_o_r'", "string", false, false }
1274}
1275
1276implement {
1277 name = "definespotcolorglobal",
1278 actions = definespotcolor,
1279 arguments = { "string", "string", "string", true }
1280}
1281
1282implement {
1283 name = "definemultitonecolorglobal",
1284 actions = definemultitonecolor,
1285 arguments = { "string", "string", "string", "string", true }
1286}
1287
1288implement {
1289 name = "registermaintextcolor",
1290 actions = function(main)
1291 colors.main = main
1292 end,
1293 arguments = "integer"
1294}
1295
1296implement {
1297 name = "definetransparency",
1298 actions = definetransparency,
1299 arguments = "2 strings"
1300}
1301
1302implement {
1303 name = "definetransparencyglobal",
1304 actions = definetransparency,
1305 arguments = { "string", "string", true }
1306}
1307
1308implement {
1309 name = "defineintermediatecolor",
1310 actions = defineintermediatecolor,
1311 arguments = { "string", "string", "integer", "integer", "integer", "integer", "string", false, "boolean" }
1312}
1313
1314implement { name = "spotcolorname", actions = { spotcolorname, context }, arguments = "integer" }
1315implement { name = "spotcolorparent", actions = { spotcolorparent, context }, arguments = "integer" }
1316implement { name = "spotcolorvalue", actions = { spotcolorvalue, context }, arguments = "integer" }
1317implement { name = "colorcomponents", actions = { colorcomponents, context }, arguments = { "integer", tokens.constant(",") } }
1318implement { name = "transparencycomponents", actions = { transparencycomponents, context }, arguments = { "integer", tokens.constant(",") } }
1319implement { name = "processcolorcomponents", actions = { processcolorcomponents, context }, arguments = { "integer", tokens.constant(",") } }
1320implement { name = "formatcolor", actions = { formatcolor, context }, arguments = { "integer", "string" } }
1321implement { name = "formatgray", actions = { formatgray, context }, arguments = { "integer", "string" } }
1322
1323implement {
1324 name = "mpcolor",
1325 actions = { mpcolor, context },
1326 arguments = { "integer", "integer", "integer" }
1327}
1328
1329implement {
1330 name = "mpoptions",
1331 actions = { mpoptions, context },
1332 arguments = { "integer", "integer", "integer" }
1333}
1334
1335local ctx_doifelse = commands.doifelse
1336
1337implement {
1338 name = "doifelsedrawingblack",
1339 actions = function() ctx_doifelse(isblack(texgetattribute(a_color))) end
1340}
1341
1342implement {
1343 name = "doifelseblack",
1344 actions = { isblack, ctx_doifelse },
1345 arguments = "integer"
1346}
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366implement { name = "startcolorset", actions = pushset, arguments = "string" }
1367implement { name = "stopcolorset", actions = popset }
1368implement { name = "usecolors", actions = usecolors, arguments = "string" }
1369
1370
1371
1372do
1373
1374 local function pgfxcolorspec(model,ca)
1375
1376 local cv = colorvalues[ca]
1377 local str
1378 if cv then
1379 if model and model ~= 0 then
1380 model = model
1381 else
1382 model = forcedmodel(texgetattribute(a_colormodel))
1383 if model == 1 then
1384 model = cv[1]
1385 end
1386 end
1387 if model == 3 then
1388 str = formatters["{rgb}{%1.3f,%1.3f,%1.3f}"](cv[3],cv[4],cv[5])
1389 elseif model == 4 then
1390 str = formatters["{cmyk}{%1.3f,%1.3f,%1.3f,%1.3f}"](cv[6],cv[7],cv[8],cv[9])
1391 else
1392 str = formatters["{rgb}{%1.3f,%1.3f,%1.3f}"](cv[2],cv[2],cv[2])
1393 end
1394 else
1395 str = "{rgb}{0,0,0}"
1396 end
1397 if trace_pgf then
1398 report_pgf("model %a, string %a",model,str)
1399 end
1400 return str
1401 end
1402
1403 implement {
1404 name = "pgfxcolorspec",
1405 actions = { pgfxcolorspec, context },
1406 arguments = { "integer", "integer" }
1407 }
1408
1409end
1410
1411
1412
1413local models = storage.allocate { "all", "gray", "rgb", "cmyk", "spot" }
1414
1415colors.models = models
1416
1417function colors.spec(name)
1418 local l = attributes_list[a_color]
1419 local t = colorvalues[l[name]] or colorvalues[l.black]
1420 return {
1421 model = models[t[1]] or models[1],
1422 s = t[2],
1423 r = t[3], g = t[4], b = t[5],
1424 c = t[6], m = t[7], y = t[8], k = t[9],
1425 }
1426end
1427
1428function colors.currentnamedmodel()
1429 return models[texgetattribute(a_colormodel)] or "gray"
1430end
1431
1432
1433
1434
1435implement {
1436 name = "negatedcolorcomponent",
1437 arguments = "string",
1438 actions = function(s)
1439 s = 1 - (tonumber(s) or 0)
1440 context((s < 0 and 0) or (s > 1 and 1) or s)
1441 end
1442}
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453do
1454
1455
1456
1457
1458 local function crap(v)
1459 return v <= 0.03928 and v/12.92 or (v+0.055/1.055)^2.4
1460 end
1461
1462 local function luminance(color)
1463 color = colorvalues[color]
1464 if color then
1465 return (0.2126 * crap(color[2]) + 0.7152 * crap(color[3]) + 0.0722 * crap(color[4])) + 0.05
1466 end
1467 end
1468
1469 local function formatluminance(color)
1470 local l = luminance(color)
1471 if l then
1472 return format("%0.3f",l)
1473 end
1474 end
1475
1476 local function formatluminanceratio(one,two)
1477 local one = luminance(one)
1478 local two = luminance(two)
1479 if one and two then
1480 return format("%0.3f",one > two and one/two or two/one)
1481 end
1482 end
1483
1484 colors.formatluminance = formatluminance
1485 colors.formatluminanceratio = formatluminanceratio
1486
1487 implement {
1488 name = "formatluminance",
1489
1490 arguments = "integer",
1491 actions = { formatluminance, context },
1492 }
1493
1494 implement {
1495 name = "formatluminanceratio",
1496
1497 arguments = { "integer", "integer" },
1498 actions = { formatluminanceratio, context },
1499 }
1500
1501end
1502 |