1if not modules then modules = { } end modules ['back-imp-lua'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to back-imp-lua.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
10
11
12local fontproperties = fonts.hashes.properties
13local fontparameters = fonts.hashes.parameters
14local fontshapes = fonts.hashes.shapes
15
16local starttiming = statistics.starttiming
17local stoptiming = statistics.stoptiming
18
19local bpfactor = number.dimenfactors.bp
20local texgetbox = tex.getbox
21
22local rulecodes = nodes.rulecodes
23local normalrule_code = rulecodes.normal
24
25
26
27
28
29
30
31
32local outlinerule_code = rulecodes.outline
33
34
35
36local pages = { }
37local fonts = { }
38local names = { }
39local mapping = { }
40local used = { }
41local shapes = { }
42local glyphs = { }
43local buffer = { }
44local metadata = nil
45local b = 0
46local converter = nil
47
48local compact = false
49local shapestoo = true
50
51local x, y, d, f, c, w, h, t, r, o
52
53local function reset()
54 buffer = { }
55 b = 0
56 t = nil
57 x = nil
58 y = nil
59 d = nil
60 f = nil
61 c = nil
62 w = nil
63 h = nil
64 r = nil
65 o = nil
66end
67
68local function result()
69 return {
70 metadata = metadata,
71 fonts = fonts,
72 pages = pages,
73 shapes = shapes,
74 }
75end
76
77
78
79local function outputfilename(driver)
80 return tex.jobname .. "-output.lua"
81end
82
83local function save()
84 local filename = outputfilename()
85 drivers.report("saving result in %a",filename)
86 starttiming(drivers)
87 local data = result()
88 if data then
89 io.savedata(filename,table.serialize(data))
90 end
91 stoptiming(drivers)
92end
93
94local function prepare(driver)
95 converter = drivers.converters.lmtx
96
97 backends.initialize("lua")
98
99 luatex.registerstopactions(1,function()
100 save()
101 end)
102end
103
104local function initialize(driver,details)
105 reset()
106end
107
108local function finalize(driver,details)
109 local n = details.pagenumber
110 local b = details.boundingbox
111 pages[n] = {
112 number = n,
113 content = buffer,
114 boundingbox = {
115 b[1] * bpfactor,
116 b[2] * bpfactor,
117 b[3] * bpfactor,
118 b[4] * bpfactor,
119 },
120 }
121 if not metadata then
122
123
124 local identity = interactions.general.getidentity()
125 local jobname = environment.jobname or tex.jobname or "unknown"
126 metadata = {
127 unit = "bp",
128 jobname = jobname,
129 title = identity.title,
130 subject = identity.subject,
131 author = identity.author,
132 keywords = identity.keywords,
133 time = os.date("%Y-%m-%d %H:%M"),
134 engine = environment.luatexengine .. " " .. environment.luatexversion,
135 context = environment.version,
136 }
137 end
138end
139
140local function wrapup(driver)
141end
142
143local function cleanup(driver)
144 reset()
145end
146
147local function convert(driver,boxnumber,pagenumber)
148 converter(driver,texgetbox(boxnumber),"page",pagenumber)
149end
150
151
152
153local function updatefontstate(id)
154 if not mapping[id] then
155 local fn = #fonts + 1
156 mapping[id] = fn
157 local properties = fontproperties[id]
158 local parameters = fontparameters[id]
159 local filename = file.basename(properties.filename)
160 local fontname = properties.fullname or properties.fontname
161 if shapestoo then
162 if not names[fontname] then
163 local sn = #shapes+1
164 names[fontname] = sn
165 shapes[sn] = { }
166 glyphs[sn] = fontshapes[id].glyphs
167 end
168 end
169 fonts[fn] = {
170 filename = filename,
171 name = fontname,
172 size = parameters.size * bpfactor,
173 shapes = shapestoo and names[fontname] or nil,
174 }
175 end
176end
177
178local function flushcharacter(current, pos_h, pos_v, pos_r, font, char)
179 local fnt = mapping[font]
180 b = b + 1
181 buffer[b] = {
182 t = "glyph" ~= t and "glyph" or nil,
183 f = font ~= f and fnt or nil,
184 c = char ~= c and char or nil,
185 x = pos_h ~= x and (pos_h * bpfactor) or nil,
186 y = pos_v ~= y and (pos_v * bpfactor) or nil,
187 d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
188 }
189 t = "glyph"
190 f = font
191 c = char
192 x = pos_h
193 y = pos_v
194 d = pos_r
195 if shapestoo then
196
197 local sn = fonts[fnt].shapes
198 local shp = shapes[sn]
199 if not shp[char] then
200 shp[char] = glyphs[sn][char]
201 end
202 end
203end
204
205local function flush_rule(current, pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
206 b = b + 1
207 buffer[b] = {
208 t = "rule" ~= t and "rule" or nil,
209 r = rule_s ~= r and rule_s or nil,
210 o = rule_s == "outline" and rule_o ~= o and (rule_o * bpfactor) or nil,
211 w = size_h ~= w and (size_h * bpfactor) or nil,
212 h = size_v ~= h and (size_v * bpfactor) or nil,
213 x = pos_h ~= x and (pos_h * bpfactor) or nil,
214 y = pos_v ~= y and (pos_v * bpfactor) or nil,
215 d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
216 }
217 t = "rule"
218 w = size_h
219 h = size_v
220 x = pos_h
221 y = pos_v
222 d = pos_r
223end
224
225local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
226 local rule_s, rule_o
227 if subtype == normalrule_code then
228 rule_s = normal_rule_code
229 elseif subtype == outlinerule_code then
230 rule_s = outline_rule_code
231 rule_o = getdata(current)
232 else
233 return
234 end
235 return flush_rule(pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
236end
237
238local function flushsimplerule(pos_h, pos_v, pos_r, size_h, size_v)
239 return flush_rule(false,pos_h,pos_v,pos_r,size_h,size_v,normalrule_code,nil)
240end
241
242local function flushspecialrule(pos_h, pos_v, pos_r, w, h, d, l, outline)
243 return flush_rule(false,pos_h,pos_v-d,pos_r,w,h+d,outline and outlinerule_code or normalrule_code)
244end
245
246
247
248
249
250
251
252drivers.install {
253 name = "lua",
254 actions = {
255 prepare = prepare,
256 initialize = initialize,
257 finalize = finalize,
258 wrapup = wrapup,
259 cleanup = cleanup,
260 convert = convert,
261 outputfilename = outputfilename,
262 },
263 flushers = {
264 updatefontstate = updatefontstate,
265 character = flushcharacter,
266 rule = flushrule,
267 simplerule = flushsimplerule,
268 specialrule = flushspecialrule,
269 }
270}
271
272
273
274local function outputfilename(driver)
275 return tex.jobname .. "-output.json"
276end
277
278local function save()
279 local filename = outputfilename()
280 drivers.report("saving result in %a",filename)
281 starttiming(drivers)
282 local data = result()
283 if data then
284 if not utilities.json then
285 require("util-jsn")
286 end
287 io.savedata(filename,utilities.json.tostring(data,not compact))
288 end
289 stoptiming(drivers)
290end
291
292local function prepare(driver)
293 converter = drivers.converters.lmtx
294 luatex.registerstopactions(1,function()
295 save()
296 end)
297end
298
299
300
301drivers.install {
302 name = "json",
303 actions = {
304 prepare = prepare,
305 wrapup = wrapup,
306 cleanup = cleanup,
307
308 initialize = initialize,
309 convert = convert,
310 finalize = finalize,
311
312 outputfilename = outputfilename,
313 },
314 flushers = {
315 updatefontstate = updatefontstate,
316 character = flushcharacter,
317 rule = flushrule,
318 simplerule = flushsimplerule,
319 specialrule = flushspecialrule,
320 setstate = function() end,
321 }
322}
323
324
325
326local function outputfilename(driver)
327 return tex.jobname .. "-output.js"
328end
329
330local function save()
331 local filename = outputfilename()
332 drivers.report("saving result in %a",filename)
333 starttiming(drivers)
334 local data = result()
335 if data then
336 if not utilities.json then
337 require("util-jsn")
338 end
339 io.savedata(filename,
340 "const JSON_CONTEXT = JSON.parse ( `" ..
341 utilities.json.tostring(data,not compact) ..
342 "` ) ;\n"
343 )
344 end
345 stoptiming(drivers)
346end
347
348local function prepare(driver)
349 converter = drivers.converters.lmtx
350
351 backends.initialize("js")
352
353 luatex.registerstopactions(1,function()
354 save()
355 end)
356end
357
358
359
360drivers.install {
361 name = "js",
362 actions = {
363 prepare = prepare,
364 initialize = initialize,
365 finalize = finalize,
366 wrapup = wrapup,
367 cleanup = cleanup,
368 convert = convert,
369 outputfilename = outputfilename,
370 },
371 flushers = {
372 updatefontstate = updatefontstate,
373 character = flushcharacter,
374 rule = flushrule,
375 simplerule = flushsimplerule,
376 specialrule = flushspecialrule,
377 }
378}
379 |