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