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