back-mps.lmt /size: 5931 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['back-mps'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to lpdf-ini.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    luatex.registerstopactions(1,function()
83        save()
84    end)
85end
86
87local function initialize(driver,details)
88    reset()
89    b = b + 1
90    buffer[b] = "\n\\startMPpage"
91end
92
93local function finalize(driver,details)
94    b = b + 1
95    buffer[b] = "\\stopMPpage\n"
96    pages[details.pagenumber] = table.concat(buffer,"\n",1,b)
97end
98
99local function wrapup(driver)
100end
101
102local function cleanup(driver)
103    reset()
104end
105
106local function convert(driver,boxnumber,pagenumber)
107    converter(driver,texgetbox(boxnumber),"page",pagenumber)
108end
109
110-- flushers
111
112local last
113
114local function updatefontstate(id)
115    if fonts[id] then
116        last = fonts[id].name
117    else
118        last = "MPSfont" .. converters.Characters(id)
119        fonts[id] = {
120            filename = file.basename(fontproperties[id].filename),
121            size     = fontparameters[id].size * bpfactor,
122            name     = last,
123        }
124    end
125end
126
127local function flushcharacter(current, pos_h, pos_v, pos_r, font, char)
128    b = b + 1
129    buffer[b] = f_glyph(last,char,pos_h*bpfactor,pos_v*bpfactor)
130end
131
132local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
133    if subtype == normalrule_code then
134        b = b + 1
135        buffer[b] = f_rule(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
136    elseif subtype == outlinerule_code then
137        b = b + 1
138        buffer[b] = f_outline(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
139    end
140end
141
142local function flushsimplerule(pos_h, pos_v, pos_r, size_h, size_v)
143    flushrule(false,pos_h,pos_v,pos_r,size_h,size_v,normalrule_code)
144end
145
146local function flushspecialrule(pos_h, pos_v, pos_r, w, h, d, l, outline)
147    flushrule(false,pos_h,pos_v-d,pos_r,w,h+d,outline and outlinerule_code or normalrule_code)
148end
149
150-- installer
151
152drivers.install {
153    name    = "mps",
154    actions = {
155        prepare         = prepare,
156        initialize      = initialize,
157        finalize        = finalize,
158        wrapup          = wrapup,
159        cleanup         = cleanup,
160        convert         = convert,
161        outputfilename  = outputfilename,
162    },
163    flushers = {
164        updatefontstate = updatefontstate,
165        character       = flushcharacter,
166        rule            = flushrule,
167        simplerule      = flushsimplerule,
168        specialrule     = flushspecialrule,
169    }
170}
171
172-- extras
173
174-- if not mp then
175--     return
176-- end
177--
178-- local mpprint    = mp.print
179-- local formatters = string.formatters
180--
181-- local f_glyph = formatters[ [[draw textext.drt("\setfontid%i\relax\char%i\relax") shifted (%N,%N);]] ]
182-- local f_rule  = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
183--
184-- local current = nil
185-- local size    = 0
186--
187-- function mp.place_buffermake(box)
188--     drivers.convert("mps",box)
189--     current = drivers.action("mps","fetch")
190--     size    = #current
191-- end
192--
193-- function mp.place_buffersize()
194--     mpprint(size)
195-- end
196--
197-- function mp.place_bufferslot(i)
198--     if i > 0 and i <= size then
199--         local b = buffer[i]
200--         local t = b[1]
201--         if t == "glyph" then
202--             mpprint(f_glyph(b[2],b[3],b[4]*bpfactor,b[5]*bpfactor))
203--         elseif t == "rule" then
204--             mpprint(f_rule(b[2]*bpfactor,b[3]*bpfactor,b[4]*bpfactor,b[5]*bpfactor))
205--         end
206--     end
207-- end
208--
209-- function mp.place_bufferwipe()
210--     current = nil
211--     size    = 0
212-- end
213