summaryrefslogtreecommitdiff
path: root/tex/context/base/lpdf-pdx.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2010-09-03 11:05:00 +0200
committerHans Hagen <pragma@wxs.nl>2010-09-03 11:05:00 +0200
commit0da1a7a94f55a5dc0d318f399eb843303d5b62f6 (patch)
treeb5493406b2f6d8954204b532df5549acbc4baee8 /tex/context/base/lpdf-pdx.lua
parentbbc8970958af29626335568414a4278d852e086f (diff)
downloadcontext-0da1a7a94f55a5dc0d318f399eb843303d5b62f6.tar.gz
beta 2010.09.03 11:05
Diffstat (limited to 'tex/context/base/lpdf-pdx.lua')
-rw-r--r--tex/context/base/lpdf-pdx.lua668
1 files changed, 0 insertions, 668 deletions
diff --git a/tex/context/base/lpdf-pdx.lua b/tex/context/base/lpdf-pdx.lua
deleted file mode 100644
index 34461c43d..000000000
--- a/tex/context/base/lpdf-pdx.lua
+++ /dev/null
@@ -1,668 +0,0 @@
-if not modules then modules = { } end modules ['lpdf-pdx'] = {
- version = 1.001,
- comment = "companion to lpdf-ini.mkiv",
- author = "Peter Rolf and Hans Hagen",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
-}
-
--- context --directives="backend.format=PDF/X-1a:2001" --trackers=backend.format yourfile
-
-local trace_pdfx = false trackers.register("backend.pdfx", function(v) trace_pdfx = v end)
-local trace_format = false trackers.register("backend.format", function(v) trace_format = v end)
-
-local report_backends = logs.new("backends")
-
-local backends, lpdf = backends, lpdf
-
-local codeinjections = backends.pdf.codeinjections -- normally it is registered
-local variables = interfaces.variables
-local viewerlayers = attributes.viewerlayers
-local colors = attributes.colors
-local transparencies = attributes.transparencies
-
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfconstant = lpdf.constant
-local pdfreference = lpdf.reference
-local pdfflushobject = lpdf.flushobject
-local pdfstring = lpdf.string
-local pdfverbose = lpdf.verbose
-local pdfobject = lpdf.object
-
-local addtoinfo, injectxmpinfo, insertxmpinfo = lpdf.addtoinfo, lpdf.injectxmpinfo, lpdf.insertxmpinfo
-
-local lower, gmatch, format, find = string.lower, string.gmatch, string.format, string.find
-local concat, serialize = table.concat, table.serialize
-local settings_to_array, settings_to_hash = utilities.parsers.settings_to_array, utilities.parsers.settings_to_hash
-
-local channels = {
- gray = 1,
- grey = 1,
- rgb = 3,
- cmyk = 4,
-}
-
-local prefixes = {
- gray = "DefaultGray",
- grey = "DefaultGray",
- rgb = "DefaultRGB",
- cmyk = "DefaultCMYK",
-}
-
-local pdfxspecification, pdfxformat = nil, nil
-
--- * correspondent document wide flags (write once) needed for permission tests
-
-local pdfx = {
- ["version"] = {
- external_icc_profiles = 1.4, -- 'p' in name; URL reference of output intent
- jbig2_compression = 1.4,
- jpeg2000_compression = 1.5, -- not supported yet
- nchannel_colorspace = 1.6, -- 'n' in name; n-channel colorspace support
- open_prepress_interface = 1.3, -- 'g' in name; reference to external graphics
- opentype_fonts = 1.6,
- optional_content = 1.5,
- transparency = 1.4,
- object_compression = 1.5,
- },
- ["default"] = {
- pdf_version = 1.7, -- todo: block tex primitive
- format_name = "default",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- spot_colors = true,
- calibrated_rgb_colors = true, -- unknown
- cielab_colors = true, -- unknown
- nchannel_colorspace = true, -- unknown
- internal_icc_profiles = true, -- controls profile inclusion
- external_icc_profiles = true, -- controls profile inclusion
- include_intents = true,
- open_prepress_interface = true, -- unknown
- opentype_fonts = true, -- out of our control
- optional_content = true, -- todo: block at lua level
- transparency = true, -- todo: block at lua level
- jbig2_compression = true, -- todo: block at lua level
- jpeg2000_compression = true, -- todo: block at lua level
- inject_metadata = function()
- -- nothing
- end
- },
- ["pdf/x-1a:2001"] = {
- pdf_version = 1.3,
- format_name = "PDF/X-1a:2001",
- gray_scale = true,
- cmyk_colors = true,
- spot_colors = true,
- internal_icc_profiles = true,
- inject_metadata = function()
- addtoinfo("GTS_PDFXVersion","PDF/X-1a:2001")
- injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2001</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
- end
- },
- ["pdf/x-1a:2003"] = {
- pdf_version = 1.4,
- format_name = "PDF/X-1a:2003",
- gray_scale = true,
- cmyk_colors = true,
- spot_colors = true,
- internal_icc_profiles = true,
- inject_metadata = function()
- addtoinfo("GTS_PDFXVersion","PDF/X-1a:2003")
- injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2003</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
- end
- },
- ["pdf/x-3:2002"] = {
- pdf_version = 1.3,
- format_name = "PDF/X-3:2002",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- include_intents = true,
- inject_metadata = function()
- addtoinfo("GTS_PDFXVersion","PDF/X-3:2002")
- end
- },
- ["pdf/x-3:2003"] = {
- pdf_version = 1.4,
- format_name = "PDF/X-3:2003",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- include_intents = true,
- jbig2_compression = true,
- inject_metadata = function()
- addtoinfo("GTS_PDFXVersion","PDF/X-3:2003")
- end
- },
- ["pdf/x-4"] = {
- pdf_version = 1.6,
- format_name = "PDF/X-4",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- include_intents = true,
- opentype_fonts = true,
- optional_content = true,
- transparency = true,
- jbig2_compression = true,
- jpeg2000_compression = true,
- object_compression = true,
- inject_metadata = function()
- injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
- insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
- insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:RenditionClass>default</xmpMM:RenditonClass>",false)
- end
- },
- ["pdf/x-4p"] = {
- pdf_version = 1.6,
- format_name = "PDF/X-4p",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- external_icc_profiles = true,
- include_intents = true,
- opentype_fonts = true,
- optional_content = true,
- transparency = true,
- jbig2_compression = true,
- jpeg2000_compression = true,
- object_compression = true,
- inject_metadata = function()
- injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4p</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
- insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
- insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:RenditionClass>default</xmpMM:RenditonClass>",false)
- end
- },
- ["pdf/x-5g"] = {
- pdf_version = 1.6,
- format_name = "PDF/X-5g",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- include_intents = true,
- open_prepress_interface = true,
- opentype_fonts = true,
- optional_content = true,
- transparency = true,
- jbig2_compression = true,
- jpeg2000_compression = true,
- object_compression = true,
- inject_metadata = function()
- -- todo
- end
- },
- ["pdf/x-5pg"] = {
- pdf_version = 1.6,
- format_name = "PDF/X-5pg",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- external_icc_profiles = true,
- include_intents = true,
- open_prepress_interface = true,
- opentype_fonts = true,
- optional_content = true,
- transparency = true,
- jbig2_compression = true,
- jpeg2000_compression = true,
- object_compression = true,
- inject_metadata = function()
- -- todo
- end
- },
- ["pdf/x-5n"] = {
- pdf_version = 1.6,
- format_name = "PDF/X-5n",
- gray_scale = true,
- cmyk_colors = true,
- rgb_colors = true,
- calibrated_rgb_colors = true,
- spot_colors = true,
- cielab_colors = true,
- internal_icc_profiles = true,
- include_intents = true,
- opentype_fonts = true,
- optional_content = true,
- transparency = true,
- jbig2_compression = true,
- jpeg2000_compression = true,
- nchannel_colorspace = true,
- object_compression = true,
- inject_metadata = function()
- -- todo
- end
- }
-}
-
-lpdf.pdfx = pdfx -- it does not hurt to have this one visible
-
-local filenames = {
- "colorprofiles.xml",
- "colorprofiles.lua",
-}
-
-local function locatefile(filename)
- local fullname = resolvers.find_file(filename,"icc")
- if not fullname or fullname == "" then
- fullname = resolvers.finders.loc(filename) -- could be specific to the project
- end
- return fullname or ""
-end
-
-local function loadprofile(name,filename)
- local profile = false
- local databases = filename and filename ~= "" and settings_to_array(filename) or filenames
- for i=1,#databases do
- local filename = locatefile(databases[i])
- if filename and filename ~= "" then
- local suffix = file.extname(filename)
- local lname = lower(name)
- if suffix == "xml" then
- local xmldata = xml.load(filename) -- no need for caching it
- if xmldata then
- profile = xml.filter(xmldata,format('xml://profiles/profile/(info|filename)[lower(text())=="%s"]/../table()',lname))
- end
- elseif suffix == "lua" then
- local luadata = loadfile(filename)
- luadata = ludata and luadata()
- if luadata then
- profile = luadata[name] or luadata[lname] -- hashed
- if not profile then
- for i=1,#luadata do
- local li = luadata[i]
- if lower(li.info) == lname then -- indexed
- profile = li
- break
- end
- end
- end
- end
- end
- if profile then
- if next(profile) then
- report_backends("profile specification '%s' loaded from '%s'",name,filename)
- return profile
- elseif trace_pdfx then
- report_backends("profile specification '%s' loaded from '%s' but empty",name,filename)
- end
- return false
- end
- end
- end
- report_backends("profile specification '%s' not found in '%s'",name,concat(filenames, ", "))
-end
-
-local function urls(url)
- if not url or url == "" then
- return nil
- else
- local u = pdfarray()
- for url in gmatch(url,"([^, ]+)") do
- if find(url,"^http") then
- u[#u+1] = pdfdictionary {
- FS = pdfconstant("URL"),
- F = pdfstring(url),
- }
- end
- end
- return u
- end
-end
-
-local function profilename(filename)
- return lower(file.basename(filename))
-end
-
-local internalprofiles = { }
-
-local function handleinternalprofile(s,include)
- local filename, colorspace = s.filename or "", s.colorspace or ""
- if filename == "" or colorspace == "" then
- report_backends("error in internal profile specification: %s",serialize(s,false))
- else
- local tag = profilename(filename)
- local profile = internalprofiles[tag]
- if not profile then
- local colorspace = lower(colorspace)
- if include then
- -- local fullname = resolvers.findctxfile(filename) or ""
- local fullname = locatefile(filename)
- local channel = channels[colorspace] or nil
- if fullname == "" then
- report_backends("error, couldn't locate profile '%s'",filename)
- elseif not channel then
- report_backends("error, couldn't resolve channel entry for colorspace '%s'",colorspace)
- else
- local a = pdfdictionary { N = channel }
- profile = pdfobject { -- does a flush too
- compresslevel = 0,
- immediate = true, -- !
- type = "stream",
- file = fullname,
- attr = a(),
- }
- internalprofiles[tag] = profile
- if trace_pdfx then
- report_backends("including '%s' color profile from '%s'",colorspace,fullname)
- end
- end
- else
- internalprofiles[tag] = true
- if trace_pdfx then
- report_backends("not including '%s' color profile '%s'",colorspace,filename)
- end
- end
- end
- return profile
- end
-end
-
-local externalprofiles = { }
-
-local function handleexternalprofile(s,include) -- specification (include ignored here)
- local name, url, filename, checksum, version, colorspace =
- s.info or s.filename or "", s.url or "", s.filename or "", s.checksum or "", s.version or "", s.colorspace or ""
- if false then -- somehow leads to invalid pdf
- local iccprofile = colors.iccprofile(filename)
- if iccprofile then
- name = name ~= "" and name or iccprofile.tags.desc.cleaned or ""
- url = url ~= "" and url or iccprofile.tags.dmnd.cleaned or ""
- checksum = checksum ~= "" and checksum or file.checksum(iccprofile.fullname) or ""
- version = version ~= "" and version or iccprofile.header.version or ""
- colorspace = colorspace ~= "" and colorspace or iccprofile.header.colorspace or ""
- end
- -- table.print(iccprofile)
- end
- if name == "" or url == "" or checksum == "" or version == "" or colorspace == "" or filename == "" then
- local profile = handleinternalprofile(s)
- if profile then
- report_backends("incomplete external profile specification, falling back to internal")
- else
- report_backends("error in external profile specification: %s",serialize(s,false))
- end
- else
- local tag = profilename(filename)
- local profile = externalprofiles[tag]
- if not profile then
- local d = pdfdictionary {
- ProfileName = name, -- not file name!
- ProfileCS = colorspace,
- URLs = urls(url), -- array containing at least one URL
- CheckSum = pdfverbose { "<", lower(checksum), ">" }, -- 16byte MD5 hash
- ICCVersion = pdfverbose { "<", version, ">" }, -- bytes 8..11 from the header of the ICC profile, as a hex string
- }
- profile = pdfflushobject(d)
- externalprofiles[tag] = profile
- end
- return profile
- end
-end
-
-local loadeddefaults = { }
-
-local function handledefaultprofile(s) -- specification
- local filename, colorspace = s.filename or "", lower(s.colorspace or "")
- if filename == "" or colorspace == "" then
- report_backends("error in default profile specification: %s",serialize(s,false))
- elseif not loadeddefaults[colorspace] then
- local tag = profilename(filename)
- local n = internalprofiles[tag] -- or externalprofiles[tag]
- if n == true then -- not internalized
- report_backends("no default profile '%s' for colorspace '%s'",filename,colorspace)
- elseif n then
- local a = pdfarray {
- pdfconstant("ICCBased"),
- pdfreference(n),
- }
- -- used in page /Resources, so this must be inserted at runtime
- lpdf.adddocumentcolorspace(prefixes[colorspace],pdfreference(pdfflushobject(a)))
- loadeddefaults[colorspace] = true
- report_backends("setting '%s' as default '%s' color space",filename,colorspace)
- else
- report_backends("no default profile '%s' for colorspace '%s'",filename,colorspace)
- end
- elseif trace_pdfx then
- report_backends("a default '%s' colorspace is already in use",colorspace)
- end
-end
-
-local loadedintents, intents = { }, pdfarray()
-
-local function handleoutputintent(s)
- local name, url, filename, id, outputcondition, info = s.info or s.filename or "", s.url or "", s.filename or "", s.id or "", s.outputcondition or "", s.info or ""
- if name == "" or id == "" then
- report_backends("error in output intent specification: %s",serialize(s,false))
- elseif not loadedintents[name] then
- local tag = profilename(filename)
- local internal, external = internalprofiles[tag], externalprofiles[tag]
- if internal or external then
- local d = {
- Type = pdfconstant("OutputIntent"),
- S = pdfconstant("GTS_PDFX"),
- OutputConditionIdentifier = id,
- RegistryName = url,
- OutputCondition = outputcondition,
- Info = info,
- }
- if internal and internal ~= true then
- d.DestOutputProfile = pdfreference(internal)
- elseif external and external ~= true then
- d.DestOutputProfileRef = pdfreference(external)
- else
- report_backends("omitting reference to profile for intent '%s'",name)
- end
- intents[#intents+1] = pdfreference(pdfflushobject(pdfdictionary(d)))
- if trace_pdfx then
- report_backends("setting output intent to '%s' with id '%s' (entry %s)",name,id,#intents)
- end
- else
- report_backends("invalid output intent '%s'",name)
- end
- loadedintents[name] = true
- elseif trace_pdfx then
- report_backends("an output intent with name '%s' is already in use",name)
- end
-end
-
-local function handleiccprofile(message,name,filename,how,options,alwaysinclude)
- if name and name ~= "" then
- local list = settings_to_array(name)
- for i=1,#list do
- local name = list[i]
- local profile = loadprofile(name,filename)
- if trace_pdfx then
- report_backends("handling %s '%s'",message,name)
- end
- if profile then
- if pdfxspecification.cmyk_colors then
- profile.colorspace = profile.colorspace or "CMYK"
- else
- profile.colorspace = profile.colorspace or "RGB"
- end
- local external = pdfxspecification.external_icc_profiles
- local internal = pdfxspecification.internal_icc_profiles
- local include = pdfxspecification.include_intents
- local always, never = options[variables.always], options[variables.never]
- if always or alwaysinclude then
- if trace_pdfx then
- report_backends("forcing internal profiles") -- can make preflight unhappy
- end
- -- internal, external = true, false
- internal, external = not never, false
- elseif never then
- if trace_pdfx then
- report_backends("forcing external profiles") -- can make preflight unhappy
- end
- internal, external = false, true
- end
- if external then
- if trace_pdfx then
- report_backends("handling external profiles cf. '%s'",name)
- end
- handleexternalprofile(profile,false)
- else
- if trace_pdfx then
- report_backends("handling internal profiles cf. '%s'",name)
- end
- if internal then
- handleinternalprofile(profile,always or include)
- else
- report_backends("no profile inclusion for '%s'",pdfxformat)
- end
- end
- how(profile)
- elseif trace_pdfx then
- report_backends("unknown profile '%s'",name)
- end
- end
- end
-end
-
-local function flushoutputintents()
- if #intents > 0 then
- lpdf.addtocatalog("OutputIntents",pdfreference(pdfflushobject(intents)))
- end
-end
-
-lpdf.registerdocumentfinalizer(flushoutputintents,2,"output intents")
-
-directives.register("backend.format", function(v)
- codeinjections.setformat(v)
-end)
-
-function codeinjections.setformat(s)
- local format, level, profile, intent, option, filename =
- s.format or "", s.level or "", s.profile or "", s.intent or "", s.option or "", s.file or ""
- if format == "" then
- -- we ignore this as we hook it in \everysetupbackend
- else
- local spec = pdfx[lower(format)]
- if spec then
- pdfxspecification, pdfxformat = spec, spec.format_name
- level = level and tonumber(level)
- report_backends("setting format to '%s'",pdfxformat)
- local pdf_version, inject_metadata = spec.pdf_version * 10, spec.inject_metadata
- local majorversion, minorversion = math.div(pdf_version,10), math.mod(pdf_version,10)
- local objectcompression = spec.object_compression and pdf_version >= 15
- local compresslevel = level or tex.pdfcompresslevel -- keep default
- local objectcompresslevel = (objectcompression and level or tex.pdfobjcompresslevel) or 0
- tex.pdfcompresslevel, tex.pdfobjcompresslevel = compresslevel, objectcompresslevel
- tex.pdfmajorversion, tex.pdfminorversion = majorversion, minorversion
- if objectcompression then
- report_backends("forcing pdf version %s.%s, compression level %s, object compression level %s",
- majorversion,minorversion,compresslevel,objectcompresslevel)
- elseif compresslevel > 0 then
- report_backends("forcing pdf version %s.%s, compression level %s, object compression disabled",
- majorversion,minorversion,compresslevel)
- else
- report_backends("forcing pdf version %s.%s, compression disabled",
- majorversion,minorversion)
- end
- --
- -- context.setupcolors { -- not this way
- -- cmyk = spec.cmyk_colors and variables.yes or variables.no,
- -- rgb = spec.rgb_colors and variables.yes or variables.no,
- -- }
- --
- colors.forcesupport(
- spec.gray_scale or false,
- spec.rgb_colors or false,
- spec.cmyk_colors or false,
- spec.spot_colors or false,
- spec.nchannel_colorspace or false
- )
- transparencies.forcesupport(
- spec.transparency or false
- )
- viewerlayers.forcesupport(
- spec.optional_content or false
- )
- viewerlayers.setfeatures(
- spec.has_order or false -- new
- )
- --
- -- spec.jbig2_compression : todo, block in image inclusion
- -- spec.jpeg2000_compression : todo, block in image inclusion
- --
- if type(inject_metadata) == "function" then
- inject_metadata()
- end
- local options = settings_to_hash(option)
- handleiccprofile("color profile",profile,filename,handledefaultprofile,options,true)
- handleiccprofile("output intent",intent,filename,handleoutputintent,options,false)
- if trace_format then
- for k, v in table.sortedhash(pdfx.default) do
- local v = pdfxspecification[k]
- if type(v) ~= "function" then
- report_backends("%s = %s",k,tostring(v or false))
- end
- end
- end
- function codeinjections.setformat(noname)
- report_backends("error, format is already set to '%s', ignoring '%s'",pdfxformat,noname.format)
- end
- else
- report_backends("error, format '%s' is not supported",format)
- end
- end
-end
-
-function codeinjections.getformatoption(key)
- return pdfxspecification and pdfxspecification[key]
-end
-
-function codeinjections.supportedformats()
- local t = { }
- for k, v in table.sortedhash(pdfx) do
- if find(k,"pdf") then
- t[#t+1] = k
- end
- end
- return t
-end
-
---~ The following is somewhat cleaner but then we need to flag that there are
---~ color spaces set so that the page flusher does not optimize the (at that
---~ moment) still empty array away. So, next(d_colorspaces) should then become
---~ a different test, i.e. also on flag. I'll add that when we need more forward
---~ referencing.
---~
---~ local function embedprofile = handledefaultprofile
---~
---~ local function flushembeddedprofiles()
---~ for colorspace, filename in next, defaults do
---~ embedprofile(colorspace,filename)
---~ end
---~ end
---~
---~ local function handledefaultprofile(s)
---~ defaults[lower(s.colorspace)] = s.filename
---~ end
---~
---~ lpdf.registerdocumentfinalizer(flushembeddedprofiles,1,"embedded color profiles")