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