luametafun-color.tex /size: 12 Kb    last modification: 2025-02-21 11:03
1% language=us runpath=texruns:manuals/luametafun
2
3\environment luametafun-style
4
5\startcomponent luametafun-color
6
7\startchapter[title={Color}]
8
9\startsection[title=Lab colors]
10
11There are by now plenty of examples made by users that use color and \METAFUN\
12provides all kind of helpers. So do we need more? When I play around with things
13or when users come with questions that then result in a nice looking graphic, the
14result might en dup as example of coding. The following is an example of showing
15of colors. We have a helper that goes from a so called lab specification to rgb
16and it does that via xyz transformations. It makes no real sense to interface
17this beyond this converter. We use this opportunity to demonstrate how to make
18an interface.
19
20\startbuffer
21\startMPdefinitions
22  vardef cielabmatrix(expr l, mina, maxa, minb, maxb, stp) =
23    image (
24      for a = mina step stp until maxa :
25        for b = minb step stp until maxb :
26          draw (a,b) withcolor labtorgb(l,a,b) ;
27        endfor ;
28      endfor ;
29    )
30  enddef ;
31\stopMPdefinitions
32\stopbuffer
33
34\typebuffer[option=TEX]
35
36\getbuffer
37
38Here we define a macro that makes a color matrix. It can be used as follows
39
40\startbuffer
41\startcombination[nx=4,ny=1]
42  {\startMPcode draw cielabmatrix(20, -100, 100, -100, 100, 5) ysized 35mm withpen pencircle scaled 2.5 ; \stopMPcode} {\type {l = 20}}
43  {\startMPcode draw cielabmatrix(40, -100, 100, -100, 100, 5) ysized 35mm withpen pencircle scaled 2.5 ; \stopMPcode} {\type {l = 40}}
44  {\startMPcode draw cielabmatrix(60, -100, 100, -100, 100, 5) ysized 35mm withpen pencircle scaled 2.5 ; \stopMPcode} {\type {l = 60}}
45  {\startMPcode draw cielabmatrix(80, -100, 100, -100, 100, 5) ysized 35mm withpen pencircle scaled 2.5 ; \stopMPcode} {\type {l = 80}}
46\stopcombination
47\stopbuffer
48
49\typebuffer[option=TEX]
50
51\startlinecorrection
52\getbuffer
53\stoplinecorrection
54
55One can of course mess around a bit:
56
57\startbuffer
58\startcombination[nx=4,ny=1]
59  {\startMPcode draw cielabmatrix(20, -100, 100, -100, 100, 10) ysized 35mm randomized 1 withpen pensquare scaled 4 ; \stopMPcode} {\type {l = 20}}
60  {\startMPcode draw cielabmatrix(40, -100, 100, -100, 100, 10) ysized 35mm randomized 1 withpen pensquare scaled 4 ; \stopMPcode} {\type {l = 40}}
61  {\startMPcode draw cielabmatrix(60, -100, 100, -100, 100, 10) ysized 35mm randomized 1 withpen pensquare scaled 4 ; \stopMPcode} {\type {l = 60}}
62  {\startMPcode draw cielabmatrix(80, -100, 100, -100, 100, 10) ysized 35mm randomized 1 withpen pensquare scaled 4 ; \stopMPcode} {\type {l = 80}}
63\stopcombination
64\stopbuffer
65
66\typebuffer[option=TEX]
67
68\startlinecorrection
69\getbuffer
70\stoplinecorrection
71
72Normally, when you don't go beyond this kind of usage, a simple macro like the
73above will do. But when you want to make something that is upward compatible
74(which is one of the principles behind the \CONTEXT\ user interface(s), you can
75do this:
76
77\startbuffer
78\startcombination[nx=4,ny=1]
79    {\startMPcode draw lmt_labtorgb [ l = 20, step = 20 ] ysized 35mm withpen pencircle scaled 8 ; \stopMPcode} {\type {l=20}}
80    {\startMPcode draw lmt_labtorgb [ l = 40, step = 20 ] ysized 35mm withpen pencircle scaled 8 ; \stopMPcode} {\type {l=40}}
81    {\startMPcode draw lmt_labtorgb [ l = 60, step = 20 ] ysized 35mm withpen pencircle scaled 8 ; \stopMPcode} {\type {l=60}}
82    {\startMPcode draw lmt_labtorgb [ l = 80, step = 20 ] ysized 35mm withpen pencircle scaled 8 ; \stopMPcode} {\type {l=80}}
83\stopcombination
84\stopbuffer
85
86\typebuffer[option=TEX]
87
88\startlinecorrection
89\getbuffer
90\stoplinecorrection
91
92This is a predefined macro in the reserved \type {lmt_} namespace (don't use that
93one yourself, create your own). First we preset the possible parameters:
94
95\starttyping[option=MP]
96presetparameters "labtorgb" [
97  mina = -100,
98  maxa =  100,
99  minb = -100,
100  maxb =  100,
101  step =    5,
102  l    =   50,
103] ;
104\stoptyping
105
106Next we define the main interface macro:
107
108\starttyping[option=MP]
109def lmt_labtorgb = applyparameters "labtorgb" "lmt_do_labtorgb" enddef ;
110\stoptyping
111
112Last we do the actual implementation, which looks a lot like the one we
113started with:
114
115\starttyping[option=MP]
116vardef lmt_do_labtorgb =
117  image (
118    pushparameters "labtorgb" ;
119      save l ; l := getparameter "l" ;
120      for a = getparameter "mina" step getparameter "step"
121            until getparameter "maxa" :
122        for b = getparameter "minb" step getparameter "step"
123            until getparameter "maxb" :
124          draw (a,b) withcolor labtorgb(l,a,b) ;
125        endfor ;
126      endfor ;
127    popparameters ;
128  )
129enddef ;
130\stoptyping
131
132Of course we can now add all kind of extra features but this is what we currently
133have. Maybe this doesn't belong in the \METAFUN\ core but it's not that much code
134and a nice demo. After all, there is much in there that is seldom used.
135
136A perceptive color space that uses the lab model is lhc. Here is an example of
137how that can be used:
138
139\startbuffer
140\startMPdefinitions
141vardef lchcolorcircle(expr l, c, n) =
142    image (
143        save p, h ; path p ; numeric h ;
144        p := arcpointlist n of fullcircle ;
145        for i within p :
146            h := i*360/n ;
147            draw
148                pathpoint scaled 50
149                withpen pencircle scaled (120/n)
150                withcolor lchtorgb(l,c,h) ;
151            draw
152                textext ("\tt\bf" & decimal h)
153                scaled .4
154                shifted (pathpoint scaled 50)
155                withcolor white ;
156        endfor ;
157    )
158enddef ;
159\stopMPdefinitions
160\stopbuffer
161
162\typebuffer[option=TEX]
163
164\getbuffer
165
166Of course you can come up with another representation than this but here is
167how it looks:
168
169\startbuffer
170\startMPcode
171draw image (
172    draw lchcolorcircle(75,100,24) ;
173    draw lchcolorcircle(50,100,24) scaled .75 ;
174    draw lchcolorcircle(25,100,24) scaled .50 ;
175) ysized 4cm ;
176\stopMPcode
177\stopbuffer
178
179\typebuffer[option=TEX]
180
181\startbuffer
182\startcombination[nx=6,ny=1,distance=.02tw]
183    {\startMPcode draw lmt_lchcircle [ l = 75, c = 100, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=75,c=100}}
184    {\startMPcode draw lmt_lchcircle [ l = 50, c = 100, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=50,c=100}}
185    {\startMPcode draw lmt_lchcircle [ l = 25, c = 100, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=25,c=100}}
186    {\startMPcode draw lmt_lchcircle [ l = 75, c =  25, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=75,c=25}}
187    {\startMPcode draw lmt_lchcircle [ l = 50, c =  25, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=50,c=25}}
188    {\startMPcode draw lmt_lchcircle [ l = 25, c =  25, steps = 12 ] xsized .15TextWidth ; \stopMPcode} {\type {l=25,c=25}}
189\stopcombination
190\stopbuffer
191
192You can get rather nice color pallets by manipulating the axis without really
193knowing what color you get. The \type {h} value is in angles and shown inside the
194circles.
195
196\startlinecorrection
197\getbuffer
198\stoplinecorrection
199
200Of course we can again wrap this into a parameter driven macro, this time \typ
201{lmt_lchcircle} which accepts \type {l}, \type {c}, \type {steps} and a
202\type {labels} boolean.
203
204\stopsection
205
206\startsection[title=Transparency]
207
208Although transparency is independent from color we discuss one aspect here. Where
209color is sort of native to \METAPOST, especially when we talk \RGB\ and \CMYK,
210other color spaces are implemented using so called prescripts, think \quotation
211{information bound to paths and related wrappers}.
212
213When you do this:
214
215\startbuffer
216\startMPcode
217path c ; c := fullcircle scaled 1cm ;
218picture p ; p := image (
219    fill c shifted ( 0mm,0) withcolor "darkred" ;
220    fill c shifted ( 5mm,0) withcolor "darkgreen" ;
221    fill c shifted (10mm,0) withcolor "darkblue" ;
222) ;
223
224draw p ; draw p shifted (3cm,0) withcolor "middlegray" ;
225\stopMPcode
226\stopbuffer
227
228\typebuffer[option=TEX]
229
230You will notice that the picture gets recolored so the color properties set on
231the picture are applied to separate elements that make it. A picture itself is
232actually just a list of objects and it has no properties of its own. A way around
233this is to wrap it in a group, bound or clip which basically means something:
234begin, list of objects, end. By putting properties on the wrapper we can support
235features that apply to what gets wrapped without adapting the properties
236directly.
237
238\startlinecorrection \getbuffer \stoplinecorrection
239
240Because transparency is also implemented with prescripts we have a problem:
241should it apply to the wrapper or to everything? In the \LUATEX\ version of the
242\METAPOST\ library the scripts get assigned to the first element that supports
243them and because there only paths can have these properties, you cannot simply
244change the transparency without looping over the picture and redraw it.
245
246\startbuffer
247\startMPcode
248picture q ; q := image (
249    fill c shifted ( 0mm,0) withcolor "darkcyan"    withtransparency (1,.5);
250    fill c shifted ( 5mm,0) withcolor "darkmagenta" withtransparency (1,.5);
251    fill c shifted (10mm,0) withcolor "darkyellow"  withtransparency (1,.5);
252) ;
253
254draw q ; draw q shifted (3cm,0) withtransparency (1,.25) ;
255\stopMPcode
256\stopbuffer
257
258\typebuffer[option=TEX]
259
260In \LUAMETATEX\ we have a way to assign the properties to the elements so we get
261three less transparent circles:
262
263\startlinecorrection \getbuffer \stoplinecorrection
264
265In \MKIV\ only the first circle becomes lighter.
266
267\startbuffer
268\startMPcode
269picture r ; r := image (
270    draw p ;
271    draw q shifted (7cm,0cm) ;
272) ;
273
274draw r ;
275draw r shifted (3cm,0) withtransparency (1,.75) ;
276\stopMPcode
277\stopbuffer
278
279\typebuffer[option=TEX]
280
281This example shows that when we draw \type {p} and \type {q} we get the elements
282at the same level (flattened) so we can indeed apply the transparency to all of
283them.
284
285\startlinecorrection \getbuffer \stoplinecorrection
286
287So, keep in mind that this only works in \MKXL\ and not in \MKVI\ (unless we also
288upgrade \LUATEX\ to support this).
289
290\stopsection
291
292\startsection[title=Surrounding color]
293
294Here is an example that shows how to make a graphic listen to the current
295color:
296
297\startbuffer
298\startcolor[blue]
299    blue before
300    \startMPcode
301        setbackendoption "noplugins" ;
302        fill fullcircle xscaled 3EmWidth yscaled 1.5ExHeight ;
303    \stopMPcode\space
304    blue after
305\stopcolor
306\stopbuffer
307
308\typebuffer[option=tex]
309
310This backend option disables {\em all} additional features so it will only work
311for for relative simple graphics. There might be more detailed control in the
312future.
313
314\startlinecorrection \getbuffer \stoplinecorrection
315
316\stopsection
317
318\stopchapter
319
320\stopcomponent
321
322% \startMPpage[offset=1ts]
323
324%     draw image (
325%         fill (unitsquare xscaled 10cm yscaled 4cm)
326%             withcolor svgcolor(0.5,0,0)
327%         ;
328
329%         registerluminositygroup ("test") (
330%             fill (unitsquare scaled 2cm) shifted (1cm,1cm)
331%                 withshademethod "circular"
332%                 withshadecolors (.6,.1)
333%         ) ;
334
335%         applyluminositygroup ("test") (
336%             fill (unitsquare scaled 2cm) shifted (1cm,1cm)
337%                 withshademethod "circular"
338%         ) ;
339
340%         draw luminositygroup (
341%             fill (unitsquare scaled 2cm) shifted (4cm,1cm)
342%                 withshademethod "circular"
343%                 withshadecolors (.6,.1)
344%         ) (
345%             fill (unitsquare scaled 2cm) shifted (4cm,1cm)
346%                 withshademethod "circular"
347%         ) ;
348
349%         draw luminosityshade (
350%             (unitsquare scaled 2cm) shifted (7cm,1cm)
351%         ) (
352%                 withshademethod "circular"
353%                 withshadecolors (.6,.1)
354%         ) (
355%                 withshademethod "circular"
356%         ) ;
357%     ) ;
358
359% \stopMPpage
360
361% \startMPpage[offset=1ts]
362
363%     draw image (
364%         fill (unitsquare xscaled 10cm yscaled 4cm)
365%             withcolor "darkblue"
366%         ;
367
368%         registerluminositygroup ("test") (
369%             fill (unitsquare scaled 2cm) shifted (1cm,1cm)
370%                 withcolor "darkgreen"
371%         ) ;
372
373%         applyluminositygroup ("test") (
374%             fill (unitsquare scaled 2cm) shifted (1cm,1cm)
375%                 withcolor "darkred"
376%         ) ;
377
378%         draw luminositygroup (
379%             fill (unitsquare scaled 2cm) shifted (4cm,1cm)
380%                 withcolor "darkgreen"
381%         ) (
382%             fill (unitsquare scaled 2cm) shifted (4cm,1cm)
383%                 withcolor "darkred"
384%         ) ;
385
386%         draw luminosityshade (
387%             (unitsquare scaled 2cm) shifted (7cm,1cm)
388%         ) (
389%                 withcolor "darkgreen"
390%         ) (
391%                 withcolor "darkred"
392%         ) ;
393%     ) ;
394
395% \stopMPpage
396