back-imp-pdp.lmt /size: 9445 b    last modification: 2024-01-16 09:02
1if not modules then modules = { } end modules ['back-imp-pdp'] = {
2    version   = 1.001,
3    comment   = "companion to back-imp-pdf.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-- We don't support late literals unless it's really needed by some third party
10-- code.
11
12local context = context
13local lpdf    = lpdf
14
15local pdfreserveobject = lpdf.reserveobject
16local pdfcompresslevel = lpdf.compresslevel
17local pdfobject        = lpdf.object
18local pdfpagereference = lpdf.pagereference
19local pdfgetxformname  = lpdf.getxformname
20local pdfminorversion  = lpdf.minorversion
21local pdfmajorversion  = lpdf.majorversion
22
23local tokenscanners    = tokens.scanners
24local scanword         = tokenscanners.word
25local scankeyword      = tokenscanners.keyword
26local scanstring       = tokenscanners.string
27local scaninteger      = tokenscanners.integer
28local scanwhd          = tokenscanners.whd
29
30local values           = tokens.values
31local dimension_value  = values.dimension
32local cardinal_value   = values.cardinal
33local integer_value    = values.integer
34
35local immediate_code   = tex.flagcodes.immediate
36
37local trace            = false  trackers.register("backend.primitives", function(v) trace = v end)
38local report           = logs.reporter("backend")
39
40local nodepool         = nodes.pool
41local newliteral       = nodepool.literal
42local newsave          = nodepool.save
43local newrestore       = nodepool.restore
44local newsetmatrix     = nodepool.setmatrix
45
46local implement        = interfaces.implement
47local constants        = interfaces.constants
48local variables        = interfaces.variables
49
50-- literals
51
52local function pdf_literal()
53    context(newliteral(scanword() or "origin",scanstring()))
54end
55
56-- objects
57
58local lastobjnum = 0
59
60local function pdf_obj(prefix)
61    if scankeyword("reserveobjnum") then
62        lastobjnum = pdfreserveobject()
63        if trace then
64            report("\\pdfobj reserveobjnum: object %i",lastobjnum)
65        end
66    else
67        local immediate    = prefix and (prefix & immediate_code) ~= 0 -- was just "true"
68        local objnum       = scankeyword("useobjnum") and scaninteger() or pdfreserveobject()
69        local uncompress   = scankeyword("uncompressed") or pdfcompresslevel() == 0
70        local streamobject = scankeyword("stream")
71        local attributes   = scankeyword("attr") and scanstring() or nil
72        local fileobject   = scankeyword("file")
73        local content      = scanstring()
74        local object = streamobject and {
75            type          = "stream",
76            objnum        = objnum,
77            immediate     = immediate,
78            attr          = attributes,
79            compresslevel = uncompress and 0 or nil,
80        } or {
81            type          = "raw",
82            objnum        = objnum,
83            immediate     = immediate,
84        }
85        if fileobject then
86            object.file = content
87         -- object.filename = content
88        else
89            object.string = content
90        end
91        pdfobject(object)
92        lastobjnum = objnum
93        if trace then
94            report("\\pdfobj: object %i",lastobjnum)
95        end
96    end
97end
98
99local function pdf_lastobj()
100    if trace then
101        report("\\lastobj: object %i",lastobjnum)
102    end
103    return cardinal_value, lastobjnum
104end
105
106local function pdf_pagereference()
107    return cardinal_value, pdfpagereference()
108end
109
110local function pdf_refobj()
111    local objnum = scaninteger()
112    if trace then
113        report("\\refobj: object %i (todo)",objnum)
114    end
115end
116
117-- annotations
118
119local lastobjnum = 0
120
121local function pdf_annot()
122    if scankeyword("reserveobjnum") then
123        lastobjnum = pdfreserveobject()
124        if trace then
125            report("\\pdfannot reserveobjnum: object %i",lastobjnum)
126        end
127    else
128        local width  = false
129        local height = false
130        local depth  = false
131        local data   = false
132        local object = false
133        local attr   = false
134        --
135        if scankeyword("useobjnum") then
136            object = scancount()
137            report("\\pdfannot useobjectnum is not (yet) supported")
138        end
139        local width, height, depth = scanwhd()
140        if scankeyword("attr") then
141            attr = scanstring()
142        end
143        data = scanstring()
144        context(backends.nodeinjections.annotation(width or 0,height or 0,depth or 0,data or ""))
145    end
146end
147
148local function pdf_dest()
149    local name   = false
150    local zoom   = false
151    local view   = false
152    local width  = false
153    local height = false
154    local depth  = false
155    if scankeyword("num") then
156        report("\\pdfdest num is not (yet) supported")
157    elseif scankeyword("name") then
158        name = scanstring()
159    end
160    if scankeyword("xyz") then
161        view = "xyz"
162        if scankeyword("zoom") then
163            report("\\pdfdest zoom is ignored")
164            zoom = scancount() -- will be divided by 1000 in the backend
165        end
166    elseif scankeyword("fitbh") then
167        view = "fitbh"
168    elseif scankeyword("fitbv") then
169        view = "fitbv"
170    elseif scankeyword("fitb") then
171        view = "fitb"
172    elseif scankeyword("fith") then
173        view = "fith"
174    elseif scankeyword("fitv") then
175        view = "fitv"
176    elseif scankeyword("fitr") then
177        view = "fitr"
178        width, height, depth = scanwhd()
179    elseif scankeyword("fit") then
180        view = "fit"
181    end
182    context(backends.nodeinjections.destination(width or 0,height or 0,depth or 0,{ name or "" },view or "fit"))
183end
184
185-- management
186
187local function pdf_save()
188    context(newsave())
189end
190
191local function pdf_restore()
192    context(newrestore())
193end
194
195local function pdf_setmatrix()
196    context(newsetmatrix(scanstring()))
197end
198
199-- extras
200
201-- extensions: literal dest annot save restore setmatrix obj refobj colorstack
202-- startlink endlink startthread endthread thread outline glyphtounicode fontattr
203-- mapfile mapline includechars catalog info names trailer
204
205local extensions = {
206    literal   = pdf_literal,
207    obj       = pdf_obj,
208    refobj    = pdf_refobj,
209    dest      = pdf_dest,
210    annot     = pdf_annot,
211    save      = pdf_save,
212    restore   = pdf_restore,
213    setmatrix = pdf_setmatrix,
214}
215
216local function pdf_extension()
217    local w = scanword(false)
218    if w then
219        local e = extensions[w]
220        if e then
221            e()
222        else
223            report("\\pdfextension: unsupported %a",w)
224        end
225    end
226end
227
228-- feedbacks: colorstackinit creationdate fontname fontobjnum fontsize lastannot
229-- lastlink lastobj pageref retval revision version xformname
230
231local feedbacks = {
232    lastobj   = pdf_lastobj,
233    pageref   = pdf_pagereference,
234    xformname = function() context(pdfgetxformname ()) end,
235}
236
237local function pdf_feedback()
238    local w = scanword(false)
239    if w then
240        local f = feedbacks[w]
241        if f then
242            return f()
243        else
244            report("\\pdffeedback: unsupported %a",w)
245        end
246    end
247end
248
249-- variables: (integers:) compresslevel decimaldigits gamma gentounicode
250-- ignoreunknownimages imageaddfilename imageapplygamma imagegamma imagehicolor
251-- imageresolution inclusioncopyfonts inclusionerrorlevel majorversion minorversion
252-- objcompresslevel omitcharset omitcidset pagebox pkfixeddpi pkresolution
253-- recompress suppressoptionalinfo uniqueresname (dimensions:) destmargin horigin
254-- linkmargin threadmargin vorigin xformmargin (tokenlists:) pageattr pageresources
255-- pagesattr pkmode trailerid xformattr xformresources
256
257local variables = {
258    minorversion = function() context(pdfminorversion()) end,
259    majorversion = function() context(pdfmajorversion()) end,
260}
261
262local function pdf_variable()
263    local w = scanword(false)
264    if w then
265        local f = variables[w]
266        if f then
267            f()
268        else
269            report("\\pdfvariable: unsupported %a",w)
270        end
271    else
272        print("missing variable")
273    end
274end
275
276-- kept (also because tikz needs including the pdftex primitives):
277
278implement { name = "pdfextension", actions = pdf_extension, public = true, untraced = true } -- , protected = true }
279implement { name = "pdffeedback",  actions = pdf_feedback,  public = true, usage = "value", untraced = true } -- expandable / todo : value
280implement { name = "pdfvariable",  actions = pdf_variable,  public = true, untraced = true } -- expandable / todo : value
281implement { name = "pdfliteral",   actions = pdf_literal,   public = true, untraced = true, protected = true }
282implement { name = "pdfobj",       actions = pdf_obj,       public = true, usage = "value", protected = true }
283implement { name = "pdflastobj",   actions = pdf_lastobj,   public = true, usage = "value", protected = true }
284implement { name = "pdfrefobj",    actions = pdf_refobj,    public = true, untraced = true, protected = true }
285
286--------- { name = "pdfannot",     actions = pdf_annot }
287--------- { name = "pdfdest",      actions = pdf_dest }
288--------- { name = "pdfsave",      actions = pdf_save }
289--------- { name = "pdfrestore",   actions = pdf_restore }
290--------- { name = "pdfsetmatrix", actions = pdf_setmatrix }
291
292-- implement {
293--     name      = "pdfstrcmp",
294--     arguments = "2 strings",
295--     usage     = "value",
296--     public    = true,
297--     actions   = function(a,b) return integer_value, (a < b and -1) or (a > b and 1) or 0 end
298-- }
299