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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/examples/attachments/attachment.rb +7 -8
  4. data/examples/attachments/nested_document.rb +6 -5
  5. data/examples/encryption/encryption.rb +5 -4
  6. data/examples/events/events.rb +7 -6
  7. data/examples/flash/flash.rb +10 -9
  8. data/examples/forms/javascript.rb +14 -13
  9. data/examples/forms/xfa.rb +67 -66
  10. data/examples/javascript/hello_world.rb +6 -5
  11. data/examples/javascript/js_emulation.rb +26 -26
  12. data/examples/loop/goto.rb +12 -11
  13. data/examples/loop/named.rb +17 -16
  14. data/examples/signature/signature.rb +11 -11
  15. data/examples/uri/javascript.rb +25 -24
  16. data/examples/uri/open-uri.rb +5 -4
  17. data/examples/uri/submitform.rb +11 -10
  18. data/lib/origami/3d.rb +330 -334
  19. data/lib/origami/acroform.rb +267 -268
  20. data/lib/origami/actions.rb +266 -278
  21. data/lib/origami/annotations.rb +659 -670
  22. data/lib/origami/array.rb +192 -196
  23. data/lib/origami/boolean.rb +66 -70
  24. data/lib/origami/catalog.rb +360 -363
  25. data/lib/origami/collections.rb +132 -133
  26. data/lib/origami/compound.rb +125 -129
  27. data/lib/origami/destinations.rb +226 -237
  28. data/lib/origami/dictionary.rb +155 -154
  29. data/lib/origami/encryption.rb +967 -923
  30. data/lib/origami/extensions/fdf.rb +270 -275
  31. data/lib/origami/extensions/ppklite.rb +323 -328
  32. data/lib/origami/filespec.rb +170 -173
  33. data/lib/origami/filters/ascii.rb +162 -167
  34. data/lib/origami/filters/ccitt/tables.rb +248 -252
  35. data/lib/origami/filters/ccitt.rb +309 -312
  36. data/lib/origami/filters/crypt.rb +31 -34
  37. data/lib/origami/filters/dct.rb +47 -50
  38. data/lib/origami/filters/flate.rb +57 -60
  39. data/lib/origami/filters/jbig2.rb +50 -53
  40. data/lib/origami/filters/jpx.rb +40 -43
  41. data/lib/origami/filters/lzw.rb +151 -155
  42. data/lib/origami/filters/predictors.rb +250 -255
  43. data/lib/origami/filters/runlength.rb +111 -115
  44. data/lib/origami/filters.rb +319 -325
  45. data/lib/origami/font.rb +173 -177
  46. data/lib/origami/functions.rb +62 -66
  47. data/lib/origami/graphics/colors.rb +203 -208
  48. data/lib/origami/graphics/instruction.rb +79 -81
  49. data/lib/origami/graphics/path.rb +141 -144
  50. data/lib/origami/graphics/patterns.rb +156 -160
  51. data/lib/origami/graphics/render.rb +51 -47
  52. data/lib/origami/graphics/state.rb +144 -142
  53. data/lib/origami/graphics/text.rb +185 -188
  54. data/lib/origami/graphics/xobject.rb +818 -804
  55. data/lib/origami/graphics.rb +25 -26
  56. data/lib/origami/header.rb +63 -65
  57. data/lib/origami/javascript.rb +718 -651
  58. data/lib/origami/linearization.rb +284 -285
  59. data/lib/origami/metadata.rb +156 -135
  60. data/lib/origami/name.rb +98 -100
  61. data/lib/origami/null.rb +49 -51
  62. data/lib/origami/numeric.rb +133 -135
  63. data/lib/origami/obfuscation.rb +180 -182
  64. data/lib/origami/object.rb +634 -631
  65. data/lib/origami/optionalcontent.rb +147 -149
  66. data/lib/origami/outline.rb +46 -48
  67. data/lib/origami/outputintents.rb +76 -77
  68. data/lib/origami/page.rb +637 -596
  69. data/lib/origami/parser.rb +214 -221
  70. data/lib/origami/parsers/fdf.rb +44 -45
  71. data/lib/origami/parsers/pdf/lazy.rb +147 -154
  72. data/lib/origami/parsers/pdf/linear.rb +104 -109
  73. data/lib/origami/parsers/pdf.rb +109 -107
  74. data/lib/origami/parsers/ppklite.rb +44 -46
  75. data/lib/origami/pdf.rb +886 -896
  76. data/lib/origami/reference.rb +116 -120
  77. data/lib/origami/signature.rb +617 -625
  78. data/lib/origami/stream.rb +560 -558
  79. data/lib/origami/string.rb +366 -368
  80. data/lib/origami/template/patterns.rb +50 -52
  81. data/lib/origami/template/widgets.rb +111 -114
  82. data/lib/origami/trailer.rb +153 -157
  83. data/lib/origami/tree.rb +55 -57
  84. data/lib/origami/version.rb +19 -19
  85. data/lib/origami/webcapture.rb +87 -90
  86. data/lib/origami/xfa/config.rb +409 -414
  87. data/lib/origami/xfa/connectionset.rb +113 -117
  88. data/lib/origami/xfa/datasets.rb +38 -42
  89. data/lib/origami/xfa/localeset.rb +33 -37
  90. data/lib/origami/xfa/package.rb +49 -52
  91. data/lib/origami/xfa/pdf.rb +54 -59
  92. data/lib/origami/xfa/signature.rb +33 -37
  93. data/lib/origami/xfa/sourceset.rb +34 -38
  94. data/lib/origami/xfa/stylesheet.rb +35 -39
  95. data/lib/origami/xfa/template.rb +1630 -1634
  96. data/lib/origami/xfa/xdc.rb +33 -37
  97. data/lib/origami/xfa/xfa.rb +132 -123
  98. data/lib/origami/xfa/xfdf.rb +34 -38
  99. data/lib/origami/xfa/xmpmeta.rb +34 -38
  100. data/lib/origami/xfa.rb +50 -53
  101. data/lib/origami/xreftable.rb +462 -462
  102. data/lib/origami.rb +37 -38
  103. data/test/test_actions.rb +22 -20
  104. data/test/test_annotations.rb +54 -52
  105. data/test/test_forms.rb +23 -21
  106. data/test/test_native_types.rb +82 -78
  107. data/test/test_object_tree.rb +25 -24
  108. data/test/test_pages.rb +43 -41
  109. data/test/test_pdf.rb +2 -0
  110. data/test/test_pdf_attachment.rb +23 -21
  111. data/test/test_pdf_create.rb +16 -15
  112. data/test/test_pdf_encrypt.rb +69 -66
  113. data/test/test_pdf_parse.rb +131 -129
  114. data/test/test_pdf_parse_lazy.rb +53 -53
  115. data/test/test_pdf_sign.rb +67 -67
  116. data/test/test_streams.rb +145 -143
  117. data/test/test_xrefs.rb +46 -45
  118. metadata +64 -8
