lpdf-swf.lua /size: 11 Kb    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['lpdf-swf'] = {
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-- The following code is based on tests by Luigi Scarso. His prototype
10-- was using tex code. This is the official implementation.
11
12local format, gsub = string.format, string.gsub
13local concat = table.concat
14local formatters = string.formatters
15
16local backends        = backends
17local lpdf            = lpdf
18local context         = context
19
20local pdfconstant     = lpdf.constant
21local pdfstring       = lpdf.string
22local pdfdictionary   = lpdf.dictionary
23local pdfarray        = lpdf.array
24local pdfreference    = lpdf.reference
25local pdfflushobject  = lpdf.flushobject
26local pdfsharedobject = lpdf.shareobjectreference
27
28local checkedkey      = lpdf.checkedkey
29
30local codeinjections = backends.pdf.codeinjections
31local nodeinjections = backends.pdf.nodeinjections
32
33local trace_swf = false  trackers.register("backend.swf", function(v) trace_swf = v end)
34
35local report_swf = logs.reporter("backend","swf")
36
37--------------------------------------------------------------------------------------
38
39local createimage = images.create
40local embedimage  = images.embed
41
42local basepoints  = number.dimenfactors.bp
43
44local f_image     = formatters["%.6N 0 0 %.6N 0 0 cm /%s Do"]
45
46local function package(image) -- see lpdf-u3d **
47    local boundingbox = image.bbox
48    local imagetag    = "Im" .. image.index -- this is not ok
49    local resources   = pdfdictionary {
50        ProcSet   = lpdf.procset(),
51        Resources = pdfdictionary {
52            XObject = pdfdictionary {
53                [imagetag] = pdfreference(image.objnum)
54            }
55        }
56    }
57    local width  = boundingbox[3]
58    local height = boundingbox[4]
59    local xform = createimage {
60        attr   = resources(),
61        stream = f_image(width,height,imagetag),
62        bbox   = { 0, 0, width/basepoints, height/basepoints },
63    }
64    embedimage(xform)
65    return xform
66end
67
68--------------------------------------------------------------------------------------
69
70local activations = {
71    click = "XA",
72    page  = "PO",
73    focus = "PV",
74}
75
76local deactivations = {
77    click = "XD",
78    page  = "PI",
79    focus = "PC",
80}
81
82table.setmetatableindex(activations,  function() return activations  .click end)
83table.setmetatableindex(deactivations,function() return deactivations.focus end)
84
85local function insertswf(spec)
86    local width     = spec.width
87    local height    = spec.height
88    local filename  = spec.foundname
89    local resources = spec.resources
90    local display   = spec.display
91    local controls  = spec.controls
92    local arguments = spec.arguments
93
94    local resources = resources and parametersets[resources]
95    local display   = display   and parametersets[display]
96    local controls  = controls  and parametersets[controls]  -- not yet used
97    local arguments = arguments and parametersets[arguments] -- not yet used
98
99    local preview   = checkedkey(display,"preview","string")
100    local toolbar   = checkedkey(display,"toolbar","boolean")
101
102    local embeddedreference = codeinjections.embedfile {
103        file     = filename,
104        compress = false,
105    }
106
107    local flash = pdfdictionary {
108        Subtype   = pdfconstant("RichMediaConfiguration"),
109        Instances = pdfarray {
110            pdfdictionary {
111                Type    = pdfconstant("RichMediaInstance"),
112                Asset   = embeddedreference,
113                Subtype = pdfconstant("Flash"), -- 3D Sound Video ... somehow still Flash too
114                Params  = pdfsharedobject(pdfdictionary {
115                    Binding   = pdfconstant("Background"), -- Foreground makes swf behave erratic
116                    FlashVars = arguments and pdfstring(table.sequenced(arguments,"&")) or nil,
117                }),
118            },
119        },
120    }
121
122    local flashreference = pdfreference(pdfflushobject(flash))
123
124    local configuration = pdfdictionary {
125        Configurations = pdfarray { flashreference },
126        Assets         = pdfdictionary {
127            Names = pdfarray {
128                pdfstring(filename),
129                embeddedreference,
130            }
131        },
132    }
133
134    -- todo: check op subpath figuur (relatief)
135
136    -- filename : ./test.swf (graphic)
137    -- root     : .
138    -- prefix   : ^%./
139    -- fullname : ./assets/whatever.xml
140    -- usedname : assets/whatever.xml
141    -- filename : assets/whatever.xml
142
143    local root          = file.dirname(filename)
144    local relativepaths = nil
145    local paths         = nil
146    if resources then
147        local names = configuration.Assets.Names
148        local prefix = false
149        if root ~= "" and root ~= "." then
150            prefix = format("^%s/",string.topattern(root))
151        end
152        if prefix and trace_swf then
153            report_swf("using strip pattern %a",prefix)
154        end
155        local function add(fullname,strip)
156            local filename = gsub(fullname,"^%./","")
157            local usedname = strip and prefix and gsub(filename,prefix,"") or filename
158            local embeddedreference = codeinjections.embedfile {
159                file     = fullname,
160                usedname = usedname,
161                keepdir  = true,
162                compress = false,
163            }
164            names[#names+1] = pdfstring(filename)
165            names[#names+1] = embeddedreference
166            if trace_swf then
167                report_swf("embedding file %a as %a",fullname,usedname)
168            end
169        end
170        relativepaths = resources.relativepaths
171        if relativepaths then
172            if trace_swf then
173                report_swf("checking %s relative paths",#relativepaths)
174            end
175            for i=1,#relativepaths do
176                local relativepath = relativepaths[i]
177                if trace_swf then
178                    report_swf("checking path %a relative to %a",relativepath,root)
179                end
180                local path = file.join(root == "" and "." or root,relativepath)
181                local files = dir.glob(path .. "/**")
182                for i=1,#files do
183                    add(files[i],true)
184                end
185            end
186        end
187        paths = resources.paths
188        if paths then
189            if trace_swf then
190                report_swf("checking absolute %s paths",#paths)
191            end
192            for i=1,#paths do
193                local path = paths[i]
194                if trace_swf then
195                    report_swf("checking path %a",path)
196                end
197                local files = dir.glob(path .. "/**")
198                for i=1,#files do
199                    add(files[i],false)
200                end
201            end
202        end
203        local relativefiles = resources.relativefiles
204        if relativefiles then
205            if trace_swf then
206                report_swf("checking %s relative files",#relativefiles)
207            end
208            for i=1,#relativefiles do
209                add(relativefiles[i],true)
210            end
211        end
212        local files = resources.files
213        if files then
214            if trace_swf then
215                report_swf("checking absolute %s files",#files)
216            end
217            for i=1,#files do
218                add(files[i],false)
219            end
220        end
221    end
222
223    local opendisplay  = display and display.open  or false
224    local closedisplay = display and display.close or false
225
226    local configurationreference = pdfreference(pdfflushobject(configuration))
227
228    local activation = pdfdictionary {
229        Type          = pdfconstant("RichMediaActivation"),
230        Condition     = pdfconstant(activations[opendisplay]),
231        Configuration = flashreference,
232        Animation     = pdfdictionary {
233            Subtype   = pdfconstant("Linear"),
234            Speed     = 1,
235            Playcount = 1,
236        },
237        Presentation  = pdfdictionary {
238         -- PassContextClick = false,
239            PassContextClick = true,
240            Style            = pdfconstant("Embedded"),
241            Toolbar          = toolbar,
242            NavigationPane   = false,
243            Transparent      = true,
244            Window           = pdfdictionary {
245                Type     = pdfconstant("RichMediaWindow"),
246                Width    = pdfdictionary {
247                    Default = 100,
248                    Min     = 100,
249                    Max     = 100,
250                },
251                Height   = pdfdictionary {
252                    Default = 100,
253                    Min     = 100,
254                    Max     = 100,
255                },
256                Position = pdfdictionary {
257                    Type    = pdfconstant("RichMediaPosition"),
258                    HAlign  = pdfconstant("Near"),
259                    VAlign  = pdfconstant("Near"),
260                    HOffset = 0,
261                    VOffset = 0,
262                }
263            }
264        },
265     -- View
266     -- Scripts
267    }
268
269    local deactivation = pdfdictionary {
270        Type      = pdfconstant("RichMediaDeactivation"),
271        Condition = pdfconstant(deactivations[closedisplay]),
272    }
273
274    local richmediasettings = pdfdictionary {
275        Type         = pdfconstant("RichMediaSettings"),
276        Activation   = activation,
277        Deactivation = deactivation,
278    }
279
280    local settingsreference = pdfreference(pdfflushobject(richmediasettings))
281
282    local appearance
283
284    if preview then
285        preview = gsub(preview,"%*",file.nameonly(filename))
286        local figure = codeinjections.getpreviewfigure { name = preview, width = width, height = height }
287        if relativepaths and not figure then
288            for i=1,#relativepaths do
289                local path = file.join(root == "" and "." or root,relativepaths[i])
290                if trace_swf then
291                    report_swf("checking preview on relative path %s",path)
292                end
293                local p = file.join(path,preview)
294                figure = codeinjections.getpreviewfigure { name = p, width = width, height = height }
295                if figure then
296                    preview = p
297                    break
298                end
299            end
300        end
301        if paths and not figure then
302            for i=1,#paths do
303                local path = paths[i]
304                if trace_swf then
305                    report_swf("checking preview on absolute path %s",path)
306                end
307                local p = file.join(path,preview)
308                figure = codeinjections.getpreviewfigure { name = p, width = width, height = height }
309                if figure then
310                    preview = p
311                    break
312                end
313            end
314        end
315        if figure then
316            local image = package(figure.status.private)
317            appearance = pdfdictionary { N = pdfreference(image.objnum) }
318            if trace_swf then
319                report_swf("using preview %s",preview)
320            end
321        end
322    end
323
324    local annotation = pdfdictionary {
325        Subtype           = pdfconstant("RichMedia"),
326        RichMediaContent  = configurationreference,
327        RichMediaSettings = settingsreference,
328        AP                = appearance,
329    }
330
331    return annotation, nil, nil
332
333end
334
335function backends.pdf.nodeinjections.insertswf(spec)
336    local annotation, preview, ref = insertswf {
337        foundname = spec.foundname,
338        width     = spec.width,
339        height    = spec.height,
340        display   = spec.display,
341        controls  = spec.controls,
342        resources = spec.resources,
343        arguments = spec.arguments,
344     -- factor    = spec.factor,
345     -- label     = spec.label,
346    }
347    context(nodeinjections.annotation(spec.width,spec.height,0,annotation())) -- the context wrap is probably also needed elsewhere
348end
349