origami 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING.LESSER +165 -0
- data/README +77 -0
- data/VERSION +1 -0
- data/bin/config/pdfcop.conf.yml +237 -0
- data/bin/gui/about.rb +46 -0
- data/bin/gui/config.rb +132 -0
- data/bin/gui/file.rb +385 -0
- data/bin/gui/hexdump.rb +74 -0
- data/bin/gui/hexview.rb +91 -0
- data/bin/gui/imgview.rb +72 -0
- data/bin/gui/menu.rb +392 -0
- data/bin/gui/properties.rb +132 -0
- data/bin/gui/signing.rb +635 -0
- data/bin/gui/textview.rb +107 -0
- data/bin/gui/treeview.rb +409 -0
- data/bin/gui/walker.rb +282 -0
- data/bin/gui/xrefs.rb +79 -0
- data/bin/pdf2graph +121 -0
- data/bin/pdf2ruby +353 -0
- data/bin/pdfcocoon +104 -0
- data/bin/pdfcop +455 -0
- data/bin/pdfdecompress +104 -0
- data/bin/pdfdecrypt +95 -0
- data/bin/pdfencrypt +112 -0
- data/bin/pdfextract +221 -0
- data/bin/pdfmetadata +123 -0
- data/bin/pdfsh +13 -0
- data/bin/pdfwalker +7 -0
- data/bin/shell/.irbrc +104 -0
- data/bin/shell/console.rb +136 -0
- data/bin/shell/hexdump.rb +83 -0
- data/origami.rb +36 -0
- data/origami/3d.rb +239 -0
- data/origami/acroform.rb +321 -0
- data/origami/actions.rb +299 -0
- data/origami/adobe/fdf.rb +259 -0
- data/origami/adobe/ppklite.rb +489 -0
- data/origami/annotations.rb +775 -0
- data/origami/array.rb +187 -0
- data/origami/boolean.rb +101 -0
- data/origami/catalog.rb +486 -0
- data/origami/destinations.rb +213 -0
- data/origami/dictionary.rb +188 -0
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +1293 -0
- data/origami/export.rb +283 -0
- data/origami/file.rb +222 -0
- data/origami/filters.rb +250 -0
- data/origami/filters/ascii.rb +189 -0
- data/origami/filters/ccitt.rb +515 -0
- data/origami/filters/crypt.rb +47 -0
- data/origami/filters/dct.rb +61 -0
- data/origami/filters/flate.rb +112 -0
- data/origami/filters/jbig2.rb +63 -0
- data/origami/filters/jpx.rb +53 -0
- data/origami/filters/lzw.rb +195 -0
- data/origami/filters/predictors.rb +276 -0
- data/origami/filters/runlength.rb +117 -0
- data/origami/font.rb +209 -0
- data/origami/functions.rb +93 -0
- data/origami/graphics.rb +33 -0
- data/origami/graphics/colors.rb +191 -0
- data/origami/graphics/instruction.rb +126 -0
- data/origami/graphics/path.rb +154 -0
- data/origami/graphics/patterns.rb +180 -0
- data/origami/graphics/state.rb +164 -0
- data/origami/graphics/text.rb +224 -0
- data/origami/graphics/xobject.rb +493 -0
- data/origami/header.rb +90 -0
- data/origami/linearization.rb +318 -0
- data/origami/metadata.rb +114 -0
- data/origami/name.rb +170 -0
- data/origami/null.rb +75 -0
- data/origami/numeric.rb +188 -0
- data/origami/obfuscation.rb +233 -0
- data/origami/object.rb +527 -0
- data/origami/outline.rb +59 -0
- data/origami/page.rb +559 -0
- data/origami/parser.rb +268 -0
- data/origami/parsers/fdf.rb +45 -0
- data/origami/parsers/pdf.rb +27 -0
- data/origami/parsers/pdf/linear.rb +113 -0
- data/origami/parsers/ppklite.rb +86 -0
- data/origami/pdf.rb +1144 -0
- data/origami/reference.rb +113 -0
- data/origami/signature.rb +474 -0
- data/origami/stream.rb +575 -0
- data/origami/string.rb +416 -0
- data/origami/trailer.rb +173 -0
- data/origami/webcapture.rb +87 -0
- data/origami/xfa.rb +3027 -0
- data/origami/xreftable.rb +447 -0
- data/templates/patterns.rb +66 -0
- data/templates/widgets.rb +173 -0
- data/templates/xdp.rb +92 -0
- data/tests/dataset/test.dummycrt +28 -0
- data/tests/dataset/test.dummykey +27 -0
- data/tests/tc_actions.rb +32 -0
- data/tests/tc_annotations.rb +85 -0
- data/tests/tc_pages.rb +37 -0
- data/tests/tc_pdfattach.rb +24 -0
- data/tests/tc_pdfencrypt.rb +110 -0
- data/tests/tc_pdfnew.rb +32 -0
- data/tests/tc_pdfparse.rb +98 -0
- data/tests/tc_pdfsig.rb +37 -0
- data/tests/tc_streams.rb +129 -0
- data/tests/ts_pdf.rb +45 -0
- metadata +193 -0
data/origami/object.rb
ADDED
@@ -0,0 +1,527 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
object.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
Origami is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Origami is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
class Bignum #:nodoc:
|
23
|
+
def to_o
|
24
|
+
Origami::Integer.new(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Fixnum #:nodoc:
|
29
|
+
def to_o
|
30
|
+
Origami::Integer.new(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Array #:nodoc:
|
35
|
+
def to_o
|
36
|
+
Origami::Array.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def shuffle
|
40
|
+
sort_by { rand }
|
41
|
+
end
|
42
|
+
|
43
|
+
def shuffle!
|
44
|
+
self.replace shuffle
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Float #:nodoc:
|
49
|
+
def to_o
|
50
|
+
Origami::Real.new(self)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Hash #:nodoc:
|
55
|
+
def to_o
|
56
|
+
Origami::Dictionary.new(self)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class TrueClass #:nodoc:
|
61
|
+
def to_o
|
62
|
+
Origami::Boolean.new(true)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class FalseClass #:nodoc:
|
67
|
+
def to_o
|
68
|
+
Origami::Boolean.new(false)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class NilClass #:nodoc:
|
73
|
+
def to_o
|
74
|
+
Origami::Null.new
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Symbol #:nodoc:
|
79
|
+
def to_o
|
80
|
+
Origami::Name.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def value
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
class String #:nodoc:
|
90
|
+
def to_o
|
91
|
+
Origami::ByteString.new(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
def is_binary_data?
|
95
|
+
( self.count( "\x00" ) > 0 ) unless empty?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Module for parsing/generating PDF files.
|
101
|
+
#
|
102
|
+
module Origami
|
103
|
+
|
104
|
+
#
|
105
|
+
# Mixin' module for objects which can store their options into an inner Dictionary.
|
106
|
+
#
|
107
|
+
module StandardObject #:nodoc:
|
108
|
+
|
109
|
+
DEFAULT_ATTRIBUTES = { :Type => Object, :Version => "1.1" } #:nodoc:
|
110
|
+
|
111
|
+
def self.included(receiver) #:nodoc:
|
112
|
+
receiver.instance_variable_set(:@fields, Hash.new(DEFAULT_ATTRIBUTES))
|
113
|
+
receiver.extend(ClassMethods)
|
114
|
+
end
|
115
|
+
|
116
|
+
module ClassMethods #:nodoc:all
|
117
|
+
|
118
|
+
def inherited(subclass)
|
119
|
+
subclass.instance_variable_set(:@fields, Marshal.load(Marshal.dump(@fields)))
|
120
|
+
end
|
121
|
+
|
122
|
+
def fields
|
123
|
+
@fields
|
124
|
+
end
|
125
|
+
|
126
|
+
def field(name, attributes)
|
127
|
+
|
128
|
+
if not @fields.has_key?(name)
|
129
|
+
@fields[name] = attributes
|
130
|
+
else
|
131
|
+
@fields[name].merge! attributes
|
132
|
+
end
|
133
|
+
|
134
|
+
define_field_methods(name)
|
135
|
+
end
|
136
|
+
|
137
|
+
def define_field_methods(field)
|
138
|
+
reader = lambda { obj = self[field]; obj.is_a?(Reference) ? obj.solve : obj }
|
139
|
+
writer = lambda { |value| self[field] = value }
|
140
|
+
set = lambda { |value| self[field] = value; self }
|
141
|
+
|
142
|
+
send(:define_method, field.id2name, reader)
|
143
|
+
send(:define_method, field.id2name + "=", writer)
|
144
|
+
send(:define_method, "set" + field.id2name, set)
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Returns an array of required fields for the current Object.
|
149
|
+
#
|
150
|
+
def required_fields
|
151
|
+
fields = []
|
152
|
+
@fields.each_pair { |name, attributes|
|
153
|
+
fields << name if attributes[:Required] == true
|
154
|
+
}
|
155
|
+
|
156
|
+
fields
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
def pre_build #:nodoc:
|
162
|
+
|
163
|
+
set_default_values
|
164
|
+
do_type_check if Origami::OPTIONS[:enable_type_checking] == true
|
165
|
+
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
# Check if an attribute is set in the current Object.
|
171
|
+
# _attr_:: The attribute name.
|
172
|
+
#
|
173
|
+
def has_field? (field)
|
174
|
+
not self[field].nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# Returns the version and level required by the current Object.
|
179
|
+
#
|
180
|
+
def pdf_version_required #:nodoc:
|
181
|
+
max = [ 1.0, 0 ]
|
182
|
+
|
183
|
+
self.each_key do |field|
|
184
|
+
attributes = self.class.fields[field.value]
|
185
|
+
|
186
|
+
current_version = attributes.has_key?(:Version) ? attributes[:Version].to_f : 0
|
187
|
+
current_level = attributes[:ExtensionLevel] || 0
|
188
|
+
current = [ current_version, current_level ]
|
189
|
+
|
190
|
+
max = current if (current <=> max) > 0
|
191
|
+
|
192
|
+
sub = self[field.value].pdf_version_required
|
193
|
+
max = sub if (sub <=> max) > 0
|
194
|
+
end
|
195
|
+
|
196
|
+
max
|
197
|
+
end
|
198
|
+
|
199
|
+
def set_default_value(field) #:nodoc:
|
200
|
+
if self.class.fields[field][:Default]
|
201
|
+
self[field] = self.class.fields[field][:Default]
|
202
|
+
self[field].pre_build
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def set_default_values #:nodoc:
|
207
|
+
self.class.required_fields.each do |field|
|
208
|
+
set_default_value(field) unless has_field?(field)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def do_type_check #:nodoc:
|
213
|
+
self.class.fields.each_pair do |field, attributes|
|
214
|
+
|
215
|
+
if not self[field].nil? and not attributes[:Type].nil?
|
216
|
+
types = attributes[:Type].is_a?(::Array) ? attributes[:Type] : [ attributes[:Type] ]
|
217
|
+
if not self[field].is_a?(Reference) and types.all? {|type| not self[field].is_a?(type)}
|
218
|
+
puts "Warning: in object #{self.class}, field `#{field.to_s}' has unexpected type #{self[field].class}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
class InvalidObjectError < Exception #:nodoc:
|
227
|
+
end
|
228
|
+
|
229
|
+
class UnterminatedObjectError < Exception #:nodoc:
|
230
|
+
attr_reader :obj
|
231
|
+
def initialize(msg,obj)
|
232
|
+
super(msg)
|
233
|
+
@obj = obj
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
#
|
238
|
+
# Parent module representing a PDF Object.
|
239
|
+
# PDF specification declares a set of primitive object types :
|
240
|
+
# * Null
|
241
|
+
# * Boolean
|
242
|
+
# * Integer
|
243
|
+
# * Real
|
244
|
+
# * Name
|
245
|
+
# * String
|
246
|
+
# * Array
|
247
|
+
# * Dictionary
|
248
|
+
# * Stream
|
249
|
+
#
|
250
|
+
module Object
|
251
|
+
|
252
|
+
TOKENS = %w{ obj endobj } #:nodoc:
|
253
|
+
|
254
|
+
@@regexp_obj = Regexp.new(WHITESPACES + "(\\d+)" + WHITESPACES + "(\\d+)" + WHITESPACES + TOKENS.first + WHITESPACES)
|
255
|
+
@@regexp_endobj = Regexp.new(WHITESPACES + TOKENS.last + WHITESPACES)
|
256
|
+
|
257
|
+
attr_accessor :no, :generation, :file_offset, :objstm_offset
|
258
|
+
attr_accessor :parent
|
259
|
+
|
260
|
+
#
|
261
|
+
# Creates a new PDF Object.
|
262
|
+
#
|
263
|
+
def initialize(*cons)
|
264
|
+
@indirect = false
|
265
|
+
@no, @generation = 0, 0
|
266
|
+
|
267
|
+
super(*cons) unless cons.empty?
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# Sets whether the object is indirect or not.
|
272
|
+
# Indirect objects are allocated numbers at build time.
|
273
|
+
#
|
274
|
+
def set_indirect(dir)
|
275
|
+
unless dir == true or dir == false
|
276
|
+
raise TypeError, "The argument must be boolean"
|
277
|
+
end
|
278
|
+
|
279
|
+
@indirect = dir
|
280
|
+
self
|
281
|
+
end
|
282
|
+
|
283
|
+
#
|
284
|
+
# Generic method called just before the object is finalized.
|
285
|
+
# At this time, no number nor generation allocation has yet been done.
|
286
|
+
#
|
287
|
+
def pre_build
|
288
|
+
self
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
# Generic method called just after the object is finalized.
|
293
|
+
# At this time, any indirect object has its own number and generation identifier.
|
294
|
+
#
|
295
|
+
def post_build
|
296
|
+
self
|
297
|
+
end
|
298
|
+
|
299
|
+
#
|
300
|
+
# Compare two objects from their respective numbers.
|
301
|
+
#
|
302
|
+
def <=>(obj)
|
303
|
+
[@no, @generation] <=> [obj.no, obj.generation]
|
304
|
+
end
|
305
|
+
|
306
|
+
#
|
307
|
+
# Returns whether the objects is indirect, which means that it is not embedded into another object.
|
308
|
+
#
|
309
|
+
def is_indirect?
|
310
|
+
@indirect
|
311
|
+
end
|
312
|
+
|
313
|
+
#
|
314
|
+
# Deep copy of an object.
|
315
|
+
#
|
316
|
+
def copy
|
317
|
+
Marshal.load(Marshal.dump(self))
|
318
|
+
end
|
319
|
+
|
320
|
+
#
|
321
|
+
# Returns an indirect reference to this object, or a Null object is this object is not indirect.
|
322
|
+
#
|
323
|
+
def reference
|
324
|
+
unless self.is_indirect?
|
325
|
+
raise InvalidObjectError, "Cannot reference a direct object"
|
326
|
+
end
|
327
|
+
|
328
|
+
ref = Reference.new(@no, @generation)
|
329
|
+
ref.parent = self
|
330
|
+
|
331
|
+
ref
|
332
|
+
end
|
333
|
+
|
334
|
+
#
|
335
|
+
# Returns an array of references pointing to the current object.
|
336
|
+
#
|
337
|
+
def xrefs
|
338
|
+
unless self.is_indirect?
|
339
|
+
raise InvalidObjectError, "Cannot find xrefs to a direct object"
|
340
|
+
end
|
341
|
+
|
342
|
+
if self.pdf.nil?
|
343
|
+
raise InvalidObjectError, "Not attached to any PDF"
|
344
|
+
end
|
345
|
+
|
346
|
+
xref_cache = Hash.new([])
|
347
|
+
@pdf.root_objects.each do |obj|
|
348
|
+
case obj
|
349
|
+
when Dictionary,Array then
|
350
|
+
xref_cache.update(obj.xref_cache) do |ref, cache1, cache2|
|
351
|
+
cache1.concat(cache2)
|
352
|
+
end
|
353
|
+
|
354
|
+
when Stream then
|
355
|
+
obj.dictionary.xref_cache.each do |ref, cache|
|
356
|
+
cache.map!{obj}
|
357
|
+
end
|
358
|
+
|
359
|
+
xref_cache.update(obj.dictionary.xref_cache) do |ref, cache1, cache2|
|
360
|
+
cache1.concat(cache2)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
xref_cache[self.reference]
|
366
|
+
end
|
367
|
+
|
368
|
+
#
|
369
|
+
# Returns the indirect object which contains this object.
|
370
|
+
# If the current object is already indirect, returns self.
|
371
|
+
#
|
372
|
+
def indirect_parent
|
373
|
+
obj = self
|
374
|
+
obj = obj.parent until obj.is_indirect?
|
375
|
+
|
376
|
+
obj
|
377
|
+
end
|
378
|
+
|
379
|
+
#
|
380
|
+
# Returns self.
|
381
|
+
#
|
382
|
+
def to_o
|
383
|
+
self
|
384
|
+
end
|
385
|
+
|
386
|
+
#
|
387
|
+
# Returns self.
|
388
|
+
#
|
389
|
+
def solve
|
390
|
+
self
|
391
|
+
end
|
392
|
+
|
393
|
+
#
|
394
|
+
# Returns the size of this object once converted to PDF code.
|
395
|
+
#
|
396
|
+
def size
|
397
|
+
to_s.size
|
398
|
+
end
|
399
|
+
|
400
|
+
#
|
401
|
+
# Returns the PDF which the object belongs to.
|
402
|
+
#
|
403
|
+
def pdf
|
404
|
+
if self.is_indirect? then @pdf
|
405
|
+
else
|
406
|
+
@parent.pdf
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def set_pdf(pdf)
|
411
|
+
if self.is_indirect? then @pdf = pdf
|
412
|
+
else
|
413
|
+
raise InvalidObjectError, "You cannot set the PDF parent of a direct object"
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
class << self
|
418
|
+
|
419
|
+
def typeof(stream, noref = false) #:nodoc:
|
420
|
+
stream.skip(REGEXP_WHITESPACES)
|
421
|
+
|
422
|
+
case stream.peek(1)
|
423
|
+
when '/' then return Name
|
424
|
+
when '<'
|
425
|
+
return (stream.peek(2) == '<<') ? Stream : HexaString
|
426
|
+
when '(' then return ByteString
|
427
|
+
when '[' then return Origami::Array
|
428
|
+
when 'n' then
|
429
|
+
return Null if stream.peek(4) == 'null'
|
430
|
+
when 't' then
|
431
|
+
return Boolean if stream.peek(4) == 'true'
|
432
|
+
when 'f' then
|
433
|
+
return Boolean if stream.peek(5) == 'false'
|
434
|
+
else
|
435
|
+
if not noref and stream.check(Reference::REGEXP_TOKEN) then return Reference
|
436
|
+
elsif stream.check(Real::REGEXP_TOKEN) then return Real
|
437
|
+
elsif stream.check(Integer::REGEXP_TOKEN) then return Integer
|
438
|
+
else
|
439
|
+
nil
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
nil
|
444
|
+
end
|
445
|
+
|
446
|
+
def parse(stream) #:nodoc:
|
447
|
+
offset = stream.pos
|
448
|
+
|
449
|
+
#
|
450
|
+
# End of body ?
|
451
|
+
#
|
452
|
+
return nil if stream.match?(/xref/) or stream.match?(/trailer/) or stream.match?(/startxref/)
|
453
|
+
|
454
|
+
if stream.scan(@@regexp_obj).nil?
|
455
|
+
raise InvalidObjectError,
|
456
|
+
"Object shall begin with '%d %d obj' statement"
|
457
|
+
end
|
458
|
+
|
459
|
+
no = stream[2].to_i
|
460
|
+
gen = stream[4].to_i
|
461
|
+
|
462
|
+
type = typeof(stream)
|
463
|
+
if type.nil?
|
464
|
+
raise InvalidObjectError,
|
465
|
+
"Cannot determine object (no:#{no},gen:#{gen}) type"
|
466
|
+
end
|
467
|
+
|
468
|
+
begin
|
469
|
+
newObj = type.parse(stream)
|
470
|
+
rescue Exception => e
|
471
|
+
raise InvalidObjectError,
|
472
|
+
"Failed to parse object (no:#{no},gen:#{gen})\n\t -> [#{e.class}] #{e.message}"
|
473
|
+
end
|
474
|
+
|
475
|
+
newObj.set_indirect(true)
|
476
|
+
newObj.no = no
|
477
|
+
newObj.generation = gen
|
478
|
+
newObj.file_offset = offset
|
479
|
+
|
480
|
+
if stream.skip(@@regexp_endobj).nil?
|
481
|
+
raise UnterminatedObjectError.new("Object shall end with 'endobj' statement", newObj)
|
482
|
+
end
|
483
|
+
|
484
|
+
newObj
|
485
|
+
end
|
486
|
+
|
487
|
+
def skip_until_next_obj(stream) #:nodoc:
|
488
|
+
stream.pos += 1 until stream.match?(@@regexp_obj) or
|
489
|
+
stream.match?(/xref/) or stream.match?(/trailer/) or stream.match?(/startxref/) or
|
490
|
+
stream.eos?
|
491
|
+
|
492
|
+
not stream.eos?
|
493
|
+
end
|
494
|
+
|
495
|
+
end
|
496
|
+
|
497
|
+
def pdf_version_required #:nodoc:
|
498
|
+
[ 1.0, 0 ]
|
499
|
+
end
|
500
|
+
|
501
|
+
#
|
502
|
+
# Returns the symbol type of this Object.
|
503
|
+
#
|
504
|
+
def type
|
505
|
+
self.class.to_s.split("::").last.to_sym
|
506
|
+
end
|
507
|
+
alias real_type type
|
508
|
+
|
509
|
+
#
|
510
|
+
# Outputs this object into PDF code.
|
511
|
+
# _data_:: The object data.
|
512
|
+
#
|
513
|
+
def to_s(data)
|
514
|
+
|
515
|
+
content = ""
|
516
|
+
content << "#{no} #{generation} obj" << EOL if self.is_indirect?
|
517
|
+
content << data
|
518
|
+
content << EOL << "endobj" << EOL if self.is_indirect?
|
519
|
+
|
520
|
+
content
|
521
|
+
end
|
522
|
+
|
523
|
+
alias output to_s
|
524
|
+
|
525
|
+
end
|
526
|
+
|
527
|
+
end
|