data/lib/origami/page.rb CHANGED
@@ -1,722 +1,763 @@
1
- =begin
2
-
3
- This file is part of Origami, PDF manipulation framework for Ruby
4
- Copyright (C) 2016 Guillaume Delugré.
5
-
6
- Origami is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- Origami is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- =end
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
- class PDF
32
+ self.Catalog.Pages.append_page(page)
33
+ yield(page) if block_given?
24
34
 
25
- #
26
- # Appends a page or list of pages to the end of the page tree.
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
- self.Catalog.Pages.append_page(page)
35
- yield(page) if block_given?
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
- self
38
- end
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
- # Page from another document must be exported.
51
- page = page.export if page.document and page.document != self
53
+ yield(page) if block_given?
52
54
 
53
- self.Catalog.Pages.insert_page(index, page)
55
+ self
56
+ end
54
57
 
55
- yield(page) if block_given?
58
+ #
59
+ # Returns an Enumerator of Page
60
+ #
61
+ def pages
62
+ init_page_tree
56
63
 
57
- self
58
- end
64
+ self.Catalog.Pages.pages
65
+ end
59
66
 
60
- #
61
- # Returns an Enumerator of Page
62
- #
63
- def pages
64
- init_page_tree
67
+ #
68
+ # Iterate through each page, returns self.
69
+ #
70
+ def each_page(&b)
71
+ init_page_tree
65
72
 
