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
531
532
533
534local function defineprocesscolordirect(settings)
535 if settings then
536 local name = settings.name
537 if name then
538 local r = settings.r
539 local g = settings.g
540 local b = settings.b
541 local w = settings.w
542 if r or g or (b and not w) then
543
544 register_color(name,'rgb', r or 0, g or 0, b or 0)
545 else
546 local c = settings.c
547 local m = settings.m
548 local y = settings.y
549 local k = settings.k
550 if c or m or y or k then
551 register_color(name,'cmyk',c or 0, m or 0, y or 0, k or 0)
552 else
553 local h = settings.h
554 local s = settings.s
555 local v = settings.v
556 if v then
557 r, g, b = colors.hsvtorgb(h or 0, s or 1, v or 1)
558 register_color(name,'rgb',r,g,b)
559 else
560 if w then
561 r, g, b = colors.hwbtorgb((tonumber(h) or 0) / 360, tonumber(b) or 1, tonumber(w) or 1)
562 register_color(name,'rgb',r,g,b)
563 else
564 local x = settings.x or h
565 if x then
566 r, g, b = lpegmatch(hexpattern,x)
567 if r and g and b then
568 register_color(name,'rgb',r,g,b)
569 else
570 register_color(name,'gray',r or 0)
571 end
572 else
573 register_color(name,'gray',s or 0)
574 end
575 end
576 end
577 end
578 end
579 local a = settings.a
580 local t = settings.t
581 if a and t then
582 transparencies.register(name,transparent[a] or a or 1,t or 1)
583 end
584 colorset[name] = true
585 valid[name] = true
586 end
587 end
588end
589
590local function isblack(ca)
591 local cv = ca > 0 and colorvalues[ca]
592 return (cv and cv[2] == 0) or false
593end
594
595colors.isblack = isblack
596
597
598
599
600
601local function definespotcolor(name,parent,str,global)
602 if parent == "" or find(parent,"=",1,true) then
603 colors.registerspotcolor(name, parent)
604 elseif name ~= parent then
605 local cp = attributes_list[a_color][parent]
606 if cp then
607 local t = settings_to_hash_strict(str)
608 if t then
609 local tp = tonumber(t.p) or 1
610 do_registerspotcolor(parent,cp,t.e,1,"",tp)
611 if name and name ~= "" then
612 definecolor(name,register_color(name,'spot',parent,1,"",tp),true)
613 local ta = t.a
614 local tt = t.t
615 if ta and tt then
616 definetransparent(name, transparencies.register(name,transparent[ta] or tonumber(ta) or 1,tonumber(tt) or 1), global)
617 elseif colors.couple then
618
619 definetransparent(name, 0, global)
620 end
621 end
622 end
623 end
624 end
625 colorset[name] = true
626end
627
628function colors.registerspotcolor(parent, str)
629 local cp = attributes_list[a_color][parent]
630 if cp then
631 local e = ""
632 if str then
633 local t = settings_to_hash_strict(str)
634 e = (t and t.e) or ""
635 end
636 do_registerspotcolor(parent, cp, e, 1, "", 1)
637 end
638end
639
640local function f(i,colors,fraction)
641 local otf = 0
642 if type(fraction) == "table" then
643 for c=1,#colors do
644 otf = otf + (tonumber(fraction[c]) or 1) * colors[c][i]
645 end
646 else
647 fraction = tonumber(fraction)
648 for c=1,#colors do
649 otf = otf + fraction * colors[c]
650 end
651 end
652 if otf > 1 then
653 otf = 1
654 end
655 return otf
656end
657
658local function definemixcolor(makecolor,name,fractions,cs,global,freeze)
659 local values = { }
660 for i=1,#cs do
661 local v = colorvalues[cs[i]]
662 if not v then
663 return
664 end
665 colorvalues[i] = v
666 end
667 if #values > 0 then
668 csone = values[1][1]
669 local ca
670 if csone == 2 then
671 ca = register_color(name,'gray',f(2,values,fractions))
672 elseif csone == 3 then
673 ca = register_color(name,'rgb', f(3,values,fractions),
674 f(4,values,fractions),
675 f(5,values,fractions))
676 elseif csone == 4 then
677 ca = register_color(name,'cmyk',f(6,values,fractions),
678 f(7,values,fractions),
679 f(8,values,fractions),
680 f(9,values,fractions))
681 else
682 ca = register_color(name,'gray',f(2,values,fractions))
683 end
684 definecolor(name,ca,global,freeze)
685 else
686 report_colors("invalid specification of components for color %a",makecolor)
687 end
688end
689
690local function definemultitonecolor(name,multispec,colorspec,selfspec)
691 local dd = { }
692 local pp = { }
693 local nn = { }
694 local max = 0
695 for k,v in gmatch(multispec,"([^=,]+)=([^%,]*)") do
696 max = max + 1
697 dd[max] = k
698 pp[max] = v
699 nn[max] = formatters["%s_%1.3g"](k,tonumber(v) or 0)
700 end
701 if max > 0 then
702 nn = concat(nn,'_')
703 local parent = gsub(lower(nn),"[^%d%a%.]+","_")
704 if not colorspec or colorspec == "" then
705
706 local cc = { }
707 for i=1,max do
708 cc[i] = resolvedname(dd[i])
709 end
710 definemixcolor(name,parent,pp,cc,true,true)
711 else
712 if selfspec ~= "" then
713 colorspec = colorspec .. "," .. selfspec
714 end
715 defineprocesscolor(parent,colorspec,true,true)
716 end
717 local cp = attributes_list[a_color][parent]
718 dd, pp = concat(dd,','), concat(pp,',')
719 if cp then
720 do_registerspotcolor(parent, cp, "", max, dd, pp)
721 definecolor(name, register_color(name, 'spot', parent, max, dd, pp), true)
722 local t = settings_to_hash_strict(selfspec)
723 if t and t.a and t.t then
724 definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
725 elseif colors.couple then
726
727 definetransparent(name, 0, global)
728 end
729 end
730 end
731 colorset[name] = true
732end
733
734colors.defineprocesscolor = defineprocesscolor
735colors.definespotcolor = definespotcolor
736colors.definemultitonecolor = definemultitonecolor
737
738colors.defineprocesscolordirect = defineprocesscolordirect
739
740
741
742
743
744local function mpcolor(model,ca,ta,default,name)
745 local cv = colorvalues[ca]
746 if cv then
747 local tv = transparencyvalues[ta]
748
749 local cm = cv[1]
750 if model == 1 then
751 model = cm
752 end
753 model = forcedmodel(model)
754 if cm == 5 and model == 4 then
755 model = 5
756 end
757 if tv then
758 if model == 2 then
759 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
760 elseif model == 3 then
761 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
762 elseif model == 4 then
763 return formatters["transparent(%s,%s,(%s,%s,%s,%s))"](tv[1],tv[2],cv[6],cv[7],cv[8],cv[9])
764 elseif model == 5 then
765
766 return formatters['transparent(%s,%s,namedcolor("%s"))'](tv[1],tv[2],name or cv[10])
767 else
768 return formatters["transparent(%s,%s,(%s,%s,%s))"](tv[1],tv[2],cv[3],cv[4],cv[5])
769 end
770 else
771 if model == 2 then
772 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
773 elseif model == 3 then
774 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
775 elseif model == 4 then
776 return formatters["(%s,%s,%s,%s)"](cv[6],cv[7],cv[8],cv[9])
777 elseif model == 5 then
778 return formatters['namedcolor("%s")'](name or cv[10])
779 else
780 return formatters["(%s,%s,%s)"](cv[3],cv[4],cv[5])
781 end
782 end
783 end
784 local tv = transparencyvalues[ta]
785 if tv then
786 return formatters["(%s,%s)"](tv[1],tv[2])
787 end
788 default = default or 0
789 return formatters["(%s,%s,%s)"](default,default,default)
790end
791
792
793
794
795
796local colornamespace = getnamespace("colornumber")
797local paletnamespace = getnamespace("colorpalet")
798
799local function namedcolorattributes(name)
800 local space = texgetattribute(a_colormodel)
801
802 local prefix = texgetmacro("currentcolorprefix")
803 local color
804 if prefix ~= "" then
805 color = valid[prefix..name]
806 if not color then
807 local n = paletnamespace .. prefix .. name
808 color = valid[n]
809 if not color then
810 color = name
811 elseif color == true then
812 color = n
813 end
814 elseif color == true then
815 color = paletnamespace .. prefix .. name
816 end
817 else
818 color = valid[name]
819 if not color then
820 return space, l_color.black
821 elseif color == true then
822 color = name
823 end
824 end
825 color = counts[color]
826 if color then
827 color = texgetcount(color)
828 else
829 color = l_color[name]
830 end
831 if color then
832 return space, color, l_transparency[name]
833 else
834 return space, l_color.black
835 end
836end
837
838colors.namedcolorattributes = namedcolorattributes
839
840local function mpnamedcolor(name)
841 local model, ca, ta = namedcolorattributes(name)
842 return mpcolor(model,ca,ta,nil,name)
843end
844
845local function mpoptions(model,ca,ta,default)
846 return formatters["withcolor %s"](mpcolor(model,ca,ta,default))
847end
848
849colors.mpcolor = mpcolor
850colors.mpnamedcolor = mpnamedcolor
851colors.mpoptions = mpoptions
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875local function formatcolor(ca,separator)
876 local cv = colorvalues[ca]
877 if cv then
878 local c, cn, f, t, model = { }, 0, 13, 13, cv[1]
879 if model == 2 then
880 f, t = 2, 2
881 elseif model == 3 then
882 f, t = 3, 5
883 elseif model == 4 then
884 f, t = 6, 9
885 end
886 for i=f,t do
887 cn = cn + 1
888 c[cn] = format("%0.3f",cv[i])
889 end
890 return concat(c,separator)
891 else
892 return "0.000"
893 end
894end
895
896local function formatgray(ca,separator)
897 local cv = colorvalues[ca]
898 return format("%0.3f",(cv and cv[2]) or 0)
899end
900
901colors.formatcolor = formatcolor
902colors.formatgray = formatgray
903
904local f_gray = formatters["s=%1.3f"]
905local f_rgb = formatters["r=%1.3f%sg=%1.3f%sb=%1.3f"]
906local f_cmyk = formatters["c=%1.3f%sm=%1.3f%sy=%1.3f%sk=%1.3f"]
907local f_spot_name = formatters["p=%s"]
908local f_spot_value = formatters["p=%1.3f"]
909local f_transparency = formatters["a=%1.3f%st=%1.3f"]
910local f_both = formatters["%s%s%s"]
911
912local function colorcomponents(ca,separator)
913 local cv = colorvalues[ca]
914 if cv then
915 local model = cv[1]
916 if model == 2 then
917 return f_gray(cv[2])
918 elseif model == 3 then
919 return f_rgb(cv[3],separator or " ",cv[4],separator or " ",cv[5])
920 elseif model == 4 then
921 return f_cmyk(cv[6],separator or " ",cv[7],separator or " ",cv[8],separator or " ",cv[9])
922 elseif type(cv[13]) == "string" then
923 return f_spot_name(cv[13])
924 else
925 return f_spot_value(cv[13])
926 end
927 else
928 return ""
929 end
930end
931
932local function transparencycomponents(ta,separator)
933 local tv = transparencyvalues[ta]
934 if tv then
935 return f_transparency(tv[1],separator or " ",tv[2])
936 else
937 return ""
938 end
939end
940
941local function processcolorcomponents(ca,separator)
942 local cs = colorcomponents(ca,separator)
943 local ts = transparencycomponents(ca,separator)
944 if cs == "" then
945 return ts
946 elseif ts == "" then
947 return cs
948 else
949 return f_both(cs,separator or " ",ts)
950 end
951end
952
953local function spotcolorname(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[10]
961 end
962 return tostring(v)
963end
964
965local function spotcolorparent(ca,default)
966 local cv, v = colorvalues[ca], "unknown"
967 if not cv and type(ca) == "string" then
968 ca = resolvedname(ca)
969 cv = colorvalues[ca]
970 end
971 if cv and cv[1] == 5 then
972 v = cv[12]
973 if v == "" then
974 v = cv[10]
975 end
976 end
977 return tostring(v)
978end
979
980local function spotcolorvalue(ca,default)
981 local cv, v = colorvalues[ca], 0
982 if not cv and type(ca) == "string" then
983 ca = resolvedname(ca)
984 cv = colorvalues[ca]
985 end
986 if cv and cv[1] == 5 then
987 v = cv[13]
988 end
989 return tostring(v)
990end
991
992colors.colorcomponents = colorcomponents
993colors.transparencycomponents = transparencycomponents
994colors.processcolorcomponents = processcolorcomponents
995colors.spotcolorname = spotcolorname
996colors.spotcolorparent = spotcolorparent
997colors.spotcolorvalue = spotcolorvalue
998
999
1000
1001local min = math.min
1002
1003
1004
1005local function inbetween(one,two,i,fraction)
1006 local o, t = one[i], two[i]
1007 local c = fraction < 0
1008 if c then
1009 fraction = - fraction
1010 end
1011 local otf = o + fraction * (t - o)
1012 if otf > 1 then
1013 otf = 1
1014 end
1015 if c then
1016 return 1 - otf
1017 else
1018 return otf
1019 end
1020end
1021
1022local function justone(one,fraction,i)
1023 local otf = fraction * one[i]
1024 if otf > 1 then
1025 otf = 1
1026 end
1027 return otf
1028end
1029
1030local function complement(one,fraction,i)
1031 local otf = - fraction * (1 - one[i])
1032 if otf > 1 then
1033 otf = 1
1034 end
1035 return otf
1036end
1037
1038colors.helpers = {
1039 inbetween = inbetween,
1040 justone = justone,
1041 complement = complement,
1042}
1043
1044defineintermediatecolor = function(name,fraction,c_one,c_two,a_one,a_two,specs,global,freeze)
1045 fraction = tonumber(fraction) or 1
1046 local one, two = colorvalues[c_one], colorvalues[c_two]
1047 if one then
1048 if two then
1049 local csone, cstwo = one[1], two[1]
1050
1051
1052
1053 local ca
1054 if csone == 2 then
1055 ca = register_color(name,'gray',inbetween(one,two,2,fraction))
1056 elseif csone == 3 then
1057 ca = register_color(name,'rgb', inbetween(one,two,3,fraction),
1058 inbetween(one,two,4,fraction),
1059 inbetween(one,two,5,fraction))
1060 elseif csone == 4 then
1061 ca = register_color(name,'cmyk',inbetween(one,two,6,fraction),
1062 inbetween(one,two,7,fraction),
1063 inbetween(one,two,8,fraction),
1064 inbetween(one,two,9,fraction))
1065 else
1066 ca = register_color(name,'gray',inbetween(one,two,2,fraction))
1067 end
1068 definecolor(name,ca,global,freeze)
1069
1070 else
1071 local inbetween = fraction < 0 and complement or justone
1072 local csone = one[1]
1073 local ca
1074 if csone == 2 then
1075 ca = register_color(name,'gray',inbetween(one,fraction,2))
1076 elseif csone == 3 then
1077 ca = register_color(name,'rgb', inbetween(one,fraction,3),
1078 inbetween(one,fraction,4),
1079 inbetween(one,fraction,5))
1080 elseif csone == 4 then
1081 ca = register_color(name,'cmyk',inbetween(one,fraction,6),
1082 inbetween(one,fraction,7),
1083 inbetween(one,fraction,8),
1084 inbetween(one,fraction,9))
1085 else
1086 ca = register_color(name,'gray',inbetween(one,fraction,2))
1087 end
1088 definecolor(name,ca,global,freeze)
1089 end
1090 end
1091 local one, two = transparencyvalues[a_one], transparencyvalues[a_two]
1092 local t = settings_to_hash_strict(specs)
1093 local ta = tonumber((t and t.a) or (one and one[1]) or (two and two[1]))
1094 local tt = tonumber((t and t.t) or (one and two and f(one,two,2,fraction)))
1095 if ta and tt then
1096 definetransparent(name,transparencies.register(name,ta,tt),global)
1097 end
1098end
1099
1100colors.defineintermediatecolor = defineintermediatecolor
1101
1102
1103
1104local patterns = {
1105 CONTEXTLMTXMODE > 0 and "colo-imp-%s.mkxl" or "",
1106 "colo-imp-%s.mkiv",
1107 "colo-imp-%s.tex",
1108
1109 "colo-%s.mkiv",
1110 "colo-%s.tex"
1111}
1112
1113local function action(name,foundname)
1114 context.loadfoundcolorsetfile(name,foundname)
1115end
1116
1117local function failure(name)
1118
1119 report_colors("unknown library %a",name)
1120end
1121
1122local function usecolors(name)
1123 resolvers.uselibrary {
1124 category = "color definition",
1125 name = name,
1126 patterns = patterns,
1127 action = action,
1128 failure = failure,
1129 onlyonce = true,
1130 }
1131end
1132
1133colors.usecolors = usecolors
1134
1135
1136
1137local currentpagecolormodel
1138
1139function colors.setpagecolormodel(model)
1140 currentpagecolormodel = model
1141end
1142
1143function colors.getpagecolormodel()
1144 return currentpagecolormodel
1145end
1146
1147
1148
1149local setcolormodel = colors.setmodel
1150
1151implement {
1152 name = "synccolorcount",
1153 actions = synccolorcount,
1154 arguments = { "string", CONTEXTLMTXMODE > 0 and "string" or "integer" }
1155}
1156
1157implement {
1158 name = "synccolor",
1159 actions = synccolor,
1160 arguments = "string",
1161}
1162
1163implement {
1164 name = "synccolorclone",
1165 actions = synccolorclone,
1166 arguments = "2 strings",
1167}
1168
1169implement {
1170 name = "setcolormodel",
1171 arguments = "2 strings",
1172 actions = function(model,weight)
1173 texsetattribute(a_colormodel,setcolormodel(model,weight))
1174 end
1175}
1176
1177implement {
1178 name = "setpagecolormodel",
1179 actions = colors.setpagecolormodel,
1180 arguments = "string",
1181}
1182
1183implement {
1184 name = "defineprocesscolorlocal",
1185 actions = defineprocesscolor,
1186 arguments = { "string", "string", false, "boolean" }
1187}
1188
1189implement {
1190 name = "defineprocesscolorglobal",
1191 actions = defineprocesscolor,
1192 arguments = { "string", "string", true, "boolean" }
1193}
1194
1195implement {
1196 name = "defineprocesscolordummy",
1197 actions = defineprocesscolor,
1198 arguments = { "'c_o_l_o_r'", "string", false, false }
1199}
1200
1201implement {
1202 name = "definespotcolorglobal",
1203 actions = definespotcolor,
1204 arguments = { "string", "string", "string", true }
1205}
1206
1207implement {
1208 name = "definemultitonecolorglobal",
1209 actions = definemultitonecolor,
1210 arguments = { "string", "string", "string", "string", true }
1211}
1212
1213implement {
1214 name = "registermaintextcolor",
1215 actions = function(main)
1216 colors.main = main
1217 end,
1218 arguments = "integer"
1219}
1220
1221implement {
1222 name = "definetransparency",
1223 actions = definetransparency,
1224 arguments = "2 strings"
1225}
1226
1227implement {
1228 name = "definetransparencyglobal",
1229 actions = definetransparency,
1230 arguments = { "string", "string", true }
1231}
1232
1233implement {
1234 name = "defineintermediatecolor",
1235 actions = defineintermediatecolor,
1236 arguments = { "string", "string", "integer", "integer", "integer", "integer", "string", false, "boolean" }
1237}
1238
1239implement { name = "spotcolorname", actions = { spotcolorname, context }, arguments = "integer" }
1240implement { name = "spotcolorparent", actions = { spotcolorparent, context }, arguments = "integer" }
1241implement { name = "spotcolorvalue", actions = { spotcolorvalue, context }, arguments = "integer" }
1242implement { name = "colorcomponents", actions = { colorcomponents, context }, arguments = { "integer", tokens.constant(",") } }
1243implement { name = "transparencycomponents", actions = { transparencycomponents, context }, arguments = { "integer", tokens.constant(",") } }
1244implement { name = "processcolorcomponents", actions = { processcolorcomponents, context }, arguments = { "integer", tokens.constant(",") } }
1245implement { name = "formatcolor", actions = { formatcolor, context }, arguments = { "integer", "string" } }
1246implement { name = "formatgray", actions = { formatgray, context }, arguments = { "integer", "string" } }
1247
1248implement {
1249 name = "mpcolor",
1250 actions = { mpcolor, context },
1251 arguments = { "integer", "integer", "integer" }
1252}
1253
1254implement {
1255 name = "mpoptions",
1256 actions = { mpoptions, context },
1257 arguments = { "integer", "integer", "integer" }
1258}
1259
1260local ctx_doifelse = commands.doifelse
1261
1262implement {
1263 name = "doifelsedrawingblack",
1264 actions = function() ctx_doifelse(isblack(texgetattribute(a_color))) end
1265}
1266
1267implement {
1268 name = "doifelseblack",
1269 actions = { isblack, ctx_doifelse },
1270 arguments = "integer"
1271}
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291implement { name = "startcolorset", actions = pushset, arguments = "string" }
1292implement { name = "stopcolorset", actions = popset }
1293implement { name = "usecolors", actions = usecolors, arguments = "string" }
1294
1295
1296
1297do
1298
1299 local function pgfxcolorspec(model,ca)
1300
1301 local cv = colorvalues[ca]
1302 local str
1303 if cv then
1304 if model and model ~= 0 then
1305 model = model
1306 else
1307 model = forcedmodel(texgetattribute(a_colormodel))
1308 if model == 1 then
1309 model = cv[1]
1310 end
1311 end
1312 if model == 3 then
1313 str = formatters["{rgb}{%1.3f,%1.3f,%1.3f}"](cv[3],cv[4],cv[5])
1314 elseif model == 4 then
1315 str = formatters["{cmyk}{%1.3f,%1.3f,%1.3f,%1.3f}"](cv[6],cv[7],cv[8],cv[9])
1316 else
1317 str = formatters["{rgb}{%1.3f,%1.3f,%1.3f}"](cv[2],cv[2],cv[2])
1318 end
1319 else
1320 str = "{rgb}{0,0,0}"
1321 end
1322 if trace_pgf then
1323 report_pgf("model %a, string %a",model,str)
1324 end
1325 return str
1326 end
1327
1328 implement {
1329 name = "pgfxcolorspec",
1330 actions = { pgfxcolorspec, context },
1331 arguments = { "integer", "integer" }
1332 }
1333
1334end
1335
1336
1337
1338local models = storage.allocate { "all", "gray", "rgb", "cmyk", "spot" }
1339
1340colors.models = models
1341
1342function colors.spec(name)
1343 local l = attributes_list[a_color]
1344 local t = colorvalues[l[name]] or colorvalues[l.black]
1345 return {
1346 model = models[t[1]] or models[1],
1347 s = t[2],
1348 r = t[3], g = t[4], b = t[5],
1349 c = t[6], m = t[7], y = t[8], k = t[9],
1350 }
1351end
1352
1353function colors.currentnamedmodel()
1354 return models[texgetattribute(a_colormodel)] or "gray"
1355end
1356
1357
1358
1359
1360implement {
1361 name = "negatedcolorcomponent",
1362 arguments = "string",
1363 actions = function(s)
1364 s = 1 - (tonumber(s) or 0)
1365 context((s < 0 and 0) or (s > 1 and 1) or s)
1366 end
1367}
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378do
1379
1380
1381
1382
1383 local function crap(v)
1384 return v <= 0.03928 and v/12.92 or (v+0.055/1.055)^2.4
1385 end
1386
1387 local function luminance(color)
1388 color = colorvalues[color]
1389 if color then
1390 return (0.2126 * crap(color[2]) + 0.7152 * crap(color[3]) + 0.0722 * crap(color[4])) + 0.05
1391 end
1392 end
1393
1394 local function formatluminance(color)
1395 local l = luminance(color)
1396 if l then
1397 return format("%0.3f",l)
1398 end
1399 end
1400
1401 local function formatluminanceratio(one,two)
1402 local one = luminance(one)
1403 local two = luminance(two)
1404 if one and two then
1405 return format("%0.3f",one > two and one/two or two/one)
1406 end
1407 end
1408
1409 colors.formatluminance = formatluminance
1410 colors.formatluminanceratio = formatluminanceratio
1411
1412 implement {
1413 name = "formatluminance",
1414
1415 arguments = "integer",
1416 actions = { formatluminance, context },
1417 }
1418
1419 implement {
1420 name = "formatluminanceratio",
1421
1422 arguments = { "integer", "integer" },
1423 actions = { formatluminanceratio, context },
1424 }
1425
1426end
1427 |