summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt')
-rw-r--r--Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt639
1 files changed, 639 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt b/Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt
new file mode 100644
index 00000000000..afb149d8af7
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkxl/lpdf-mis.lmt
@@ -0,0 +1,639 @@
+if not modules then modules = { } end modules ['lpdf-mis'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Although we moved most pdf handling to the lua end, we didn't change
+-- the overall approach. For instance we share all resources i.e. we
+-- don't make subsets for each xform or page. The current approach is
+-- quite efficient. A big difference between MkII and MkIV is that we
+-- now use forward references. In this respect the MkII code shows that
+-- it evolved over a long period, when backends didn't provide forward
+-- referencing and references had to be tracked in multiple passes. Of
+-- course there are a couple of more changes.
+
+local next, tostring, type = next, tostring, type
+local format, gsub, formatters = string.format, string.gsub, string.formatters
+local concat, flattened = table.concat, table.flattened
+local settings_to_array = utilities.parsers.settings_to_array
+
+local backends, lpdf, nodes = backends, lpdf, nodes
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local getpagedimensions = layouts.getpagedimensions
+local getcanvas = layouts.getcanvas
+
+local nuts = nodes.nuts
+local copy_node = nuts.copy
+
+local nodepool = nuts.pool
+local setstate = nodepool.setstate
+local register = nodepool.register
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfverbose = lpdf.verbose
+local pdfstring = lpdf.string
+local pdfaction = lpdf.action
+
+local pdfflushobject
+local pdfflushstreamobject
+local pdfminorversion
+
+updaters.register("backend.update.lpdf",function()
+ pdfflushobject = lpdf.flushobject
+ pdfflushstreamobject = lpdf.flushstreamobject
+ pdfminorversion = lpdf.minorversion
+end)
+
+local formattedtimestamp = lpdf.pdftimestamp
+local adddocumentextgstate = lpdf.adddocumentextgstate
+local addtocatalog = lpdf.addtocatalog
+local addtoinfo = lpdf.addtoinfo
+local addtopageattributes = lpdf.addtopageattributes
+local addtonames = lpdf.addtonames
+
+local pdfgetmetadata = lpdf.getmetadata
+
+local texset = tex.set
+
+local variables = interfaces.variables
+
+local v_stop = variables.stop
+local v_none = variables.none
+local v_max = variables.max
+local v_bookmark = variables.bookmark
+local v_fit = variables.fit
+local v_doublesided = variables.doublesided
+local v_singlesided = variables.singlesided
+local v_default = variables.default
+local v_auto = variables.auto
+local v_fixed = variables.fixed
+local v_landscape = variables.landscape
+local v_portrait = variables.portrait
+local v_page = variables.page
+local v_paper = variables.paper
+local v_attachment = variables.attachment
+local v_layer = variables.layer
+local v_lefttoright = variables.lefttoright
+local v_righttoleft = variables.righttoleft
+local v_title = variables.title
+local v_nomenubar = variables.nomenubar
+
+local positive = register(setstate("/GSpositive gs"))
+local negative = register(setstate("/GSnegative gs"))
+local overprint = register(setstate("/GSoverprint gs"))
+local knockout = register(setstate("/GSknockout gs"))
+
+local omitextraboxes = false
+
+directives.register("backend.omitextraboxes", function(v) omitextraboxes = v end)
+
+local function initializenegative()
+ local a = pdfarray { 0, 1 }
+ local g = pdfconstant("ExtGState")
+ local d = pdfdictionary {
+ FunctionType = 4,
+ Range = a,
+ Domain = a,
+ }
+ local negative = pdfdictionary { Type = g, TR = pdfreference(pdfflushstreamobject("{ 1 exch sub }",d)) } -- can be shared
+ local positive = pdfdictionary { Type = g, TR = pdfconstant("Identity") }
+ adddocumentextgstate("GSnegative", pdfreference(pdfflushobject(negative)))
+ adddocumentextgstate("GSpositive", pdfreference(pdfflushobject(positive)))
+ initializenegative = nil
+end
+
+local function initializeoverprint()
+ local g = pdfconstant("ExtGState")
+ local knockout = pdfdictionary { Type = g, OP = false, OPM = 0 }
+ local overprint = pdfdictionary { Type = g, OP = true, OPM = 1 }
+ adddocumentextgstate("GSknockout", pdfreference(pdfflushobject(knockout)))
+ adddocumentextgstate("GSoverprint", pdfreference(pdfflushobject(overprint)))
+ initializeoverprint = nil
+end
+
+function nodeinjections.overprint()
+ if initializeoverprint then initializeoverprint() end
+ return copy_node(overprint)
+end
+function nodeinjections.knockout ()
+ if initializeoverprint then initializeoverprint() end
+ return copy_node(knockout)
+end
+
+function nodeinjections.positive()
+ if initializenegative then initializenegative() end
+ return copy_node(positive)
+end
+function nodeinjections.negative()
+ if initializenegative then initializenegative() end
+ return copy_node(negative)
+end
+
+-- function codeinjections.addtransparencygroup()
+-- -- png: /CS /DeviceRGB /I true
+-- local d = pdfdictionary {
+-- S = pdfconstant("Transparency"),
+-- I = true,
+-- K = true,
+-- }
+-- lpdf.registerpagefinalizer(function() addtopageattributes("Group",d) end) -- hm
+-- end
+
+-- actions (todo: store and update when changed)
+
+local openpage, closepage, opendocument, closedocument
+
+function codeinjections.registerdocumentopenaction(open)
+ opendocument = open
+end
+
+function codeinjections.registerdocumentcloseaction(close)
+ closedocument = close
+end
+
+function codeinjections.registerpageopenaction(open)
+ openpage = open
+end
+
+function codeinjections.registerpagecloseaction(close)
+ closepage = close
+end
+
+local function flushdocumentactions()
+ if opendocument then
+ addtocatalog("OpenAction",pdfaction(opendocument))
+ end
+ if closedocument then
+ addtocatalog("CloseAction",pdfaction(closedocument))
+ end
+end
+
+local function flushpageactions()
+ if openpage or closepage then
+ local d = pdfdictionary()
+ if openpage then
+ d.O = pdfaction(openpage)
+ end
+ if closepage then
+ d.C = pdfaction(closepage)
+ end
+ addtopageattributes("AA",d)
+ end
+end
+
+lpdf.registerpagefinalizer (flushpageactions, "page actions")
+lpdf.registerdocumentfinalizer(flushdocumentactions,"document actions")
+
+--- info : this can change and move elsewhere
+
+local identity = { }
+
+function codeinjections.setupidentity(specification)
+ for k, v in next, specification do
+ if v ~= "" then
+ identity[k] = v
+ end
+ end
+end
+
+function codeinjections.getidentityvariable(name)
+ return identity[name]
+end
+
+local done = false -- using "setupidentity = function() end" fails as the meaning is frozen in register
+
+local function setupidentity()
+ if not done then
+ local metadata = pdfgetmetadata()
+ local creator = metadata.creator
+ local version = metadata.contextversion
+ local time = metadata.time
+ local jobname = environment.jobname or tex.jobname or "unknown"
+ --
+ local title = identity.title
+ if not title or title == "" then
+ title = tex.jobname
+ end
+ addtoinfo("Title", pdfunicode(title), title)
+ local subtitle = identity.subtitle or ""
+ if subtitle ~= "" then
+ addtoinfo("Subject", pdfunicode(subtitle), subtitle)
+ end
+ local author = identity.author or ""
+ if author ~= "" then
+ addtoinfo("Author", pdfunicode(author), author) -- '/Author' in /Info, 'Creator' in XMP
+ end
+ addtoinfo("Creator", pdfunicode(creator), creator)
+ addtoinfo("CreationDate", pdfstring(formattedtimestamp(time)))
+ local date = identity.date or ""
+ local pdfdate = date and formattedtimestamp(date)
+ if pdfdate then
+ addtoinfo("ModDate", pdfstring(pdfdate), date)
+ else
+ -- users should enter the date in 2010-01-19T23:27:50+01:00 format
+ -- and if not provided that way we use the creation time instead
+ addtoinfo("ModDate", pdfstring(formattedtimestamp(time)),time)
+ end
+ local keywords = identity.keywords or ""
+ if keywords ~= "" then
+ keywords = concat(settings_to_array(keywords), " ")
+ addtoinfo("Keywords", pdfunicode(keywords), keywords)
+ end
+ local id = lpdf.id()
+ addtoinfo("ID", pdfstring(id), id) -- needed for pdf/x
+ --
+ addtoinfo("ConTeXt.Version",version)
+ addtoinfo("ConTeXt.Time",os.date("%Y-%m-%d %H:%M"))
+ addtoinfo("ConTeXt.Jobname",jobname)
+ addtoinfo("ConTeXt.Url","www.pragma-ade.com")
+ addtoinfo("ConTeXt.Support","contextgarden.net")
+ addtoinfo("TeX.Support","tug.org")
+ --
+ done = true
+ else
+ -- no need for a message
+ end
+end
+
+lpdf.registerpagefinalizer(setupidentity,"identity")
+
+-- or when we want to be able to set things after pag e1:
+--
+-- lpdf.registerdocumentfinalizer(setupidentity,1,"identity")
+
+local function flushjavascripts()
+ local t = interactions.javascripts.flushpreambles()
+ if #t > 0 then
+ local a = pdfarray()
+ local pdf_javascript = pdfconstant("JavaScript")
+ for i=1,#t do
+ local ti = t[i]
+ local name = ti[1]
+ local script = ti[2]
+ local j = pdfdictionary {
+ S = pdf_javascript,
+ JS = pdfreference(pdfflushstreamobject(script)),
+ }
+ a[#a+1] = pdfstring(name)
+ a[#a+1] = pdfreference(pdfflushobject(j))
+ end
+ addtonames("JavaScript",pdfreference(pdfflushobject(pdfdictionary{ Names = a })))
+ end
+end
+
+lpdf.registerdocumentfinalizer(flushjavascripts,"javascripts")
+
+-- -- --
+
+local plusspecs = {
+ [v_max] = {
+ mode = "FullScreen",
+ },
+ [v_bookmark] = {
+ mode = "UseOutlines",
+ },
+ [v_attachment] = {
+ mode = "UseAttachments",
+ },
+ [v_layer] = {
+ mode = "UseOC",
+ },
+ [v_fit] = {
+ fit = true,
+ },
+ [v_doublesided] = {
+ layout = "TwoColumnRight",
+ },
+ [v_fixed] = {
+ fixed = true,
+ },
+ [v_landscape] = {
+ duplex = "DuplexFlipShortEdge",
+ },
+ [v_portrait] = {
+ duplex = "DuplexFlipLongEdge",
+ },
+ [v_page] = {
+ duplex = "Simplex" ,
+ },
+ [v_paper] = {
+ paper = true,
+ },
+ [v_title] ={
+ title = true,
+ },
+ [v_lefttoright] ={
+ direction = "L2R",
+ },
+ [v_righttoleft] ={
+ direction = "R2L",
+ },
+ [v_nomenubar] ={
+ nomenubar = true,
+ },
+}
+
+local pagespecs = {
+ --
+ [v_max] = plusspecs[v_max],
+ [v_bookmark] = plusspecs[v_bookmark],
+ [v_attachment] = plusspecs[v_attachment],
+ [v_layer] = plusspecs[v_layer],
+ [v_lefttoright] = plusspecs[v_lefttoright],
+ [v_righttoleft] = plusspecs[v_righttoleft],
+ [v_title] = plusspecs[v_title],
+ --
+ [v_none] = {
+ },
+ [v_fit] = {
+ mode = "UseNone",
+ fit = true,
+ },
+ [v_doublesided] = {
+ mode = "UseNone",
+ layout = "TwoColumnRight",
+ fit = true,
+ },
+ [v_singlesided] = {
+ mode = "UseNone"
+ },
+ [v_default] = {
+ mode = "UseNone",
+ layout = "auto",
+ },
+ [v_auto] = {
+ mode = "UseNone",
+ layout = "auto",
+ },
+ [v_fixed] = {
+ mode = "UseNone",
+ layout = "auto",
+ fixed = true, -- noscale
+ },
+ [v_landscape] = {
+ mode = "UseNone",
+ layout = "auto",
+ fixed = true,
+ duplex = "DuplexFlipShortEdge",
+ },
+ [v_portrait] = {
+ mode = "UseNone",
+ layout = "auto",
+ fixed = true,
+ duplex = "DuplexFlipLongEdge",
+ },
+ [v_page] = {
+ mode = "UseNone",
+ layout = "auto",
+ fixed = true,
+ duplex = "Simplex",
+ },
+ [v_paper] = {
+ mode = "UseNone",
+ layout = "auto",
+ fixed = true,
+ duplex = "Simplex",
+ paper = true,
+ },
+ [v_nomenubar] = {
+ mode = "UseNone",
+ layout = "auto",
+ nomenubar = true,
+ },
+}
+
+local function documentspecification()
+ local canvas = getcanvas()
+
+ -- move this to layo-ini ?
+
+ local pagespec = canvas.pagespec
+ if not pagespec or pagespec == "" then
+ pagespec = v_default
+ end
+ local settings = settings_to_array(pagespec)
+ -- so the first one detemines the defaults
+ local first = settings[1]
+ local defaults = pagespecs[first]
+ local spec = defaults or pagespecs[v_default]
+ -- successive keys can modify this
+ if spec.layout == "auto" then
+ if canvas.doublesided then
+ local s = pagespecs[v_doublesided] -- to be checked voor interfaces
+ for k, v in next, s do
+ spec[k] = v
+ end
+ else
+ spec.layout = false
+ end
+ end
+ -- we start at 2 when we have a valid first default set
+ for i=defaults and 2 or 1,#settings do
+ local s = plusspecs[settings[i]]
+ if s then
+ for k, v in next, s do
+ spec[k] = v
+ end
+ end
+ end
+
+ -- maybe interfaces.variables
+ local layout = spec.layout
+ local mode = spec.mode
+ local fit = spec.fit
+ local fixed = spec.fixed
+ local duplex = spec.duplex
+ local paper = spec.paper
+ local title = spec.title
+ local direction = spec.direction
+ local nomenubar = spec.nomenubar
+ if layout then
+ addtocatalog("PageLayout",pdfconstant(layout))
+ end
+ if mode then
+ addtocatalog("PageMode",pdfconstant(mode))
+ end
+ local prints = nil
+ local marked = canvas.marked
+ local copies = canvas.copies
+ if marked then
+ local pages = structures.pages
+ local marked = pages.allmarked(marked)
+ local nofmarked = marked and #marked or 0
+ if nofmarked > 0 then
+ -- the spec is wrong in saying that numbering starts at 1 which of course makes
+ -- sense as most real documents start with page 0 .. sigh
+ for i=1,#marked do marked[i] = marked[i] - 1 end
+ prints = pdfarray(flattened(pages.toranges(marked)))
+ end
+ end
+ if fit or fixed or duplex or copies or paper or prints or title or direction or nomenubar then
+ addtocatalog("ViewerPreferences",pdfdictionary {
+ FitWindow = fit and true or nil,
+ PrintScaling = fixed and pdfconstant("None") or nil,
+ Duplex = duplex and pdfconstant(duplex) or nil,
+ NumCopies = copies and copies or nil,
+ PickTrayByPDFSize = paper and true or nil,
+ PrintPageRange = prints or nil,
+ DisplayDocTitle = title and true or nil,
+ Direction = direction and pdfconstant(direction) or nil,
+ HideMenubar = nomenubar and true or nil,
+ })
+ end
+ addtoinfo ("Trapped", pdfconstant("False")) -- '/Trapped' in /Info, 'Trapped' in XMP
+ addtocatalog("Version", pdfconstant(format("1.%s",pdfminorversion())))
+ addtocatalog("Lang", pdfstring(tokens.getters.macro("currentmainlanguage")))
+end
+
+-- temp hack: the mediabox is not under our control and has a precision of 5 digits
+
+local factor = number.dimenfactors.bp
+local f_value = formatters["%.6N"]
+
+local function boxvalue(n) -- we could share them
+ return pdfverbose(f_value(factor * n))
+end
+
+local function pagespecification()
+ local canvas = getcanvas()
+ local paperwidth = canvas.paperwidth
+ local paperheight = canvas.paperheight
+ local leftoffset = canvas.leftoffset
+ local topoffset = canvas.topoffset
+ --
+ local llx = leftoffset
+ local urx = canvas.width - leftoffset
+ local lly = paperheight + topoffset - canvas.height
+ local ury = paperheight - topoffset
+ -- boxes can be cached
+ local function extrabox(WhatBox,offset,always)
+ if offset ~= 0 or always then
+ addtopageattributes(WhatBox, pdfarray {
+ boxvalue(llx + offset),
+ boxvalue(lly + offset),
+ boxvalue(urx - offset),
+ boxvalue(ury - offset),
+ })
+ end
+ end
+ if omitextraboxes then
+ -- only useful for testing / comparing
+ else
+ extrabox("CropBox",canvas.cropoffset,true) -- mandate for rendering
+ extrabox("TrimBox",canvas.trimoffset,true) -- mandate for pdf/x
+ extrabox("BleedBox",canvas.bleedoffset) -- optional
+ -- extrabox("ArtBox",canvas.artoffset) -- optional .. unclear what this is meant to do
+ end
+end
+
+lpdf.registerpagefinalizer(pagespecification,"page specification")
+lpdf.registerdocumentfinalizer(documentspecification,"document specification")
+
+-- Page Label support ...
+--
+-- In principle we can also support /P (prefix) as we can just use the verbose form
+-- and we can then forget about the /St (start) as we don't care about those few
+-- extra bytes due to lack of collapsing. Anyhow, for that we need a stupid prefix
+-- variant and that's not on the agenda now.
+
+local map = {
+ numbers = "D",
+ Romannumerals = "R",
+ romannumerals = "r",
+ Characters = "A",
+ characters = "a",
+}
+
+-- local function featurecreep()
+-- local pages, lastconversion, list = structures.pages.tobesaved, nil, pdfarray()
+-- local getstructureset = structures.sets.get
+-- for i=1,#pages do
+-- local p = pages[i]
+-- if not p then
+-- return -- fatal error
+-- else
+-- local numberdata = p.numberdata
+-- if numberdata then
+-- local conversionset = numberdata.conversionset
+-- if conversionset then
+-- local conversion = getstructureset("structure:conversions",p.block,conversionset,1,"numbers")
+-- if conversion ~= lastconversion then
+-- lastconversion = conversion
+-- list[#list+1] = i - 1 -- pdf starts numbering at 0
+-- list[#list+1] = pdfdictionary { S = pdfconstant(map[conversion] or map.numbers) }
+-- end
+-- end
+-- end
+-- if not lastconversion then
+-- lastconversion = "numbers"
+-- list[#list+1] = i - 1 -- pdf starts numbering at 0
+-- list[#list+1] = pdfdictionary { S = pdfconstant(map.numbers) }
+-- end
+-- end
+-- end
+-- addtocatalog("PageLabels", pdfdictionary { Nums = list })
+-- end
+
+local function featurecreep()
+ local pages = structures.pages.tobesaved
+ local list = pdfarray()
+ local getset = structures.sets.get
+ local stopped = false
+ local oldlabel = nil
+ local olconversion = nil
+ for i=1,#pages do
+ local p = pages[i]
+ if not p then
+ return -- fatal error
+ end
+ local label = p.viewerprefix or ""
+ if p.status == v_stop then
+ if not stopped then
+ list[#list+1] = i - 1 -- pdf starts numbering at 0
+ list[#list+1] = pdfdictionary {
+ P = pdfunicode(label),
+ }
+ stopped = true
+ end
+ oldlabel = nil
+ oldconversion = nil
+ stopped = false
+ else
+ local numberdata = p.numberdata
+ local conversion = nil
+ local number = p.number
+ if numberdata then
+ local conversionset = numberdata.conversionset
+ if conversionset then
+ conversion = getset("structure:conversions",p.block,conversionset,1,"numbers")
+ end
+ end
+ conversion = conversion and map[conversion] or map.numbers
+ if number == 1 or oldlabel ~= label or oldconversion ~= conversion then
+ list[#list+1] = i - 1 -- pdf starts numbering at 0
+ list[#list+1] = pdfdictionary {
+ S = pdfconstant(conversion),
+ St = number,
+ P = label ~= "" and pdfunicode(label) or nil,
+ }
+ end
+ oldlabel = label
+ oldconversion = conversion
+ stopped = false
+ end
+ end
+ addtocatalog("PageLabels", pdfdictionary { Nums = list })
+end
+
+lpdf.registerdocumentfinalizer(featurecreep,"featurecreep")