66
- self.Catalog.Pages.pages
67
- end
73
+ self.Catalog.Pages.each_page(&b)
74
+ end
68
75
 
69
- #
70
- # Iterate through each page, returns self.
71
- #
72
- def each_page(&b)
73
- init_page_tree
76
+ #
77
+ # Get the n-th Page object.
78
+ #
79
+ def get_page(n)
80
+ init_page_tree
74
81
 
75
- self.Catalog.Pages.each_page(&b)
76
- end
82
+ self.Catalog.Pages.get_page(n)
83
+ end
77
84
 
78
- #
79
- # Get the n-th Page object.
80
- #
81
- def get_page(n)
82
- init_page_tree
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
- self.Catalog.Pages.get_page(n)
85
- end
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
- # Calls block for each named page.
96
- #
97
- def each_named_page(&b)
98
- each_name(Names::PAGES, &b)
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
- private
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
- def init_page_tree #:nodoc:
104
- unless self.Catalog.key?(:Pages)
105
- self.Catalog.Pages = PageTreeNode.new
106
- return
107
- end
113
+ module ResourcesHolder
114
+ def add_extgstate(extgstate, name = nil)
115
+ add_resource(Resources::EXTGSTATE, extgstate, name)
116
+ end
108
117
 
109
- unless self.Catalog.Pages.is_a?(PageTreeNode)
110
- raise InvalidPageTreeError, "Root page node is not a PageTreeNode"
111
- end
112
- end
118
+ def add_colorspace(colorspace, name = nil)
119
+ add_resource(Resources::COLORSPACE, colorspace, name)
113
120
  end
114
121
 
115
- module ResourcesHolder
122
+ def add_pattern(pattern, name = nil)
123
+ add_resource(Resources::PATTERN, pattern, name)
124
+ end
116
125
 
117
- def add_extgstate(extgstate, name = nil)
118
- add_resource(Resources::EXTGSTATE, extgstate, name)
119
- end
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
- def add_pattern(pattern, name = nil)
125
- add_resource(Resources::PATTERN, pattern, name)
126
- end
130
+ def add_xobject(xobject, name = nil)
131
+ add_resource(Resources::XOBJECT, xobject, name)
132
+ end
127
133
 
128
- def add_shading(shading, name = nil)
129
- add_resource(Resources::SHADING, shading, name)
130
- end
134
+ def add_font(font, name = nil)
135
+ add_resource(Resources::FONT, font, name)
136
+ end
131
137
 
132
- def add_xobject(xobject, name = nil)
133
- add_resource(Resources::XOBJECT, xobject, name)
134
- end
138
+ def add_properties(properties, name = nil)
139
+ add_resource(Resources::PROPERTIES, properties, name)
140
+ end
135
141
 
136
- def add_font(font, name = nil)
137
- add_resource(Resources::FONT, font, name)
138
- end
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
- def add_properties(properties, name = nil)
141
- add_resource(Resources::PROPERTIES, properties, name)
142
- end
152
+ name ||= new_id(type)
153
+ target = is_a?(Resources) ? self : (self.Resources ||= Resources.new)
143
154
 
144
- #
145
- # Adds a resource of the specified _type_ in the current object.
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
- name ||= new_id(type)
155
- target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
158
+ name
159
+ end
156
160
 
157
- rsrc_dict = (target[type] and target[type].solve) || (target[type] = Dictionary.new)
158
- rsrc_dict[name.to_sym] = rsrc
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
- name
161
- end
167
+ rsrc = target[type]&.solve
162
168
 
163
- #
164
- # Iterates over the resources by _type_.
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
- rsrc = (target[type] and target[type].solve)
172
+ rsrc.each_pair do |name, obj|
173
+ yield(name.value, obj.solve)
174
+ end
175
+ end
170
176
 
