origami-docspring 2.2.0 → 2.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/examples/attachments/attachment.rb +7 -8
- data/examples/attachments/nested_document.rb +6 -5
- data/examples/encryption/encryption.rb +5 -4
- data/examples/events/events.rb +7 -6
- data/examples/flash/flash.rb +10 -9
- data/examples/forms/javascript.rb +14 -13
- data/examples/forms/xfa.rb +67 -66
- data/examples/javascript/hello_world.rb +6 -5
- data/examples/javascript/js_emulation.rb +26 -26
- data/examples/loop/goto.rb +12 -11
- data/examples/loop/named.rb +17 -16
- data/examples/signature/signature.rb +11 -11
- data/examples/uri/javascript.rb +25 -24
- data/examples/uri/open-uri.rb +5 -4
- data/examples/uri/submitform.rb +11 -10
- data/lib/origami/3d.rb +330 -334
- data/lib/origami/acroform.rb +267 -268
- data/lib/origami/actions.rb +266 -278
- data/lib/origami/annotations.rb +659 -670
- data/lib/origami/array.rb +192 -196
- data/lib/origami/boolean.rb +66 -70
- data/lib/origami/catalog.rb +360 -363
- data/lib/origami/collections.rb +132 -133
- data/lib/origami/compound.rb +125 -129
- data/lib/origami/destinations.rb +226 -237
- data/lib/origami/dictionary.rb +155 -154
- data/lib/origami/encryption.rb +967 -923
- data/lib/origami/extensions/fdf.rb +270 -275
- data/lib/origami/extensions/ppklite.rb +323 -328
- data/lib/origami/filespec.rb +170 -173
- data/lib/origami/filters/ascii.rb +162 -167
- data/lib/origami/filters/ccitt/tables.rb +248 -252
- data/lib/origami/filters/ccitt.rb +309 -312
- data/lib/origami/filters/crypt.rb +31 -34
- data/lib/origami/filters/dct.rb +47 -50
- data/lib/origami/filters/flate.rb +57 -60
- data/lib/origami/filters/jbig2.rb +50 -53
- data/lib/origami/filters/jpx.rb +40 -43
- data/lib/origami/filters/lzw.rb +151 -155
- data/lib/origami/filters/predictors.rb +250 -255
- data/lib/origami/filters/runlength.rb +111 -115
- data/lib/origami/filters.rb +319 -325
- data/lib/origami/font.rb +173 -177
- data/lib/origami/functions.rb +62 -66
- data/lib/origami/graphics/colors.rb +203 -208
- data/lib/origami/graphics/instruction.rb +79 -81
- data/lib/origami/graphics/path.rb +141 -144
- data/lib/origami/graphics/patterns.rb +156 -160
- data/lib/origami/graphics/render.rb +51 -47
- data/lib/origami/graphics/state.rb +144 -142
- data/lib/origami/graphics/text.rb +185 -188
- data/lib/origami/graphics/xobject.rb +818 -804
- data/lib/origami/graphics.rb +25 -26
- data/lib/origami/header.rb +63 -65
- data/lib/origami/javascript.rb +718 -651
- data/lib/origami/linearization.rb +284 -285
- data/lib/origami/metadata.rb +156 -135
- data/lib/origami/name.rb +98 -100
- data/lib/origami/null.rb +49 -51
- data/lib/origami/numeric.rb +133 -135
- data/lib/origami/obfuscation.rb +180 -182
- data/lib/origami/object.rb +634 -631
- data/lib/origami/optionalcontent.rb +147 -149
- data/lib/origami/outline.rb +46 -48
- data/lib/origami/outputintents.rb +76 -77
- data/lib/origami/page.rb +637 -596
- data/lib/origami/parser.rb +214 -221
- data/lib/origami/parsers/fdf.rb +44 -45
- data/lib/origami/parsers/pdf/lazy.rb +147 -154
- data/lib/origami/parsers/pdf/linear.rb +104 -109
- data/lib/origami/parsers/pdf.rb +109 -107
- data/lib/origami/parsers/ppklite.rb +44 -46
- data/lib/origami/pdf.rb +886 -896
- data/lib/origami/reference.rb +116 -120
- data/lib/origami/signature.rb +617 -625
- data/lib/origami/stream.rb +560 -558
- data/lib/origami/string.rb +366 -368
- data/lib/origami/template/patterns.rb +50 -52
- data/lib/origami/template/widgets.rb +111 -114
- data/lib/origami/trailer.rb +153 -157
- data/lib/origami/tree.rb +55 -57
- data/lib/origami/version.rb +19 -19
- data/lib/origami/webcapture.rb +87 -90
- data/lib/origami/xfa/config.rb +409 -414
- data/lib/origami/xfa/connectionset.rb +113 -117
- data/lib/origami/xfa/datasets.rb +38 -42
- data/lib/origami/xfa/localeset.rb +33 -37
- data/lib/origami/xfa/package.rb +49 -52
- data/lib/origami/xfa/pdf.rb +54 -59
- data/lib/origami/xfa/signature.rb +33 -37
- data/lib/origami/xfa/sourceset.rb +34 -38
- data/lib/origami/xfa/stylesheet.rb +35 -39
- data/lib/origami/xfa/template.rb +1630 -1634
- data/lib/origami/xfa/xdc.rb +33 -37
- data/lib/origami/xfa/xfa.rb +132 -123
- data/lib/origami/xfa/xfdf.rb +34 -38
- data/lib/origami/xfa/xmpmeta.rb +34 -38
- data/lib/origami/xfa.rb +50 -53
- data/lib/origami/xreftable.rb +462 -462
- data/lib/origami.rb +37 -38
- data/test/test_actions.rb +22 -20
- data/test/test_annotations.rb +54 -52
- data/test/test_forms.rb +23 -21
- data/test/test_native_types.rb +82 -78
- data/test/test_object_tree.rb +25 -24
- data/test/test_pages.rb +43 -41
- data/test/test_pdf.rb +2 -0
- data/test/test_pdf_attachment.rb +23 -21
- data/test/test_pdf_create.rb +16 -15
- data/test/test_pdf_encrypt.rb +69 -66
- data/test/test_pdf_parse.rb +131 -129
- data/test/test_pdf_parse_lazy.rb +53 -53
- data/test/test_pdf_sign.rb +67 -67
- data/test/test_streams.rb +145 -143
- data/test/test_xrefs.rb +46 -45
- metadata +64 -8
data/lib/origami/page.rb
CHANGED
@@ -1,722 +1,763 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# This file is part of Origami, PDF manipulation framework for Ruby
|
5
|
+
# Copyright (C) 2016 Guillaume Delugré.
|
6
|
+
#
|
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
20
|
|
21
21
|
module Origami
|
22
|
+
class PDF
|
23
|
+
#
|
24
|
+
# Appends a page or list of pages to the end of the page tree.
|
25
|
+
# _page_:: The page to append to the document. Creates a new Page if not specified.
|
26
|
+
#
|
27
|
+
# Pass the Page object if a block is present.
|
28
|
+
#
|
29
|
+
def append_page(page = Page.new)
|
30
|
+
init_page_tree
|
22
31
|
|
23
|
-
|
32
|
+
self.Catalog.Pages.append_page(page)
|
33
|
+
yield(page) if block_given?
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
# _page_:: The page to append to the document. Creates a new Page if not specified.
|
28
|
-
#
|
29
|
-
# Pass the Page object if a block is present.
|
30
|
-
#
|
31
|
-
def append_page(page = Page.new)
|
32
|
-
init_page_tree
|
35
|
+
self
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
#
|
39
|
+
# Inserts a page at position _index_ into the document.
|
40
|
+
# _index_:: Page index (starting from one).
|
41
|
+
# _page_:: The page to insert into the document. Creates a new one if none given.
|
42
|
+
#
|
43
|
+
# Pass the Page object if a block is present.
|
44
|
+
#
|
45
|
+
def insert_page(index, page = Page.new)
|
46
|
+
init_page_tree
|
36
47
|
|
37
|
-
|
38
|
-
|
48
|
+
# Page from another document must be exported.
|
49
|
+
page = page.export if page.document && (page.document != self)
|
39
50
|
|
40
|
-
|
41
|
-
# Inserts a page at position _index_ into the document.
|
42
|
-
# _index_:: Page index (starting from one).
|
43
|
-
# _page_:: The page to insert into the document. Creates a new one if none given.
|
44
|
-
#
|
45
|
-
# Pass the Page object if a block is present.
|
46
|
-
#
|
47
|
-
def insert_page(index, page = Page.new)
|
48
|
-
init_page_tree
|
51
|
+
self.Catalog.Pages.insert_page(index, page)
|
49
52
|
|
50
|
-
|
51
|
-
page = page.export if page.document and page.document != self
|
53
|
+
yield(page) if block_given?
|
52
54
|
|
53
|
-
|
55
|
+
self
|
56
|
+
end
|
54
57
|
|
55
|
-
|
58
|
+
#
|
59
|
+
# Returns an Enumerator of Page
|
60
|
+
#
|
61
|
+
def pages
|
62
|
+
init_page_tree
|
56
63
|
|
57
|
-
|
58
|
-
|
64
|
+
self.Catalog.Pages.pages
|
65
|
+
end
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
67
|
+
#
|
68
|
+
# Iterate through each page, returns self.
|
69
|
+
#
|
70
|
+
def each_page(&b)
|
71
|
+
init_page_tree
|
65
72
|
|
66
|
-
|
67
|
-
|
73
|
+
self.Catalog.Pages.each_page(&b)
|
74
|
+
end
|
68
75
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
76
|
+
#
|
77
|
+
# Get the n-th Page object.
|
78
|
+
#
|
79
|
+
def get_page(n)
|
80
|
+
init_page_tree
|
74
81
|
|
75
|
-
|
76
|
-
|
82
|
+
self.Catalog.Pages.get_page(n)
|
83
|
+
end
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
85
|
+
#
|
86
|
+
# Lookup page in the page name directory.
|
87
|
+
#
|
88
|
+
def get_page_by_name(name)
|
89
|
+
resolve_name Names::PAGES, name
|
90
|
+
end
|
83
91
|
|
84
|
-
|
85
|
-
|
92
|
+
#
|
93
|
+
# Calls block for each named page.
|
94
|
+
#
|
95
|
+
def each_named_page(&b)
|
96
|
+
each_name(Names::PAGES, &b)
|
97
|
+
end
|
86
98
|
|
87
|
-
|
88
|
-
# Lookup page in the page name directory.
|
89
|
-
#
|
90
|
-
def get_page_by_name(name)
|
91
|
-
resolve_name Names::PAGES, name
|
92
|
-
end
|
99
|
+
private
|
93
100
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
101
|
+
def init_page_tree # :nodoc:
|
102
|
+
unless self.Catalog.key?(:Pages)
|
103
|
+
self.Catalog.Pages = PageTreeNode.new
|
104
|
+
return
|
105
|
+
end
|
100
106
|
|
101
|
-
|
107
|
+
unless self.Catalog.Pages.is_a?(PageTreeNode)
|
108
|
+
raise InvalidPageTreeError, "Root page node is not a PageTreeNode"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
102
112
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
113
|
+
module ResourcesHolder
|
114
|
+
def add_extgstate(extgstate, name = nil)
|
115
|
+
add_resource(Resources::EXTGSTATE, extgstate, name)
|
116
|
+
end
|
108
117
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
end
|
118
|
+
def add_colorspace(colorspace, name = nil)
|
119
|
+
add_resource(Resources::COLORSPACE, colorspace, name)
|
113
120
|
end
|
114
121
|
|
115
|
-
|
122
|
+
def add_pattern(pattern, name = nil)
|
123
|
+
add_resource(Resources::PATTERN, pattern, name)
|
124
|
+
end
|
116
125
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
def add_colorspace(colorspace, name = nil)
|
121
|
-
add_resource(Resources::COLORSPACE, colorspace, name)
|
122
|
-
end
|
126
|
+
def add_shading(shading, name = nil)
|
127
|
+
add_resource(Resources::SHADING, shading, name)
|
128
|
+
end
|
123
129
|
|
124
|
-
|
125
|
-
|
126
|
-
|
130
|
+
def add_xobject(xobject, name = nil)
|
131
|
+
add_resource(Resources::XOBJECT, xobject, name)
|
132
|
+
end
|
127
133
|
|
128
|
-
|
129
|
-
|
130
|
-
|
134
|
+
def add_font(font, name = nil)
|
135
|
+
add_resource(Resources::FONT, font, name)
|
136
|
+
end
|
131
137
|
|
132
|
-
|
133
|
-
|
134
|
-
|
138
|
+
def add_properties(properties, name = nil)
|
139
|
+
add_resource(Resources::PROPERTIES, properties, name)
|
140
|
+
end
|
135
141
|
|
136
|
-
|
137
|
-
|
138
|
-
|
142
|
+
#
|
143
|
+
# Adds a resource of the specified _type_ in the current object.
|
144
|
+
# If _name_ is not specified, a new name will be automatically generated.
|
145
|
+
#
|
146
|
+
def add_resource(type, rsrc, name = nil)
|
147
|
+
if name.nil?
|
148
|
+
rsrc_name = resources(type).key(rsrc)
|
149
|
+
return rsrc_name if rsrc_name
|
150
|
+
end
|
139
151
|
|
140
|
-
|
141
|
-
|
142
|
-
end
|
152
|
+
name ||= new_id(type)
|
153
|
+
target = is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
143
154
|
|
144
|
-
|
145
|
-
|
146
|
-
# If _name_ is not specified, a new name will be automatically generated.
|
147
|
-
#
|
148
|
-
def add_resource(type, rsrc, name = nil)
|
149
|
-
if name.nil?
|
150
|
-
rsrc_name = self.resources(type).key(rsrc)
|
151
|
-
return rsrc_name if rsrc_name
|
152
|
-
end
|
155
|
+
rsrc_dict = target[type]&.solve || (target[type] = Dictionary.new)
|
156
|
+
rsrc_dict[name.to_sym] = rsrc
|
153
157
|
|
154
|
-
|
155
|
-
|
158
|
+
name
|
159
|
+
end
|
156
160
|
|
157
|
-
|
158
|
-
|
161
|
+
#
|
162
|
+
# Iterates over the resources by _type_.
|
163
|
+
#
|
164
|
+
def each_resource(type)
|
165
|
+
target = is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
159
166
|
|
160
|
-
|
161
|
-
end
|
167
|
+
rsrc = target[type]&.solve
|
162
168
|
|
163
|
-
|
164
|
-
|
165
|
-
#
|
166
|
-
def each_resource(type)
|
167
|
-
target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
|
169
|
+
return enum_for(__method__, type) { rsrc.is_a?(Dictionary) ? rsrc.length : 0 } unless block_given?
|
170
|
+
return unless rsrc.is_a?(Dictionary)
|
168
171
|
|
169
|
-
|
172
|
+
rsrc.each_pair do |name, obj|
|
173
|
+
yield(name.value, obj.solve)
|
174
|
+
end
|
175
|
+
end
|
170
176
|
|
171
|
-
|
172
|
-
|
177
|
+
def each_colorspace(&block)
|
178
|
+
each_resource(Resources::COLORSPACE, &block)
|
179
|
+
end
|
173
180
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
end
|
181
|
+
def each_extgstate(&block)
|
182
|
+
each_resource(Resources::EXTGSTATE, &block)
|
183
|
+
end
|
178
184
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
def each_shading(&block); each_resource(Resources::SHADING, &block) end
|
183
|
-
def each_xobject(&block); each_resource(Resources::XOBJECT, &block) end
|
184
|
-
def each_font(&block); each_resource(Resources::FONT, &block) end
|
185
|
-
def each_property(&block); each_resource(Resources::PROPERTIES, &block) end
|
186
|
-
|
187
|
-
def extgstates; each_extgstate.to_h end
|
188
|
-
def colorspaces; each_colorspace.to_h end
|
189
|
-
def patterns; each_pattern.to_h end
|
190
|
-
def shadings; each_shading.to_h end
|
191
|
-
def xobjects; each_xobject.to_h end
|
192
|
-
def fonts; each_font.to_h end
|
193
|
-
def properties; each_property.to_h end
|
194
|
-
|
195
|
-
#
|
196
|
-
# Returns a Hash of all resources in the object or only the specified _type_.
|
197
|
-
#
|
198
|
-
def resources(type = nil)
|
199
|
-
if type.nil?
|
200
|
-
self.extgstates
|
201
|
-
.merge self.colorspaces
|
202
|
-
.merge self.patterns
|
203
|
-
.merge self.shadings
|
204
|
-
.merge self.xobjects
|
205
|
-
.merge self.fonts
|
206
|
-
.merge self.properties
|
207
|
-
else
|
208
|
-
self.each_resource(type).to_h
|
209
|
-
end
|
210
|
-
end
|
185
|
+
def each_pattern(&block)
|
186
|
+
each_resource(Resources::PATTERN, &block)
|
187
|
+
end
|
211
188
|
|
212
|
-
|
189
|
+
def each_shading(&block)
|
190
|
+
each_resource(Resources::SHADING, &block)
|
191
|
+
end
|
213
192
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
Resources::EXTGSTATE => 'ExtG',
|
218
|
-
Resources::COLORSPACE => 'CS',
|
219
|
-
Resources::PATTERN => 'P',
|
220
|
-
Resources::SHADING => 'Sh',
|
221
|
-
Resources::XOBJECT => 'Im',
|
222
|
-
Resources::FONT => 'F',
|
223
|
-
Resources::PROPERTIES => 'Pr'
|
224
|
-
}[type]
|
193
|
+
def each_xobject(&block)
|
194
|
+
each_resource(Resources::XOBJECT, &block)
|
195
|
+
end
|
225
196
|
|
226
|
-
|
227
|
-
|
197
|
+
def each_font(&block)
|
198
|
+
each_resource(Resources::FONT, &block)
|
199
|
+
end
|
228
200
|
|
229
|
-
|
201
|
+
def each_property(&block)
|
202
|
+
each_resource(Resources::PROPERTIES, &block)
|
203
|
+
end
|
230
204
|
|
231
|
-
|
232
|
-
|
205
|
+
def extgstates
|
206
|
+
each_extgstate.to_h
|
233
207
|
end
|
234
208
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
class Resources < Dictionary
|
239
|
-
include StandardObject
|
240
|
-
include ResourcesHolder
|
209
|
+
def colorspaces
|
210
|
+
each_colorspace.to_h
|
211
|
+
end
|
241
212
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
SHADING = :Shading
|
246
|
-
XOBJECT = :XObject
|
247
|
-
FONT = :Font
|
248
|
-
PROPERTIES = :Properties
|
213
|
+
def patterns
|
214
|
+
each_pattern.to_h
|
215
|
+
end
|
249
216
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
field SHADING, :Type => Dictionary, :Version => "1.3"
|
254
|
-
field XOBJECT, :Type => Dictionary
|
255
|
-
field FONT, :Type => Dictionary
|
256
|
-
field :ProcSet, :Type => Array.of(Name)
|
257
|
-
field PROPERTIES, :Type => Dictionary, :Version => "1.2"
|
217
|
+
def shadings
|
218
|
+
each_shading.to_h
|
219
|
+
end
|
258
220
|
|
259
|
-
|
260
|
-
|
221
|
+
def xobjects
|
222
|
+
each_xobject.to_h
|
223
|
+
end
|
261
224
|
|
262
|
-
|
263
|
-
|
225
|
+
def fonts
|
226
|
+
each_font.to_h
|
264
227
|
end
|
265
228
|
|
266
|
-
|
229
|
+
def properties
|
230
|
+
each_property.to_h
|
267
231
|
end
|
268
232
|
|
269
233
|
#
|
270
|
-
#
|
234
|
+
# Returns a Hash of all resources in the object or only the specified _type_.
|
271
235
|
#
|
272
|
-
|
273
|
-
|
236
|
+
def resources(type = nil)
|
237
|
+
if type.nil?
|
238
|
+
extgstates
|
239
|
+
.merge colorspaces
|
240
|
+
.merge patterns
|
241
|
+
.merge shadings
|
242
|
+
.merge xobjects
|
243
|
+
.merge fonts
|
244
|
+
.merge properties
|
245
|
+
else
|
246
|
+
each_resource(type).to_h
|
247
|
+
end
|
248
|
+
end
|
274
249
|
|
275
|
-
|
276
|
-
field :Parent, :Type => PageTreeNode
|
277
|
-
field :Kids, :Type => Array, :Default => [], :Required => true
|
278
|
-
field :Count, :Type => Integer, :Default => 0, :Required => true
|
250
|
+
private
|
279
251
|
|
280
|
-
|
281
|
-
|
252
|
+
def new_id(type, prefix = nil) # :nodoc:
|
253
|
+
prefix ||=
|
254
|
+
{
|
255
|
+
Resources::EXTGSTATE => 'ExtG',
|
256
|
+
Resources::COLORSPACE => 'CS',
|
257
|
+
Resources::PATTERN => 'P',
|
258
|
+
Resources::SHADING => 'Sh',
|
259
|
+
Resources::XOBJECT => 'Im',
|
260
|
+
Resources::FONT => 'F',
|
261
|
+
Resources::PROPERTIES => 'Pr'
|
262
|
+
}[type]
|
282
263
|
|
283
|
-
|
284
|
-
|
285
|
-
end
|
264
|
+
rsrc = resources(type)
|
265
|
+
n = '1'
|
286
266
|
|
287
|
-
|
288
|
-
self.Count = self.pages.count
|
267
|
+
n.next! while rsrc.include?((prefix + n).to_sym)
|
289
268
|
|
290
|
-
|
291
|
-
|
269
|
+
Name.new(prefix + n)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
#
|
274
|
+
# Class representing a Resources Dictionary for a Page.
|
275
|
+
#
|
276
|
+
class Resources < Dictionary
|
277
|
+
include StandardObject
|
278
|
+
include ResourcesHolder
|
279
|
+
|
280
|
+
EXTGSTATE = :ExtGState
|
281
|
+
COLORSPACE = :ColorSpace
|
282
|
+
PATTERN = :Pattern
|
283
|
+
SHADING = :Shading
|
284
|
+
XOBJECT = :XObject
|
285
|
+
FONT = :Font
|
286
|
+
PROPERTIES = :Properties
|
287
|
+
|
288
|
+
field EXTGSTATE, Type: Dictionary
|
289
|
+
field COLORSPACE, Type: Dictionary
|
290
|
+
field PATTERN, Type: Dictionary
|
291
|
+
field SHADING, Type: Dictionary, Version: "1.3"
|
292
|
+
field XOBJECT, Type: Dictionary
|
293
|
+
field FONT, Type: Dictionary
|
294
|
+
field :ProcSet, Type: Array.of(Name)
|
295
|
+
field PROPERTIES, Type: Dictionary, Version: "1.2"
|
296
|
+
|
297
|
+
def pre_build
|
298
|
+
add_font(Font::Type1::Standard::Helvetica.new.pre_build) unless self.Font
|
299
|
+
|
300
|
+
super
|
301
|
+
end
|
302
|
+
end
|
292
303
|
|
293
|
-
|
294
|
-
|
295
|
-
#
|
296
|
-
def insert_page(n, page)
|
297
|
-
raise IndexError, "Page numbers are referenced starting from 1" if n < 1
|
298
|
-
|
299
|
-
kids = self.Kids
|
300
|
-
unless kids.is_a?(Array)
|
301
|
-
raise InvalidPageTreeError, "Kids must be an Array"
|
302
|
-
end
|
303
|
-
|
304
|
-
count = 0
|
305
|
-
kids.each_with_index do |kid, index|
|
306
|
-
node = kid.solve
|
307
|
-
|
308
|
-
case node
|
309
|
-
when Page
|
310
|
-
count = count + 1
|
311
|
-
if count == n
|
312
|
-
kids.insert(index, page)
|
313
|
-
page.Parent = self
|
314
|
-
self.Count += 1
|
315
|
-
return self
|
316
|
-
end
|
317
|
-
|
318
|
-
when PageTreeNode
|
319
|
-
count = count + node.Count
|
320
|
-
if count >= n
|
321
|
-
node.insert_page(n - count + node.Count, page)
|
322
|
-
self.Count += 1
|
323
|
-
return self
|
324
|
-
end
|
325
|
-
else
|
326
|
-
raise InvalidPageTreeError, "not a Page or PageTreeNode"
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
raise IndexError, "Out of order page index" unless count + 1 == n
|
331
|
-
|
332
|
-
self.append_page(page)
|
333
|
-
end
|
304
|
+
class InvalidPageTreeError < Error # :nodoc:
|
305
|
+
end
|
334
306
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
end
|
307
|
+
#
|
308
|
+
# Class representing a node in a Page tree.
|
309
|
+
#
|
310
|
+
class PageTreeNode < Dictionary
|
311
|
+
include StandardObject
|
341
312
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
return enum_for(__method__) { self.Count.to_i } unless block_given?
|
313
|
+
field :Type, Type: Name, Default: :Pages, Required: true
|
314
|
+
field :Parent, Type: PageTreeNode
|
315
|
+
field :Kids, Type: Array, Default: [], Required: true
|
316
|
+
field :Count, Type: Integer, Default: 0, Required: true
|
347
317
|
|
348
|
-
|
349
|
-
|
350
|
-
end
|
318
|
+
def initialize(hash = {}, parser = nil)
|
319
|
+
super
|
351
320
|
|
352
|
-
|
353
|
-
|
354
|
-
|
321
|
+
set_default_values # Ensure that basic tree fields are present.
|
322
|
+
set_indirect(true)
|
323
|
+
end
|
355
324
|
|
356
|
-
|
325
|
+
def pre_build # :nodoc:
|
326
|
+
self.Count = pages.count
|
357
327
|
|
358
|
-
|
359
|
-
|
360
|
-
node = self.Kids[n].solve
|
328
|
+
super
|
329
|
+
end
|
361
330
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
331
|
+
#
|
332
|
+
# Inserts a page into the node at a specified position (starting from 1).
|
333
|
+
#
|
334
|
+
def insert_page(n, page)
|
335
|
+
raise IndexError, "Page numbers are referenced starting from 1" if n < 1
|
336
|
+
|
337
|
+
kids = self.Kids
|
338
|
+
unless kids.is_a?(Array)
|
339
|
+
raise InvalidPageTreeError, "Kids must be an Array"
|
340
|
+
end
|
341
|
+
|
342
|
+
count = 0
|
343
|
+
kids.each_with_index do |kid, index|
|
344
|
+
node = kid.solve
|
345
|
+
|
346
|
+
case node
|
347
|
+
when Page
|
348
|
+
count += 1
|
349
|
+
if count == n
|
350
|
+
kids.insert(index, page)
|
351
|
+
page.Parent = self
|
352
|
+
self.Count += 1
|
353
|
+
return self
|
354
|
+
end
|
370
355
|
|
371
|
-
|
356
|
+
when PageTreeNode
|
357
|
+
count += node.Count
|
358
|
+
if count >= n
|
359
|
+
node.insert_page(n - count + node.Count, page)
|
360
|
+
self.Count += 1
|
361
|
+
return self
|
362
|
+
end
|
363
|
+
else
|
364
|
+
raise InvalidPageTreeError, "not a Page or PageTreeNode"
|
372
365
|
end
|
366
|
+
end
|
373
367
|
|
374
|
-
|
375
|
-
# Get the n-th Page object in this node, starting from 1.
|
376
|
-
#
|
377
|
-
def get_page(n)
|
378
|
-
raise IndexError, "Page numbers are referenced starting from 1" if n < 1
|
379
|
-
raise IndexError, "Page not found" if n > self.Count.to_i
|
368
|
+
raise IndexError, "Out of order page index" unless count + 1 == n
|
380
369
|
|
381
|
-
|
382
|
-
|
370
|
+
append_page(page)
|
371
|
+
end
|
383
372
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
end
|
373
|
+
#
|
374
|
+
# Returns an Array of Pages inheriting this tree node.
|
375
|
+
#
|
376
|
+
def pages
|
377
|
+
each_page.to_a
|
378
|
+
end
|
391
379
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
end
|
380
|
+
#
|
381
|
+
# Iterate through each page of that node.
|
382
|
+
#
|
383
|
+
def each_page(browsed_nodes: [], &block)
|
384
|
+
return enum_for(__method__) { self.Count.to_i } unless block_given?
|
398
385
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
def append_page(page)
|
403
|
-
self.Kids ||= []
|
404
|
-
self.Kids.push(page)
|
405
|
-
self.Count += 1
|
386
|
+
if browsed_nodes.any? { |node| node.equal?(self) }
|
387
|
+
raise InvalidPageTreeError, "Cyclic tree graph detected"
|
388
|
+
end
|
406
389
|
|
407
|
-
|
390
|
+
unless self.Kids.is_a?(Array)
|
391
|
+
raise InvalidPageTreeError, "Kids must be an Array"
|
392
|
+
end
|
393
|
+
|
394
|
+
browsed_nodes.push(self)
|
395
|
+
|
396
|
+
unless self.Count.nil?
|
397
|
+
[self.Count.value, self.Kids.length].min.times do |n|
|
398
|
+
node = self.Kids[n].solve
|
399
|
+
|
400
|
+
case node
|
401
|
+
when PageTreeNode then node.each_page(browsed_nodes: browsed_nodes, &block)
|
402
|
+
when Page then yield(node)
|
403
|
+
else
|
404
|
+
raise InvalidPageTreeError, "not a Page or PageTreeNode"
|
405
|
+
end
|
408
406
|
end
|
407
|
+
end
|
408
|
+
|
409
|
+
self
|
409
410
|
end
|
410
411
|
|
411
|
-
|
412
|
-
|
412
|
+
#
|
413
|
+
# Get the n-th Page object in this node, starting from 1.
|
414
|
+
#
|
415
|
+
def get_page(n)
|
416
|
+
raise IndexError, "Page numbers are referenced starting from 1" if n < 1
|
417
|
+
raise IndexError, "Page not found" if n > self.Count.to_i
|
413
418
|
|
414
|
-
|
415
|
-
|
416
|
-
UPPER_ROMAN = :R
|
417
|
-
LOWER_ROMAN = :r
|
418
|
-
UPPER_ALPHA = :A
|
419
|
-
LOWER_ALPHA = :a
|
420
|
-
end
|
419
|
+
each_page.lazy.drop(n - 1).first or raise IndexError, "Page not found"
|
420
|
+
end
|
421
421
|
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
422
|
+
#
|
423
|
+
# Removes all pages in the node.
|
424
|
+
#
|
425
|
+
def clear_pages
|
426
|
+
self.Count = 0
|
427
|
+
self.Kids = []
|
426
428
|
end
|
427
429
|
|
428
|
-
#
|
429
|
-
|
430
|
-
|
431
|
-
|
430
|
+
#
|
431
|
+
# Returns true unless the node is empty.
|
432
|
+
#
|
433
|
+
def pages?
|
434
|
+
each_page.size > 0
|
435
|
+
end
|
432
436
|
|
433
437
|
#
|
434
|
-
#
|
438
|
+
# Append a page at the end of this node.
|
435
439
|
#
|
436
|
-
|
437
|
-
|
438
|
-
|
440
|
+
def append_page(page)
|
441
|
+
self.Kids ||= []
|
442
|
+
self.Kids.push(page)
|
443
|
+
self.Count += 1
|
439
444
|
|
440
|
-
|
441
|
-
|
445
|
+
page.Parent = self
|
446
|
+
end
|
447
|
+
end
|
442
448
|
|
443
|
-
|
444
|
-
|
449
|
+
class PageLabel < Dictionary
|
450
|
+
include StandardObject
|
445
451
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
# Box color information dictionary associated to a Page.
|
454
|
-
#
|
455
|
-
class BoxColorInformation < Dictionary
|
456
|
-
include StandardObject
|
457
|
-
|
458
|
-
field :CropBox, :Type => BoxStyle
|
459
|
-
field :BleedBox, :Type => BoxStyle
|
460
|
-
field :TrimBox, :Type => BoxStyle
|
461
|
-
field :ArtBox, :Type => BoxStyle
|
462
|
-
end
|
452
|
+
module Style
|
453
|
+
DECIMAL = :D
|
454
|
+
UPPER_ROMAN = :R
|
455
|
+
LOWER_ROMAN = :r
|
456
|
+
UPPER_ALPHA = :A
|
457
|
+
LOWER_ALPHA = :a
|
458
|
+
end
|
463
459
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
field :Type, :Type => Name, :Default => :NavNode
|
471
|
-
field :NA, :Type => Dictionary # Next action
|
472
|
-
field :PA, :Type => Dictionary # Prev action
|
473
|
-
field :Next, :Type => NavigationNode
|
474
|
-
field :Prev, :Type => NavigationNode
|
475
|
-
field :Dur, :Type => Number
|
476
|
-
end
|
460
|
+
field :Type, Type: Name, Default: :PageLabel
|
461
|
+
field :S, Type: Name
|
462
|
+
field :P, Type: String
|
463
|
+
field :St, Type: Integer
|
464
|
+
end
|
477
465
|
|
478
|
-
|
479
|
-
|
480
|
-
#
|
481
|
-
class AdditionalActions < Dictionary
|
482
|
-
include StandardObject
|
466
|
+
# Forward declarations.
|
467
|
+
class ContentStream < Stream; end
|
483
468
|
|
484
|
-
|
485
|
-
field :C, :Type => Dictionary, :Version => "1.2" # Page Close
|
486
|
-
end
|
469
|
+
class Annotation < Dictionary; end
|
487
470
|
|
488
|
-
|
489
|
-
A0 = Rectangle[width: 2384, height: 3370]
|
490
|
-
A1 = Rectangle[width: 1684, height: 2384]
|
491
|
-
A2 = Rectangle[width: 1191, height: 1684]
|
492
|
-
A3 = Rectangle[width: 842, height: 1191]
|
493
|
-
A4 = Rectangle[width: 595, height: 842]
|
494
|
-
A5 = Rectangle[width: 420, height: 595]
|
495
|
-
A6 = Rectangle[width: 298, height: 420]
|
496
|
-
A7 = Rectangle[width: 210, height: 298]
|
497
|
-
A8 = Rectangle[width: 147, height: 210]
|
498
|
-
A9 = Rectangle[width: 105, height: 147]
|
499
|
-
A10 = Rectangle[width: 74, height: 105]
|
500
|
-
|
501
|
-
B0 = Rectangle[width: 2836, height: 4008]
|
502
|
-
B1 = Rectangle[width: 2004, height: 2835]
|
503
|
-
B2 = Rectangle[width: 1417, height: 2004]
|
504
|
-
B3 = Rectangle[width: 1001, height: 1417]
|
505
|
-
B4 = Rectangle[width: 709, height: 1001]
|
506
|
-
B5 = Rectangle[width: 499, height: 709]
|
507
|
-
B6 = Rectangle[width: 354, height: 499]
|
508
|
-
B7 = Rectangle[width: 249, height: 354]
|
509
|
-
B8 = Rectangle[width: 176, height: 249]
|
510
|
-
B9 = Rectangle[width: 125, height: 176]
|
511
|
-
B10 = Rectangle[width: 88, height: 125]
|
512
|
-
end
|
471
|
+
module Graphics; class ImageXObject < Stream; end end
|
513
472
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
field :BleedBox, :Type => Rectangle, :Version => "1.3"
|
521
|
-
field :TrimBox, :Type => Rectangle, :Version => "1.3"
|
522
|
-
field :ArtBox, :Type => Rectangle, :Version => "1.3"
|
523
|
-
field :BoxColorInfo, :Type => BoxColorInformation, :Version => "1.4"
|
524
|
-
field :Contents, :Type => [ ContentStream, Array.of(ContentStream) ]
|
525
|
-
field :Rotate, :Type => Integer, :Default => 0
|
526
|
-
field :Group, :Type => Dictionary, :Version => "1.4"
|
527
|
-
field :Thumb, :Type => Graphics::ImageXObject
|
528
|
-
field :B, :Type => Array, :Version => "1.1"
|
529
|
-
field :Dur, :Type => Integer, :Version => "1.1"
|
530
|
-
field :Trans, :Type => Dictionary, :Version => "1.1"
|
531
|
-
field :Annots, :Type => Array.of(Annotation)
|
532
|
-
field :AA, :Type => AdditionalActions, :Version => "1.2"
|
533
|
-
field :Metadata, :Type => MetadataStream, :Version => "1.4"
|
534
|
-
field :PieceInfo, :Type => Dictionary, :Version => "1.2"
|
535
|
-
field :StructParents, :Type => Integer, :Version => "1.3"
|
536
|
-
field :ID, :Type => String
|
537
|
-
field :PZ, :Type => Number
|
538
|
-
field :SeparationInfo, :Type => Dictionary, :Version => "1.3"
|
539
|
-
field :Tabs, :Type => Name, :Version => "1.5"
|
540
|
-
field :TemplateAssociated, :Type => Name, :Version => "1.5"
|
541
|
-
field :PresSteps, :Type => NavigationNode, :Version => "1.5"
|
542
|
-
field :UserUnit, :Type => Number, :Default => 1.0, :Version => "1.6"
|
543
|
-
field :VP, :Type => Dictionary, :Version => "1.6"
|
544
|
-
|
545
|
-
def initialize(hash = {}, parser = nil)
|
546
|
-
super(hash, parser)
|
547
|
-
|
548
|
-
set_indirect(true)
|
549
|
-
end
|
473
|
+
#
|
474
|
+
# Class representing a Page in the PDF document.
|
475
|
+
#
|
476
|
+
class Page < Dictionary
|
477
|
+
include StandardObject
|
478
|
+
include ResourcesHolder
|
550
479
|
|
551
|
-
|
552
|
-
|
480
|
+
class BoxStyle < Dictionary
|
481
|
+
include StandardObject
|
553
482
|
|
554
|
-
|
555
|
-
|
483
|
+
SOLID = :S
|
484
|
+
DASH = :D
|
556
485
|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
return enum_for(__method__) do
|
564
|
-
case contents
|
565
|
-
when Array then contents.length
|
566
|
-
when Stream then 1
|
567
|
-
else
|
568
|
-
0
|
569
|
-
end
|
570
|
-
end unless block_given?
|
571
|
-
|
572
|
-
case contents
|
573
|
-
when Stream then yield(contents)
|
574
|
-
when Array then contents.each { |stm| yield(stm.solve) }
|
575
|
-
end
|
576
|
-
end
|
486
|
+
field :C, Type: Array.of(Number), Default: [0.0, 0.0, 0.0]
|
487
|
+
field :W, Type: Number, Default: 1
|
488
|
+
field :S, Type: Name, Default: SOLID
|
489
|
+
field :D, Type: Array.of(Integer)
|
490
|
+
end
|
577
491
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
end
|
492
|
+
#
|
493
|
+
# Box color information dictionary associated to a Page.
|
494
|
+
#
|
495
|
+
class BoxColorInformation < Dictionary
|
496
|
+
include StandardObject
|
584
497
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
498
|
+
field :CropBox, Type: BoxStyle
|
499
|
+
field :BleedBox, Type: BoxStyle
|
500
|
+
field :TrimBox, Type: BoxStyle
|
501
|
+
field :ArtBox, Type: BoxStyle
|
502
|
+
end
|
590
503
|
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
504
|
+
#
|
505
|
+
# Class representing a navigation node associated to a Page.
|
506
|
+
#
|
507
|
+
class NavigationNode < Dictionary
|
508
|
+
include StandardObject
|
509
|
+
|
510
|
+
field :Type, Type: Name, Default: :NavNode
|
511
|
+
field :NA, Type: Dictionary # Next action
|
512
|
+
field :PA, Type: Dictionary # Prev action
|
513
|
+
field :Next, Type: NavigationNode
|
514
|
+
field :Prev, Type: NavigationNode
|
515
|
+
field :Dur, Type: Number
|
516
|
+
end
|
596
517
|
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
518
|
+
#
|
519
|
+
# Class representing additional actions which can be associated to a Page.
|
520
|
+
#
|
521
|
+
class AdditionalActions < Dictionary
|
522
|
+
include StandardObject
|
602
523
|
|
603
|
-
|
604
|
-
|
524
|
+
field :O, Type: Dictionary, Version: "1.2" # Page Open
|
525
|
+
field :C, Type: Dictionary, Version: "1.2" # Page Close
|
526
|
+
end
|
605
527
|
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
528
|
+
module Format
|
529
|
+
A0 = Rectangle[width: 2384, height: 3370]
|
530
|
+
A1 = Rectangle[width: 1684, height: 2384]
|
531
|
+
A2 = Rectangle[width: 1191, height: 1684]
|
532
|
+
A3 = Rectangle[width: 842, height: 1191]
|
533
|
+
A4 = Rectangle[width: 595, height: 842]
|
534
|
+
A5 = Rectangle[width: 420, height: 595]
|
535
|
+
A6 = Rectangle[width: 298, height: 420]
|
536
|
+
A7 = Rectangle[width: 210, height: 298]
|
537
|
+
A8 = Rectangle[width: 147, height: 210]
|
538
|
+
A9 = Rectangle[width: 105, height: 147]
|
539
|
+
A10 = Rectangle[width: 74, height: 105]
|
540
|
+
|
541
|
+
B0 = Rectangle[width: 2836, height: 4008]
|
542
|
+
B1 = Rectangle[width: 2004, height: 2835]
|
543
|
+
B2 = Rectangle[width: 1417, height: 2004]
|
544
|
+
B3 = Rectangle[width: 1001, height: 1417]
|
545
|
+
B4 = Rectangle[width: 709, height: 1001]
|
546
|
+
B5 = Rectangle[width: 499, height: 709]
|
547
|
+
B6 = Rectangle[width: 354, height: 499]
|
548
|
+
B7 = Rectangle[width: 249, height: 354]
|
549
|
+
B8 = Rectangle[width: 176, height: 249]
|
550
|
+
B9 = Rectangle[width: 125, height: 176]
|
551
|
+
B10 = Rectangle[width: 88, height: 125]
|
552
|
+
end
|
610
553
|
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
554
|
+
field :Type, Type: Name, Default: :Page, Required: true
|
555
|
+
field :Parent, Type: PageTreeNode, Required: true
|
556
|
+
field :LastModified, Type: String, Version: "1.3"
|
557
|
+
field :Resources, Type: Resources, Required: true
|
558
|
+
field :MediaBox, Type: Rectangle, Default: Format::A4, Required: true
|
559
|
+
field :CropBox, Type: Rectangle
|
560
|
+
field :BleedBox, Type: Rectangle, Version: "1.3"
|
561
|
+
field :TrimBox, Type: Rectangle, Version: "1.3"
|
562
|
+
field :ArtBox, Type: Rectangle, Version: "1.3"
|
563
|
+
field :BoxColorInfo, Type: BoxColorInformation, Version: "1.4"
|
564
|
+
field :Contents, Type: [ContentStream, Array.of(ContentStream)]
|
565
|
+
field :Rotate, Type: Integer, Default: 0
|
566
|
+
field :Group, Type: Dictionary, Version: "1.4"
|
567
|
+
field :Thumb, Type: Graphics::ImageXObject
|
568
|
+
field :B, Type: Array, Version: "1.1"
|
569
|
+
field :Dur, Type: Integer, Version: "1.1"
|
570
|
+
field :Trans, Type: Dictionary, Version: "1.1"
|
571
|
+
field :Annots, Type: Array.of(Annotation)
|
572
|
+
field :AA, Type: AdditionalActions, Version: "1.2"
|
573
|
+
field :Metadata, Type: MetadataStream, Version: "1.4"
|
574
|
+
field :PieceInfo, Type: Dictionary, Version: "1.2"
|
575
|
+
field :StructParents, Type: Integer, Version: "1.3"
|
576
|
+
field :ID, Type: String
|
577
|
+
field :PZ, Type: Number
|
578
|
+
field :SeparationInfo, Type: Dictionary, Version: "1.3"
|
579
|
+
field :Tabs, Type: Name, Version: "1.5"
|
580
|
+
field :TemplateAssociated, Type: Name, Version: "1.5"
|
581
|
+
field :PresSteps, Type: NavigationNode, Version: "1.5"
|
582
|
+
field :UserUnit, Type: Number, Default: 1.0, Version: "1.6"
|
583
|
+
field :VP, Type: Dictionary, Version: "1.6"
|
584
|
+
|
585
|
+
def initialize(hash = {}, parser = nil)
|
586
|
+
super
|
587
|
+
|
588
|
+
set_indirect(true)
|
589
|
+
end
|
617
590
|
|
618
|
-
|
619
|
-
|
620
|
-
#
|
621
|
-
def add_flash_application(swfspec, params = {})
|
622
|
-
options =
|
623
|
-
{
|
624
|
-
windowed: false,
|
625
|
-
transparent: false,
|
626
|
-
navigation_pane: false,
|
627
|
-
toolbar: false,
|
628
|
-
pass_context_click: false,
|
629
|
-
activation: Annotation::RichMedia::Activation::PAGE_OPEN,
|
630
|
-
deactivation: Annotation::RichMedia::Deactivation::PAGE_CLOSE,
|
631
|
-
flash_vars: nil
|
632
|
-
}
|
633
|
-
options.update(params)
|
634
|
-
|
635
|
-
annot = create_richmedia(:Flash, swfspec, options)
|
636
|
-
add_annotation(annot)
|
637
|
-
|
638
|
-
annot
|
639
|
-
end
|
591
|
+
def pre_build
|
592
|
+
self.Resources = Resources.new.pre_build unless has_key?(:Resources)
|
640
593
|
|
641
|
-
|
642
|
-
|
643
|
-
#
|
644
|
-
def onOpen(action)
|
645
|
-
self.AA ||= Page::AdditionalActions.new
|
646
|
-
self.AA.O = action
|
594
|
+
super
|
595
|
+
end
|
647
596
|
|
648
|
-
|
649
|
-
|
597
|
+
#
|
598
|
+
# Iterates over all the ContentStreams of the Page.
|
599
|
+
#
|
600
|
+
def each_content_stream
|
601
|
+
contents = self.Contents
|
602
|
+
|
603
|
+
unless block_given?
|
604
|
+
return enum_for(__method__) do
|
605
|
+
case contents
|
606
|
+
when Array then contents.length
|
607
|
+
when Stream then 1
|
608
|
+
else
|
609
|
+
0
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
case contents
|
615
|
+
when Stream then yield(contents)
|
616
|
+
when Array then contents.each { |stm| yield(stm.solve) }
|
617
|
+
end
|
618
|
+
end
|
650
619
|
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
620
|
+
#
|
621
|
+
# Returns an Array of ContentStreams for the Page.
|
622
|
+
#
|
623
|
+
def content_streams
|
624
|
+
each_content_stream.to_a
|
625
|
+
end
|
657
626
|
|
658
|
-
|
659
|
-
|
627
|
+
#
|
628
|
+
# Add an Annotation to the Page.
|
629
|
+
#
|
630
|
+
def add_annotation(*annotations)
|
631
|
+
self.Annots ||= []
|
660
632
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
self.PresSteps.NA = action
|
633
|
+
annotations.each do |annot|
|
634
|
+
annot.solve[:P] = self if indirect?
|
635
|
+
self.Annots << annot
|
636
|
+
end
|
637
|
+
end
|
667
638
|
|
668
|
-
|
669
|
-
|
639
|
+
#
|
640
|
+
# Iterate through each Annotation of the Page.
|
641
|
+
#
|
642
|
+
def each_annotation
|
643
|
+
annots = self.Annots
|
670
644
|
|
671
|
-
|
672
|
-
|
673
|
-
#
|
674
|
-
def onNavigateBackward(action) #:nodoc:
|
675
|
-
self.PresSteps ||= NavigationNode.new
|
676
|
-
self.PresSteps.PA = action
|
645
|
+
return enum_for(__method__) { annots.is_a?(Array) ? annots.length : 0 } unless block_given?
|
646
|
+
return unless annots.is_a?(Array)
|
677
647
|
|
678
|
-
|
679
|
-
|
648
|
+
annots.each do |annot|
|
649
|
+
yield(annot.solve)
|
650
|
+
end
|
651
|
+
end
|
680
652
|
|
681
|
-
|
653
|
+
#
|
654
|
+
# Returns the array of Annotation objects of the Page.
|
655
|
+
#
|
656
|
+
def annotations
|
657
|
+
each_annotation.to_a
|
658
|
+
end
|
659
|
+
|
660
|
+
#
|
661
|
+
# Embed a SWF Flash application in the page.
|
662
|
+
#
|
663
|
+
def add_flash_application(swfspec, params = {})
|
664
|
+
options =
|
665
|
+
{
|
666
|
+
windowed: false,
|
667
|
+
transparent: false,
|
668
|
+
navigation_pane: false,
|
669
|
+
toolbar: false,
|
670
|
+
pass_context_click: false,
|
671
|
+
activation: Annotation::RichMedia::Activation::PAGE_OPEN,
|
672
|
+
deactivation: Annotation::RichMedia::Deactivation::PAGE_CLOSE,
|
673
|
+
flash_vars: nil
|
674
|
+
}
|
675
|
+
options.update(params)
|
676
|
+
|
677
|
+
annot = create_richmedia(:Flash, swfspec, options)
|
678
|
+
add_annotation(annot)
|
679
|
+
|
680
|
+
annot
|
681
|
+
end
|
682
682
|
|
683
|
-
|
684
|
-
|
685
|
-
|
683
|
+
#
|
684
|
+
# Will execute an action when the page is opened.
|
685
|
+
#
|
686
|
+
def onOpen(action)
|
687
|
+
self.AA ||= Page::AdditionalActions.new
|
688
|
+
self.AA.O = action
|
686
689
|
|
687
|
-
|
688
|
-
|
689
|
-
rmparams.Binding = Annotation::RichMedia::Parameters::Binding::BACKGROUND
|
690
|
-
rmparams.FlashVars = params[:flash_vars]
|
691
|
-
rminstance.Asset = content
|
690
|
+
self
|
691
|
+
end
|
692
692
|
|
693
|
-
|
694
|
-
|
695
|
-
|
693
|
+
#
|
694
|
+
# Will execute an action when the page is closed.
|
695
|
+
#
|
696
|
+
def onClose(action)
|
697
|
+
self.AA ||= Page::AdditionalActions.new
|
698
|
+
self.AA.C = action
|
696
699
|
|
697
|
-
|
698
|
-
|
699
|
-
rmcontent.Assets.Names = NameLeaf.new(content.F.value => content)
|
700
|
+
self
|
701
|
+
end
|
700
702
|
|
701
|
-
|
703
|
+
#
|
704
|
+
# Will execute an action when navigating forward from this page.
|
705
|
+
#
|
706
|
+
def onNavigateForward(action) # :nodoc:
|
707
|
+
self.PresSteps ||= NavigationNode.new
|
708
|
+
self.PresSteps.NA = action
|
702
709
|
|
703
|
-
|
704
|
-
|
705
|
-
rmactivation.Condition = params[:activation]
|
706
|
-
rmactivation.Configuration = rmconfig
|
707
|
-
rmactivation.Animation = Annotation::RichMedia::Animation.new(:PlayCount => -1, :Subtype => :Linear, :Speed => 1.0)
|
708
|
-
rmpres = rmactivation.Presentation = Annotation::RichMedia::Presentation.new
|
709
|
-
rmpres.Style = Annotation::RichMedia::Presentation::WINDOWED if params[:windowed]
|
710
|
-
rmpres.Transparent = params[:transparent]
|
711
|
-
rmpres.NavigationPane = params[:navigation_pane]
|
712
|
-
rmpres.Toolbar = params[:toolbar]
|
713
|
-
rmpres.PassContextClick = params[:pass_context_click]
|
710
|
+
self
|
711
|
+
end
|
714
712
|
|
715
|
-
|
716
|
-
|
713
|
+
#
|
714
|
+
# Will execute an action when navigating backward from this page.
|
715
|
+
#
|
716
|
+
def onNavigateBackward(action) # :nodoc:
|
717
|
+
self.PresSteps ||= NavigationNode.new
|
718
|
+
self.PresSteps.PA = action
|
717
719
|
|
718
|
-
|
719
|
-
end
|
720
|
+
self
|
720
721
|
end
|
721
722
|
|
723
|
+
private
|
724
|
+
|
725
|
+
def create_richmedia(type, content, params) # :nodoc:
|
726
|
+
content.set_indirect(true)
|
727
|
+
richmedia = Annotation::RichMedia.new.set_indirect(true)
|
728
|
+
|
729
|
+
rminstance = Annotation::RichMedia::Instance.new.set_indirect(true)
|
730
|
+
rmparams = rminstance.Params = Annotation::RichMedia::Parameters.new
|
731
|
+
rmparams.Binding = Annotation::RichMedia::Parameters::Binding::BACKGROUND
|
732
|
+
rmparams.FlashVars = params[:flash_vars]
|
733
|
+
rminstance.Asset = content
|
734
|
+
|
735
|
+
rmconfig = Annotation::RichMedia::Configuration.new.set_indirect(true)
|
736
|
+
rmconfig.Instances = [rminstance]
|
737
|
+
rmconfig.Subtype = type
|
738
|
+
|
739
|
+
rmcontent = richmedia.RichMediaContent = Annotation::RichMedia::Content.new.set_indirect(true)
|
740
|
+
rmcontent.Assets = NameTreeNode.new
|
741
|
+
rmcontent.Assets.Names = NameLeaf.new(content.F.value => content)
|
742
|
+
|
743
|
+
rmcontent.Configurations = [rmconfig]
|
744
|
+
|
745
|
+
rmsettings = richmedia.RichMediaSettings = Annotation::RichMedia::Settings.new
|
746
|
+
rmactivation = rmsettings.Activation = Annotation::RichMedia::Activation.new
|
747
|
+
rmactivation.Condition = params[:activation]
|
748
|
+
rmactivation.Configuration = rmconfig
|
749
|
+
rmactivation.Animation = Annotation::RichMedia::Animation.new(PlayCount: -1, Subtype: :Linear, Speed: 1.0)
|
750
|
+
rmpres = rmactivation.Presentation = Annotation::RichMedia::Presentation.new
|
751
|
+
rmpres.Style = Annotation::RichMedia::Presentation::WINDOWED if params[:windowed]
|
752
|
+
rmpres.Transparent = params[:transparent]
|
753
|
+
rmpres.NavigationPane = params[:navigation_pane]
|
754
|
+
rmpres.Toolbar = params[:toolbar]
|
755
|
+
rmpres.PassContextClick = params[:pass_context_click]
|
756
|
+
|
757
|
+
rmdeactivation = rmsettings.Deactivation = Annotation::RichMedia::Deactivation.new
|
758
|
+
rmdeactivation.Condition = params[:deactivation]
|
759
|
+
|
760
|
+
richmedia
|
761
|
+
end
|
762
|
+
end
|
722
763
|
end
|