origami 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/bin/gui/config.rb +2 -1
- data/bin/gui/file.rb +118 -240
- data/bin/gui/gtkhex.rb +5 -5
- data/bin/gui/hexview.rb +20 -16
- data/bin/gui/imgview.rb +1 -1
- data/bin/gui/menu.rb +138 -158
- data/bin/gui/properties.rb +46 -48
- data/bin/gui/signing.rb +183 -214
- data/bin/gui/textview.rb +1 -1
- data/bin/gui/treeview.rb +13 -7
- data/bin/gui/walker.rb +102 -71
- data/bin/gui/xrefs.rb +1 -1
- data/bin/pdf2ruby +3 -3
- data/bin/pdfcop +18 -11
- data/bin/pdfextract +14 -5
- data/bin/pdfmetadata +3 -3
- data/bin/shell/console.rb +8 -8
- data/bin/shell/hexdump.rb +4 -4
- data/examples/attachments/nested_document.rb +1 -1
- data/examples/javascript/hello_world.rb +3 -3
- data/lib/origami.rb +0 -1
- data/lib/origami/acroform.rb +3 -3
- data/lib/origami/array.rb +1 -3
- data/lib/origami/boolean.rb +1 -3
- data/lib/origami/catalog.rb +3 -9
- data/lib/origami/destinations.rb +2 -2
- data/lib/origami/dictionary.rb +15 -29
- data/lib/origami/encryption.rb +334 -692
- data/lib/origami/extensions/fdf.rb +3 -2
- data/lib/origami/extensions/ppklite.rb +5 -9
- data/lib/origami/filespec.rb +2 -2
- data/lib/origami/filters.rb +54 -36
- data/lib/origami/filters/ascii.rb +67 -49
- data/lib/origami/filters/ccitt.rb +4 -236
- data/lib/origami/filters/ccitt/tables.rb +267 -0
- data/lib/origami/filters/crypt.rb +1 -1
- data/lib/origami/filters/dct.rb +0 -1
- data/lib/origami/filters/flate.rb +3 -43
- data/lib/origami/filters/lzw.rb +62 -99
- data/lib/origami/filters/predictors.rb +135 -105
- data/lib/origami/filters/runlength.rb +34 -22
- data/lib/origami/graphics.rb +2 -2
- data/lib/origami/graphics/colors.rb +89 -63
- data/lib/origami/graphics/path.rb +14 -14
- data/lib/origami/graphics/patterns.rb +31 -33
- data/lib/origami/graphics/render.rb +0 -1
- data/lib/origami/graphics/state.rb +9 -9
- data/lib/origami/graphics/text.rb +17 -17
- data/lib/origami/graphics/xobject.rb +102 -92
- data/lib/origami/javascript.rb +91 -68
- data/lib/origami/linearization.rb +22 -20
- data/lib/origami/metadata.rb +1 -1
- data/lib/origami/name.rb +1 -3
- data/lib/origami/null.rb +1 -3
- data/lib/origami/numeric.rb +3 -13
- data/lib/origami/object.rb +100 -72
- data/lib/origami/page.rb +24 -28
- data/lib/origami/parser.rb +34 -51
- data/lib/origami/parsers/fdf.rb +2 -2
- data/lib/origami/parsers/pdf.rb +41 -18
- data/lib/origami/parsers/pdf/lazy.rb +83 -46
- data/lib/origami/parsers/pdf/linear.rb +19 -10
- data/lib/origami/parsers/ppklite.rb +1 -1
- data/lib/origami/pdf.rb +150 -206
- data/lib/origami/reference.rb +4 -6
- data/lib/origami/signature.rb +76 -48
- data/lib/origami/stream.rb +69 -63
- data/lib/origami/string.rb +2 -19
- data/lib/origami/trailer.rb +25 -22
- data/lib/origami/version.rb +1 -1
- data/lib/origami/xfa.rb +6 -4
- data/lib/origami/xreftable.rb +29 -29
- data/test/test_annotations.rb +16 -38
- data/test/test_pdf_attachment.rb +1 -1
- data/test/test_pdf_parse.rb +1 -1
- data/test/test_xrefs.rb +2 -2
- metadata +4 -4
- data/lib/origami/export.rb +0 -247
data/lib/origami/string.rb
CHANGED
@@ -105,16 +105,6 @@ module Origami
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
-
module ClassMethods #:nodoc:all
|
109
|
-
def native_type; Origami::String end
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.included(receiver) #:nodoc:
|
113
|
-
receiver.extend(ClassMethods)
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.native_type; Origami::String end #:nodoc:
|
117
|
-
|
118
108
|
include Origami::Object
|
119
109
|
|
120
110
|
attr_accessor :encoding
|
@@ -188,7 +178,7 @@ module Origami
|
|
188
178
|
super(str)
|
189
179
|
end
|
190
180
|
|
191
|
-
def self.parse(stream,
|
181
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
192
182
|
offset = stream.pos
|
193
183
|
|
194
184
|
if stream.skip(@@regexp_open).nil?
|
@@ -252,7 +242,7 @@ module Origami
|
|
252
242
|
super(str)
|
253
243
|
end
|
254
244
|
|
255
|
-
def self.parse(stream,
|
245
|
+
def self.parse(stream, _parser = nil) #:nodoc:
|
256
246
|
offset = stream.pos
|
257
247
|
|
258
248
|
unless stream.skip(@@regexp_open)
|
@@ -381,13 +371,6 @@ module Origami
|
|
381
371
|
attr_reader :year, :month, :day, :hour, :min, :sec, :utc_offset
|
382
372
|
|
383
373
|
def initialize(year:, month: 1, day: 1, hour: 0, min: 0, sec: 0, utc_offset: 0)
|
384
|
-
raise InvalidDateError, "Invalid year #{year}" unless (0..9999) === year
|
385
|
-
raise InvalidDateError, "Invalid month #{month}" unless (1..12) === month
|
386
|
-
raise InvalidDateError, "Invalid day #{day}" unless (1..31) === day
|
387
|
-
raise InvalidDateError, "Invalid hour #{hour}" unless (0..23) === hour
|
388
|
-
raise InvalidDateError, "Invalid minute #{min}" unless (0..59) === min
|
389
|
-
raise InvalidDateError, "Invalid second #{sec}" unless (0..59) === sec
|
390
|
-
|
391
374
|
@year, @month, @day, @hour, @min, @sec = year, month, day, hour, min, sec
|
392
375
|
@utc_offset = utc_offset
|
393
376
|
|
data/lib/origami/trailer.rb
CHANGED
@@ -22,6 +22,29 @@ module Origami
|
|
22
22
|
|
23
23
|
class PDF
|
24
24
|
|
25
|
+
#
|
26
|
+
# Returns the current trailer.
|
27
|
+
# This might be either a Trailer or XRefStream.
|
28
|
+
#
|
29
|
+
def trailer
|
30
|
+
#
|
31
|
+
# First look for a standard trailer dictionary
|
32
|
+
#
|
33
|
+
if @revisions.last.trailer.has_dictionary?
|
34
|
+
trl = @revisions.last.trailer
|
35
|
+
|
36
|
+
#
|
37
|
+
# Otherwise look for a xref stream.
|
38
|
+
#
|
39
|
+
else
|
40
|
+
trl = @revisions.last.xrefstm
|
41
|
+
end
|
42
|
+
|
43
|
+
raise InvalidPDFError, "No trailer found" if trl.nil?
|
44
|
+
|
45
|
+
trl
|
46
|
+
end
|
47
|
+
|
25
48
|
private
|
26
49
|
|
27
50
|
def trailer_key?(attr) #:nodoc:
|
@@ -35,7 +58,7 @@ module Origami
|
|
35
58
|
return rev.trailer[attr].solve
|
36
59
|
elsif rev.has_xrefstm?
|
37
60
|
xrefstm = rev.xrefstm
|
38
|
-
if xrefstm.is_a?(XRefStream) and xrefstm.
|
61
|
+
if xrefstm.is_a?(XRefStream) and xrefstm.key?(attr)
|
39
62
|
return xrefstm[attr].solve
|
40
63
|
end
|
41
64
|
end
|
@@ -44,29 +67,9 @@ module Origami
|
|
44
67
|
nil
|
45
68
|
end
|
46
69
|
|
47
|
-
def get_trailer_info #:nodoc:
|
48
|
-
#
|
49
|
-
# First look for a standard trailer dictionary
|
50
|
-
#
|
51
|
-
if @revisions.last.trailer.has_dictionary?
|
52
|
-
@revisions.last.trailer
|
53
|
-
|
54
|
-
#
|
55
|
-
# Otherwise look for a xref stream.
|
56
|
-
#
|
57
|
-
else
|
58
|
-
@revisions.last.xrefstm
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
70
|
def generate_id
|
63
|
-
info = get_trailer_info
|
64
|
-
if info.nil?
|
65
|
-
raise InvalidPDFError, "Cannot access trailer information"
|
66
|
-
end
|
67
|
-
|
68
71
|
id = HexaString.new Random.new.bytes 16
|
69
|
-
|
72
|
+
self.trailer.ID = [ id, id ]
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
data/lib/origami/version.rb
CHANGED
data/lib/origami/xfa.rb
CHANGED
@@ -47,21 +47,21 @@ module Origami
|
|
47
47
|
|
48
48
|
def xfa_attribute(name)
|
49
49
|
# Attribute getter.
|
50
|
-
attr_getter = "attr_#{name
|
50
|
+
attr_getter = "attr_#{name}"
|
51
51
|
remove_method(attr_getter) rescue NameError
|
52
52
|
define_method(attr_getter) do
|
53
53
|
self.attributes[name.to_s]
|
54
54
|
end
|
55
55
|
|
56
56
|
# Attribute setter.
|
57
|
-
attr_setter = "attr_#{name
|
57
|
+
attr_setter = "attr_#{name}="
|
58
58
|
remove_method(attr_setter) rescue NameError
|
59
59
|
define_method(attr_setter) do |value|
|
60
60
|
self.attributes[names.to_s] = value
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
def xfa_node(name, type,
|
64
|
+
def xfa_node(name, type, _range = (0..Float::INFINITY))
|
65
65
|
|
66
66
|
adder = "add_#{name}"
|
67
67
|
remove_method(adder) rescue NameError
|
@@ -220,7 +220,7 @@ module Origami
|
|
220
220
|
def initialize(record = "")
|
221
221
|
super('record')
|
222
222
|
|
223
|
-
self.text =
|
223
|
+
self.text = record
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
@@ -1099,6 +1099,8 @@ module Origami
|
|
1099
1099
|
|
1100
1100
|
def initialize(text = "")
|
1101
1101
|
super('toolTip')
|
1102
|
+
|
1103
|
+
self.text = text
|
1102
1104
|
end
|
1103
1105
|
end
|
1104
1106
|
|
data/lib/origami/xreftable.rb
CHANGED
@@ -25,26 +25,15 @@ module Origami
|
|
25
25
|
# Tries to strip any xrefs information off the document.
|
26
26
|
#
|
27
27
|
def remove_xrefs
|
28
|
-
|
29
|
-
# Delete a XRefStream and its ancestors.
|
30
|
-
delete_xrefstm = -> (xrefstm) do
|
31
|
-
prev = xrefstm.Prev
|
32
|
-
delete_object(xrefstm.reference)
|
33
|
-
|
34
|
-
if prev.is_a?(Integer) and (prev_stm = get_object_by_offset(prev)).is_a?(XRefStream)
|
35
|
-
delete_xrefstm.call(prev_stm)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
28
|
@revisions.reverse_each do |rev|
|
40
29
|
if rev.has_xrefstm?
|
41
|
-
|
30
|
+
delete_object(rev.xrefstm.reference)
|
42
31
|
end
|
43
32
|
|
44
|
-
if rev.trailer.
|
33
|
+
if rev.trailer.XRefStm.is_a?(Integer)
|
45
34
|
xrefstm = get_object_by_offset(rev.trailer.XRefStm)
|
46
35
|
|
47
|
-
|
36
|
+
delete_object(xrefstm.reference) if xrefstm.is_a?(XRefStream)
|
48
37
|
end
|
49
38
|
|
50
39
|
rev.xrefstm = rev.xreftable = nil
|
@@ -135,6 +124,8 @@ module Origami
|
|
135
124
|
# A subsection contains a continute set of XRef.
|
136
125
|
#
|
137
126
|
class Subsection
|
127
|
+
include Enumerable
|
128
|
+
|
138
129
|
@@regexp = Regexp.new("(?<start>\\d+) (?<size>\\d+)" + WHITESPACES + "(\\r?\\n|\\r\\n?)")
|
139
130
|
|
140
131
|
attr_reader :range
|
@@ -228,6 +219,8 @@ module Origami
|
|
228
219
|
# A section contains a set of XRefSubsection.
|
229
220
|
#
|
230
221
|
class Section
|
222
|
+
include Enumerable
|
223
|
+
|
231
224
|
TOKEN = "xref"
|
232
225
|
|
233
226
|
@@regexp_open = Regexp.new(WHITESPACES + TOKEN + WHITESPACES + "(\\r?\\n|\\r\\n?)")
|
@@ -337,7 +330,7 @@ module Origami
|
|
337
330
|
#
|
338
331
|
# An xref poiting to an Object embedded in an ObjectStream.
|
339
332
|
#
|
340
|
-
class
|
333
|
+
class XRefToCompressedObject
|
341
334
|
attr_accessor :objstmno, :index
|
342
335
|
|
343
336
|
def initialize(objstmno, index)
|
@@ -356,6 +349,9 @@ module Origami
|
|
356
349
|
|
357
350
|
[ type , objstmno, index ].pack("B#{type_w}B#{field1_w}B#{field2_w}")
|
358
351
|
end
|
352
|
+
|
353
|
+
def used?; true end
|
354
|
+
def free?; false end
|
359
355
|
end
|
360
356
|
|
361
357
|
class InvalidXRefStreamObjectError < InvalidStreamObjectError ; end
|
@@ -406,7 +402,7 @@ module Origami
|
|
406
402
|
def pre_build #:nodoc:
|
407
403
|
load! if @xrefs.nil?
|
408
404
|
|
409
|
-
self.W = [ 1, 2, 2 ] unless
|
405
|
+
self.W = [ 1, 2, 2 ] unless self.key?(:W)
|
410
406
|
self.Size = @xrefs.length + 1
|
411
407
|
|
412
408
|
save!
|
@@ -496,18 +492,10 @@ module Origami
|
|
496
492
|
end
|
497
493
|
|
498
494
|
def load! #:nodoc:
|
499
|
-
if @xrefs.nil? and
|
500
|
-
widths = self.W
|
501
|
-
|
502
|
-
if not widths.is_a?(Array) or widths.length != 3 or widths.any?{|width| not width.is_a?(Integer) }
|
503
|
-
raise InvalidXRefStreamObjectError, "W field must be an array of 3 integers"
|
504
|
-
end
|
505
|
-
|
495
|
+
if @xrefs.nil? and self.key?(:W)
|
506
496
|
decode!
|
507
497
|
|
508
|
-
type_w =
|
509
|
-
field1_w = self.W[1]
|
510
|
-
field2_w = self.W[2]
|
498
|
+
type_w, field1_w, field2_w = field_widths
|
511
499
|
|
512
500
|
entrymask = "B#{type_w << 3}B#{field1_w << 3}B#{field2_w << 3}"
|
513
501
|
size = @data.size / (type_w + field1_w + field2_w)
|
@@ -515,15 +503,14 @@ module Origami
|
|
515
503
|
xentries = @data.unpack(entrymask * size).map!{|field| field.to_i(2) }
|
516
504
|
|
517
505
|
@xrefs = []
|
518
|
-
|
519
|
-
type,field1,field2 = xentries[i*3].ord,xentries[i*3+1].ord,xentries[i*3+2].ord
|
506
|
+
xentries.each_slice(3) do |type, field1, field2|
|
520
507
|
case type
|
521
508
|
when XREF_FREE
|
522
509
|
@xrefs << XRef.new(field1, field2, XRef::FREE)
|
523
510
|
when XREF_USED
|
524
511
|
@xrefs << XRef.new(field1, field2, XRef::USED)
|
525
512
|
when XREF_COMPRESSED
|
526
|
-
@xrefs <<
|
513
|
+
@xrefs << XRefToCompressedObject.new(field1, field2)
|
527
514
|
end
|
528
515
|
end
|
529
516
|
else
|
@@ -539,6 +526,19 @@ module Origami
|
|
539
526
|
|
540
527
|
encode!
|
541
528
|
end
|
529
|
+
|
530
|
+
#
|
531
|
+
# Check and return the internal field widths.
|
532
|
+
#
|
533
|
+
def field_widths
|
534
|
+
widths = self.W
|
535
|
+
|
536
|
+
unless widths.is_a?(Array) and widths.length == 3 and widths.all? {|w| w.is_a?(Integer) and w >= 0 }
|
537
|
+
raise InvalidXRefStreamObjectError, "Invalid W field: #{widths}"
|
538
|
+
end
|
539
|
+
|
540
|
+
widths
|
541
|
+
end
|
542
542
|
end
|
543
543
|
|
544
544
|
end
|
data/test/test_annotations.rb
CHANGED
@@ -7,55 +7,33 @@ class TestAnnotations < Minitest::Test
|
|
7
7
|
@page = Page.new
|
8
8
|
@action = Action::JavaScript["app.alert(null);"]
|
9
9
|
@output = StringIO.new
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_annotations
|
13
|
-
circle = Annotation::Circle.new
|
14
|
-
square = Annotation::Square.new
|
15
|
-
text = Annotation::Text.new
|
16
|
-
link = Annotation::Link.new
|
17
|
-
file = Annotation::FileAttachment.new
|
18
|
-
screen = Annotation::Screen.new
|
19
|
-
sound = Annotation::Sound.new
|
20
|
-
pushbutton = Annotation::Widget::PushButton.new
|
21
|
-
checkbox = Annotation::Widget::CheckBox.new
|
22
|
-
radio = Annotation::Widget::Radio.new
|
23
|
-
edit = Annotation::Widget::Text.new
|
24
|
-
combo = Annotation::Widget::ComboBox.new
|
25
|
-
list = Annotation::Widget::ListBox.new
|
26
|
-
sig = Annotation::Widget::Signature.new
|
27
10
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
11
|
+
@types = [
|
12
|
+
Annotation::Circle, Annotation::Square,
|
13
|
+
Annotation::Text, Annotation::Link,
|
14
|
+
Annotation::FileAttachment, Annotation::Screen,
|
15
|
+
Annotation::Sound, Annotation::Widget::CheckBox,
|
16
|
+
Annotation::Widget::Radio, Annotation::Widget::Text,
|
17
|
+
Annotation::Widget::ComboBox, Annotation::Widget::ListBox,
|
18
|
+
Annotation::Widget::Signature
|
33
19
|
]
|
20
|
+
end
|
34
21
|
|
22
|
+
def test_annotations
|
35
23
|
@target.append_page @page
|
36
24
|
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@page.add_annotation file
|
42
|
-
@page.add_annotation screen
|
43
|
-
@page.add_annotation sound
|
44
|
-
@page.add_annotation pushbutton
|
45
|
-
@page.add_annotation checkbox
|
46
|
-
@page.add_annotation radio
|
47
|
-
@page.add_annotation edit
|
48
|
-
@page.add_annotation combo
|
49
|
-
@page.add_annotation list
|
50
|
-
@page.add_annotation sig
|
25
|
+
annotations = @types.map(&:new)
|
26
|
+
annotations.each do |annotation|
|
27
|
+
@page.add_annotation(annotation)
|
28
|
+
end
|
51
29
|
|
52
30
|
@page.each_annotation do |annotation|
|
53
31
|
assert_kind_of Annotation, annotation
|
54
32
|
|
55
|
-
assert
|
33
|
+
assert annotations.include?(annotation)
|
56
34
|
end
|
57
35
|
|
58
|
-
assert_equal @page.annotations.size,
|
36
|
+
assert_equal @page.annotations.size, annotations.size
|
59
37
|
|
60
38
|
@target.save(@output)
|
61
39
|
end
|
data/test/test_pdf_attachment.rb
CHANGED
@@ -17,7 +17,7 @@ class TestAttachment < Minitest::Test
|
|
17
17
|
pdf = PDF.read(@output, ignore_errors: false, verbosity: Parser::VERBOSE_QUIET)
|
18
18
|
|
19
19
|
assert_equal pdf.each_named_embedded_file.count, 1
|
20
|
-
|
20
|
+
assert_nil pdf.get_embedded_file_by_name("foo.baz")
|
21
21
|
|
22
22
|
file = pdf.get_embedded_file_by_name('foo.bar')
|
23
23
|
refute_equal file, nil
|
data/test/test_pdf_parse.rb
CHANGED
data/test/test_xrefs.rb
CHANGED
@@ -47,13 +47,13 @@ class TestXrefs < MiniTest::Test
|
|
47
47
|
xrefstm = pdf.revisions.last.xrefstm
|
48
48
|
|
49
49
|
assert_instance_of XRefStream, xrefstm
|
50
|
-
assert xrefstm.entries.all?{ |xref| xref.is_a?(XRef) or xref.is_a?(
|
50
|
+
assert xrefstm.entries.all?{ |xref| xref.is_a?(XRef) or xref.is_a?(XRefToCompressedObject) }
|
51
51
|
|
52
52
|
pdf.each_object(compressed: true) do |object|
|
53
53
|
xref = xrefstm.find(object.no)
|
54
54
|
|
55
55
|
if object.parent.is_a?(ObjectStream)
|
56
|
-
assert_instance_of
|
56
|
+
assert_instance_of XRefToCompressedObject, xref
|
57
57
|
assert_equal xref.objstmno, object.parent.no
|
58
58
|
assert_equal xref.index, object.parent.index(object.no)
|
59
59
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: origami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume Delugré
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -116,13 +116,13 @@ files:
|
|
116
116
|
- lib/origami/destinations.rb
|
117
117
|
- lib/origami/dictionary.rb
|
118
118
|
- lib/origami/encryption.rb
|
119
|
-
- lib/origami/export.rb
|
120
119
|
- lib/origami/extensions/fdf.rb
|
121
120
|
- lib/origami/extensions/ppklite.rb
|
122
121
|
- lib/origami/filespec.rb
|
123
122
|
- lib/origami/filters.rb
|
124
123
|
- lib/origami/filters/ascii.rb
|
125
124
|
- lib/origami/filters/ccitt.rb
|
125
|
+
- lib/origami/filters/ccitt/tables.rb
|
126
126
|
- lib/origami/filters/crypt.rb
|
127
127
|
- lib/origami/filters/dct.rb
|
128
128
|
- lib/origami/filters/flate.rb
|
@@ -208,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
208
|
requirements:
|
209
209
|
- gtk2 to run the graphical interface
|
210
210
|
rubyforge_project:
|
211
|
-
rubygems_version: 2.
|
211
|
+
rubygems_version: 2.6.8
|
212
212
|
signing_key:
|
213
213
|
specification_version: 4
|
214
214
|
summary: Ruby framework to manipulate PDF documents
|
data/lib/origami/export.rb
DELETED
@@ -1,247 +0,0 @@
|
|
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
|
-
# Exports the document to a dot Graphiz file.
|
27
|
-
# _filename_:: The path where to save the file.
|
28
|
-
#
|
29
|
-
def export_to_graph(path)
|
30
|
-
|
31
|
-
appearance = -> (object) do
|
32
|
-
label = object.type.to_s
|
33
|
-
case object
|
34
|
-
when Catalog
|
35
|
-
fontcolor = "red"
|
36
|
-
color = "mistyrose"
|
37
|
-
shape = "ellipse"
|
38
|
-
when Name, Number
|
39
|
-
label = object.value
|
40
|
-
fontcolor = "brown"
|
41
|
-
color = "lightgoldenrodyellow"
|
42
|
-
shape = "polygon"
|
43
|
-
when String
|
44
|
-
label = object.value if (object.ascii_only? and object.length <= 50)
|
45
|
-
fontcolor = "red"
|
46
|
-
color = "white"
|
47
|
-
shape = "polygon"
|
48
|
-
when Array
|
49
|
-
fontcolor = "darkgreen"
|
50
|
-
color = "lightcyan"
|
51
|
-
shape = "ellipse"
|
52
|
-
else
|
53
|
-
fontcolor = "blue"
|
54
|
-
color = "aliceblue"
|
55
|
-
shape = "ellipse"
|
56
|
-
end
|
57
|
-
|
58
|
-
{ label: label, fontcolor: fontcolor, color: color, shape: shape }
|
59
|
-
end
|
60
|
-
|
61
|
-
add_edges = -> (fd, object) do
|
62
|
-
if object.is_a?(Array) or object.is_a?(ObjectStream)
|
63
|
-
object.each do |subobj|
|
64
|
-
fd << "\t#{object.object_id} -> #{subobj.solve.object_id}\n"
|
65
|
-
end
|
66
|
-
|
67
|
-
elsif object.is_a?(Dictionary)
|
68
|
-
object.each_pair do |name, subobj|
|
69
|
-
fd << "\t#{object.object_id} -> #{subobj.solve.object_id} "
|
70
|
-
fd << "[label=\"#{name.value}\",fontsize=9];\n"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
if object.is_a?(Stream)
|
75
|
-
object.dictionary.each_pair do |key, value|
|
76
|
-
fd << "\t#{object.object_id} -> #{value.solve.object_id} "
|
77
|
-
fd << "[label=\"#{key.value}\",fontsize=9];\n"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
graph_name = "PDF" if graph_name.nil? or graph_name.empty?
|
83
|
-
fd = File.open(path, "w")
|
84
|
-
|
85
|
-
begin
|
86
|
-
fd << "digraph #{graph_name} {\n\n"
|
87
|
-
|
88
|
-
objects = self.objects(include_keys: false).find_all{ |obj| not obj.is_a?(Reference) }
|
89
|
-
|
90
|
-
objects.each do |object|
|
91
|
-
attr = appearance[object]
|
92
|
-
|
93
|
-
fd << "\t#{object.object_id} "
|
94
|
-
fd << "[label=\"#{attr[:label]}\",shape=#{attr[:shape]},color=#{attr[:color]},style=filled,fontcolor=#{attr[:fontcolor]},fontsize=16];\n"
|
95
|
-
|
96
|
-
if object.is_a?(Stream)
|
97
|
-
object.dictionary.each do |value|
|
98
|
-
unless value.is_a?(Reference)
|
99
|
-
attr = appearance[value]
|
100
|
-
fd << "\t#{value.object_id} "
|
101
|
-
fd << "[label=\"#{attr[:label]}\",shape=#{attr[:shape]},color=#{attr[:color]},style=filled,fontcolor=#{attr[:fontcolor]},fontsize=16];\n"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
add_edges.call(fd, object)
|
107
|
-
end
|
108
|
-
|
109
|
-
fd << "\n}"
|
110
|
-
ensure
|
111
|
-
fd.close
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
#
|
116
|
-
# Exports the document to a GraphML file.
|
117
|
-
# _filename_:: The path where to save the file.
|
118
|
-
#
|
119
|
-
def export_to_graphml(path)
|
120
|
-
require 'rexml/document'
|
121
|
-
|
122
|
-
declare_node = -> (id, attr) do
|
123
|
-
<<-XML
|
124
|
-
<node id="#{id}">
|
125
|
-
<data key="d0">
|
126
|
-
<y:ShapeNode>
|
127
|
-
<y:NodeLabel>#{attr[:label]}</y:NodeLabel>
|
128
|
-
</y:ShapeNode>
|
129
|
-
</data>
|
130
|
-
</node>
|
131
|
-
XML
|
132
|
-
end
|
133
|
-
|
134
|
-
declare_edge = -> (id, src, dest, label = nil) do
|
135
|
-
<<-XML
|
136
|
-
<edge id="#{id}" source="#{src}" target="#{dest}">
|
137
|
-
<data key="d1">
|
138
|
-
<y:PolyLineEdge>
|
139
|
-
<y:LineStyle type="line" width="1.0" color="#000000"/>
|
140
|
-
<y:Arrows source="none" target="standard"/>
|
141
|
-
<y:EdgeLabel>#{label.to_s}</y:EdgeLabel>
|
142
|
-
</y:PolyLineEdge>
|
143
|
-
</data>
|
144
|
-
</edge>
|
145
|
-
XML
|
146
|
-
end
|
147
|
-
|
148
|
-
appearance = -> (object) do
|
149
|
-
label = object.type.to_s
|
150
|
-
case object
|
151
|
-
when Catalog
|
152
|
-
fontcolor = "red"
|
153
|
-
color = "mistyrose"
|
154
|
-
shape = "doublecircle"
|
155
|
-
when Name, Number
|
156
|
-
label = object.value
|
157
|
-
fontcolor = "orange"
|
158
|
-
color = "lightgoldenrodyellow"
|
159
|
-
shape = "polygon"
|
160
|
-
when String
|
161
|
-
label = object.value if (object.ascii_only? and object.length <= 50)
|
162
|
-
fontcolor = "red"
|
163
|
-
color = "white"
|
164
|
-
shape = "polygon"
|
165
|
-
when Array
|
166
|
-
fontcolor = "green"
|
167
|
-
color = "lightcyan"
|
168
|
-
shape = "ellipse"
|
169
|
-
else
|
170
|
-
fontcolor = "blue"
|
171
|
-
color = "aliceblue"
|
172
|
-
shape = "ellipse"
|
173
|
-
end
|
174
|
-
|
175
|
-
{ label: label, fontcolor: fontcolor, color: color, shape: shape }
|
176
|
-
end
|
177
|
-
|
178
|
-
add_edges = -> (xml, object, id) do
|
179
|
-
if object.is_a?(Array) or object.is_a?(ObjectStream)
|
180
|
-
object.each do |subobj|
|
181
|
-
xml << declare_edge["e#{id}", "n#{object.object_id}", "n#{subobj.solve.object_id}"]
|
182
|
-
id = id + 1
|
183
|
-
end
|
184
|
-
|
185
|
-
elsif object.is_a?(Dictionary)
|
186
|
-
object.each_pair do |name, subobj|
|
187
|
-
xml << declare_edge["e#{id}", "n#{object.object_id}", "n#{subobj.solve.object_id}",
|
188
|
-
name.value]
|
189
|
-
id = id + 1
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
if object.is_a?(Stream)
|
194
|
-
object.dictionary.each_pair do |key, value|
|
195
|
-
xml << declare_edge["e#{id}", "n#{object.object_id}", "n#{value.object_id}", key.value]
|
196
|
-
id = id + 1
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
id
|
201
|
-
end
|
202
|
-
|
203
|
-
graph_name = "PDF" if graph_name.nil? or graph_name.empty?
|
204
|
-
|
205
|
-
edge_nb = 1
|
206
|
-
xml = <<-XML
|
207
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
208
|
-
<graphml xmlns="http://graphml.graphdrawing.org/xmlns/graphml"
|
209
|
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
210
|
-
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns/graphml
|
211
|
-
http://www.yworks.com/xml/schema/graphml/1.0/ygraphml.xsd"
|
212
|
-
xmlns:y="http://www.yworks.com/xml/graphml">
|
213
|
-
<key id="d0" for="node" yfiles.type="nodegraphics"/>
|
214
|
-
<key id="d1" for="edge" yfiles.type="edgegraphics"/>
|
215
|
-
<graph id="#{graph_name}" edgedefault="directed">
|
216
|
-
XML
|
217
|
-
|
218
|
-
objects = self.objects(include_keys: false).find_all{ |obj| not obj.is_a?(Reference) }
|
219
|
-
|
220
|
-
objects.each do |object|
|
221
|
-
xml << declare_node["n#{object.object_id}", appearance[object]]
|
222
|
-
|
223
|
-
if object.is_a?(Stream)
|
224
|
-
object.dictionary.each do |value|
|
225
|
-
unless value.is_a?(Reference)
|
226
|
-
xml << declare_node[value.object_id, appearance[value]]
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
edge_nb = add_edges[xml, object, edge_nb]
|
232
|
-
end
|
233
|
-
|
234
|
-
xml << '</graph>' << "\n"
|
235
|
-
xml << '</graphml>'
|
236
|
-
|
237
|
-
doc = REXML::Document.new(xml)
|
238
|
-
formatter = REXML::Formatters::Pretty.new(4)
|
239
|
-
formatter.compact = true
|
240
|
-
|
241
|
-
File.open(path, "w") do |fd|
|
242
|
-
formatter.write(doc, fd)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
end
|