origami 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING.LESSER +165 -0
- data/README +77 -0
- data/VERSION +1 -0
- data/bin/config/pdfcop.conf.yml +237 -0
- data/bin/gui/about.rb +46 -0
- data/bin/gui/config.rb +132 -0
- data/bin/gui/file.rb +385 -0
- data/bin/gui/hexdump.rb +74 -0
- data/bin/gui/hexview.rb +91 -0
- data/bin/gui/imgview.rb +72 -0
- data/bin/gui/menu.rb +392 -0
- data/bin/gui/properties.rb +132 -0
- data/bin/gui/signing.rb +635 -0
- data/bin/gui/textview.rb +107 -0
- data/bin/gui/treeview.rb +409 -0
- data/bin/gui/walker.rb +282 -0
- data/bin/gui/xrefs.rb +79 -0
- data/bin/pdf2graph +121 -0
- data/bin/pdf2ruby +353 -0
- data/bin/pdfcocoon +104 -0
- data/bin/pdfcop +455 -0
- data/bin/pdfdecompress +104 -0
- data/bin/pdfdecrypt +95 -0
- data/bin/pdfencrypt +112 -0
- data/bin/pdfextract +221 -0
- data/bin/pdfmetadata +123 -0
- data/bin/pdfsh +13 -0
- data/bin/pdfwalker +7 -0
- data/bin/shell/.irbrc +104 -0
- data/bin/shell/console.rb +136 -0
- data/bin/shell/hexdump.rb +83 -0
- data/origami.rb +36 -0
- data/origami/3d.rb +239 -0
- data/origami/acroform.rb +321 -0
- data/origami/actions.rb +299 -0
- data/origami/adobe/fdf.rb +259 -0
- data/origami/adobe/ppklite.rb +489 -0
- data/origami/annotations.rb +775 -0
- data/origami/array.rb +187 -0
- data/origami/boolean.rb +101 -0
- data/origami/catalog.rb +486 -0
- data/origami/destinations.rb +213 -0
- data/origami/dictionary.rb +188 -0
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +1293 -0
- data/origami/export.rb +283 -0
- data/origami/file.rb +222 -0
- data/origami/filters.rb +250 -0
- data/origami/filters/ascii.rb +189 -0
- data/origami/filters/ccitt.rb +515 -0
- data/origami/filters/crypt.rb +47 -0
- data/origami/filters/dct.rb +61 -0
- data/origami/filters/flate.rb +112 -0
- data/origami/filters/jbig2.rb +63 -0
- data/origami/filters/jpx.rb +53 -0
- data/origami/filters/lzw.rb +195 -0
- data/origami/filters/predictors.rb +276 -0
- data/origami/filters/runlength.rb +117 -0
- data/origami/font.rb +209 -0
- data/origami/functions.rb +93 -0
- data/origami/graphics.rb +33 -0
- data/origami/graphics/colors.rb +191 -0
- data/origami/graphics/instruction.rb +126 -0
- data/origami/graphics/path.rb +154 -0
- data/origami/graphics/patterns.rb +180 -0
- data/origami/graphics/state.rb +164 -0
- data/origami/graphics/text.rb +224 -0
- data/origami/graphics/xobject.rb +493 -0
- data/origami/header.rb +90 -0
- data/origami/linearization.rb +318 -0
- data/origami/metadata.rb +114 -0
- data/origami/name.rb +170 -0
- data/origami/null.rb +75 -0
- data/origami/numeric.rb +188 -0
- data/origami/obfuscation.rb +233 -0
- data/origami/object.rb +527 -0
- data/origami/outline.rb +59 -0
- data/origami/page.rb +559 -0
- data/origami/parser.rb +268 -0
- data/origami/parsers/fdf.rb +45 -0
- data/origami/parsers/pdf.rb +27 -0
- data/origami/parsers/pdf/linear.rb +113 -0
- data/origami/parsers/ppklite.rb +86 -0
- data/origami/pdf.rb +1144 -0
- data/origami/reference.rb +113 -0
- data/origami/signature.rb +474 -0
- data/origami/stream.rb +575 -0
- data/origami/string.rb +416 -0
- data/origami/trailer.rb +173 -0
- data/origami/webcapture.rb +87 -0
- data/origami/xfa.rb +3027 -0
- data/origami/xreftable.rb +447 -0
- data/templates/patterns.rb +66 -0
- data/templates/widgets.rb +173 -0
- data/templates/xdp.rb +92 -0
- data/tests/dataset/test.dummycrt +28 -0
- data/tests/dataset/test.dummykey +27 -0
- data/tests/tc_actions.rb +32 -0
- data/tests/tc_annotations.rb +85 -0
- data/tests/tc_pages.rb +37 -0
- data/tests/tc_pdfattach.rb +24 -0
- data/tests/tc_pdfencrypt.rb +110 -0
- data/tests/tc_pdfnew.rb +32 -0
- data/tests/tc_pdfparse.rb +98 -0
- data/tests/tc_pdfsig.rb +37 -0
- data/tests/tc_streams.rb +129 -0
- data/tests/ts_pdf.rb +45 -0
- metadata +193 -0
data/origami/outline.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
outline.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
|
9
|
+
All right reserved.
|
10
|
+
|
11
|
+
Origami is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU Lesser General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
Origami is distributed in the hope that it will be useful,
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
GNU Lesser General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU Lesser General Public License
|
22
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
module Origami
|
27
|
+
|
28
|
+
class Outline < Dictionary
|
29
|
+
include StandardObject
|
30
|
+
|
31
|
+
field :Type, :Type => Name, :Default => :Outlines
|
32
|
+
field :First, :Type => Dictionary
|
33
|
+
field :Last, :Type => Dictionary
|
34
|
+
field :Count, :Type => Integer
|
35
|
+
end
|
36
|
+
|
37
|
+
class OutlineItem < Dictionary
|
38
|
+
include StandardObject
|
39
|
+
|
40
|
+
module Style
|
41
|
+
ITALIC = 1 << 0
|
42
|
+
BOLD = 1 << 1
|
43
|
+
end
|
44
|
+
|
45
|
+
field :Title, :Type => String, :Required => true
|
46
|
+
field :Parent, :Type => Dictionary, :Required => true
|
47
|
+
field :Prev, :Type => Dictionary
|
48
|
+
field :Next, :Type => Dictionary
|
49
|
+
field :First, :Type => Dictionary
|
50
|
+
field :Last, :Type => Dictionary
|
51
|
+
field :Count, :Type => Integer
|
52
|
+
field :Dest, :Type => [ Name, String, Array ]
|
53
|
+
field :A, :Type => Dictionary, :Version => "1.1"
|
54
|
+
field :SE, :Type => Dictionary, :Version => "1.3"
|
55
|
+
field :C, :Type => Array, :Default => [ 0.0, 0.0, 0.0 ], :Version => "1.4"
|
56
|
+
field :F, :Type => Integer, :Default => 0, :Version => "1.4"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/origami/page.rb
ADDED
@@ -0,0 +1,559 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
page.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
Origami is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Origami is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
module Origami
|
23
|
+
|
24
|
+
class PDF
|
25
|
+
|
26
|
+
def append_page(page = Page.new, *more)
|
27
|
+
raise InvalidPDFError, "Invalid page tree" if not self.Catalog or not self.Catalog.Pages or not self.Catalog.Pages.is_a?(PageTreeNode)
|
28
|
+
pages = [ page ].concat(more)
|
29
|
+
|
30
|
+
treeroot = self.Catalog.Pages
|
31
|
+
|
32
|
+
treeroot.Kids ||= [] #:nodoc:
|
33
|
+
treeroot.Kids.concat(pages)
|
34
|
+
treeroot.Count = treeroot.Kids.length
|
35
|
+
|
36
|
+
pages.each do |page|
|
37
|
+
page.Parent = treeroot
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def insert_page(index, page)
|
44
|
+
raise InvalidPDFError, "Invalid page tree" if not self.Catalog or not self.Catalog.Pages or not self.Catalog.Pages.is_a?(PageTreeNode)
|
45
|
+
|
46
|
+
self.Catalog.Pages.insert_page(index, page)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Returns an array of Page
|
52
|
+
#
|
53
|
+
def pages
|
54
|
+
raise InvalidPDFError, "Invalid page tree" if not self.Catalog or not self.Catalog.Pages or not self.Catalog.Pages.is_a?(PageTreeNode)
|
55
|
+
|
56
|
+
self.Catalog.Pages.children
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Iterate through each page, returns self.
|
61
|
+
#
|
62
|
+
def each_page(&b)
|
63
|
+
raise InvalidPDFError, "Invalid page tree" if not self.Catalog or not self.Catalog.Pages or not self.Catalog.Pages.is_a?(PageTreeNode)
|
64
|
+
|
65
|
+
self.Catalog.Pages.each_page(&b)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Get the n-th Page object.
|
71
|
+
#
|
72
|
+
def get_page(n)
|
73
|
+
raise InvalidPDFError, "Invalid page tree" if not self.Catalog or not self.Catalog.Pages or not self.Catalog.Pages.is_a?(PageTreeNode)
|
74
|
+
|
75
|
+
self.Catalog.Pages.get_page(n)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Lookup page in the page name directory.
|
80
|
+
#
|
81
|
+
def get_page_by_name(name)
|
82
|
+
resolve_name Names::Root::PAGES, name
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Calls block for each named page.
|
87
|
+
#
|
88
|
+
def each_named_page(&b)
|
89
|
+
each_name(Names::Root::PAGES, &b)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module ResourcesHolder
|
94
|
+
|
95
|
+
def add_extgstate(name, extgstate)
|
96
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
97
|
+
|
98
|
+
target.ExtGState ||= {}
|
99
|
+
target.ExtGState[name] = extgstate
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_colorspace(name, colorspace)
|
105
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
106
|
+
|
107
|
+
csdir = target[:ColorSpace] ||= {}
|
108
|
+
(csdir.is_a?(Reference) ? csdir.solve : csdir)[name] = colorspace
|
109
|
+
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_pattern(name, pattern)
|
114
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
115
|
+
|
116
|
+
target.Pattern ||= {}
|
117
|
+
target.Pattern[name] = pattern
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_shading(name, shading)
|
123
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
124
|
+
|
125
|
+
target.Shading ||= {}
|
126
|
+
target.Shading[name] = shading
|
127
|
+
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def add_xobject(name, xobject)
|
132
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
133
|
+
|
134
|
+
target.XObject ||= {}
|
135
|
+
target.XObject[name] = xobject
|
136
|
+
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_font(name, font)
|
141
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
142
|
+
|
143
|
+
target.Font ||= {}
|
144
|
+
target.Font[name] = font
|
145
|
+
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def add_properties(name, properties)
|
150
|
+
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
151
|
+
|
152
|
+
target.Properties ||= {}
|
153
|
+
target.Properties[name] = properties
|
154
|
+
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# Class representing a Resources Dictionary for a Page.
|
162
|
+
#
|
163
|
+
class Resources < Dictionary
|
164
|
+
|
165
|
+
include StandardObject
|
166
|
+
include ResourcesHolder
|
167
|
+
|
168
|
+
field :ExtGState, :Type => Dictionary
|
169
|
+
field :ColorSpace, :Type => Dictionary
|
170
|
+
field :Pattern, :Type => Dictionary
|
171
|
+
field :Shading, :Type => Dictionary, :Version => "1.3"
|
172
|
+
field :XObject, :Type => Dictionary
|
173
|
+
field :Font, :Type => Dictionary
|
174
|
+
field :ProcSet, :Type => Array
|
175
|
+
field :Properties, :Type => Dictionary, :Version => "1.2"
|
176
|
+
|
177
|
+
def pre_build
|
178
|
+
unless self.Font
|
179
|
+
fnt = Font::Type1::Standard::Helvetica.new.pre_build
|
180
|
+
fnt.Name = :F1
|
181
|
+
|
182
|
+
add_font(fnt.Name, fnt)
|
183
|
+
end
|
184
|
+
|
185
|
+
super
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Class representing a node in a Page tree.
|
192
|
+
#
|
193
|
+
class PageTreeNode < Dictionary
|
194
|
+
include StandardObject
|
195
|
+
|
196
|
+
field :Type, :Type => Name, :Default => :Pages, :Required => true
|
197
|
+
field :Parent, :Type => Dictionary
|
198
|
+
field :Kids, :Type => Array, :Default => [], :Required => true
|
199
|
+
field :Count, :Type => Integer, :Default => 0, :Required => true
|
200
|
+
|
201
|
+
def initialize(hash = {})
|
202
|
+
self.Count = 0
|
203
|
+
self.Kids = []
|
204
|
+
|
205
|
+
super(hash)
|
206
|
+
|
207
|
+
set_indirect(true)
|
208
|
+
end
|
209
|
+
|
210
|
+
def pre_build #:nodoc:
|
211
|
+
self.Count = self.children.length
|
212
|
+
|
213
|
+
super
|
214
|
+
end
|
215
|
+
|
216
|
+
def insert_page(index, page)
|
217
|
+
|
218
|
+
if index > self.Count
|
219
|
+
raise IndexError, "Invalid index for page tree"
|
220
|
+
end
|
221
|
+
|
222
|
+
count = 0
|
223
|
+
kids = self.Kids
|
224
|
+
|
225
|
+
kids.length.times { |n|
|
226
|
+
if count == index
|
227
|
+
kids.insert(n, page)
|
228
|
+
self.Count = self.Count + 1
|
229
|
+
page.Parent = self
|
230
|
+
return self
|
231
|
+
else
|
232
|
+
node = kids[n].is_a?(Reference) ? kids[n].solve : kids[n]
|
233
|
+
case node
|
234
|
+
when Page
|
235
|
+
count = count + 1
|
236
|
+
next
|
237
|
+
when PageTreeNode
|
238
|
+
if count + node.Count > index
|
239
|
+
node.insert_page(index - count, page)
|
240
|
+
self.Count = self.Count + 1
|
241
|
+
return self
|
242
|
+
else
|
243
|
+
count = count + node.Count
|
244
|
+
next
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
}
|
249
|
+
|
250
|
+
if count == index
|
251
|
+
self << page
|
252
|
+
else
|
253
|
+
raise IndexError, "An error occured while inserting page"
|
254
|
+
end
|
255
|
+
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# Returns an array of Page inheriting this tree node.
|
261
|
+
#
|
262
|
+
def children
|
263
|
+
pageset = []
|
264
|
+
|
265
|
+
unless self.Count.nil?
|
266
|
+
[ self.Count.value, self.Kids.length ].min.times do |n|
|
267
|
+
node = self.Kids[n].is_a?(Reference) ? self.Kids[n].solve : self.Kids[n]
|
268
|
+
case node
|
269
|
+
when PageTreeNode then pageset.concat(node.children)
|
270
|
+
when Page then pageset << node
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
pageset
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# Iterate through each page of that node.
|
280
|
+
#
|
281
|
+
def each_page(&b)
|
282
|
+
unless self.Count.nil?
|
283
|
+
[ self.Count.value, self.Kids.length ].min.times do |n|
|
284
|
+
node = self.Kids[n].is_a?(Reference) ? self.Kids[n].solve : self.Kids[n]
|
285
|
+
case node
|
286
|
+
when PageTreeNode then node.each_page(&b)
|
287
|
+
when Page then b.call(node)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
#
|
294
|
+
# Get the n-th Page object in this node, starting from 1.
|
295
|
+
#
|
296
|
+
def get_page(n)
|
297
|
+
raise IndexError, "Page numbers are referenced starting from 1" if n < 1
|
298
|
+
|
299
|
+
decount = n
|
300
|
+
loop do
|
301
|
+
[ self.Count.value, self.Kids.length ].min.times do |i|
|
302
|
+
node = self.Kids[i].is_a?(Reference) ? self.Kids[i].solve : self.Kids[i]
|
303
|
+
|
304
|
+
case node
|
305
|
+
when Page
|
306
|
+
decount = decount - 1
|
307
|
+
return node if decount == 0
|
308
|
+
|
309
|
+
when PageTreeNode
|
310
|
+
nchilds = [ node.Count.value, node.Kids.length ].min
|
311
|
+
if nchilds >= decount
|
312
|
+
return node.get_page(decount)
|
313
|
+
else
|
314
|
+
decount -= nchilds
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def << (pageset)
|
322
|
+
pageset = [pageset] unless pageset.is_a?(::Array)
|
323
|
+
raise TypeError, "Cannot add anything but Page and PageTreeNode to this node" unless pageset.all? { |item| item.is_a?(Page) or item.is_a?(PageTreeNode) }
|
324
|
+
|
325
|
+
self.Kids ||= Array.new
|
326
|
+
self.Kids.concat(pageset)
|
327
|
+
self.Count = self.Kids.length
|
328
|
+
|
329
|
+
pageset.each do |node|
|
330
|
+
node.Parent = self
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
#
|
336
|
+
# Class representing a Page in the PDF document.
|
337
|
+
#
|
338
|
+
class Page < Dictionary
|
339
|
+
|
340
|
+
include StandardObject
|
341
|
+
include ResourcesHolder
|
342
|
+
|
343
|
+
field :Type, :Type => Name, :Default => :Page, :Required => true
|
344
|
+
field :Parent, :Type => Dictionary, :Required => true
|
345
|
+
field :LastModified, :Type => String, :Version => "1.3"
|
346
|
+
field :Resources, :Type => Dictionary, :Required => true
|
347
|
+
field :MediaBox, :Type => Array, :Default => Rectangle[ :llx => 0, :lly => 0, :urx => 795, :ury => 842 ], :Required => true
|
348
|
+
field :CropBox, :Type => Array
|
349
|
+
field :BleedBox, :Type => Array, :Version => "1.3"
|
350
|
+
field :TrimBox, :Type => Array, :Version => "1.3"
|
351
|
+
field :ArtBox, :Type => Array, :Version => "1.3"
|
352
|
+
field :BoxColorInfo, :Type => Dictionary, :Version => "1.4"
|
353
|
+
field :Contents, :Type => [ Stream, Array ]
|
354
|
+
field :Rotate, :Type => Integer, :Default => 0
|
355
|
+
field :Group, :Type => Dictionary, :Version => "1.4"
|
356
|
+
field :Thumb, :Type => Stream
|
357
|
+
field :B, :Type => Array, :Version => "1.1"
|
358
|
+
field :Dur, :Type => Integer, :Version => "1.1"
|
359
|
+
field :Trans, :Type => Dictionary, :Version => "1.1"
|
360
|
+
field :Annots, :Type => Array
|
361
|
+
field :AA, :Type => Dictionary, :Version => "1.2"
|
362
|
+
field :Metadata, :Type => Stream, :Version => "1.4"
|
363
|
+
field :PieceInfo, :Type => Dictionary, :Version => "1.2"
|
364
|
+
field :StructParents, :Type => Integer, :Version => "1.3"
|
365
|
+
field :ID, :Type => String
|
366
|
+
field :PZ, :Type => Number
|
367
|
+
field :SeparationInfo, :Type => Dictionary, :Version => "1.3"
|
368
|
+
field :Tabs, :Type => Name, :Version => "1.5"
|
369
|
+
field :TemplateAssociated, :Type => Name, :Version => "1.5"
|
370
|
+
field :PresSteps, :Type => Dictionary, :Version => "1.5"
|
371
|
+
field :UserUnit, :Type => Number, :Default => 1.0, :Version => "1.6"
|
372
|
+
field :VP, :Type => Dictionary, :Version => "1.6"
|
373
|
+
|
374
|
+
def initialize(hash = {})
|
375
|
+
super(hash)
|
376
|
+
|
377
|
+
set_indirect(true)
|
378
|
+
end
|
379
|
+
|
380
|
+
def pre_build
|
381
|
+
self.Resources = Resources.new.pre_build unless self.has_key?(:Resources)
|
382
|
+
|
383
|
+
super
|
384
|
+
end
|
385
|
+
|
386
|
+
#
|
387
|
+
# Add an Annotation to the Page.
|
388
|
+
#
|
389
|
+
def add_annot(*annotations)
|
390
|
+
unless annotations.all?{|annot| annot.is_a?(Annotation) or annot.is_a?(Reference)}
|
391
|
+
raise TypeError, "Only Annotation objects must be passed."
|
392
|
+
end
|
393
|
+
|
394
|
+
self.Annots ||= []
|
395
|
+
|
396
|
+
annotations.each do |annot|
|
397
|
+
annot.solve[:P] = self if is_indirect?
|
398
|
+
self.Annots << annot
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
#
|
403
|
+
# Iterate through each Annotation of the Page.
|
404
|
+
#
|
405
|
+
def each_annot(&b)
|
406
|
+
annots = self.Annots
|
407
|
+
return unless annots.is_a?(Array)
|
408
|
+
|
409
|
+
annots.each do |annot|
|
410
|
+
b.call(annot.solve)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
#
|
415
|
+
# Embed a SWF Flash application in the page.
|
416
|
+
#
|
417
|
+
def add_flash_application(swfspec, params = {})
|
418
|
+
options =
|
419
|
+
{
|
420
|
+
:windowed => false,
|
421
|
+
:transparent => false,
|
422
|
+
:navigation_pane => false,
|
423
|
+
:toolbar => false,
|
424
|
+
:pass_context_click => false,
|
425
|
+
:activation => Annotation::RichMedia::Activation::PAGE_OPEN,
|
426
|
+
:deactivation => Annotation::RichMedia::Deactivation::PAGE_CLOSE,
|
427
|
+
:flash_vars => nil
|
428
|
+
}
|
429
|
+
options.update(params)
|
430
|
+
|
431
|
+
annot = create_richmedia(:Flash, swfspec, options)
|
432
|
+
add_annot(annot)
|
433
|
+
|
434
|
+
annot
|
435
|
+
end
|
436
|
+
|
437
|
+
#
|
438
|
+
# Will execute an action when the page is opened.
|
439
|
+
#
|
440
|
+
def onOpen(action)
|
441
|
+
unless action.is_a?(Action) or action.is_a?(Reference)
|
442
|
+
raise TypeError, "An Action object must be passed."
|
443
|
+
end
|
444
|
+
|
445
|
+
self.AA ||= PageAdditionalActions.new
|
446
|
+
self.AA.O = action
|
447
|
+
|
448
|
+
self
|
449
|
+
end
|
450
|
+
|
451
|
+
#
|
452
|
+
# Will execute an action when the page is closed.
|
453
|
+
#
|
454
|
+
def onClose(action)
|
455
|
+
unless action.is_a?(Action) or action.is_a?(Reference)
|
456
|
+
raise TypeError, "An Action object must be passed."
|
457
|
+
end
|
458
|
+
|
459
|
+
self.AA ||= PageAdditionalActions.new
|
460
|
+
self.AA.C = action
|
461
|
+
|
462
|
+
self
|
463
|
+
end
|
464
|
+
|
465
|
+
#
|
466
|
+
# Will execute an action when navigating forward from this page.
|
467
|
+
#
|
468
|
+
def onNavigateForward(action) #:nodoc:
|
469
|
+
unless action.is_a?(Action) or action.is_a?(Reference)
|
470
|
+
raise TypeError, "An Action object must be passed."
|
471
|
+
end
|
472
|
+
|
473
|
+
self.PresSteps ||= NavigationNode.new
|
474
|
+
self.PresSteps.NA = action
|
475
|
+
|
476
|
+
self
|
477
|
+
end
|
478
|
+
|
479
|
+
#
|
480
|
+
# Will execute an action when navigating backward from this page.
|
481
|
+
#
|
482
|
+
def onNavigateBackward(action) #:nodoc:
|
483
|
+
unless action.is_a?(Action) or action.is_a?(Reference)
|
484
|
+
raise TypeError, "An Action object must be passed."
|
485
|
+
end
|
486
|
+
|
487
|
+
self.PresSteps ||= NavigationNode.new
|
488
|
+
self.PresSteps.PA = action
|
489
|
+
|
490
|
+
self
|
491
|
+
end
|
492
|
+
|
493
|
+
private
|
494
|
+
|
495
|
+
def create_richmedia(type, content, params) #:nodoc:
|
496
|
+
content.set_indirect(true)
|
497
|
+
richmedia = Annotation::RichMedia.new.set_indirect(true)
|
498
|
+
|
499
|
+
rminstance = Annotation::RichMedia::Instance.new.set_indirect(true)
|
500
|
+
rmparams = rminstance.Params = Annotation::RichMedia::Parameters.new
|
501
|
+
rmparams.Binding = Annotation::RichMedia::Parameters::Binding::BACKGROUND
|
502
|
+
rmparams.FlashVars = params[:flash_vars]
|
503
|
+
rminstance.Asset = content
|
504
|
+
|
505
|
+
rmconfig = Annotation::RichMedia::Configuration.new.set_indirect(true)
|
506
|
+
rmconfig.Instances = [ rminstance ]
|
507
|
+
rmconfig.Subtype = type
|
508
|
+
|
509
|
+
rmcontent = richmedia.RichMediaContent = Annotation::RichMedia::Content.new.set_indirect(true)
|
510
|
+
rmcontent.Assets = NameTreeNode.new
|
511
|
+
rmcontent.Assets.Names = NameLeaf.new(content.F.value => content)
|
512
|
+
|
513
|
+
rmcontent.Configurations = [ rmconfig ]
|
514
|
+
|
515
|
+
rmsettings = richmedia.RichMediaSettings = Annotation::RichMedia::Settings.new
|
516
|
+
rmactivation = rmsettings.Activation = Annotation::RichMedia::Activation.new
|
517
|
+
rmactivation.Condition = params[:activation]
|
518
|
+
rmactivation.Configuration = rmconfig
|
519
|
+
rmactivation.Animation = Annotation::RichMedia::Animation.new(:PlayCount => -1, :Subtype => :Linear, :Speed => 1.0)
|
520
|
+
rmpres = rmactivation.Presentation = Annotation::RichMedia::Presentation.new
|
521
|
+
rmpres.Style = Annotation::RichMedia::Presentation::WINDOWED if params[:windowed]
|
522
|
+
rmpres.Transparent = params[:transparent]
|
523
|
+
rmpres.NavigationPane = params[:navigation_pane]
|
524
|
+
rmpres.Toolbar = params[:toolbar]
|
525
|
+
rmpres.PassContextClick = params[:pass_context_click]
|
526
|
+
|
527
|
+
rmdeactivation = rmsettings.Deactivation = Annotation::RichMedia::Deactivation.new
|
528
|
+
rmdeactivation.Condition = params[:deactivation]
|
529
|
+
|
530
|
+
richmedia
|
531
|
+
end
|
532
|
+
|
533
|
+
end
|
534
|
+
|
535
|
+
#
|
536
|
+
# Class representing additional actions which can be associated to a Page.
|
537
|
+
#
|
538
|
+
class PageAdditionalActions < Dictionary
|
539
|
+
include StandardObject
|
540
|
+
|
541
|
+
field :O, :Type => Dictionary, :Version => "1.2" # Page Open
|
542
|
+
field :C, :Type => Dictionary, :Version => "1.2" # Page Close
|
543
|
+
end
|
544
|
+
|
545
|
+
#
|
546
|
+
# Class representing a navigation node associated to a Page.
|
547
|
+
#
|
548
|
+
class NavigationNode < Dictionary
|
549
|
+
include StandardObject
|
550
|
+
|
551
|
+
field :Type, :Type => Name, :Default => :NavNode
|
552
|
+
field :NA, :Type => Dictionary # Next action
|
553
|
+
field :PA, :Type => Dictionary # Prev action
|
554
|
+
field :Next, :Type => Dictionary
|
555
|
+
field :Prev, :Type => Dictionary
|
556
|
+
field :Dur, :Type => Number
|
557
|
+
end
|
558
|
+
|
559
|
+
end
|