171
- return enum_for(__method__, type) { rsrc.is_a?(Dictionary) ? rsrc.length : 0 } unless block_given?
172
- return unless rsrc.is_a?(Dictionary)
177
+ def each_colorspace(&block)
178
+ each_resource(Resources::COLORSPACE, &block)
179
+ end
173
180
 
174
- rsrc.each_pair do |name, obj|
175
- yield(name.value, obj.solve)
176
- end
177
- end
181
+ def each_extgstate(&block)
182
+ each_resource(Resources::EXTGSTATE, &block)
183
+ end
178
184
 
179
- def each_colorspace(&block); each_resource(Resources::COLORSPACE, &block) end
180
- def each_extgstate(&block); each_resource(Resources::EXTGSTATE, &block) end
181
- def each_pattern(&block); each_resource(Resources::PATTERN, &block) end
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
- private
189
+ def each_shading(&block)
190
+ each_resource(Resources::SHADING, &block)
191
+ end
213
192
 
214
- def new_id(type, prefix = nil) #:nodoc:
215
- prefix ||=
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
- rsrc = self.resources(type)
227
- n = '1'
197
+ def each_font(&block)
198
+ each_resource(Resources::FONT, &block)
199
+ end
228
200
 
229
- n.next! while rsrc.include?((prefix + n).to_sym)
201
+ def each_property(&block)
202
+ each_resource(Resources::PROPERTIES, &block)
203
+ end
230
204
 
231
- Name.new(prefix + n)
232
- end
205
+ def extgstates
206
+ each_extgstate.to_h
233
207
  end
234
208
 
235
- #
236
- # Class representing a Resources Dictionary for a Page.
237
- #
238
- class Resources < Dictionary
239
- include StandardObject
240
- include ResourcesHolder
209
+ def colorspaces
210
+ each_colorspace.to_h
211
+ end
241
212
 
242
- EXTGSTATE = :ExtGState
243
- COLORSPACE = :ColorSpace
244
- PATTERN = :Pattern
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
- field EXTGSTATE, :Type => Dictionary
251
- field COLORSPACE, :Type => Dictionary
252
- field PATTERN, :Type => Dictionary
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
- def pre_build
260
- add_font(Font::Type1::Standard::Helvetica.new.pre_build) unless self.Font
221
+ def xobjects
222
+ each_xobject.to_h
223
+ end
261
224
 
262
- super
263
- end
225
+ def fonts
226
+ each_font.to_h
264
227
  end
265
228
 
266
- class InvalidPageTreeError < Error #:nodoc:
229
+ def properties
230
+ each_property.to_h
267
231
  end
268
232
 
269
233
  #
270
- # Class representing a node in a Page tree.
234
+ # Returns a Hash of all resources in the object or only the specified _type_.
271
235
  #
272
- class PageTreeNode < Dictionary
273
- include StandardObject
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
- field :Type, :Type => Name, :Default => :Pages, :Required => true
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
- def initialize(hash = {}, parser = nil)
281
- super
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
- set_default_values # Ensure that basic tree fields are present.
284
- set_indirect(true)
285
- end
264
+ rsrc = resources(type)
265
+ n = '1'
286
266
 
287
- def pre_build #:nodoc:
288
- self.Count = self.pages.count
267
+ n.next! while rsrc.include?((prefix + n).to_sym)
289
268
 
290
- super
291
- end
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
- # Inserts a page into the node at a specified position (starting from 1).
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
- # Returns an Array of Pages inheriting this tree node.
337
- #
338
- def pages
339
- self.each_page.to_a
340
- end
307
+ #
308
+ # Class representing a node in a Page tree.
309
+ #
310
+ class PageTreeNode < Dictionary
311
+ include StandardObject
341
312
 
342
- #
343
- # Iterate through each page of that node.
344
- #
345
- def each_page(browsed_nodes: [], &block)
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
- if browsed_nodes.any?{|node| node.equal?(self)}
349
- raise InvalidPageTreeError, "Cyclic tree graph detected"
350
- end
318
+ def initialize(hash = {}, parser = nil)
319
+ super
351
320
 
