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