mtx-metapost.lua /size: 8096 b    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['mtx-metapost'] = { -- this was mtx-mptopdf
2    version   = 0.100,
3    comment   = "companion to mtxrun.lua",
4    author    = "Taco Hoekwater & Hans Hagen",
5    copyright = "ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- todo: load map files
10
11local helpinfo = [[
12<?xml version="1.0"?>
13<application>
14 <metadata>
15  <entry name="name">mtx-metapost</entry>
16  <entry name="detail">MetaPost to PDF processor</entry>
17  <entry name="version">0.10</entry>
18 </metadata>
19 <flags>
20  <category name="basic">
21   <subcategory>
22    <flag name="rawmp"><short>raw metapost run</short></flag>
23    <flag name="metafun"><short>use metafun instead of plain</short></flag>
24    <flag name="latex"><short>force <ref name="tex=latex"/></short></flag>
25    <flag name="texexec"><short>force texexec usage (mkii)</short></flag>
26    <flag name="split"><short>split single result file into pages</short></flag>
27   </subcategory>
28  </category>
29 </flags>
30 <examples>
31  <category>
32   <title>Examples</title>
33   <subcategory>
34    <example><command>mtxrun --script metapost yourfile.mp</command></example>
35    <example><command>mtxrun --script metapost --split yourfile.mp</command></example>
36    <example><command>mtxrun --script metapost yourfile.123 myfile.mps</command></example>
37   </subcategory>
38  </category>
39 </examples>
40 <comments>
41  <comment>other usage resembles mptopdf.pl</comment>
42 </comments>
43</application>
44]]
45
46local application = logs.application {
47    name     = "mtx-metapost",
48    banner   = "MetaPost to PDF processor 0.10",
49    helpinfo = helpinfo,
50}
51
52local report = application.report
53
54scripts             = scripts             or { }
55scripts.mptopdf     = scripts.mptopdf     or { }
56scripts.mptopdf.aux = scripts.mptopdf.aux or { }
57
58local format, find, gsub = string.format, string.find, string.gsub
59
60local function assumes_latex(filename)
61    local d = io.loaddata(filename) or ""
62    return find(d,"\\documentstyle") or find(d,"\\documentclass") or find(d,"\\begin{document}")
63end
64
65local basemaps = "original-base.map,original-ams-base.map,original-ams-euler.map,original-public-lm.map"
66
67local wrapper  = "\\starttext\n%s\n%s\\stoptext"
68local loadmap  = "\\loadmapfile[%s]\n"
69local template = "\\startTEXpage\n\\convertMPtoPDF{%s}{1}{1}\n\\stopTEXpage"
70local texified = "\\starttext\n%s\n\\stoptext"
71local splitter = "\\startTEXpage\\externalfigure[%s][page=%s]\\stopTEXpage"
72local tempname = "mptopdf-temp.tex"
73
74local function do_mapfiles(mapfiles)
75    local maps = { }
76    for i=1,#mapfiles do
77        local mapfile = mapfiles[i]
78        application.report("using map file %a",mapfile)
79        maps[i] = format(loadmap,mapfile)
80    end
81    return table.concat(maps)
82end
83
84local function do_convert(filename,mapfiles)
85    if find(filename,".%d+$") or find(filename,"%.mps$") then
86        local body = format(template,filename)
87        local maps = do_mapfiles(mapfiles)
88        io.savedata(tempname,format(wrapper,maps,body))
89        local resultname = format("%s-%s.pdf",file.nameonly(filename),file.suffix(filename))
90        local result = os.execute(format([[context --once --batch --purge --result=%s "%s"]],resultname,tempname))
91        return lfs.isfile(resultname) and resultname
92    end
93end
94
95local function do_split(filename,numbers,mapfiles)
96    local name = file.nameonly(filename)
97    local maps = do_mapfiles(mapfiles)
98    for i=1,#numbers do
99        local body = format(splitter,file.addsuffix(name,"pdf"),i)
100        io.savedata(tempname,format(wrapper,maps,body))
101        local resultname = format("%s-%s.pdf",name,numbers[i])
102        local result = os.execute(format([[context --once --batch --purge --result=%s "%s"]],resultname,tempname))
103    end
104end
105
106local function do_texify(str)
107    -- This only works for flat mp files i.e. outer beginfigs. Normally a
108    -- context user will directly make a tex file. Of course we can make
109    -- this script more clever, but why should we as better methods exist.
110    local numbers = { }
111    str = "\\startMPinclusions\n".. str .. "\n\\stopMPinclusions"
112    str = gsub(str,"beginfig%s*%(%s*(.-)%s*%)%s*;%s*",function(s)
113        numbers[#numbers+1] = tonumber(s) or 0
114        return "\n\\stopMPinclusions\n\\startMPpage\n"
115    end)
116    str = gsub(str,"%s*endfig%s*;%s*","\n\\stopMPpage\n\\startMPinclusions\n")
117    str = gsub(str,"\\startMPinclusions%s*\\stopMPinclusions","")
118    str = gsub(str,"[\n\r]+","\n")
119    return format(texified,str), numbers
120end
121
122local function do_convert_all(filename,mapfiles)
123    local results = dir.glob(file.nameonly(filename) .. ".*") -- reset
124    local report = { }
125    for i=1,#results do
126        local filename = results[i]
127        local resultname = do_convert(filename,mapfiles)
128        if resultname then
129            report[#report+1] = { filename, resultname }
130        end
131    end
132    if #report > 0 then
133        report("number of converted files: %i", #report)
134        report()
135        for i=1,#report do
136            local r = report[i]
137            report("%s => %s", r[1], r[2])
138        end
139    else
140        report("no files are converted for '%s'",filename)
141    end
142end
143
144local function do_convert_one(filename,mapfiles)
145    local resultname = do_convert(filename,mapfiles)
146    if resultname then
147        report("%s => %s", filename,resultname)
148    else
149        report("no result for '%s'",filename)
150    end
151end
152
153function scripts.mptopdf.convertall()
154    local rawmp    = environment.arguments.rawmp    or false
155    local metafun  = environment.arguments.metafun  or false
156    local latex    = environment.arguments.latex    or false
157    local pattern  = environment.arguments.pattern  or false
158    local split    = environment.arguments.split    or false
159    local files    = pattern and dir.glob(file.nameonly(filename)) or environment.files
160    local mapfiles = utilities.parsers.settings_to_array(environment.arguments.mapfiles or basemaps)
161    if #files > 0 then
162        for i=1,#files do
163            local filename = files[i]
164            if file.suffix(filename) == "mp" then
165                local command, convert, texdata, numbers
166                if rawmp then
167                    if metafun then
168                        command, convert = format("mpost --progname=mpost --mem=metafun %s",filename), true
169                    else
170                        command, convert = format("mpost --mem=mpost %s",filename), true
171                    end
172                else
173                    if latex or assumes_latex(filename) then
174                        command, convert = format("mpost --mem=mpost --tex=latex %s",filename), true
175                    elseif texexec then
176                        command, convert = format("texexec --mptex %s",filename), true
177                    else
178                        texdata, numbers = do_texify(io.loaddata(filename) or "")
179                        io.savedata(tempname,texdata)
180                        command, convert = format("context --result=%s --purge --once %s",file.nameonly(filename),tempname), false
181                    end
182                end
183                report("running: %s",command)
184                local done = os.execute(command)
185                if done then
186                    if convert then
187                        do_convert_all(filename,mapfiles)
188                    elseif split then
189                        do_split(filename,numbers,mapfiles)
190                        -- already pdf, maybe optionally split
191                    end
192                else
193                    report("error while processing mp file '%s'", filename)
194                end
195            else
196                do_convert_one(filename,mapfiles)
197            end
198        end
199    else
200        report("no files match to process")
201    end
202end
203
204if environment.argument("exporthelp") then
205    application.export(environment.argument("exporthelp"),environment.files[1])
206elseif environment.files[1] then
207    scripts.mptopdf.convertall()
208else
209    if not environment.argument("help") then
210        report("provide MP output file (or pattern)")
211        report()
212    end
213    application.help()
214end
215