352
- unless self.Kids.is_a?(Array)
353
- raise InvalidPageTreeError, "Kids must be an Array"
354
- end
321
+ set_default_values # Ensure that basic tree fields are present.
322
+ set_indirect(true)
323
+ end
355
324
 
356
- browsed_nodes.push(self)
325
+ def pre_build # :nodoc:
326
+ self.Count = pages.count
357
327
 
358
- unless self.Count.nil?
359
- [ self.Count.value, self.Kids.length ].min.times do |n|
360
- node = self.Kids[n].solve
328
+ super
329
+ end
361
330
 
362
- case node
363
- when PageTreeNode then node.each_page(browsed_nodes: browsed_nodes, &block)
364
- when Page then yield(node)
365
- else
366
- raise InvalidPageTreeError, "not a Page or PageTreeNode"
367
- end
368
- end
369
- end
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
- self
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
- self.each_page.lazy.drop(n - 1).first or raise IndexError, "Page not found"
382
- end
370
+ append_page(page)
371
+ end
383
372
 
384
- #
385
- # Removes all pages in the node.
386
- #
387
- def clear_pages
388
- self.Count = 0
389
- self.Kids = []
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
- # Returns true unless the node is empty.
394
- #
395
- def pages?
396
- self.each_page.size > 0
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
- # Append a page at the end of this node.
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
- page.Parent = self
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
- class PageLabel < Dictionary
412
- include StandardObject
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
- module Style
415
- DECIMAL = :D
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
- field :Type, :Type => Name, :Default => :PageLabel
423
- field :S, :Type => Name
424
- field :P, :Type => String
425
- field :St, :Type => Integer
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
- # Forward declarations.
429
- class ContentStream < Stream; end
430
- class Annotation < Dictionary; end
431
- module Graphics; class ImageXObject < Stream; end end
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
- # Class representing a Page in the PDF document.
438
+ # Append a page at the end of this node.
435
439
  #
436
- class Page < Dictionary
437
- include StandardObject
438
- include ResourcesHolder
440
+ def append_page(page)
441
+ self.Kids ||= []
442
+ self.Kids.push(page)
443
+ self.Count += 1
439
444
 
440
- class BoxStyle < Dictionary
441
- include StandardObject
445
+ page.Parent = self
446
+ end
447
+ end
442
448
 
443
- SOLID = :S
444
- DASH = :D
449
+ class PageLabel < Dictionary
450
+ include StandardObject
445
451
 
446
- field :C, :Type => Array.of(Number), :Default => [0.0, 0.0, 0.0]
447
- field :W, :Type => Number, :Default => 1
448
- field :S, :Type => Name, :Default => SOLID
449
- field :D, :Type => Array.of(Integer)
450
- end
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
- # Class representing a navigation node associated to a Page.
466
- #
467
- class NavigationNode < Dictionary
468
- include StandardObject
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
- # Class representing additional actions which can be associated to a Page.
480
- #
481
- class AdditionalActions < Dictionary
482
- include StandardObject
466
+ # Forward declarations.
467
+ class ContentStream < Stream; end
483
468
 
484
- field :O, :Type => Dictionary, :Version => "1.2" # Page Open
485
- field :C, :Type => Dictionary, :Version => "1.2" # Page Close
486
- end
469
+ class Annotation < Dictionary; end
487
470
 
488
- module Format
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
- field :Type, :Type => Name, :Default => :Page, :Required => true
515
- field :Parent, :Type => PageTreeNode, :Required => true
516
- field :LastModified, :Type => String, :Version => "1.3"
517
- field :Resources, :Type => Resources, :Required => true
518
- field :MediaBox, :Type => Rectangle, :Default => Format::A4, :Required => true
519
- field :CropBox, :Type => Rectangle
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
- def pre_build
552
- self.Resources = Resources.new.pre_build unless self.has_key?(:Resources)
480
+ class BoxStyle < Dictionary
481
+ include StandardObject
553
482
 
