origamindee 3.0.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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +89 -0
  3. data/COPYING.LESSER +165 -0
  4. data/README.md +131 -0
  5. data/bin/config/pdfcop.conf.yml +236 -0
  6. data/bin/pdf2pdfa +87 -0
  7. data/bin/pdf2ruby +333 -0
  8. data/bin/pdfcop +476 -0
  9. data/bin/pdfdecompress +97 -0
  10. data/bin/pdfdecrypt +91 -0
  11. data/bin/pdfencrypt +113 -0
  12. data/bin/pdfexplode +223 -0
  13. data/bin/pdfextract +277 -0
  14. data/bin/pdfmetadata +143 -0
  15. data/bin/pdfsh +12 -0
  16. data/bin/shell/console.rb +128 -0
  17. data/bin/shell/hexdump.rb +59 -0
  18. data/bin/shell/irbrc +69 -0
  19. data/examples/README.md +34 -0
  20. data/examples/attachments/attachment.rb +38 -0
  21. data/examples/attachments/nested_document.rb +51 -0
  22. data/examples/encryption/encryption.rb +28 -0
  23. data/examples/events/events.rb +72 -0
  24. data/examples/flash/flash.rb +37 -0
  25. data/examples/flash/helloworld.swf +0 -0
  26. data/examples/forms/javascript.rb +54 -0
  27. data/examples/forms/xfa.rb +115 -0
  28. data/examples/javascript/hello_world.rb +22 -0
  29. data/examples/javascript/js_emulation.rb +54 -0
  30. data/examples/loop/goto.rb +32 -0
  31. data/examples/loop/named.rb +33 -0
  32. data/examples/signature/signature.rb +65 -0
  33. data/examples/uri/javascript.rb +56 -0
  34. data/examples/uri/open-uri.rb +21 -0
  35. data/examples/uri/submitform.rb +47 -0
  36. data/lib/origami/3d.rb +364 -0
  37. data/lib/origami/acroform.rb +321 -0
  38. data/lib/origami/actions.rb +318 -0
  39. data/lib/origami/annotations.rb +711 -0
  40. data/lib/origami/array.rb +242 -0
  41. data/lib/origami/boolean.rb +90 -0
  42. data/lib/origami/catalog.rb +418 -0
  43. data/lib/origami/collections.rb +144 -0
  44. data/lib/origami/compound.rb +161 -0
  45. data/lib/origami/destinations.rb +252 -0
  46. data/lib/origami/dictionary.rb +192 -0
  47. data/lib/origami/encryption.rb +1084 -0
  48. data/lib/origami/extensions/fdf.rb +347 -0
  49. data/lib/origami/extensions/ppklite.rb +422 -0
  50. data/lib/origami/filespec.rb +197 -0
  51. data/lib/origami/filters/ascii.rb +211 -0
  52. data/lib/origami/filters/ccitt/tables.rb +267 -0
  53. data/lib/origami/filters/ccitt.rb +357 -0
  54. data/lib/origami/filters/crypt.rb +38 -0
  55. data/lib/origami/filters/dct.rb +54 -0
  56. data/lib/origami/filters/flate.rb +69 -0
  57. data/lib/origami/filters/jbig2.rb +57 -0
  58. data/lib/origami/filters/jpx.rb +47 -0
  59. data/lib/origami/filters/lzw.rb +170 -0
  60. data/lib/origami/filters/predictors.rb +292 -0
  61. data/lib/origami/filters/runlength.rb +129 -0
  62. data/lib/origami/filters.rb +364 -0
  63. data/lib/origami/font.rb +196 -0
  64. data/lib/origami/functions.rb +79 -0
  65. data/lib/origami/graphics/colors.rb +230 -0
  66. data/lib/origami/graphics/instruction.rb +98 -0
  67. data/lib/origami/graphics/path.rb +182 -0
  68. data/lib/origami/graphics/patterns.rb +174 -0
  69. data/lib/origami/graphics/render.rb +62 -0
  70. data/lib/origami/graphics/state.rb +149 -0
  71. data/lib/origami/graphics/text.rb +225 -0
  72. data/lib/origami/graphics/xobject.rb +918 -0
  73. data/lib/origami/graphics.rb +38 -0
  74. data/lib/origami/header.rb +75 -0
  75. data/lib/origami/javascript.rb +713 -0
  76. data/lib/origami/linearization.rb +330 -0
  77. data/lib/origami/metadata.rb +172 -0
  78. data/lib/origami/name.rb +135 -0
  79. data/lib/origami/null.rb +65 -0
  80. data/lib/origami/numeric.rb +181 -0
  81. data/lib/origami/obfuscation.rb +245 -0
  82. data/lib/origami/object.rb +760 -0
  83. data/lib/origami/optionalcontent.rb +183 -0
  84. data/lib/origami/outline.rb +54 -0
  85. data/lib/origami/outputintents.rb +85 -0
  86. data/lib/origami/page.rb +722 -0
  87. data/lib/origami/parser.rb +269 -0
  88. data/lib/origami/parsers/fdf.rb +56 -0
  89. data/lib/origami/parsers/pdf/lazy.rb +176 -0
  90. data/lib/origami/parsers/pdf/linear.rb +122 -0
  91. data/lib/origami/parsers/pdf.rb +118 -0
  92. data/lib/origami/parsers/ppklite.rb +57 -0
  93. data/lib/origami/pdf.rb +1108 -0
  94. data/lib/origami/reference.rb +134 -0
  95. data/lib/origami/signature.rb +702 -0
  96. data/lib/origami/stream.rb +705 -0
  97. data/lib/origami/string.rb +444 -0
  98. data/lib/origami/template/patterns.rb +56 -0
  99. data/lib/origami/template/widgets.rb +151 -0
  100. data/lib/origami/trailer.rb +190 -0
  101. data/lib/origami/tree.rb +62 -0
  102. data/lib/origami/version.rb +23 -0
  103. data/lib/origami/webcapture.rb +100 -0
  104. data/lib/origami/xfa/config.rb +453 -0
  105. data/lib/origami/xfa/connectionset.rb +146 -0
  106. data/lib/origami/xfa/datasets.rb +49 -0
  107. data/lib/origami/xfa/localeset.rb +42 -0
  108. data/lib/origami/xfa/package.rb +59 -0
  109. data/lib/origami/xfa/pdf.rb +73 -0
  110. data/lib/origami/xfa/signature.rb +42 -0
  111. data/lib/origami/xfa/sourceset.rb +43 -0
  112. data/lib/origami/xfa/stylesheet.rb +44 -0
  113. data/lib/origami/xfa/template.rb +1691 -0
  114. data/lib/origami/xfa/xdc.rb +42 -0
  115. data/lib/origami/xfa/xfa.rb +146 -0
  116. data/lib/origami/xfa/xfdf.rb +43 -0
  117. data/lib/origami/xfa/xmpmeta.rb +43 -0
  118. data/lib/origami/xfa.rb +62 -0
  119. data/lib/origami/xreftable.rb +557 -0
  120. data/lib/origami.rb +47 -0
  121. data/test/dataset/calc.pdf +85 -0
  122. data/test/dataset/crypto.pdf +36 -0
  123. data/test/dataset/empty.pdf +49 -0
  124. data/test/test_actions.rb +27 -0
  125. data/test/test_annotations.rb +68 -0
  126. data/test/test_forms.rb +30 -0
  127. data/test/test_native_types.rb +83 -0
  128. data/test/test_object_tree.rb +33 -0
  129. data/test/test_pages.rb +60 -0
  130. data/test/test_pdf.rb +20 -0
  131. data/test/test_pdf_attachment.rb +34 -0
  132. data/test/test_pdf_create.rb +24 -0
  133. data/test/test_pdf_encrypt.rb +102 -0
  134. data/test/test_pdf_parse.rb +134 -0
  135. data/test/test_pdf_parse_lazy.rb +69 -0
  136. data/test/test_pdf_sign.rb +97 -0
  137. data/test/test_streams.rb +184 -0
  138. data/test/test_xrefs.rb +67 -0
  139. metadata +280 -0
