back-imp-mps.lmt /size: 6107 b    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['back-imp-mps'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to back-imp-mps.mkiv",
5    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10local fontproperties    = fonts.hashes.properties
11local fontparameters    = fonts.hashes.parameters
12
13local starttiming       = statistics.starttiming
14local stoptiming        = statistics.stoptiming
15
16local texgetbox         = tex.getbox
17local formatters        = string.formatters
18
19local rulecodes         = nodes.rulecodes
20
21local normalrule_code   <const> = rulecodes.normal
22----- boxrule_code      <const> = rulecodes.box
23----- imagerule_code    <const> = rulecodes.image
24----- emptyrule_code    <const> = rulecodes.empty
25----- userrule_code     <const> = rulecodes.user
26----- overrule_code     <const> = rulecodes.over
27----- underrule_code    <const> = rulecodes.under
28----- fractionrule_code <const> = rulecodes.fraction
29----- radicalrule_code  <const> = rulecodes.radical
30local outlinerule_code  <const> = rulecodes.outline
31
32local bpfactor          <const> = number.dimenfactors.bp
33
34local fonts     = { }
35local pages     = { }
36local buffer    = { }
37local b         = 0
38local converter = nil
39
40local function reset()
41    buffer = { }
42    b      = 0
43end
44
45-- todo: high efficient helpers:
46
47local f_font    = formatters[ "\\definefont[%s][file:%s*none @ %sbp]\n" ]
48
49local f_glyph   = formatters[ [[draw textext.drt("\%s\char%i\relax") shifted (%N,%N);]] ]
50local f_rule    = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
51local f_outline = formatters[ [[draw unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
52
53-- actions
54
55local function outputfilename(driver)
56    return tex.jobname .. "-output.tex"
57end
58
59local function save() -- might become a driver function that already is plugged into stopactions
60    starttiming(drivers)
61    if #pages > 0 then
62        local filename = outputfilename()
63        drivers.report("saving result in %a",filename)
64        reset()
65        b = b + 1
66        buffer[b] = "\\starttext\n"
67        for k, v in table.sortedhash(fonts) do
68            b = b + 1
69            buffer[b] = f_font(v.name,v.filename,v.size)
70        end
71        for i=1,#pages do
72            b = b + 1
73            buffer[b] = pages[i]
74        end
75        b = b + 1
76        buffer[b] = "\\stoptext\n"
77        io.savedata(filename,table.concat(buffer,"",1,b))
78    end
79    stoptiming(drivers)
80end
81
82local function prepare(driver)
83    converter = drivers.converters.lmtx
84 -- if not environment.initex then
85        backends.initialize("mps")
86 -- end
87    luatex.registerstopactions(1,function()
88        save()
89    end)
90end
91
92local function initialize(driver,details)
93    reset()
94    b = b + 1
95    buffer[b] = "\n\\startMPpage"
96end
97
98local function finalize(driver,details)
99    b = b + 1
100    buffer[b] = "\\stopMPpage\n"
101    pages[details.pagenumber] = table.concat(buffer,"\n",1,b)
102end
103
104local function wrapup(driver)
105end
106
107local function cleanup(driver)
108    reset()
109end
110
111local function convert(driver,boxnumber,pagenumber)
112    converter(driver,texgetbox(boxnumber),"page",pagenumber)
113end
114
115-- flushers
116
117local last
118
119local function updatefontstate(id)
120    if fonts[id] then
121        last = fonts[id].name
122    else
123        last = "MPSfont" .. converters.Characters(id)
124        fonts[id] = {
125            filename = file.basename(fontproperties[id].filename),
126            size     = fontparameters[id].size * bpfactor,
127            name     = last,
128        }
129    end
130end
131
132local function flushcharacter(current, pos_h, pos_v, pos_r, font, char)
133    b = b + 1
134    buffer[b] = f_glyph(last,char,pos_h*bpfactor,pos_v*bpfactor)
135end
136
137local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
138    if subtype == normalrule_code then
139        b = b + 1
140        buffer[b] = f_rule(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
141    elseif subtype == outlinerule_code then
142        b = b + 1
143        buffer[b] = f_outline(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
144    end
145end
146
147local function flushsimplerule(pos_h, pos_v, pos_r, size_h, size_v)
148    flushrule(false,pos_h,pos_v,pos_r,size_h,size_v,normalrule_code)
149end
150
151local function flushspecialrule(pos_h, pos_v, pos_r, w, h, d, l, outline)
152    flushrule(false,pos_h,pos_v-d,pos_r,w,h+d,outline and outlinerule_code or normalrule_code)
153end
154
155-- installer
156
157drivers.install {
158    name    = "mps",
159    actions = {
160        prepare         = prepare,
161        initialize      = initialize,
162        finalize        = finalize,
163        wrapup          = wrapup,
164        cleanup         = cleanup,
165        convert         = convert,
166        outputfilename  = outputfilename,
167    },
168    flushers = {
169        updatefontstate = updatefontstate,
170        character       = flushcharacter,
171        rule            = flushrule,
172        simplerule      = flushsimplerule,
173        specialrule     = flushspecialrule,
174    }
175}
176
177-- extras
178
179-- if not mp then
180--     return
181-- end
182--
183-- local mpprint    = mp.print
184-- local formatters = string.formatters
185--
186-- local f_glyph = formatters[ [[draw textext.drt("\setfontid%i\relax\char%i\relax") shifted (%N,%N);]] ]
187-- local f_rule  = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
188--
189-- local current = nil
190-- local size    = 0
191--
192-- function mp.place_buffermake(box)
193--     drivers.convert("mps",box)
194--     current = drivers.action("mps","fetch")
195--     size    = #current
196-- end
197--
198-- function mp.place_buffersize()
199--     mpprint(size)
200-- end
201--
202-- function mp.place_bufferslot(i)
203--     if i > 0 and i <= size then
204--         local b = buffer[i]
205--         local t = b[1]
206--         if t == "glyph" then
207--             mpprint(f_glyph(b[2],b[3],b[4]*bpfactor,b[5]*bpfactor))
208--         elseif t == "rule" then
209--             mpprint(f_rule(b[2]*bpfactor,b[3]*bpfactor,b[4]*bpfactor,b[5]*bpfactor))
210--         end
211--     end
212-- end
213--
214-- function mp.place_bufferwipe()
215--     current = nil
216--     size    = 0
217-- end
218