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