@@ -0,0 +1,722 @@
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
20
+
21
+ module Origami
22
+
23
+ class PDF
24
+
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
33
+
34
+ self.Catalog.Pages.append_page(page)
35
+ yield(page) if block_given?
36
+
37
+ self
38
+ end
39
+
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
49
+
50
+ # Page from another document must be exported.
51
+ page = page.export if page.document and page.document != self
52
+
53
+ self.Catalog.Pages.insert_page(index, page)
54
+
55
+ yield(page) if block_given?
56
+
57
+ self
58
+ end
59
+
60
+ #
61
+ # Returns an Enumerator of Page
62
+ #
63
+ def pages
64
+ init_page_tree
65
+
66
+ self.Catalog.Pages.pages
67
+ end
68
+
69
+ #
70
+ # Iterate through each page, returns self.
71
+ #
72
+ def each_page(&b)
73
+ init_page_tree
74
+
75
+ self.Catalog.Pages.each_page(&b)
76
+ end
77
+
78
+ #
79
+ # Get the n-th Page object.
80
+ #
81
+ def get_page(n)
82
+ init_page_tree
83
+
84
+ self.Catalog.Pages.get_page(n)
85
+ end
86
+
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
93
+
94
+ #
95
+ # Calls block for each named page.
96
+ #
97
+ def each_named_page(&b)
98
+ each_name(Names::PAGES, &b)
99
+ end
100
+
101
+ private
102
+
103
+ def init_page_tree #:nodoc:
104
+ unless self.Catalog.key?(:Pages)
105
+ self.Catalog.Pages = PageTreeNode.new
106
+ return
107
+ end
108
+
109
+ unless self.Catalog.Pages.is_a?(PageTreeNode)
110
+ raise InvalidPageTreeError, "Root page node is not a PageTreeNode"
111
+ end
112
+ end
113
+ end
114
+
115
+ module ResourcesHolder
116
+
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
123
+
124
+ def add_pattern(pattern, name = nil)
125
+ add_resource(Resources::PATTERN, pattern, name)
126
+ end
127
+
128
+ def add_shading(shading, name = nil)
129
+ add_resource(Resources::SHADING, shading, name)
130
+ end
131
+
132
+ def add_xobject(xobject, name = nil)
133
+ add_resource(Resources::XOBJECT, xobject, name)
134
+ end
135
+
136
+ def add_font(font, name = nil)
137
+ add_resource(Resources::FONT, font, name)
138
+ end
139
+
140
+ def add_properties(properties, name = nil)
141
+ add_resource(Resources::PROPERTIES, properties, name)
142
+ end
143
+
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
153
+
154
+ name ||= new_id(type)
155
+ target = self.is_a?(Resources) ? self : (self.Resources ||= Resources.new)
156
+
157
+ rsrc_dict = (target[type] and target[type].solve) || (target[type] = Dictionary.new)
158
+ rsrc_dict[name.to_sym] = rsrc
159
+
160
+ name
161
+ end
162
+
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)
168
+
169
+ rsrc = (target[type] and target[type].solve)
170
+
171
+ return enum_for(__method__, type) { rsrc.is_a?(Dictionary) ? rsrc.length : 0 } unless block_given?
172
+ return unless rsrc.is_a?(Dictionary)
173
+
174
+ rsrc.each_pair do |name, obj|
175
+ yield(name.value, obj.solve)
176
+ end
177
+ end
178
+
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
211
+
212
+ private
213
+
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]
225
+
226
+ rsrc = self.resources(type)
227
+ n = '1'
228
+
229
+ n.next! while rsrc.include?((prefix + n).to_sym)
230
+
231
+ Name.new(prefix + n)
232
+ end
233
+ end
234
+
235
+ #
236
+ # Class representing a Resources Dictionary for a Page.
237
+ #
238
+ class Resources < Dictionary
239
+ include StandardObject
240
+ include ResourcesHolder
241
+
242
+ EXTGSTATE = :ExtGState
243
+ COLORSPACE = :ColorSpace
244
+ PATTERN = :Pattern
245
+ SHADING = :Shading
246
+ XOBJECT = :XObject
247
+ FONT = :Font
248
+ PROPERTIES = :Properties
249
+
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"
258
+
259
+ def pre_build
260
+ add_font(Font::Type1::Standard::Helvetica.new.pre_build) unless self.Font
261
+
262
+ super
263
+ end
264
+ end
265
+
266
+ class InvalidPageTreeError < Error #:nodoc:
267
+ end
268
+
269
+ #
270
+ # Class representing a node in a Page tree.
271
+ #
272
+ class PageTreeNode < Dictionary
273
+ include StandardObject
274
+
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
279
+
280
+ def initialize(hash = {}, parser = nil)
281
+ super
282
+
283
+ set_default_values # Ensure that basic tree fields are present.
284
+ set_indirect(true)
285
+ end
286
+
287
+ def pre_build #:nodoc:
288
+ self.Count = self.pages.count
289
+
290
+ super
291
+ end
292
+
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
334
+
335
+ #
336
+ # Returns an Array of Pages inheriting this tree node.
337
+ #
338
+ def pages
339
+ self.each_page.to_a
340
+ end
341
+
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?
347
+
348
+ if browsed_nodes.any?{|node| node.equal?(self)}
349
+ raise InvalidPageTreeError, "Cyclic tree graph detected"
350
+ end
351
+
352
+ unless self.Kids.is_a?(Array)
353
+ raise InvalidPageTreeError, "Kids must be an Array"
354
+ end
355
+
356
+ browsed_nodes.push(self)
357
+
358
+ unless self.Count.nil?
359
+ [ self.Count.value, self.Kids.length ].min.times do |n|
360
+ node = self.Kids[n].solve
361
+
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
370
+
371
+ self
372
+ end
373
+
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
380
+
381
+ self.each_page.lazy.drop(n - 1).first or raise IndexError, "Page not found"
382
+ end
383
+
384
+ #
385
+ # Removes all pages in the node.
386
+ #
387
+ def clear_pages
388
+ self.Count = 0
389
+ self.Kids = []
390
+ end
391
+
392
+ #
393
+ # Returns true unless the node is empty.
394
+ #
395
+ def pages?
396
+ self.each_page.size > 0
397
+ end
398
+
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
406
+
407
+ page.Parent = self
408
+ end
409
+ end
410
+
411
+ class PageLabel < Dictionary
412
+ include StandardObject
413
+
414
+ module Style
415
+ DECIMAL = :D
416
+ UPPER_ROMAN = :R
417
+ LOWER_ROMAN = :r
418
+ UPPER_ALPHA = :A
419
+ LOWER_ALPHA = :a
420
+ end
421
+
422
+ field :Type, :Type => Name, :Default => :PageLabel
423
+ field :S, :Type => Name
424
+ field :P, :Type => String
425
+ field :St, :Type => Integer
426
+ end
427
+
428
+ # Forward declarations.
429
+ class ContentStream < Stream; end
430
+ class Annotation < Dictionary; end
431
+ module Graphics; class ImageXObject < Stream; end end
432
+
433
+ #
434
+ # Class representing a Page in the PDF document.
435
+ #
436
+ class Page < Dictionary
437
+ include StandardObject
438
+ include ResourcesHolder
439
+
440
+ class BoxStyle < Dictionary
441
+ include StandardObject
442
+
443
+ SOLID = :S
444
+ DASH = :D
445
+
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
463
+
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
477
+
478
+ #
479
+ # Class representing additional actions which can be associated to a Page.
480
+ #
481
+ class AdditionalActions < Dictionary
482
+ include StandardObject
483
+
484
+ field :O, :Type => Dictionary, :Version => "1.2" # Page Open
485
+ field :C, :Type => Dictionary, :Version => "1.2" # Page Close
486
+ end
487
+
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
513
+
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
550
+
551
+ def pre_build
552
+ self.Resources = Resources.new.pre_build unless self.has_key?(:Resources)
553
+
554
+ super
555
+ end
556
+
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
577
+
578
+ #
579
+ # Returns an Array of ContentStreams for the Page.
580
+ #
581
+ def content_streams
582
+ self.each_content_stream.to_a
583
+ end
584
+
585
+ #
586
+ # Add an Annotation to the Page.
587
+ #
588
+ def add_annotation(*annotations)
589
+ self.Annots ||= []
590
+
591
+ annotations.each do |annot|
592
+ annot.solve[:P] = self if self.indirect?
593
+ self.Annots << annot
594
+ end
595
+ end
596
+
597
+ #
598
+ # Iterate through each Annotation of the Page.
599
+ #
600
+ def each_annotation
601
+ annots = self.Annots
602
+
603
+ return enum_for(__method__) { annots.is_a?(Array) ? annots.length : 0 } unless block_given?
604
+ return unless annots.is_a?(Array)
605
+
606
+ annots.each do |annot|
607
+ yield(annot.solve)
608
+ end
609
+ end
610
+
611
+ #
612
+ # Returns the array of Annotation objects of the Page.
613
+ #
614
+ def annotations
615
+ self.each_annotation.to_a
616
+ end
617
+
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
640
+
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
647
+
648
+ self
649
+ end
650
+
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
657
+
658
+ self
659
+ end
660
+
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
667
+
668
+ self
669
+ end
670
+
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
677
+
678
+ self
679
+ end
680
+
681
+ private
682
+
683
+ def create_richmedia(type, content, params) #:nodoc:
684
+ content.set_indirect(true)
685
+ richmedia = Annotation::RichMedia.new.set_indirect(true)
686
+
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
692
+
693
+ rmconfig = Annotation::RichMedia::Configuration.new.set_indirect(true)
694
+ rmconfig.Instances = [ rminstance ]
695
+ rmconfig.Subtype = type
696
+
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
+
701
+ rmcontent.Configurations = [ rmconfig ]
702
+
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]
714
+
715
+ rmdeactivation = rmsettings.Deactivation = Annotation::RichMedia::Deactivation.new
716
+ rmdeactivation.Condition = params[:deactivation]
717
+
718
+ richmedia
719
+ end
720
+ end
721
+
722
+ end