From 85b7bc695629926641c7cb752fd478adfdf374f3 Mon Sep 17 00:00:00 2001 From: Marius Date: Sun, 4 Jul 2010 15:32:09 +0300 Subject: stable 2010-05-24 13:10 --- tex/context/base/back-pdf.lua | 469 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 tex/context/base/back-pdf.lua (limited to 'tex/context/base/back-pdf.lua') diff --git a/tex/context/base/back-pdf.lua b/tex/context/base/back-pdf.lua new file mode 100644 index 000000000..54e22f1a2 --- /dev/null +++ b/tex/context/base/back-pdf.lua @@ -0,0 +1,469 @@ +if not modules then modules = { } end modules ['back-pdf'] = { + version = 1.001, + comment = "companion to back-pdf.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- we will move code to lpdf-* files (second cleanup stage) + +--[[ldx-- +

This module implements a couple of cleanup methods. We need these +in order to meet the specification. Watch the double +parenthesis; they are needed because otherwise we would pass more +than one argument to .

+--ldx]]-- + +local type, next, tostring = type, next, tostring +local char, byte, format, gsub, rep, gmatch = string.char, string.byte, string.format, string.gsub, string.rep, string.gmatch +local concat = table.concat +local round = math.round +local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues +local texsprint, texwrite = tex.sprint, tex.write +local ctxcatcodes = tex.ctxcatcodes + +local copy_node = node.copy + +local nodeinjections = backends.pdf.nodeinjections +local codeinjections = backends.pdf.codeinjections +local registrations = backends.pdf.registrations + +local pdfliteral, register = nodes.pdfliteral, nodes.register + +local pdfconstant = lpdf.constant +local pdfstring = lpdf.string +local pdfdictionary = lpdf.dictionary +local pdfarray = lpdf.array +local pdfreference = lpdf.reference +local pdfverbose = lpdf.verbose +local pdfflushobject = lpdf.flushobject +local pdfreserveobject = lpdf.reserveobject +local pdfannotation = nodes.pdfannotation + +local pdfreserveobj = pdf.reserveobj +local pdfimmediateobj = pdf.immediateobj + +function nodeinjections.rgbcolor(r,g,b) + return register(pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b))) +end + +function nodeinjections.cmykcolor(c,m,y,k) + return register(pdfliteral(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k))) +end + +function nodeinjections.graycolor(s) -- caching 0/1 does not pay off + return register(pdfliteral(format("%s g %s G",s,s))) +end + +function nodeinjections.spotcolor(n,f,d,p) + if type(p) == "string" then + p = gsub(p,","," ") -- brr misuse of spot + end + return register(pdfliteral(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p))) +end + +function nodeinjections.transparency(n) + return register(pdfliteral(format("/Tr%s gs",n))) +end + +local effects = { + normal = 0, + inner = 0, + outer = 1, + both = 2, + hidden = 3, +} + +function nodeinjections.effect(effect,stretch,rulethickness) + -- always, no zero test (removed) + rulethickness = number.dimenfactors["bp"] * rulethickness + effect = effects[effect] or effects['normal'] + return register(pdfliteral(format("%s Tc %s w %s Tr",stretch,rulethickness,effect))) -- watch order +end + +-- cached .. + +local cache = { } + +function nodeinjections.startlayer(name) + local c = cache[name] + if not c then + c = register(pdfliteral(format("/OC /%s BDC",name))) + cache[name] = c + end + return copy_node(c) +end + +local stop = register(pdfliteral("EMC")) + +function nodeinjections.stoplayer() + return copy_node(stop) +end + +local cache = { } + +function nodeinjections.switchlayer(name) + local c = cache[name] + if not c then + c = register(pdfliteral(format("EMC /OC /%s BDC",name))) + end + return copy_node(c) +end + +-- code + +function codeinjections.insertmovie(specification) + -- managed in figure inclusion: width, height, factor, repeat, controls, preview, label, foundname + local width = specification.width + local height = specification.height + local factor = specification.factor or number.dimenfactors.bp + local moviedict = pdfdictionary { + F = specification.foundname, + Aspect = pdfarray { factor * width, factor * height }, + Poster = (specification.preview and true) or false, + } + local controldict = pdfdictionary { + ShowControls = (specification.controls and true) or false, + Mode = (specification["repeat"] and pdfconstant("Repeat")) or nil, + } + local action = pdfdictionary { + Subtype = pdfconstant("Movie"), + Border = pdfarray { 0, 0, 0 }, + T = format("movie %s",specification.label), + Movie = moviedict, + A = controldict, + } + node.write(pdfannotation(width,height,0,action())) +end + +function codeinjections.insertsound(specification) + -- rmanaged in interaction: repeat, label, foundname + local soundclip = interactions.soundclip(specification.label) + if soundclip then + local controldict = pdfdictionary { + Mode = (specification["repeat"] and pdfconstant("Repeat")) or nil + } + local sounddict = pdfdictionary { + F = soundclip.filename + } + local action = pdfdictionary { + Subtype = pdfconstant("Movie"), + Border = pdfarray { 0, 0, 0 }, + T = format("sound %s",specification.label), + Movie = sounddict, + A = controldict, + } + node.write(pdfannotation(0,0,0,action())) + end +end + +-- spot- and indexcolors + +local pdf_separation = pdfconstant("Separation") +local pdf_indexed = pdfconstant("Indexed") +local pdf_device_n = pdfconstant("DeviceN") +local pdf_device_rgb = pdfconstant("DeviceRGB") +local pdf_device_cmyk = pdfconstant("DeviceCMYK") +local pdf_device_gray = pdfconstant("DeviceGray") +local pdf_extgstate = pdfconstant("ExtGState") + +local pdf_rbg_range = pdfarray { 0, 1, 0, 1, 0, 1 } +local pdf_cmyk_range = pdfarray { 0, 1, 0, 1, 0, 1, 0, 1 } +local pdf_gray_range = pdfarray { 0, 1 } + +local rgb_function = "dup %s mul exch dup %s mul exch %s mul" +local cmyk_function = "dup %s mul exch dup %s mul exch dup %s mul exch %s mul" +local gray_function = "%s mul" + +local documentcolorspaces = pdfdictionary() + +local spotcolorhash = { } -- not needed +local spotcolornames = { } +local indexcolorhash = { } +local delayedindexcolors = { } + +function registrations.spotcolorname(name,e) + spotcolornames[name] = e or name +end + +local function registersomespotcolor(name,noffractions,names,p,colorspace,range,funct) + noffractions = tonumber(noffractions) or 1 -- to be checked + if noffractions == 0 then + -- can't happen + elseif noffractions == 1 then + local dictionary = pdfdictionary { + FunctionType = 4, + Domain = { 0, 1 }, + Range = range, + } + local n = pdfimmediateobj("stream",format("{ %s }",funct),dictionary()) + local array = pdfarray { + pdf_separation, + pdfconstant(spotcolornames[name] or name), + colorspace, + pdfreference(n), + } + local m = pdfimmediateobj(tostring(array)) + local mr = pdfreference(m) + spotcolorhash[name] = m + documentcolorspaces[name] = mr + lpdf.adddocumentcolorspace(name,mr) + else + local cnames = pdfarray() + local domain = pdfarray() + for n in gmatch(names,"[^,]+") do + cnames[#cnames+1] = pdfconstant(spotcolornames[n] or n) + domain[#domain+1] = 0 + domain[#domain+1] = 1 + end + local dictionary = pdfdictionary { + FunctionType = 4, + Domain = domain, + Range = range, + } + local n = pdfimmediateobj("stream",format("{ %s %s }",rep("pop ",noffractions),funct),dictionary()) + local array = pdfarray { + pdf_device_n, + cnames, + colorspace, + pdfreference(n), + } + local m = pdfimmediateobj(tostring(array)) + local mr = pdfreference(m) + spotcolorhash[name] = m + documentcolorspaces[name] = mr + lpdf.adddocumentcolorspace(name,mr) + end +end + +function registersomeindexcolor(name,noffractions,names,p,colorspace,range,funct) + noffractions = tonumber(noffractions) or 1 -- to be checked + local cnames = pdfarray() + local domain = pdfarray() + if names == "" then + names = name .. ",None" + else + names = names .. ",None" + end + for n in gmatch(names,"[^,]+") do + cnames[#cnames+1] = pdfconstant(spotcolornames[n] or n) + domain[#domain+1] = 0 + domain[#domain+1] = 1 + end + local dictionary = pdfdictionary { + FunctionType = 4, + Domain = domain, + Range = range, + } + local n = pdfimmediateobj("stream",format("{ %s %s }",rep("exch pop ",noffractions),funct),dictionary()) -- exch pop + local a = pdfarray { + pdf_device_n, + cnames, + colorspace, + pdfreference(n), + } + if p == "" then + p = "1" + else + p = p .. ",1" + end + local pi = { } + for pp in gmatch(p,"[^,]+") do + pi[#pi+1] = tonumber(pp) + end + local vector, set, n = { }, { }, #pi + for i=255,0,-1 do + for j=1,n do + set[j] = format("%02X",round(pi[j]*i)) + end + vector[#vector+1] = concat(set) + end + vector = pdfverbose { "<", concat(vector, " "), ">" } + local n = pdfimmediateobj(tostring(pdfarray{ pdf_indexed, a, 255, vector })) + lpdf.adddocumentcolorspace(format("%s_indexed",name),pdfreference(n)) + return n +end + +-- actually, names (parent) is the hash + +local function delayindexcolor(name,names,func) + local hash = (names ~= "" and names) or name + -- logs.report("index colors","delaying '%s'",name) + delayedindexcolors[hash] = func +end + +local function indexcolorref(name) -- actually, names (parent) is the hash + if not indexcolorhash[name] then + -- logs.report("index colors","registering '%s'",name) + local delayedindexcolor = delayedindexcolors[name] + if type(delayedindexcolor) == "function" then + indexcolorhash[name] = delayedindexcolor() + delayedindexcolors[name] = true + end + end + return indexcolorhash[name] +end + +function registrations.rgbspotcolor(name,noffractions,names,p,r,g,b) +--~ print(name,noffractions,names,p,r,g,b) + if noffractions == 1 then + registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format(rgb_function,r,g,b)) + else + registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format("%s %s %s",r,g,b)) + end + delayindexcolor(name,names,function() + return registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b)) + end) +end + +function registrations.cmykspotcolor(name,noffractions,names,p,c,m,y,k) + if noffractions == 1 then + registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k)) + else + registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format("%s %s %s %s",c,m,y,k)) + end + delayindexcolor(name,names,function() + return registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k)) + end) +end + +function registrations.grayspotcolor(name,noffractions,names,p,s) + if noffractions == 1 then + registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s)) + else + registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,s) + end + delayindexcolor(name,names,function() + return registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s)) + end) +end + +function registrations.rgbindexcolor(name,noffractions,names,p,r,g,b) + registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b)) +end + +function registrations.cmykindexcolor(name,noffractions,names,p,c,m,y,k) + registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k)) +end + +function registrations.grayindexcolor(name,noffractions,names,p,s) + registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,gray_function) +end + +function codeinjections.setfigurecolorspace(data,figure) + local color = data.request.color + if color then + local ref = indexcolorref(color) + if ref then + figure.colorspace = ref + data.used.color = color + end + end +end + +-- transparency + +local transparencies = { [0] = + pdfconstant("Normal"), + pdfconstant("Normal"), + pdfconstant("Multiply"), + pdfconstant("Screen"), + pdfconstant("Overlay"), + pdfconstant("SoftLight"), + pdfconstant("HardLight"), + pdfconstant("ColorDodge"), + pdfconstant("ColorBurn"), + pdfconstant("Darken"), + pdfconstant("Lighten"), + pdfconstant("Difference"), + pdfconstant("Exclusion"), + pdfconstant("Compatible"), +} + +local documenttransparencies = { } +local transparencyhash = { } -- share objects + +local done = false + +function registrations.transparency(n,a,t) + if not done then + local d = pdfdictionary { + Type = pdf_extgstate, + ca = 1, + CA = 1, + BM = transparencies[1], + AIS = false, + } + local m = pdfimmediateobj(tostring(d)) + local mr = pdfreference(m) + transparencyhash[0] = m + documenttransparencies[0] = mr + lpdf.adddocumentextgstate("Tr0",mr) + done = true + end + if n > 0 and not transparencyhash[n] then + local d = pdfdictionary { + Type = pdf_extgstate, + ca = tonumber(t), + CA = tonumber(t), + BM = transparencies[a] or transparencies[0], + AIS = false, + } + local m = pdfimmediateobj(tostring(d)) + local mr = pdfreference(m) + transparencyhash[n] = m + documenttransparencies[n] = mr + lpdf.adddocumentextgstate(format("Tr%s",n),mr) + end +end + +function codeinjections.adddocumentinfo(key,value) + lpdf.addtoinfo(key,lpdf.tosixteen(value)) +end + +-- graphics + +function codeinjections.setfigurealternative(data,figure) + local display = data.request.display + if display and display ~= "" then + local request = data.request + figures.push { + name = request.display, + page = request.page, + size = request.size, + prefix = request.prefix, + cache = request.cache, + width = request.width, + height = request.height, + } + figures.identify() + local displayfigure = figures.check() + if displayfigure then + -- figure.aform = true + img.immediatewrite(figure) + local a = lpdf.array { + lpdf.dictionary { + Image = lpdf.reference(figure.objnum), + DefaultForPrinting = true, + } + } + local d = lpdf.dictionary { + Alternates = lpdf.reference(pdf.immediateobj(tostring(a))), + } + displayfigure.attr = d() + return displayfigure, figures.current() + end + end +end + +-- eventually we need to load this runtime +-- +-- backends.install((environment and environment.arguments and environment.arguments.backend) or "pdf") +-- +-- but now we need to force this as we also load the pdf tex part which hooks into all kind of places + +codeinjections.finalizepage = lpdf.finalizepage +codeinjections.finalizedocument = lpdf.finalizedocument + +backends.install("pdf") -- cgit v1.2.3