1if not modules then modules = { } end modules ['meta-pdf'] = {
2 version = 1.001,
3 comment = "companion to meta-pdf.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
9if true then
10 return
11end
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29local concat, format, find, gsub, gmatch = table.concat, string.format, string.find, string.gsub, string.gmatch
30local tostring, tonumber, select = tostring, tonumber, select
31local lpegmatch = lpeg.match
32
33metapost = metapost or { }
34local metapost = metapost
35local context = context
36
37metapost.mptopdf = metapost.mptopdf or { }
38local mptopdf = metapost.mptopdf
39
40mptopdf.parsers = { }
41mptopdf.parser = 'none'
42mptopdf.nofconverted = 0
43
44function mptopdf.reset()
45 mptopdf.data = ""
46 mptopdf.path = { }
47 mptopdf.stack = { }
48 mptopdf.texts = { }
49 mptopdf.version = 0
50 mptopdf.shortcuts = false
51 mptopdf.resetpath()
52end
53
54function mptopdf.resetpath()
55 mptopdf.stack.close = false
56 mptopdf.stack.path = { }
57 mptopdf.stack.concat = nil
58 mptopdf.stack.special = false
59end
60
61mptopdf.reset()
62
63function mptopdf.parsers.none()
64
65end
66
67function mptopdf.parse()
68 mptopdf.parsers[mptopdf.parser]()
69end
70
71
72
73mptopdf.steps = { }
74
75mptopdf.descapes = {
76 ['('] = "\\\\char40 ",
77 [')'] = "\\\\char41 ",
78 ['"'] = "\\\\char92 "
79}
80
81function mptopdf.descape(str)
82 str = gsub(str,"\\(%d%d%d)",function(n)
83 return "\\char" .. tonumber(n,8) .. " "
84 end)
85 return gsub(str,"\\([%(%)\\])",mptopdf.descapes)
86end
87
88function mptopdf.steps.descape(str)
89 str = gsub(str,"\\(%d%d%d)",function(n)
90 return "\\\\char" .. tonumber(n,8) .. " "
91 end)
92 return gsub(str,"\\([%(%)\\])",mptopdf.descapes)
93end
94
95function mptopdf.steps.strip()
96 mptopdf.data = gsub(mptopdf.data,"^(.-)%%+Page:.-%c+(.*)%s+%a+%s+%%+EOF.*$", function(preamble, graphic)
97 local bbox = "0 0 0 0"
98 for b in gmatch(preamble,"%%%%%a+oundingBox: +(.-)%c+") do
99 bbox = b
100 end
101 local name, version = gmatch(preamble,"%%%%Creator: +(.-) +(.-) ")
102 mptopdf.version = tostring(version or "0")
103 if find(preamble,"/hlw{0 dtransform",1,true) then
104 mptopdf.shortcuts = true
105 end
106
107 return bbox .. " boundingbox\n" .. "\nbegindata\n" .. graphic .. "\nenddata\n"
108 end, 1)
109 mptopdf.data = gsub(mptopdf.data,"%%%%MetaPostSpecials: +(.-)%c+", "%1 specials\n", 1)
110 mptopdf.data = gsub(mptopdf.data,"%%%%MetaPostSpecial: +(.-)%c+", "%1 special\n")
111 mptopdf.data = gsub(mptopdf.data,"%%.-%c+", "")
112end
113
114function mptopdf.steps.cleanup()
115 if not mptopdf.shortcuts then
116 mptopdf.data = gsub(mptopdf.data,"gsave%s+fill%s+grestore%s+stroke", "both")
117 mptopdf.data = gsub(mptopdf.data,"([%d%.]+)%s+([%d%.]+)%s+dtransform%s+exch%s+truncate%s+exch%s+idtransform%s+pop%s+setlinewidth", function(wx,wy)
118 if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
119 end)
120 mptopdf.data = gsub(mptopdf.data,"([%d%.]+)%s+([%d%.]+)%s+dtransform%s+truncate%s+idtransform%s+setlinewidth%s+pop", function(wx,wy)
121 if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
122 end)
123 end
124end
125
126function mptopdf.steps.convert()
127 mptopdf.data = gsub(mptopdf.data,"%c%((.-)%) (.-) (.-) fshow", function(str,font,scale)
128 mptopdf.texts[mptopdf.texts+1] = {mptopdf.steps.descape(str), font, scale}
129 return "\n" .. #mptopdf.texts .. " textext"
130 end)
131 mptopdf.data = gsub(mptopdf.data,"%[%s*(.-)%s*%]", function(str)
132 return gsub(str,"%s+"," ")
133 end)
134 local t
135 mptopdf.data = gsub(mptopdf.data,"%s*([^%a]-)%s*(%a+)", function(args,cmd)
136 if cmd == "textext" then
137 t = mptopdf.texts[tonumber(args)]
138 return "metapost.mps.textext(" .. "\"" .. t[2] .. "\"," .. t[3] .. ",\"" .. t[1] .. "\")\n"
139 else
140 return "metapost.mps." .. cmd .. "(" .. gsub(args," +",",") .. ")\n"
141 end
142 end)
143end
144
145function mptopdf.steps.process()
146 assert(loadstring(mptopdf.data))()
147end
148
149function mptopdf.parsers.gsub()
150 mptopdf.steps.strip()
151 mptopdf.steps.cleanup()
152 mptopdf.steps.convert()
153 mptopdf.steps.process()
154end
155
156
157
158
159
160function mptopdf.pdfcode(str)
161 context.pdfliteral(str)
162end
163
164function mptopdf.texcode(str)
165 context(str)
166end
167
168
169
170function mptopdf.flushconcat()
171 if mptopdf.stack.concat then
172 mptopdf.pdfcode(concat(mptopdf.stack.concat," ") .. " cm")
173 mptopdf.stack.concat = nil
174 end
175end
176
177function mptopdf.flushpath(cmd)
178
179 if #mptopdf.stack.path > 0 then
180 local path = { }
181 if mptopdf.stack.concat then
182 local sx, sy = mptopdf.stack.concat[1], mptopdf.stack.concat[4]
183 local rx, ry = mptopdf.stack.concat[2], mptopdf.stack.concat[3]
184 local tx, ty = mptopdf.stack.concat[5], mptopdf.stack.concat[6]
185 local d = (sx*sy) - (rx*ry)
186 local function mpconcat(px, py)
187 return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d
188 end
189 local stackpath = mptopdf.stack.path
190 for k=1,#stackpath do
191 local v = stackpath[k]
192 v[1],v[2] = mpconcat(v[1],v[2])
193 if #v == 7 then
194 v[3],v[4] = mpconcat(v[3],v[4])
195 v[5],v[6] = mpconcat(v[5],v[6])
196 end
197 path[#path+1] = concat(v," ")
198 end
199 else
200 local stackpath = mptopdf.stack.path
201 for k=1,#stackpath do
202 path[#path+1] = concat(stackpath[k]," ")
203 end
204 end
205 mptopdf.flushconcat()
206 mptopdf.texcode("\\MPSpath{" .. concat(path," ") .. "}")
207 if mptopdf.stack.close then
208 mptopdf.texcode("\\MPScode{h " .. cmd .. "}")
209 else
210 mptopdf.texcode("\\MPScode{" .. cmd .."}")
211 end
212 end
213 mptopdf.resetpath()
214end
215
216function mptopdf.loaded(name)
217 local ok, n
218 mptopdf.reset()
219 ok, mptopdf.data, n = resolvers.loadbinfile(name, 'tex')
220 return ok
221end
222
223if not mptopdf.parse then
224 function mptopdf.parse() end
225end
226
227function mptopdf.convertmpstopdf(name)
228 if mptopdf.loaded(name) then
229 mptopdf.nofconverted = mptopdf.nofconverted + 1
230 statistics.starttiming(mptopdf)
231 mptopdf.parse()
232 mptopdf.reset()
233 statistics.stoptiming(mptopdf)
234 else
235 context("file " .. name .. " not found")
236 end
237end
238
239
240
241metapost.mps = metapost.mps or { }
242local mps = metapost.mps or { }
243
244function mps.creator(a, b, c)
245 mptopdf.version = tonumber(b)
246end
247
248function mps.creationdate(a)
249 mptopdf.date= a
250end
251
252function mps.newpath()
253 mptopdf.stack.path = { }
254end
255
256function mps.boundingbox(llx, lly, urx, ury)
257 mptopdf.texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
258end
259
260function mps.moveto(x,y)
261 mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"m"}
262end
263
264function mps.curveto(ax, ay, bx, by, cx, cy)
265 mptopdf.stack.path[#mptopdf.stack.path+1] = {ax,ay,bx,by,cx,cy,"c"}
266end
267
268function mps.lineto(x,y)
269 mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"l"}
270end
271
272function mps.rlineto(x,y)
273 local dx, dy = 0, 0
274 if #mptopdf.stack.path > 0 then
275 dx, dy = mptopdf.stack.path[#mptopdf.stack.path][1], mptopdf.stack.path[#mptopdf.stack.path][2]
276 end
277 mptopdf.stack.path[#mptopdf.stack.path+1] = {dx,dy,"l"}
278end
279
280function mps.translate(tx,ty)
281 mptopdf.pdfcode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm")
282end
283
284function mps.scale(sx,sy)
285 mptopdf.stack.concat = {sx,0,0,sy,0,0}
286end
287
288function mps.concat(sx, rx, ry, sy, tx, ty)
289 mptopdf.stack.concat = {sx,rx,ry,sy,tx,ty}
290end
291
292function mps.setlinejoin(d)
293 mptopdf.pdfcode(d .. " j")
294end
295
296function mps.setlinecap(d)
297 mptopdf.pdfcode(d .. " J")
298end
299
300function mps.setmiterlimit(d)
301 mptopdf.pdfcode(d .. " M")
302end
303
304function mps.gsave()
305 mptopdf.pdfcode("q")
306end
307
308function mps.grestore()
309 mptopdf.pdfcode("Q")
310end
311
312function mps.setdash(...)
313 local n = select("#",...)
314 mptopdf.pdfcode("[" .. concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d")
315end
316
317function mps.resetdash()
318 mptopdf.pdfcode("[ ] 0 d")
319end
320
321function mps.setlinewidth(d)
322 mptopdf.pdfcode(d .. " w")
323end
324
325function mps.closepath()
326 mptopdf.stack.close = true
327end
328
329function mps.fill()
330 mptopdf.flushpath('f')
331end
332
333function mps.stroke()
334 mptopdf.flushpath('S')
335end
336
337function mps.both()
338 mptopdf.flushpath('B')
339end
340
341function mps.clip()
342 mptopdf.flushpath('W n')
343end
344
345function mps.textext(font, scale, str)
346 local dx, dy = 0, 0
347 if #mptopdf.stack.path > 0 then
348 dx, dy = mptopdf.stack.path[1][1], mptopdf.stack.path[1][2]
349 end
350 mptopdf.flushconcat()
351 mptopdf.texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
352 mptopdf.resetpath()
353end
354
355
356
357
358
359
360
361
362
363
364function mps.setrgbcolor(r,g,b)
365 r, g = tonumber(r), tonumber(g)
366 if r == 0.0123 and g < 0.1 then
367 mptopdf.texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
368 elseif r == 0.123 and g < 0.1 then
369 mptopdf.texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
370 else
371 mptopdf.texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}")
372 end
373end
374
375function mps.setcmykcolor(c,m,y,k)
376 mptopdf.texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}")
377end
378
379function mps.setgray(s)
380 mptopdf.texcode("\\MPSgray{" .. s .. "}")
381end
382
383function mps.specials(version,signal,factor)
384end
385
386function mps.special(...)
387 local n = select("#",...)
388 mptopdf.texcode("\\MPSbegin\\MPSset{" .. concat({...},"}\\MPSset{",2,n) .. "}\\MPSend")
389end
390
391function mps.begindata()
392end
393
394function mps.enddata()
395end
396
397function mps.showpage()
398end
399
400mps.n = mps.newpath
401mps.p = mps.closepath
402mps.l = mps.lineto
403mps.r = mps.rlineto
404mps.m = mps.moveto
405mps.c = mps.curveto
406mps.hlw = mps.setlinewidth
407mps.vlw = mps.setlinewidth
408
409mps.C = mps.setcmykcolor
410mps.G = mps.setgray
411mps.R = mps.setrgbcolor
412
413mps.lj = mps.setlinejoin
414mps.ml = mps.setmiterlimit
415mps.lc = mps.setlinecap
416mps.sd = mps.setdash
417mps.rd = mps.resetdash
418
419mps.S = mps.stroke
420mps.F = mps.fill
421mps.B = mps.both
422mps.W = mps.clip
423
424mps.q = mps.gsave
425mps.Q = mps.grestore
426
427mps.s = mps.scale
428mps.t = mps.concat
429
430mps.P = mps.showpage
431
432
433
434function mps.attribute(id,value)
435 mptopdf.texcode("\\attribute " .. id .. "=" .. value .. " ")
436
437end
438
439
440
441
442
443
444
445do
446
447 local byte = string.byte
448 local digit = lpeg.R("09")
449 local spec = digit^2 * lpeg.P("::::") * digit^2
450 local text = lpeg.Cc("{") * (
451 lpeg.P("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
452 lpeg.P(" ") / function(n) return "\\c32" end +
453 lpeg.P(1) / function(n) return "\\c" .. byte(n) end
454 ) * lpeg.Cc("}")
455 local package = lpeg.Cs(spec + text^0)
456
457 function mps.fshow(str,font,scale)
458 mps.textext(font,scale,lpegmatch(package,str))
459 end
460
461end
462
463do
464
465 local eol = lpeg.S('\r\n')^1
466 local sp = lpeg.P(' ')^1
467 local space = lpeg.S(' \r\n')^1
468 local number = lpeg.S('0123456789.-+')^1
469 local nonspace = lpeg.P(1-lpeg.S(' \r\n'))^1
470
471 local cnumber = lpeg.C(number)
472 local cstring = lpeg.C(nonspace)
473
474 local specials = (lpeg.P("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
475 local special = (lpeg.P("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
476 local boundingbox = (lpeg.P("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
477 local highresboundingbox = (lpeg.P("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
478
479 local setup = lpeg.P("%%BeginSetup") * (1 - lpeg.P("%%EndSetup") )^1
480 local prolog = lpeg.P("%%BeginProlog") * (1 - lpeg.P("%%EndProlog"))^1
481 local comment = lpeg.P('%')^1 * (1 - eol)^1
482
483 local curveto = ((cnumber * sp)^6 * lpeg.P("curveto") ) / mps.curveto
484 local lineto = ((cnumber * sp)^2 * lpeg.P("lineto") ) / mps.lineto
485 local rlineto = ((cnumber * sp)^2 * lpeg.P("rlineto") ) / mps.rlineto
486 local moveto = ((cnumber * sp)^2 * lpeg.P("moveto") ) / mps.moveto
487 local setrgbcolor = ((cnumber * sp)^3 * lpeg.P("setrgbcolor") ) / mps.setrgbcolor
488 local setcmykcolor = ((cnumber * sp)^4 * lpeg.P("setcmykcolor") ) / mps.setcmykcolor
489 local setgray = ((cnumber * sp)^1 * lpeg.P("setgray") ) / mps.setgray
490 local newpath = ( lpeg.P("newpath") ) / mps.newpath
491 local closepath = ( lpeg.P("closepath") ) / mps.closepath
492 local fill = ( lpeg.P("fill") ) / mps.fill
493 local stroke = ( lpeg.P("stroke") ) / mps.stroke
494 local clip = ( lpeg.P("clip") ) / mps.clip
495 local both = ( lpeg.P("gsave fill grestore")) / mps.both
496 local showpage = ( lpeg.P("showpage") )
497 local setlinejoin = ((cnumber * sp)^1 * lpeg.P("setlinejoin") ) / mps.setlinejoin
498 local setlinecap = ((cnumber * sp)^1 * lpeg.P("setlinecap") ) / mps.setlinecap
499 local setmiterlimit = ((cnumber * sp)^1 * lpeg.P("setmiterlimit") ) / mps.setmiterlimit
500 local gsave = ( lpeg.P("gsave") ) / mps.gsave
501 local grestore = ( lpeg.P("grestore") ) / mps.grestore
502
503 local setdash = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("setdash")) / mps.setdash
504 local concat = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("concat") ) / mps.concat
505 local scale = ( (cnumber * sp^0)^6 * sp * lpeg.P("concat") ) / mps.concat
506
507 local fshow = (lpeg.P("(") * lpeg.C((1-lpeg.P(")"))^1) * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
508 local fshow = (lpeg.P("(") *
509 lpeg.Cs( ( lpeg.P("\\(")/"\\050" + lpeg.P("\\)")/"\\051" + (1-lpeg.P(")")) )^1 )
510 * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
511
512 local setlinewidth_x = (lpeg.P("0") * sp * cnumber * sp * lpeg.P("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
513 local setlinewidth_y = (cnumber * sp * lpeg.P("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
514
515 local c = ((cnumber * sp)^6 * lpeg.P("c") ) / mps.curveto
516 local l = ((cnumber * sp)^2 * lpeg.P("l") ) / mps.lineto
517 local r = ((cnumber * sp)^2 * lpeg.P("r") ) / mps.rlineto
518 local m = ((cnumber * sp)^2 * lpeg.P("m") ) / mps.moveto
519 local vlw = ((cnumber * sp)^1 * lpeg.P("vlw")) / mps.setlinewidth
520 local hlw = ((cnumber * sp)^1 * lpeg.P("hlw")) / mps.setlinewidth
521
522 local R = ((cnumber * sp)^3 * lpeg.P("R") ) / mps.setrgbcolor
523 local C = ((cnumber * sp)^4 * lpeg.P("C") ) / mps.setcmykcolor
524 local G = ((cnumber * sp)^1 * lpeg.P("G") ) / mps.setgray
525
526 local lj = ((cnumber * sp)^1 * lpeg.P("lj") ) / mps.setlinejoin
527 local ml = ((cnumber * sp)^1 * lpeg.P("ml") ) / mps.setmiterlimit
528 local lc = ((cnumber * sp)^1 * lpeg.P("lc") ) / mps.setlinecap
529
530 local n = lpeg.P("n") / mps.newpath
531 local p = lpeg.P("p") / mps.closepath
532 local S = lpeg.P("S") / mps.stroke
533 local F = lpeg.P("F") / mps.fill
534 local B = lpeg.P("B") / mps.both
535 local W = lpeg.P("W") / mps.clip
536 local P = lpeg.P("P") / mps.showpage
537
538 local q = lpeg.P("q") / mps.gsave
539 local Q = lpeg.P("Q") / mps.grestore
540
541 local sd = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("sd")) / mps.setdash
542 local rd = ( lpeg.P("rd")) / mps.resetdash
543
544 local s = ( (cnumber * sp^0)^2 * lpeg.P("s") ) / mps.scale
545 local t = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("t") ) / mps.concat
546
547
548
549 local attribute = ((cnumber * sp)^2 * lpeg.P("attribute")) / mps.attribute
550 local A = ((cnumber * sp)^2 * lpeg.P("A")) / mps.attribute
551
552 local preamble = (
553 prolog + setup +
554 boundingbox + highresboundingbox + specials + special +
555 comment
556 )
557
558 local procset = (
559 lj + ml + lc +
560 c + l + m + n + p + r +
561 A +
562 R + C + G +
563 S + F + B + W +
564 vlw + hlw +
565 Q + q +
566 sd + rd +
567 t + s +
568 fshow +
569 P
570 )
571
572 local verbose = (
573 curveto + lineto + moveto + newpath + closepath + rlineto +
574 setrgbcolor + setcmykcolor + setgray +
575 attribute +
576 setlinejoin + setmiterlimit + setlinecap +
577 stroke + fill + clip + both +
578 setlinewidth_x + setlinewidth_y +
579 gsave + grestore +
580 concat + scale +
581 fshow +
582 setdash +
583 showpage
584 )
585
586
587
588 local captures_old = ( space + verbose + preamble )^0
589 local captures_new = ( space + procset + preamble + verbose )^0
590
591 function mptopdf.parsers.lpeg()
592 if find(mptopdf.data,"%%BeginResource: procset mpost",1,true) then
593 lpegmatch(captures_new,mptopdf.data)
594 else
595 lpegmatch(captures_old,mptopdf.data)
596 end
597 end
598
599end
600
601mptopdf.parser = 'lpeg'
602
603
604
605statistics.register("mps conversion time",function()
606 local n = mptopdf.nofconverted
607 if n > 0 then
608 return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n)
609 else
610 return nil
611 end
612end)
613 |