1
2
3\startcomponent cldgraphics
4
5\environment cldenvironment
6
7\startchapter[title=Graphics]
8
9\startsection[title=The regular interface]
10
11If you are familiar with \CONTEXT, which by now probably is the case, you will
12have noticed that it integrates the \METAPOST\ graphic subsystem. Drawing a
13graphic is not that complex:
14
15\startbuffer
16context.startMPcode()
17context [[
18 draw
19 fullcircle scaled 1cm
20 withpen pencircle scaled 1mm
21 withcolor .5white
22 dashed dashpattern (on 2mm off 2mm) ;
23 ]]
24context.stopMPcode()
25\stopbuffer
26
27\typebuffer
28
29We get a gray dashed circle rendered with an one millimeter thick line:
30
31\startlinecorrection
32\ctxluabuffer
33\stoplinecorrection
34
35So, we just use the regular commands and pass the drawing code as strings.
36Although \METAPOST\ is a rather normal language and therefore offers loops and
37conditions and the lot, you might want to use \LUA\ for anything else than the
38drawing commands. Of course this is much less efficient, but it could be that you
39dont care about speed. The next example demonstrates the interface for building
40graphics piecewise.
41
42\startbuffer
43context.resetMPdrawing()
44
45context.startMPdrawing()
46context([[fill fullcircle scaled 5cm withcolor (0,0,.5) ;]])
47context.stopMPdrawing()
48
49context.MPdrawing("pickup pencircle scaled .5mm ;")
50context.MPdrawing("drawoptions(withcolor white) ;")
51
52for i=0,50,5 do
53 context.startMPdrawing()
54 context("draw fullcircle scaled
55 context.stopMPdrawing()
56end
57
58for i=0,50,5 do
59 context.MPdrawing("draw fullsquare scaled " .. i .. "mm ;")
60end
61
62context.MPdrawingdonetrue()
63
64context.getMPdrawing()
65\stopbuffer
66
67\typebuffer
68
69This gives:
70
71\startlinecorrection
72\ctxluabuffer
73\stoplinecorrection
74
75I the first loop we can use the format options associated with the simple \type
76{context} call. This will not work in the second case. Even worse, passing more
77than one argument will definitely give a faulty graphic definition. This is why
78we have a special interface for \METAFUN. The code above can also be written as:
79
80\startbuffer
81local metafun = context.metafun
82
83metafun.start()
84
85metafun("fill fullcircle scaled 5cm withcolor
86 metafun.color("darkblue"))
87
88metafun("pickup pencircle scaled .5mm ;")
89metafun("drawoptions(withcolor white) ;")
90
91for i=0,50,5 do
92 metafun("draw fullcircle scaled
93end
94
95for i=0,50,5 do
96 metafun("draw fullsquare scaled
97end
98
99metafun.stop()
100\stopbuffer
101
102\typebuffer
103
104Watch the call to \type {color}, this will pass definitions at the \TEX\ end to
105\METAPOST. Of course you really need to ask yourself \quotation {Do I want to use
106\METAPOST\ this way?}. Using \LUA\ loops instead of \METAPOST\ ones makes much
107more sense in the following case:
108
109\startbuffer
110local metafun = context.metafun
111
112function metafun.barchart(t)
113 metafun.start()
114 local t = t.data
115 for i=1,#t do
116 metafun("draw unitsquare xyscaled(
117 10, t[i]*10, i*10)
118 end
119 metafun.stop()
120end
121
122local one = { 1, 4, 6, 2, 3, }
123local two = { 8, 1, 3, 5, 9, }
124
125context.startcombination()
126 context.combination(metafun.delayed.barchart { data = one }, "one")
127 context.combination(metafun.delayed.barchart { data = two }, "two")
128context.stopcombination()
129\stopbuffer
130
131\typebuffer
132
133We get two barcharts alongside:
134
135\startlinecorrection
136\ctxluabuffer
137\stoplinecorrection
138
139\startbuffer
140local template = [[
141 path p, q ; color c[] ;
142 c1 := \MPcolor{darkblue} ;
143 c2 := \MPcolor{darkred} ;
144 p := fullcircle scaled 50 ;
145 l := length p ;
146 n :=
147 q := subpath (0,
148 draw q withcolor c2 withpen pencircle scaled 1 ;
149 fill fullcircle scaled 5 shifted point length q of q withcolor c1 ;
150 setbounds currentpicture to unitsquare shifted (0.5,0.5) scaled 60 ;
151 draw boundingbox currentpicture withcolor c1 ;
152 currentpicture := currentpicture xsized(1cm) ;
153]]
154
155local function steps(n)
156 for i=0,n do
157 context.metafun.start()
158 context.metafun(template,n,i)
159 context.metafun.stop()
160 if i < n then
161 context.quad()
162 end
163 end
164end
165
166context.hbox(function() steps(10) end)
167\stopbuffer
168
169\typebuffer
170
171\startlinecorrection
172\ctxluabuffer
173\stoplinecorrection
174
175Using a template is quite convenient but at some point you can loose track of the
176replacement values. Also, adding an extra value can force you to adapt the
177following ones which enlarges the change for making an error. An alternative is
178to use the template mechanism. Although this mechanism was originally made for
179other purposes, you can use it for whatever you like.
180
181\startbuffer
182local template = [[
183 path p ; p := fullcircle scaled 4cm ;
184 draw p withpen pencircle scaled .5mm withcolor red ;
185 freedotlabel ("
186 freedotlabel ("
187 freedotlabel ("
188 freedotlabel ("
189]]
190
191local variables = {
192 lefttop = "one",
193 righttop = "two",
194 leftbottom = "three",
195 rightbottom = "four" ,
196}
197
198context.metafun.start()
199 context.metafun(utilities.templates.replace(template,variables))
200context.metafun.stop()
201\stopbuffer
202
203\typebuffer
204
205Here we use named placeholders and pass a table with associated values to the
206replacement function. Apart from convenience its also more readable. And the
207overhead is rather minimal.
208
209\startlinecorrection
210\ctxluabuffer
211\stoplinecorrection
212
213To some extent we fool ourselves with this kind of \LUA fication of \METAPOST\
214code. Of course we can make a nice \METAPOST\ library and put the code in a macro
215instead. In that sense, doing this in \CONTEXT\ directly often gives better and
216more efficient code.
217
218Of course you can use all relevant commands in the \LUA\ interface, like:
219
220\starttyping
221context.startMPpage()
222 context("draw origin")
223 for i=0,100,10 do
224 context("..{down}(
225 end
226 context(" withcolor \\MPcolor{darkred} ;")
227context.stopMPpage()
228\stoptyping
229
230to get a graphic that has its own page. Dont use the \type {metafun} namespace
231here, as it will not work here. This drawing looks like:
232
233\startlinecorrection
234\startluacode
235context.startMPcode()
236 context("draw origin")
237 for i=0,100,10 do
238 context("..{down}(%d,0)",i)
239 end
240 context(" withcolor red ;")
241context.stopMPcode()
242\stopluacode
243\stoplinecorrection
244
245\stopsection
246
247\startsection[title=The \LUA\ interface]
248
249Messing around with graphics is normally not needed and if you do it, youd
250better know what youre doing. For \TEX\ a graphic is just a black box: a
251rectangle with dimensions. You specify a graphic, in a format that the backend
252can deal with, either or not apply some scaling and from then on a reference to
253that graphic, normally wrapped in a normal \TEX\ box, enters the typesetting
254machinery. Because the backend, the part that is responsible for translating
255typeset content onto a viewable or printable format like \PDF, is built into
256\LUATEX, at some point the real image has to be injected and the backend can only
257handle a few image formats: \PNG, \JPG, \JBIG\ and \PDF.
258
259In \CONTEXT\ some more image formats are supported but in practice this boils
260down to converting the image to a format that the backend can handle. Such a
261conversion depends on an external programs and in order not to redo the
262conversion each run \CONTEXT\ keeps track of the need to redo it.
263
264Some converters are built in, for example one that deals with \GIF\ images. This
265is normally not a preferred format, but it happens that we have to deal with it
266in cases where organizations use that format (if only because they use the web).
267Here is how this works at the \LUA\ end:
268
269\starttyping
270figures.converters.gif = {
271 pdf = function(oldname,newname)
272 os.execute(string.format("gm convert
273 end
274}
275\stoptyping
276
277We use \type {gm} (Graphic Magic) for the conversion and pass the old and new
278names. Given this definition at the \TEX\ end we can say:
279
280\starttyping
281\externalfigure[whatever.gif][width=4cm]
282\stoptyping
283
284Here is a another one:
285
286\starttyping
287figures.converters.bmp = {
288 pdf = function(oldname,newname)
289 os.execute(string.format("gm convert
290 end
291}
292\stoptyping
293
294In both examples we convert to \PDF\ because including this filetype is quite
295fast. But you can also go to other formats:
296
297\starttyping
298figures.converters.png = {
299 png = function(oldname,newname,resolution)
300 local command = string.format(gm convert depth 1 "
301 logs.report(string.format("running command
302 os.execute(command)
303 end
304}
305\stoptyping
306
307Instead of directly defining such a table, you can better do this:
308
309\starttyping
310figures.converters.png = figures.converters.png or { }
311
312figures.converters.png.png = function(oldname,newname,resolution)
313 local command = string.format(gm convert depth 1 "
314 logs.report(string.format("running command
315 os.execute(command)
316end
317\stoptyping
318
319Here we check if a table exists and if not we extend the table. Such converters
320work out of the box if you specify the suffix, but you can also opt for a simple:
321
322\starttyping
323\externalfigure[whatever][width=4cm]
324\stoptyping
325
326In this case \CONTEXT\ will check for all known supported formats, which is not
327that efficient when no graphic can be found. In order to let for instance files
328with suffix \type {bmp} can be included you have to register it as follows. The
329second argument is the target.
330
331\starttyping
332figures.registersuffix("bmp","bmp")
333\stoptyping
334
335At some point more of the graphic inclusion helpers will be opened up for general
336use but for now this is what you have available.
337
338\stopsection
339
340\stopchapter
341
342\stopcomponent
343 |