1if not modules then modules = { } end modules ['lpdf-mis'] = {
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
11
12
13
14
15
16
17
18local next, tostring, type = next, tostring, type
19local format, gsub, formatters = string.format, string.gsub, string.formatters
20local concat, flattened = table.concat, table.flattened
21local settings_to_array = utilities.parsers.settings_to_array
22
23local pdfbackend = backends and backends.registered.pdf or { }
24local nodeinjections = pdfbackend.nodeinjections
25local codeinjections = pdfbackend.codeinjections
26local registrations = pdfbackend.registrations
27
28local getpagedimensions = layouts.getpagedimensions
29local getcanvas = layouts.getcanvas
30
31local nodes = nodes
32local nuts = nodes.nuts
33local copy_node = nuts.copy
34
35local nodepool = nuts.pool
36local setstate = nodepool.setstate
37local register = nodepool.register
38
39local lpdf = lpdf
40local pdfdictionary = lpdf.dictionary
41local pdfarray = lpdf.array
42local pdfconstant = lpdf.constant
43local pdfreference = lpdf.reference
44local pdfunicode = lpdf.unicode
45local pdfverbose = lpdf.verbose
46local pdfstring = lpdf.string
47local pdfaction = lpdf.action
48local pdfflushobject = lpdf.flushobject
49local pdfflushstreamobject = lpdf.flushstreamobject
50local pdfminorversion = lpdf.minorversion
51
52local adddocumentextgstate = lpdf.adddocumentextgstate
53local addtocatalog = lpdf.addtocatalog
54local addtoinfo = lpdf.addtoinfo
55local addtopageattributes = lpdf.addtopageattributes
56local addtonames = lpdf.addtonames
57
58local texset = tex.set
59
60local variables = interfaces.variables
61
62local v_stop = variables.stop
63local v_none = variables.none
64local v_max = variables.max
65local v_bookmark = variables.bookmark
66local v_fit = variables.fit
67local v_doublesided = variables.doublesided
68local v_singlesided = variables.singlesided
69local v_default = variables.default
70local v_auto = variables.auto
71local v_fixed = variables.fixed
72local v_landscape = variables.landscape
73local v_portrait = variables.portrait
74local v_page = variables.page
75local v_paper = variables.paper
76local v_attachment = variables.attachment
77local v_layer = variables.layer
78local v_lefttoright = variables.lefttoright
79local v_righttoleft = variables.righttoleft
80local v_title = variables.title
81local v_nomenubar = variables.nomenubar
82
83local positive = register(setstate("/GSpositive gs"))
84local negative = register(setstate("/GSnegative gs"))
85local overprint = register(setstate("/GSoverprint gs"))
86local knockout = register(setstate("/GSknockout gs"))
87
88local omitextraboxes = false
89
90directives.register("backend.omitextraboxes", function(v) omitextraboxes = v end)
91
92local function initializenegative()
93 local a = pdfarray { 0, 1 }
94 local g = pdfconstant("ExtGState")
95 local d = pdfdictionary {
96 FunctionType = 4,
97 Range = a,
98 Domain = a,
99 }
100 local negative = pdfdictionary { Type = g, TR = pdfreference(pdfflushstreamobject("{ 1 exch sub }",d)) }
101 local positive = pdfdictionary { Type = g, TR = pdfconstant("Identity") }
102 adddocumentextgstate("GSnegative", pdfreference(pdfflushobject(negative)))
103 adddocumentextgstate("GSpositive", pdfreference(pdfflushobject(positive)))
104 initializenegative = nil
105end
106
107local function initializeoverprint()
108 local g = pdfconstant("ExtGState")
109 local knockout = pdfdictionary { Type = g, OP = false, OPM = 0 }
110 local overprint = pdfdictionary { Type = g, OP = true, OPM = 1 }
111 adddocumentextgstate("GSknockout", pdfreference(pdfflushobject(knockout)))
112 adddocumentextgstate("GSoverprint", pdfreference(pdfflushobject(overprint)))
113 initializeoverprint = nil
114end
115
116function nodeinjections.overprint()
117 if initializeoverprint then initializeoverprint() end
118 return copy_node(overprint)
119end
120function nodeinjections.knockout ()
121 if initializeoverprint then initializeoverprint() end
122 return copy_node(knockout)
123end
124
125function nodeinjections.positive()
126 if initializenegative then initializenegative() end
127 return copy_node(positive)
128end
129function nodeinjections.negative()
130 if initializenegative then initializenegative() end
131 return copy_node(negative)
132end
133
134
135
136
137
138
139
140
141
142
143
144
145
146local openpage, closepage, opendocument, closedocument
147
148function codeinjections.registerdocumentopenaction(open)
149 opendocument = open
150end
151
152function codeinjections.registerdocumentcloseaction(close)
153 closedocument = close
154end
155
156function codeinjections.registerpageopenaction(open)
157 openpage = open
158end
159
160function codeinjections.registerpagecloseaction(close)
161 closepage = close
162end
163
164local function flushdocumentactions()
165 if opendocument then
166 addtocatalog("OpenAction",pdfaction(opendocument))
167 end
168 if closedocument then
169 addtocatalog("CloseAction",pdfaction(closedocument))
170 end
171end
172
173local function flushpageactions()
174 if openpage or closepage then
175 local d = pdfdictionary()
176 if openpage then
177 d.O = pdfaction(openpage)
178 end
179 if closepage then
180 d.C = pdfaction(closepage)
181 end
182 addtopageattributes("AA",d)
183 end
184end
185
186lpdf.registerpagefinalizer (flushpageactions, "page actions")
187lpdf.registerdocumentfinalizer(flushdocumentactions,"document actions")
188
189
190
191
192
193
194
195local function flushjavascripts()
196 local t = interactions.javascripts.flushpreambles()
197 if #t > 0 then
198 local a = pdfarray()
199 local pdf_javascript = pdfconstant("JavaScript")
200 for i=1,#t do
201 local ti = t[i]
202 local name = ti[1]
203 local script = ti[2]
204 local j = pdfdictionary {
205 S = pdf_javascript,
206 JS = pdfreference(pdfflushstreamobject(script)),
207 }
208 a[#a+1] = pdfstring(name)
209 a[#a+1] = pdfreference(pdfflushobject(j))
210 end
211 addtonames("JavaScript",pdfreference(pdfflushobject(pdfdictionary{ Names = a })))
212 end
213end
214
215lpdf.registerdocumentfinalizer(flushjavascripts,"javascripts")
216
217
218
219local plusspecs = {
220 [v_max] = {
221 mode = "FullScreen",
222 },
223 [v_bookmark] = {
224 mode = "UseOutlines",
225 },
226 [v_attachment] = {
227 mode = "UseAttachments",
228 },
229 [v_layer] = {
230 mode = "UseOC",
231 },
232 [v_fit] = {
233 fit = true,
234 },
235 [v_doublesided] = {
236 layout = "TwoColumnRight",
237 },
238 [v_fixed] = {
239 fixed = true,
240 },
241 [v_landscape] = {
242 duplex = "DuplexFlipShortEdge",
243 },
244 [v_portrait] = {
245 duplex = "DuplexFlipLongEdge",
246 },
247 [v_page] = {
248 duplex = "Simplex" ,
249 },
250 [v_paper] = {
251 paper = true,
252 },
253 [v_title] ={
254 title = true,
255 },
256 [v_lefttoright] ={
257 direction = "L2R",
258 },
259 [v_righttoleft] ={
260 direction = "R2L",
261 },
262 [v_nomenubar] ={
263 nomenubar = true,
264 },
265}
266
267local pagespecs = {
268
269 [v_max] = plusspecs[v_max],
270 [v_bookmark] = plusspecs[v_bookmark],
271 [v_attachment] = plusspecs[v_attachment],
272 [v_layer] = plusspecs[v_layer],
273 [v_lefttoright] = plusspecs[v_lefttoright],
274 [v_righttoleft] = plusspecs[v_righttoleft],
275 [v_title] = plusspecs[v_title],
276
277 [v_none] = {
278 },
279 [v_fit] = {
280 mode = "UseNone",
281 fit = true,
282 },
283 [v_doublesided] = {
284 mode = "UseNone",
285 layout = "TwoColumnRight",
286 fit = true,
287 },
288 [v_singlesided] = {
289 mode = "UseNone"
290 },
291 [v_default] = {
292 mode = "UseNone",
293 layout = "auto",
294 },
295 [v_auto] = {
296 mode = "UseNone",
297 layout = "auto",
298 },
299 [v_fixed] = {
300 mode = "UseNone",
301 layout = "auto",
302 fixed = true,
303 },
304 [v_landscape] = {
305 mode = "UseNone",
306 layout = "auto",
307 fixed = true,
308 duplex = "DuplexFlipShortEdge",
309 },
310 [v_portrait] = {
311 mode = "UseNone",
312 layout = "auto",
313 fixed = true,
314 duplex = "DuplexFlipLongEdge",
315 },
316 [v_page] = {
317 mode = "UseNone",
318 layout = "auto",
319 fixed = true,
320 duplex = "Simplex",
321 },
322 [v_paper] = {
323 mode = "UseNone",
324 layout = "auto",
325 fixed = true,
326 duplex = "Simplex",
327 paper = true,
328 },
329 [v_nomenubar] = {
330 mode = "UseNone",
331 layout = "auto",
332 nomenubar = true,
333 },
334}
335
336local function documentspecification()
337 local canvas = getcanvas()
338
339
340
341 local pagespec = canvas.pagespec
342 if not pagespec or pagespec == "" then
343 pagespec = v_default
344 end
345 local settings = settings_to_array(pagespec)
346
347 local first = settings[1]
348 local defaults = pagespecs[first]
349 local spec = defaults or pagespecs[v_default]
350
351 if spec.layout == "auto" then
352 if canvas.doublesided then
353 local s = pagespecs[v_doublesided]
354 for k, v in next, s do
355 spec[k] = v
356 end
357 else
358 spec.layout = false
359 end
360 end
361
362 for i=defaults and 2 or 1,#settings do
363 local s = plusspecs[settings[i]]
364 if s then
365 for k, v in next, s do
366 spec[k] = v
367 end
368 end
369 end
370
371 local layout = spec.layout
372 local mode = spec.mode
373 local fit = spec.fit
374 local fixed = spec.fixed
375 local duplex = spec.duplex
376 local paper = spec.paper
377 local title = spec.title
378 local direction = spec.direction
379 local nomenubar = spec.nomenubar
380 if layout then
381 addtocatalog("PageLayout",pdfconstant(layout))
382 end
383 if mode then
384 addtocatalog("PageMode",pdfconstant(mode))
385 end
386 local prints = nil
387 local marked = canvas.marked
388 local copies = canvas.copies
389 if marked then
390 local pages = structures.pages
391 local marked = pages.allmarked(marked)
392 local nofmarked = marked and #marked or 0
393 if nofmarked > 0 then
394
395
396 for i=1,#marked do marked[i] = marked[i] - 1 end
397 prints = pdfarray(flattened(pages.toranges(marked)))
398 end
399 end
400 if fit or fixed or duplex or copies or paper or prints or title or direction or nomenubar then
401 addtocatalog("ViewerPreferences",pdfdictionary {
402 FitWindow = fit and true or nil,
403 PrintScaling = fixed and pdfconstant("None") or nil,
404 Duplex = duplex and pdfconstant(duplex) or nil,
405 NumCopies = copies and copies or nil,
406 PickTrayByPDFSize = paper and true or nil,
407 PrintPageRange = prints or nil,
408 DisplayDocTitle = title and true or nil,
409 Direction = direction and pdfconstant(direction) or nil,
410 HideMenubar = nomenubar and true or nil,
411 })
412 end
413 addtoinfo ("Trapped", pdfconstant("False"))
414 addtocatalog("Version", pdfconstant(format("1.%s",pdfminorversion())))
415 addtocatalog("Lang", pdfstring(tokens.getters.macro("currentmainlanguage")))
416end
417
418local bpfactor = number.dimenfactors.bp
419
420local function pagespecification()
421 local canvas = getcanvas()
422 local paperwidth = canvas.paperwidth
423 local paperheight = canvas.paperheight
424 local leftoffset = canvas.leftoffset
425 local topoffset = canvas.topoffset
426
427 local llx = leftoffset
428 local urx = canvas.width - leftoffset
429 local lly = paperheight + topoffset - canvas.height
430 local ury = paperheight - topoffset
431
432 local function extrabox(WhatBox,offset,always)
433 if offset ~= 0 or always then
434 addtopageattributes(WhatBox, pdfarray {
435 (llx + offset) * bpfactor,
436 (lly + offset) * bpfactor,
437 (urx - offset) * bpfactor,
438 (ury - offset) * bpfactor,
439 })
440 end
441 end
442 if omitextraboxes then
443
444 else
445 extrabox("CropBox",canvas.cropoffset,true)
446 extrabox("TrimBox",canvas.trimoffset,true)
447 extrabox("BleedBox",canvas.bleedoffset)
448
449 end
450end
451
452lpdf.registerpagefinalizer(pagespecification,"page specification")
453lpdf.registerdocumentfinalizer(documentspecification,"document specification")
454
455
456
457
458
459
460
461
462local map = {
463 numbers = "D",
464 Romannumerals = "R",
465 romannumerals = "r",
466 Characters = "A",
467 characters = "a",
468}
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500local function featurecreep()
501 local pages = structures.pages.tobesaved
502 local list = pdfarray()
503 local getset = structures.sets.get
504 local stopped = false
505 local oldlabel = nil
506 local olconversion = nil
507 for i=1,#pages do
508 local p = pages[i]
509 if not p then
510 return
511 end
512 local label = p.viewerprefix or ""
513 if p.status == v_stop then
514 if not stopped then
515 list[#list+1] = i - 1
516 list[#list+1] = pdfdictionary {
517 P = pdfunicode(label),
518 }
519 stopped = true
520 end
521 oldlabel = nil
522 oldconversion = nil
523 stopped = false
524 else
525 local numberdata = p.numberdata
526 local conversion = nil
527 local number = p.number
528 if numberdata then
529 local conversionset = numberdata.conversionset
530 if conversionset then
531 conversion = getset("structure:conversions",p.block,conversionset,1,"numbers")
532 end
533 end
534
535
536 conversion = conversion and map[conversion] or map.numbers
537 if number == 1 or oldlabel ~= label or oldconversion ~= conversion then
538 list[#list+1] = i - 1
539 list[#list+1] = pdfdictionary {
540 S = pdfconstant(conversion),
541 St = number,
542 P = label ~= "" and pdfunicode(label) or nil,
543 }
544 end
545 oldlabel = label
546 oldconversion = conversion
547 stopped = false
548 end
549 end
550 addtocatalog("PageLabels", pdfdictionary { Nums = list })
551end
552
553lpdf.registerdocumentfinalizer(featurecreep,"featurecreep")
554 |