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,557 @@
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
+ # Tries to strip any xrefs information off the document.
26
+ #
27
+ def remove_xrefs
28
+ @revisions.reverse_each do |rev|
29
+ if rev.xrefstm?
30
+ delete_object(rev.xrefstm.reference)
31
+ end
32
+
33
+ if rev.trailer.XRefStm.is_a?(Integer)
34
+ xrefstm = get_object_by_offset(rev.trailer.XRefStm)
35
+
36
+ delete_object(xrefstm.reference) if xrefstm.is_a?(XRefStream)
37
+ end
38
+
39
+ rev.xrefstm = rev.xreftable = nil
40
+ end
41
+ end
42
+ end
43
+
44
+ class InvalidXRefError < Error #:nodoc:
45
+ end
46
+
47
+ #
48
+ # Class representing a Cross-reference information.
49
+ #
50
+ class XRef
51
+
52
+ FREE = "f"
53
+ USED = "n"
54
+ FIRSTFREE = 65535
55
+
56
+ @@regexp = /(?<offset>\d{10}) (?<gen>\d{5}) (?<state>n|f)(\r\n| \r| \n)/
57
+
58
+ attr_accessor :offset, :generation, :state
59
+
60
+ #
61
+ # Creates a new XRef.
62
+ # _offset_:: The file _offset_ of the referenced Object.
63
+ # _generation_:: The generation number of the referenced Object.
64
+ # _state_:: The state of the referenced Object (FREE or USED).
65
+ #
66
+ def initialize(offset, generation, state)
67
+ @offset, @generation, @state = offset, generation, state
68
+ end
69
+
70
+ def self.parse(stream) #:nodoc:
71
+ scanner = Parser.init_scanner(stream)
72
+
73
+ if scanner.scan(@@regexp).nil?
74
+ raise InvalidXRefError, "Invalid XRef format"
75
+ end
76
+
77
+ offset = scanner['offset'].to_i
78
+ generation = scanner['gen'].to_i
79
+ state = scanner['state']
80
+
81
+ XRef.new(offset, generation, state)
82
+ end
83
+
84
+ #
85
+ # Returns true if the associated object is used.
86
+ #
87
+ def used?
88
+ @state == USED
89
+ end
90
+
91
+ #
92
+ # Returns true if the associated object is freed.
93
+ #
94
+ def free?
95
+ @state == FREE
96
+ end
97
+
98
+ #
99
+ # Marks an XRef as freed.
100
+ #
101
+ def free!
102
+ @state = FREE
103
+ end
104
+
105
+ #
106
+ # Outputs self into PDF code.
107
+ #
108
+ def to_s(eol: $/)
109
+ off = @offset.to_s.rjust(10, '0')
110
+ gen = @generation.to_s.rjust(5, '0')
111
+
112
+ "#{off} #{gen} #{@state}" + eol.rjust(2, ' ')
113
+ end
114
+
115
+ def to_xrefstm_data(type_w, field1_w, field2_w)
116
+ type_w <<= 3
117
+ field1_w <<= 3
118
+ field2_w <<= 3
119
+
120
+ type = ((@state == FREE) ? "\000" : "\001").unpack("B#{type_w}")[0]
121
+
122
+ offset = @offset.to_s(2).rjust(field1_w, '0')
123
+ generation = @generation.to_s(2).rjust(field2_w, '0')
124
+
125
+ [ type , offset, generation ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
126
+ end
127
+
128
+ class InvalidXRefSubsectionError < Error #:nodoc:
129
+ end
130
+
131
+ #
132
+ # Class representing a cross-reference subsection.
133
+ # A subsection contains a continute set of XRef.
134
+ #
135
+ class Subsection
136
+ include Enumerable
137
+
138
+ @@regexp = Regexp.new("(?<start>\\d+) (?<size>\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
139
+
140
+ attr_reader :range
141
+
142
+ #
143
+ # Creates a new XRef subsection.
144
+ # _start_:: The number of the first object referenced in the subsection.
145
+ # _entries_:: An array of XRef.
146
+ #
147
+ def initialize(start, entries = [])
148
+ @entries = entries.dup
149
+ @range = Range.new(start, start + entries.size - 1)
150
+ end
151
+
152
+ def self.parse(stream) #:nodoc:
153
+ scanner = Parser.init_scanner(stream)
154
+
155
+ if scanner.scan(@@regexp).nil?
156
+ raise InvalidXRefSubsectionError, "Bad subsection format"
157
+ end
158
+
159
+ start = scanner['start'].to_i
160
+ size = scanner['size'].to_i
161
+
162
+ xrefs = []
163
+ size.times do
164
+ xrefs << XRef.parse(scanner)
165
+ end
166
+
167
+ XRef::Subsection.new(start, xrefs)
168
+ end
169
+
170
+ #
171
+ # Returns whether this subsection contains information about a particular object.
172
+ # _no_:: The Object number.
173
+ #
174
+ def has_object?(no)
175
+ @range.include?(no)
176
+ end
177
+
178
+ #
179
+ # Returns XRef associated with a given object.
180
+ # _no_:: The Object number.
181
+ #
182
+ def [](no)
183
+ @entries[no - @range.begin]
184
+ end
185
+
186
+ #
187
+ # Processes each XRef in the subsection.
188
+ #
189
+ def each(&b)
190
+ @entries.each(&b)
191
+ end
192
+
193
+ #
194
+ # Processes each XRef in the subsection, passing the XRef and the object number to the block.
195
+ #
196
+ def each_with_number
197
+ return enum_for(__method__) { self.size } unless block_given?
198
+
199
+ counter = @range.to_enum
200
+ @entries.each do |entry|
201
+ yield(entry, counter.next)
202
+ end
203
+ end
204
+
205
+ #
206
+ # The number of entries in the subsection.
207
+ #
208
+ def size
209
+ @entries.size
210
+ end
211
+
212
+ #
213
+ # Outputs self into PDF code.
214
+ #
215
+ def to_s(eol: $/)
216
+ section = "#{@range.begin} #{@range.end - @range.begin + 1}" + eol
217
+ @entries.each do |xref|
218
+ section << xref.to_s(eol: eol)
219
+ end
220
+
221
+ section
222
+ end
223
+ end
224
+
225
+ class InvalidXRefSectionError < Error #:nodoc:
226
+ end
227
+
228
+ #
229
+ # Class representing a Cross-reference table.
230
+ # A section contains a set of XRef::Subsection.
231
+ #
232
+ class Section
233
+ include Enumerable
234
+
235
+ TOKEN = "xref"
236
+
237
+ @@regexp_open = Regexp.new(WHITESPACES + TOKEN + WHITESPACES + "(\\r?\\n|\\r\\n?)")
238
+ @@regexp_sub = Regexp.new("(\\d+) (\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
239
+
240
+ #
241
+ # Creates a new XRef section.
242
+ # _subsections_:: An array of XRefSubsection.
243
+ #
244
+ def initialize(subsections = [])
245
+ @subsections = subsections
246
+ end
247
+
248
+ def self.parse(stream) #:nodoc:
249
+ scanner = Parser.init_scanner(stream)
250
+
251
+ if scanner.skip(@@regexp_open).nil?
252
+ raise InvalidXRefSectionError, "No xref token found"
253
+ end
254
+
255
+ subsections = []
256
+ while scanner.match?(@@regexp_sub) do
257
+ subsections << XRef::Subsection.parse(scanner)
258
+ end
259
+
260
+ XRef::Section.new(subsections)
261
+ end
262
+
263
+ #
264
+ # Appends a new subsection.
265
+ # _subsection_:: A XRefSubsection.
266
+ #
267
+ def <<(subsection)
268
+ @subsections << subsection
269
+ end
270
+
271
+ #
272
+ # Returns a XRef associated with a given object.
273
+ # _no_:: The Object number.
274
+ #
275
+ def [](no)
276
+ @subsections.each do |s|
277
+ return s[no] if s.has_object?(no)
278
+ end
279
+
280
+ nil
281
+ end
282
+ alias find []
283
+
284
+ #
285
+ # Processes each XRef in each Subsection.
286
+ #
287
+ def each(&b)
288
+ return enum_for(__method__) { self.size } unless block_given?
289
+
290
+ @subsections.each do |subsection|
291
+ subsection.each(&b)
292
+ end
293
+ end
294
+
295
+ #
296
+ # Processes each XRef in each Subsection, passing the XRef and the object number.
297
+ #
298
+ def each_with_number(&b)
299
+ return enum_for(__method__) { self.size } unless block_given?
300
+
301
+ @subsections.each do |subsection|
302
+ subsection.each_with_number(&b)
303
+ end
304
+ end
305
+
306
+ #
307
+ # Processes each Subsection in this table.
308
+ #
309
+ def each_subsection(&b)
310
+ @subsections.each(&b)
311
+ end
312
+
313
+ #
314
+ # Returns an Array of Subsection.
315
+ #
316
+ def subsections
317
+ @subsections
318
+ end
319
+
320
+ #
321
+ # Clear all the entries.
322
+ #
323
+ def clear
324
+ @subsections.clear
325
+ end
326
+
327
+ #
328
+ # The number of XRef entries in the Section.
329
+ #
330
+ def size
331
+ @subsections.reduce(0) { |total, subsection| total + subsection.size }
332
+ end
333
+
334
+ #
335
+ # Outputs self into PDF code.
336
+ #
337
+ def to_s(eol: $/)
338
+ "xref" << eol << @subsections.map{|sub| sub.to_s(eol: eol)}.join
339
+ end
340
+ end
341
+ end
342
+
343
+ #
344
+ # An xref poiting to an Object embedded in an ObjectStream.
345
+ #
346
+ class XRefToCompressedObject
347
+ attr_accessor :objstmno, :index
348
+
349
+ def initialize(objstmno, index)
350
+ @objstmno = objstmno
351
+ @index = index
352
+ end
353
+
354
+ def to_xrefstm_data(type_w, field1_w, field2_w)
355
+ type_w <<= 3
356
+ field1_w <<= 3
357
+ field2_w <<= 3
358
+
359
+ type = "\002".unpack("B#{type_w}")[0]
360
+ objstmno = @objstmno.to_s(2).rjust(field1_w, '0')
361
+ index = @index.to_s(2).rjust(field2_w, '0')
362
+
363
+ [ type , objstmno, index ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
364
+ end
365
+
366
+ def used?; true end
367
+ def free?; false end
368
+ end
369
+
370
+ class InvalidXRefStreamObjectError < InvalidStreamObjectError ; end
371
+
372
+ #
373
+ # Class representing a XRef Stream.
374
+ #
375
+ class XRefStream < Stream
376
+ include Enumerable
377
+ include StandardObject
378
+
379
+ XREF_FREE = 0
380
+ XREF_USED = 1
381
+ XREF_COMPRESSED = 2
382
+
383
+ #
384
+ # Xref fields
385
+ #
386
+ field :Type, :Type => Name, :Default => :XRef, :Required => true, :Version => "1.5"
387
+ field :Size, :Type => Integer, :Required => true
388
+ field :Index, :Type => Array.of(Integer, Integer)
389
+ field :Prev, :Type => Integer
390
+ field :W, :Type => Array.of(Integer, length: 3), :Required => true
391
+
392
+ #
393
+ # Trailer fields
394
+ #
395
+ field :Root, :Type => Catalog, :Required => true
396
+ field :Encrypt, :Type => Encryption::Standard::Dictionary
397
+ field :Info, :Type => Metadata
398
+ field :ID, :Type => Array.of(String, length: 2)
399
+
400
+ def initialize(data = "", dictionary = {})
401
+ super(data, dictionary)
402
+
403
+ @xrefs = nil
404
+ end
405
+
406
+ def entries
407
+ load! if @xrefs.nil?
408
+
409
+ @xrefs
410
+ end
411
+
412
+ #
413
+ # Returns XRef entries present in this stream.
414
+ #
415
+ def pre_build #:nodoc:
416
+ load! if @xrefs.nil?
417
+
418
+ self.W = [ 1, 2, 2 ] unless self.key?(:W)
419
+ self.Size = @xrefs.length + 1
420
+
421
+ save!
422
+
423
+ super
424
+ end
425
+
426
+ #
427
+ # Adds an XRef to this Stream.
428
+ #
429
+ def <<(xref)
430
+ load! if @xrefs.nil?
431
+
432
+ @xrefs << xref
433
+ end
434
+
435
+ #
436
+ # Iterates over each XRef present in the stream.
437
+ #
438
+ def each(&b)
439
+ load! if @xrefs.nil?
440
+
441
+ @xrefs.each(&b)
442
+ end
443
+
444
+ #
445
+ # Iterates over each XRef present in the stream, passing the XRef and its object number.
446
+ #
447
+ def each_with_number
448
+ return enum_for(__method__) unless block_given?
449
+
450
+ load! if @xrefs.nil?
451
+
452
+ ranges = object_ranges
453
+ xrefs = @xrefs.to_enum
454
+
455
+ ranges.each do |range|
456
+ range.each do |no|
457
+ begin
458
+ yield(xrefs.next, no)
459
+ rescue StopIteration
460
+ raise InvalidXRefStreamObjectError, "Range is bigger than number of entries"
461
+ end
462
+ end
463
+ end
464
+ end
465
+
466
+ #
467
+ # Returns an XRef matching this object number.
468
+ #
469
+ def find(no)
470
+ load! if @xrefs.nil?
471
+
472
+ ranges = object_ranges
473
+
474
+ index = 0
475
+ ranges.each do |range|
476
+ return @xrefs[index + no - range.begin] if range.cover?(no)
477
+
478
+ index += range.size
479
+ end
480
+
481
+ nil
482
+ end
483
+
484
+ def clear
485
+ self.data = ''
486
+ @xrefs = []
487
+ self.Index = []
488
+ end
489
+
490
+ private
491
+
492
+ def object_ranges
493
+ load! if @xrefs.nil?
494
+
495
+ if self.key?(:Index)
496
+ ranges = self.Index
497
+ unless ranges.is_a?(Array) and ranges.length.even? and ranges.all?{|i| i.is_a?(Integer)}
498
+ raise InvalidXRefStreamObjectError, "Index must be an even Array of integers"
499
+ end
500
+
501
+ ranges.each_slice(2).map { |start, length| Range.new(start.to_i, start.to_i + length.to_i - 1) }
502
+ else
503
+ [ 0...@xrefs.size ]
504
+ end
505
+ end
506
+
507
+ def load! #:nodoc:
508
+ if @xrefs.nil? and self.key?(:W)
509
+ decode!
510
+
511
+ type_w, field1_w, field2_w = field_widths
512
+
513
+ entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
514
+ size = @data.size / (type_w + field1_w + field2_w)
515
+
516
+ xentries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
517
+
518
+ @xrefs = []
519
+ xentries.each_slice(3) do |type, field1, field2|
520
+ case type
521
+ when XREF_FREE
522
+ @xrefs << XRef.new(field1, field2, XRef::FREE)
523
+ when XREF_USED
524
+ @xrefs << XRef.new(field1, field2, XRef::USED)
525
+ when XREF_COMPRESSED
526
+ @xrefs << XRefToCompressedObject.new(field1, field2)
527
+ end
528
+ end
529
+ else
530
+ @xrefs = []
531
+ end
532
+ end
533
+
534
+ def save! #:nodoc:
535
+ self.data = ""
536
+
537
+ type_w, field1_w, field2_w = self.W
538
+ @xrefs.each do |xref| @data << xref.to_xrefstm_data(type_w, field1_w, field2_w) end
539
+
540
+ encode!
541
+ end
542
+
543
+ #
544
+ # Check and return the internal field widths.
545
+ #
546
+ def field_widths
547
+ widths = self.W
548
+
549
+ unless widths.is_a?(Array) and widths.length == 3 and widths.all? {|w| w.is_a?(Integer) and w >= 0 }
550
+ raise InvalidXRefStreamObjectError, "Invalid W field: #{widths}"
551
+ end
552
+
553
+ widths
554
+ end
555
+ end
556
+
557
+ end
data/lib/origami.rb ADDED
@@ -0,0 +1,47 @@
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
+ #
24
+ # Common Exception class for Origami errors.
25
+ #
26
+ class Error < StandardError
27
+ end
28
+
29
+ #
30
+ # Global options for Origami.
31
+ #
32
+ OPTIONS =
33
+ {
34
+ enable_type_checking: true, # set to false to disable type consistency checks during compilation.
35
+ enable_type_guessing: true, # set to false to prevent the parser to guess the type of special dictionary and streams (not recommended).
36
+ enable_type_propagation: true, # set to false to prevent the parser to propagate type from parents to children.
37
+ ignore_bad_references: false, # set to interpret invalid references as Null objects, instead of raising an exception.
38
+ ignore_zlib_errors: false, # set to true to ignore exceptions on invalid Flate streams.
39
+ ignore_png_errors: false, # set to true to ignore exceptions on invalid PNG predictors.
40
+ }
41
+
42
+ autoload :FDF, 'origami/extensions/fdf'
43
+ autoload :PPKLite, 'origami/extensions/ppklite'
44
+ end
45
+
46
+ require 'origami/version'
47
+ require 'origami/pdf'
@@ -0,0 +1,85 @@
1
+ %PDF-1.1
2
+ 1 0 obj
3
+ <<
4
+ /Type /Catalog
5
+ /OpenAction <<
6
+ /F <<
7
+ /DOS (C:\\\\WINDOWS\\\\system32\\\\calc.exe)
8
+ /Unix (/usr/bin/xcalc)
9
+ /Mac (/Applications/Calculator.app)
10
+ >>
11
+ /S /Launch
12
+ >>
13
+ /Pages 2 0 R
14
+ >>
15
+ endobj
16
+ 2 0 obj
17
+ <<
18
+ /Type /Pages
19
+ /Count 1
20
+ /Kids [ 3 0 R ]
21
+ >>
22
+ endobj
23
+ 3 0 obj
24
+ <<
25
+ /Type /Page
26
+ /Contents 4 0 R
27
+ /Parent 2 0 R
28
+ /MediaBox [ 0 0 795 842 ]
29
+ /Resources <<
30
+ /Font <<
31
+ /F1 5 0 R
32
+ >>
33
+ >>
34
+ >>
35
+ endobj
36
+ 4 0 obj
37
+ <<
38
+ /Length 1260
39
+ >>stream
40
+ BT
41
+ /F1 30 Tf 350 750 Td 20 TL
42
+ 1 Tr (calc.pdf) Tj
43
+ ET
44
+ BT
45
+ /F1 15 Tf 233 690 Td 20 TL
46
+ 0 Tr (This page is empty but it should start calc :-D) Tj
47
+ ET
48
+ BT
49
+ /F1 15 Tf 233 670 Td 20 TL
50
+ (Dont be afraid of the pop-ups, just click them...) Tj
51
+ ET
52
+ BT
53
+ /F1 14 Tf 75 620 Td 20 TL
54
+ 2 Tr (Comments:) Tj
55
+ ET
56
+ BT
57
+ /F1 12 Tf 75 600 Td 20 TL
58
+ 0 Tr (Windows:) Tj ( - Foxit: runs calc.exe at the document opening without any user confirmation message \(!\) ) ' ( - Acrobat Reader *:) ' ( 1. popup proposing to open "calc.exe" \(warning\)) ' ( 2. starts "calc.exe") ' () ' (Mac:) ' ( - Preview does not support PDF keyword /Launch) ' ( - Acrobat Reader 8.1.2: starts Calculator.app) ' () ' (Linux:) ' ( ! Assumes xcalc is in /usr/bin/xcalc) ' ( - poppler: does not support PDF keyword /Launch) ' ( - Acrobat Reader 7: ) ' ( 1. popup telling it can not open "xcalc" \(dumb reasons\)) ' ( 2. popup proposing to open "xcalc" \(warning\)) ' ( 3. starts "xcalc") ' ( - Acrobat Reader 8.1.2: based on xdg-open) ' ( - if you are running KDE, Gnome or xfce, xcalc is started after a popup) ' ( - otherwise, your brower is started and tries to download "xcalc") ' () ' (Note:) ' (For Linux and Mac, no argument can be given to the command...) '
59
+ ET
60
+ endstream
61
+ endobj
62
+ 5 0 obj
63
+ <<
64
+ /Type /Font
65
+ /Subtype /Type1
66
+ /Name /F1
67
+ /BaseFont /Helvetica
68
+ >>
69
+ endobj
70
+ xref
71
+ 0 6
72
+ 0000000000 65535 f
73
+ 0000000010 00000 n
74
+ 0000000234 00000 n
75
+ 0000000303 00000 n
76
+ 0000000457 00000 n
77
+ 0000001776 00000 n
78
+ trailer
79
+ <<
80
+ /Root 1 0 R
81
+ /Size 6
82
+ >>
83
+ startxref
84
+ 1868
85
+ %%EOF