1if not modules then modules = { } end modules ['lpdf-ren'] = {
2 version = 1.001,
3 comment = "companion to lpdf-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11local tostring, tonumber, next = tostring, tonumber, next
12local concat = table.concat
13local formatters = string.formatters
14local settings_to_array = utilities.parsers.settings_to_array
15local getrandom = utilities.randomizer.get
16
17local pdfbackend = backends.registered.pdf
18local nodeinjections = pdfbackend.nodeinjections
19local codeinjections = pdfbackend.codeinjections
20local registrations = pdfbackend.registrations
21
22local viewerlayers = attributes.viewerlayers
23
24local references = structures.references
25
26references.executers = references.executers or { }
27local executers = references.executers
28
29local variables = interfaces.variables
30
31local v_no <const> = variables.no
32local v_yes <const> = variables.yes
33local v_start <const> = variables.start
34local v_stop <const> = variables.stop
35local v_reset <const> = variables.reset
36local v_auto <const> = variables.auto
37local v_random <const> = variables.random
38
39local lpdf = lpdf
40local pdfconstant = lpdf.constant
41local pdfdictionary = lpdf.dictionary
42local pdfarray = lpdf.array
43local pdfreference = lpdf.reference
44local pdfflushobject = lpdf.flushobject
45local pdfreserveobject = lpdf.reserveobject
46local addtopageattributes = lpdf.addtopageattributes
47local addtopageresources = lpdf.addtopageresources
48local addtocatalog = lpdf.addtocatalog
49
50local escaped = lpdf.escaped
51
52local nodes = nodes
53local nuts = nodes.nuts
54
55local copy_node = nuts.copy
56
57local nodepool = nuts.pool
58local register = nodepool.register
59local setstate = nodepool.setstate
60
61local pdf_ocg = pdfconstant("OCG")
62local pdf_ocmd = pdfconstant("OCMD")
63local pdf_off = pdfconstant("OFF")
64local pdf_on = pdfconstant("ON")
65local pdf_view = pdfconstant("View")
66local pdf_design = pdfconstant("Design")
67local pdf_toggle = pdfconstant("Toggle")
68local pdf_setocgstate = pdfconstant("SetOCGState")
69
70local pdf_print = {
71 [v_yes] = pdfdictionary { PrintState = pdf_on },
72 [v_no ] = pdfdictionary { PrintState = pdf_off },
73}
74
75local pdf_intent = {
76 [v_yes] = pdf_view,
77 [v_no] = pdf_design,
78}
79
80local pdf_export = {
81
82
83 [v_yes] = pdfdictionary { ExportState = pdf_on },
84 [v_no] = pdfdictionary { ExportState = pdf_on },
85}
86
87
88
89
90
91
92
93local pdfln, pdfld = { }, { }
94local textlayers, hidelayers, videlayers = pdfarray(), pdfarray(), pdfarray()
95local pagelayers, pagelayersreference, cache = nil, nil, { }
96local alphabetic = { }
97
98local escapednames = table.setmetatableindex(function(t,k)
99
100 local v = escaped(k,true)
101 t[k] = v
102 return v
103end)
104
105local specifications = { }
106local initialized = { }
107
108local function useviewerlayer(name)
109 if not environment.initex and not initialized[name] then
110 local specification = specifications[name]
111 if specification then
112 specifications[name] = nil
113 initialized [name] = true
114 if not pagelayers then
115 pagelayers = pdfdictionary()
116 pagelayersreference = pdfreserveobject()
117 end
118 local tag = specification.tag
119
120 local nn = pdfreserveobject()
121 local nr = pdfreference(nn)
122 local nd = pdfdictionary {
123 Type = pdf_ocg,
124 Name = specification.title or "unknown",
125 Intent = pdf_intent[specification.editable or v_yes],
126 Usage = {
127 Print = pdf_print [specification.printable or v_yes],
128 Export = pdf_export[specification.export or v_yes],
129 },
130 }
131 cache[#cache+1] = { nn, nd }
132 pdfln[tag] = nr
133 local dn = pdfreserveobject()
134 local dr = pdfreference(dn)
135 local dd = pdfdictionary {
136 Type = pdf_ocmd,
137 OCGs = pdfarray { nr },
138 }
139 cache[#cache+1] = { dn, dd }
140 pdfld[tag] = dr
141 textlayers[#textlayers+1] = nr
142 alphabetic[tag] = nr
143 if specification.visible == v_start then
144 videlayers[#videlayers+1] = nr
145 else
146 hidelayers[#hidelayers+1] = nr
147 end
148
149 pagelayers[tag] = dr
150 else
151
152 end
153 end
154end
155
156function codeinjections.defineviewerlayer(specification)
157 if viewerlayers.supported and textlayers then
158 local tag = specification.tag
159 if not specifications[tag] then
160 specifications[tag] = specification
161 end
162 end
163end
164
165function codeinjections.setupviewerlayer(specification)
166 if viewerlayers.supported and textlayers then
167 local tag = specification.tag
168 local set = tag and specifications[tag]
169 if set then
170 for k, v in next, specification do set[k] = v end
171 end
172 end
173end
174
175codeinjections.useviewerlayer = useviewerlayer
176
177local function layerreference(name)
178 local r = pdfln[name]
179 if r then
180 return r
181 else
182 useviewerlayer(name)
183 return pdfln[name]
184 end
185end
186
187lpdf.layerreference = layerreference
188
189local function flushtextlayers()
190 if viewerlayers.supported then
191 if pagelayers then
192 pdfflushobject(pagelayersreference,pagelayers)
193 end
194 for i=1,#cache do
195 local ci = cache[i]
196 pdfflushobject(ci[1],ci[2])
197 end
198 if textlayers and #textlayers > 0 then
199 local sortedlayers = { }
200 for k, v in table.sortedhash(alphabetic) do
201 sortedlayers[#sortedlayers+1] = v
202 end
203 local d = pdfdictionary {
204 OCGs = textlayers,
205 D = pdfdictionary {
206 Name = "Document",
207
208 Order = (viewerlayers.hasorder and sortedlayers) or nil,
209 ON = videlayers,
210 OFF = hidelayers,
211 BaseState = pdf_on,
212 AS = pdfarray {
213 pdfdictionary {
214 Category = pdfarray { pdfconstant("Print") },
215 Event = pdfconstant("Print"),
216 OCGs = (viewerlayers.hasorder and sortedlayers) or nil,
217 }
218 },
219 },
220 }
221 addtocatalog("OCProperties",d)
222 textlayers = nil
223 end
224 end
225end
226
227local function flushpagelayers()
228 if pagelayers then
229 addtopageresources("Properties",pdfreference(pagelayersreference))
230 end
231end
232
233lpdf.registerpagefinalizer (flushpagelayers,"layers")
234lpdf.registerdocumentfinalizer(flushtextlayers,"layers")
235
236local function setlayer(what,arguments)
237
238 arguments = (type(arguments) == "table" and arguments) or settings_to_array(arguments)
239 local state = pdfarray { what }
240 for i=1,#arguments do
241 local p = layerreference(arguments[i])
242 if p then
243 state[#state+1] = p
244 end
245 end
246 return pdfdictionary {
247 S = pdf_setocgstate,
248 State = state,
249 }
250end
251
252function executers.hidelayer (arguments) return setlayer(pdf_off, arguments) end
253function executers.videlayer (arguments) return setlayer(pdf_on, arguments) end
254function executers.togglelayer(arguments) return setlayer(pdf_toggle,arguments) end
255
256
257
258
259local f_bdc = formatters["/OC %s BDC"]
260local s_emc = "EMC"
261
262function codeinjections.startlayer(name)
263 if not name then
264 name = "unknown"
265 end
266 useviewerlayer(name)
267 return f_bdc(escapednames[name])
268end
269
270function codeinjections.stoplayer(name)
271 return s_emc
272end
273
274local cache = { }
275local stop = nil
276
277function nodeinjections.startlayer(name)
278 local c = cache[name]
279 if not c then
280 useviewerlayer(name)
281 c = register(setstate(f_bdc(escapednames[name])))
282 cache[name] = c
283 end
284 return copy_node(c)
285end
286
287function nodeinjections.stoplayer()
288 if not stop then
289 stop = register(setstate(s_emc))
290 end
291 return copy_node(stop)
292end
293
294
295
296local values = viewerlayers.values
297local startlayer = codeinjections.startlayer
298local stoplayer = codeinjections.stoplayer
299
300function nodeinjections.startstackedlayer(s,t,first,last)
301 local r = { }
302 for i=first,last do
303 r[#r+1] = startlayer(values[t[i]])
304 end
305 r = concat(r," ")
306 return setstate(r)
307end
308
309function nodeinjections.stopstackedlayer(s,t,first,last)
310 local r = { }
311 for i=last,first,-1 do
312 r[#r+1] = stoplayer()
313 end
314 r = concat(r," ")
315 return setstate(r)
316end
317
318function nodeinjections.changestackedlayer(s,t1,first1,last1,t2,first2,last2)
319 local r = { }
320 for i=last1,first1,-1 do
321 r[#r+1] = stoplayer()
322 end
323 for i=first2,last2 do
324 r[#r+1] = startlayer(values[t2[i]])
325 end
326 r = concat(r," ")
327 return setstate(r)
328end
329
330
331
332local pagetransitions = {
333 {"split","in","vertical"}, {"split","in","horizontal"},
334 {"split","out","vertical"}, {"split","out","horizontal"},
335 {"blinds","horizontal"}, {"blinds","vertical"},
336 {"box","in"}, {"box","out"},
337 {"wipe","east"}, {"wipe","west"}, {"wipe","north"}, {"wipe","south"},
338 {"dissolve"},
339 {"glitter","east"}, {"glitter","south"},
340 {"fly","in","east"}, {"fly","in","west"}, {"fly","in","north"}, {"fly","in","south"},
341 {"fly","out","east"}, {"fly","out","west"}, {"fly","out","north"}, {"fly","out","south"},
342 {"push","east"}, {"push","west"}, {"push","north"}, {"push","south"},
343 {"cover","east"}, {"cover","west"}, {"cover","north"}, {"cover","south"},
344 {"uncover","east"}, {"uncover","west"}, {"uncover","north"}, {"uncover","south"},
345 {"fade"},
346}
347
348local mapping = {
349 split = { "S" , pdfconstant("Split") },
350 blinds = { "S" , pdfconstant("Blinds") },
351 box = { "S" , pdfconstant("Box") },
352 wipe = { "S" , pdfconstant("Wipe") },
353 dissolve = { "S" , pdfconstant("Dissolve") },
354 glitter = { "S" , pdfconstant("Glitter") },
355 replace = { "S" , pdfconstant("R") },
356 fly = { "S" , pdfconstant("Fly") },
357 push = { "S" , pdfconstant("Push") },
358 cover = { "S" , pdfconstant("Cover") },
359 uncover = { "S" , pdfconstant("Uncover") },
360 fade = { "S" , pdfconstant("Fade") },
361 horizontal = { "Dm" , pdfconstant("H") },
362 vertical = { "Dm" , pdfconstant("V") },
363 ["in"] = { "M" , pdfconstant("I") },
364 out = { "M" , pdfconstant("O") },
365 east = { "Di" , 0 },
366 north = { "Di" , 90 },
367 west = { "Di" , 180 },
368 south = { "Di" , 270 },
369}
370
371local last = 0
372
373
374
375function codeinjections.setpagetransition(specification)
376 local n, delay = specification.n, specification.delay
377 if not n or n == "" then
378 return
379 elseif n == v_auto then
380 if last >= #pagetransitions then
381 last = 0
382 end
383 n = last + 1
384 elseif n == v_stop then
385 return
386 elseif n == v_reset then
387 last = 0
388 return
389 elseif n == v_random then
390 n = getrandom("transition",1,#pagetransitions)
391 else
392 n = tonumber(n)
393 end
394 local t = n and pagetransitions[n] or pagetransitions[1]
395 if not t then
396 t = settings_to_array(n)
397 end
398 if t and #t > 0 then
399 local d = pdfdictionary()
400 for i=1,#t do
401 local m = mapping[t[i]]
402 d[m[1]] = m[2]
403 end
404 delay = tonumber(delay)
405 if delay and delay > 0 then
406 addtopageattributes("Dur",delay)
407 end
408 addtopageattributes("Trans",d)
409 end
410end
411 |