554
- super
555
- end
483
+ SOLID = :S
484
+ DASH = :D
556
485
 
557
- #
558
- # Iterates over all the ContentStreams of the Page.
559
- #
560
- def each_content_stream
561
- contents = self.Contents
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
- # Returns an Array of ContentStreams for the Page.
580
- #
581
- def content_streams
582
- self.each_content_stream.to_a
583
- end
492
+ #
493
+ # Box color information dictionary associated to a Page.
494
+ #
495
+ class BoxColorInformation < Dictionary
496
+ include StandardObject
584
497
 
585
- #
586
- # Add an Annotation to the Page.
587
- #
588
- def add_annotation(*annotations)
589
- self.Annots ||= []
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
- annotations.each do |annot|
592
- annot.solve[:P] = self if self.indirect?
593
- self.Annots << annot
594
- end
595
- end
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
- # Iterate through each Annotation of the Page.
599
- #
600
- def each_annotation
601
- annots = self.Annots
518
+ #
519
+ # Class representing additional actions which can be associated to a Page.
520
+ #
521
+ class AdditionalActions < Dictionary
522
+ include StandardObject
602
523
 
603
- return enum_for(__method__) { annots.is_a?(Array) ? annots.length : 0 } unless block_given?
604
- return unless annots.is_a?(Array)
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
- annots.each do |annot|
607
- yield(annot.solve)
608
- end
609
- end
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
- # Returns the array of Annotation objects of the Page.
613
- #
614
- def annotations
615
- self.each_annotation.to_a
616
- end
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
- # Embed a SWF Flash application in the page.
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
- # Will execute an action when the page is opened.
643
- #
644
- def onOpen(action)
645
- self.AA ||= Page::AdditionalActions.new
646
- self.AA.O = action
594
+ super
595
+ end
647
596
 
648
- self
649
- end
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
- # Will execute an action when the page is closed.
653
- #
654
- def onClose(action)
655
- self.AA ||= Page::AdditionalActions.new
656
- self.AA.C = action
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
- self
659
- end
627
+ #
628
+ # Add an Annotation to the Page.
629
+ #
630
+ def add_annotation(*annotations)
631
+ self.Annots ||= []
660
632
 
661
- #
662
- # Will execute an action when navigating forward from this page.
663
- #
664
- def onNavigateForward(action) #:nodoc:
665
- self.PresSteps ||= NavigationNode.new
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
- self
669
- end
639
+ #
640
+ # Iterate through each Annotation of the Page.
641
+ #
642
+ def each_annotation
643
+ annots = self.Annots
670
644
 
671
- #
672
- # Will execute an action when navigating backward from this page.
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
- self
679
- end
648
+ annots.each do |annot|
649
+ yield(annot.solve)
650
+ end
651
+ end
680
652
 
681
- private
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
- def create_richmedia(type, content, params) #:nodoc:
684
- content.set_indirect(true)
685
- richmedia = Annotation::RichMedia.new.set_indirect(true)
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
- rminstance = Annotation::RichMedia::Instance.new.set_indirect(true)
688
- rmparams = rminstance.Params = Annotation::RichMedia::Parameters.new
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
- rmconfig = Annotation::RichMedia::Configuration.new.set_indirect(true)
694
- rmconfig.Instances = [ rminstance ]
695
- rmconfig.Subtype = type
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
- rmcontent = richmedia.RichMediaContent = Annotation::RichMedia::Content.new.set_indirect(true)
698
- rmcontent.Assets = NameTreeNode.new
699
- rmcontent.Assets.Names = NameLeaf.new(content.F.value => content)
700
+ self
701
+ end
700
702
 
701
- rmcontent.Configurations = [ rmconfig ]
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
- rmsettings = richmedia.RichMediaSettings = Annotation::RichMedia::Settings.new
704
- rmactivation = rmsettings.Activation = Annotation::RichMedia::Activation.new
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
- rmdeactivation = rmsettings.Deactivation = Annotation::RichMedia::Deactivation.new
716
- rmdeactivation.Condition = params[:deactivation]
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
- richmedia
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