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