pdf-core 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/COPYING +2 -0
- data/GPLv2 +340 -0
- data/GPLv3 +674 -0
- data/Gemfile +3 -0
- data/LICENSE +56 -0
- data/Rakefile +11 -0
- data/pdf-core.gemspec +3 -1
- data/spec/filters_spec.rb +34 -0
- data/spec/name_tree_spec.rb +122 -0
- data/spec/object_store_spec.rb +49 -0
- data/spec/pdf_object_spec.rb +172 -0
- data/spec/reference_spec.rb +62 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/stream_spec.rb +59 -0
- metadata +15 -2
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PDF::Core is copyrighted free software produced by Gregory Brown along with
|
2
|
+
community contributions. See git log for authorship information.
|
3
|
+
|
4
|
+
Licensing terms follow:
|
5
|
+
|
6
|
+
You can redistribute PDF::Core and/or modify it under either the terms of the GPLv2
|
7
|
+
or GPLv3 (see GPLv2 and GPLv3 files), or the conditions below:
|
8
|
+
|
9
|
+
1. You may make and give away verbatim copies of the source form of the
|
10
|
+
software without restriction, provided that you duplicate all of the
|
11
|
+
original copyright notices and associated disclaimers.
|
12
|
+
|
13
|
+
2. You may modify your copy of the software in any way, provided that
|
14
|
+
you do at least ONE of the following:
|
15
|
+
|
16
|
+
a) place your modifications in the Public Domain or otherwise
|
17
|
+
make them Freely Available, such as by posting said
|
18
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
19
|
+
the author to include your modifications in the software.
|
20
|
+
|
21
|
+
b) use the modified software only within your corporation or
|
22
|
+
organization.
|
23
|
+
|
24
|
+
c) rename any non-standard executables so the names do not conflict
|
25
|
+
with standard executables, which must also be provided.
|
26
|
+
|
27
|
+
d) make other distribution arrangements with the author.
|
28
|
+
|
29
|
+
3. You may distribute the software in object code or executable
|
30
|
+
form, provided that you do at least ONE of the following:
|
31
|
+
|
32
|
+
a) distribute the executables and library files of the software,
|
33
|
+
together with instructions (in the manual page or equivalent)
|
34
|
+
on where to get the original distribution.
|
35
|
+
|
36
|
+
b) accompany the distribution with the machine-readable source of
|
37
|
+
the software.
|
38
|
+
|
39
|
+
c) give non-standard executables non-standard names, with
|
40
|
+
instructions on where to get the original software distribution.
|
41
|
+
|
42
|
+
d) make other distribution arrangements with the author.
|
43
|
+
|
44
|
+
4. You may modify and include the part of the software into any other
|
45
|
+
software (possibly commercial).
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/Rakefile
ADDED
data/pdf-core.gemspec
CHANGED
@@ -3,7 +3,9 @@ Gem::Specification.new do |spec|
|
|
3
3
|
spec.version = File.read(File.expand_path('VERSION', File.dirname(__FILE__))).strip
|
4
4
|
spec.platform = Gem::Platform::RUBY
|
5
5
|
spec.summary = "PDF::Core is used by Prawn to render PDF documents"
|
6
|
-
spec.files = Dir.glob("{lib}/**/**/*") +
|
6
|
+
spec.files = Dir.glob("{lib,spec}/**/**/*") +
|
7
|
+
["COPYING", "GPLv2", "GPLv3", "LICENSE"] +
|
8
|
+
["Gemfile", "Rakefile"] +
|
7
9
|
["pdf-core.gemspec"]
|
8
10
|
spec.require_path = "lib"
|
9
11
|
spec.required_ruby_version = '>= 1.9.3'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative "spec_helper"
|
4
|
+
|
5
|
+
FILTERS = {
|
6
|
+
:FlateDecode => {'test' => "x\x9C+I-.\x01\x00\x04]\x01\xC1".force_encoding(Encoding::ASCII_8BIT) },
|
7
|
+
:DCTDecode => {'test' => "test"}
|
8
|
+
}
|
9
|
+
|
10
|
+
FILTERS.each do |filter_name, examples|
|
11
|
+
filter = PDF::Core::Filters.const_get(filter_name)
|
12
|
+
|
13
|
+
describe "#{filter_name} filter" do
|
14
|
+
it "should encode stream" do
|
15
|
+
examples.each do |in_stream, out_stream|
|
16
|
+
filter.encode(in_stream).should == out_stream
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should decode stream" do
|
21
|
+
examples.each do |in_stream, out_stream|
|
22
|
+
filter.decode(out_stream).should == in_stream
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be symmetric" do
|
27
|
+
examples.each do |in_stream, out_stream|
|
28
|
+
filter.decode(filter.encode(in_stream)).should == in_stream
|
29
|
+
|
30
|
+
filter.encode(filter.decode(out_stream)).should == out_stream
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
def tree_dump(tree)
|
4
|
+
if tree.is_a?(PDF::Core::NameTree::Node)
|
5
|
+
"[" + tree.children.map { |child| tree_dump(child) }.join(",") + "]"
|
6
|
+
else
|
7
|
+
"#{tree.name}=#{tree.value}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def tree_add(tree, *args)
|
12
|
+
args.each do |(name, value)|
|
13
|
+
tree.add(name, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def tree_value(name, value)
|
18
|
+
PDF::Core::NameTree::Value.new(name, value)
|
19
|
+
end
|
20
|
+
|
21
|
+
# FIXME: This is a dummy that's meant to stand in for a Prawn::Document.
|
22
|
+
# It causes the tests to pass but I have no idea if it's really a
|
23
|
+
# sufficient test double or not.
|
24
|
+
class RefExposingDocument
|
25
|
+
def initialize
|
26
|
+
@object_store = []
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :object_store
|
30
|
+
|
31
|
+
def ref!(obj)
|
32
|
+
@object_store << obj
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "Name Tree" do
|
37
|
+
before(:each) { @pdf = RefExposingDocument.new }
|
38
|
+
|
39
|
+
it "should have no children when first initialized" do
|
40
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
41
|
+
node.children.length.should == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have no subtrees while child limit is not reached" do
|
45
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
46
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3])
|
47
|
+
tree_dump(node).should == "[one=1,three=3,two=2]"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should split into subtrees when limit is exceeded" do
|
51
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
52
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
53
|
+
tree_dump(node).should == "[[four=4,one=1],[three=3,two=2]]"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should create a two new references when root is split" do
|
57
|
+
ref_count = @pdf.object_store.length
|
58
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
59
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
60
|
+
@pdf.object_store.length.should == ref_count+2
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should create a one new reference when subtree is split" do
|
64
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
65
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
66
|
+
|
67
|
+
ref_count = @pdf.object_store.length # save when root is split
|
68
|
+
tree_add(node, ["five", 5], ["six", 6], ["seven", 7])
|
69
|
+
tree_dump(node).should == "[[five=5,four=4,one=1],[seven=7,six=6],[three=3,two=2]]"
|
70
|
+
@pdf.object_store.length.should == ref_count+1
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should keep tree balanced when subtree split cascades to root" do
|
74
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
75
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
76
|
+
tree_add(node, ["five", 5], ["six", 6], ["seven", 7], ["eight", 8])
|
77
|
+
tree_dump(node).should == "[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should maintain order of already properly ordered nodes" do
|
81
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
82
|
+
tree_add(node, ["eight", 8], ["five", 5], ["four", 4], ["one", 1])
|
83
|
+
tree_add(node, ['seven', 7], ['six', 6], ['three', 3], ['two', 2])
|
84
|
+
tree_dump(node).should == "[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should emit only :Names key with to_hash if root is only node" do
|
88
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
89
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3])
|
90
|
+
node.to_hash.should ==(
|
91
|
+
{ :Names => [tree_value("one", 1), tree_value("three", 3), tree_value("two", 2)] }
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should emit only :Kids key with to_hash if root has children" do
|
96
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
97
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
98
|
+
node.to_hash.should ==({ :Kids => node.children.map { |child| child.ref } })
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should emit :Limits and :Names keys with to_hash for leaf node" do
|
102
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
103
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
104
|
+
node.children.first.to_hash.should ==(
|
105
|
+
{ :Limits => %w(four one),
|
106
|
+
:Names => [tree_value("four", 4), tree_value("one", 1)] }
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should emit :Limits and :Kids keys with to_hash for inner node" do
|
111
|
+
node = PDF::Core::NameTree::Node.new(@pdf, 3)
|
112
|
+
tree_add(node, ["one", 1], ["two", 2], ["three", 3], ["four", 4])
|
113
|
+
tree_add(node, ["five", 5], ["six", 6], ["seven", 7], ["eight", 8])
|
114
|
+
tree_add(node, ["nine", 9], ["ten", 10], ["eleven", 11], ["twelve", 12])
|
115
|
+
tree_add(node, ["thirteen", 13], ["fourteen", 14], ["fifteen", 15], ["sixteen", 16])
|
116
|
+
node.children.first.to_hash.should ==(
|
117
|
+
{ :Limits => %w(eight one),
|
118
|
+
:Kids => node.children.first.children.map { |child| child.ref } }
|
119
|
+
)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative "spec_helper"
|
4
|
+
|
5
|
+
describe "PDF::Core::ObjectStore" do
|
6
|
+
before(:each) do
|
7
|
+
@store = PDF::Core::ObjectStore.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should create required roots by default, including info passed to new" do
|
11
|
+
store = PDF::Core::ObjectStore.new(:info => {:Test => 3})
|
12
|
+
store.size.should == 3 # 3 default roots
|
13
|
+
store.info.data[:Test].should == 3
|
14
|
+
store.pages.data[:Count].should == 0
|
15
|
+
store.root.data[:Pages].should == store.pages
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it "should add to its objects when ref() is called" do
|
20
|
+
count = @store.size
|
21
|
+
@store.ref("blah")
|
22
|
+
@store.size.should == count + 1
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should accept push with a Prawn::Reference" do
|
26
|
+
r = PDF::Core::Reference(123, "blah")
|
27
|
+
@store.push(r)
|
28
|
+
@store[r.identifier].should == r
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should accept arbitrary data and use it to create a Prawn::Reference" do
|
32
|
+
@store.push(123, "blahblah")
|
33
|
+
@store[123].data.should == "blahblah"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be Enumerable, yielding in order of submission" do
|
37
|
+
# higher IDs to bypass the default roots
|
38
|
+
[10, 11, 12].each do |id|
|
39
|
+
@store.push(id, "some data #{id}")
|
40
|
+
end
|
41
|
+
@store.map{|ref| ref.identifier}[-3..-1].should == [10, 11, 12]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should accept option to disabling PDF scaling in PDF clients" do
|
45
|
+
@store = PDF::Core::ObjectStore.new(:print_scaling => :none)
|
46
|
+
@store.root.data[:ViewerPreferences].should == {:PrintScaling => :None}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
require_relative "spec_helper"
|
3
|
+
|
4
|
+
# See PDF Reference, Sixth Edition (1.7) pp51-60 for details
|
5
|
+
describe "PDF Object Serialization" do
|
6
|
+
|
7
|
+
it "should convert Ruby's nil to PDF null" do
|
8
|
+
PDF::Core::PdfObject(nil).should == "null"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should convert Ruby booleans to PDF booleans" do
|
12
|
+
PDF::Core::PdfObject(true).should == "true"
|
13
|
+
PDF::Core::PdfObject(false).should == "false"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should convert a Ruby number to PDF number" do
|
17
|
+
PDF::Core::PdfObject(1).should == "1"
|
18
|
+
PDF::Core::PdfObject(1.214112421).should == "1.214112421"
|
19
|
+
# scientific notation is not valid in PDF
|
20
|
+
PDF::Core::PdfObject(0.000005).should == "0.000005"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should convert a Ruby time object to a PDF timestamp" do
|
24
|
+
t = Time.now
|
25
|
+
PDF::Core::PdfObject(t).should == t.strftime("(D:%Y%m%d%H%M%S%z").chop.chop + "'00')"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should convert a Ruby string to PDF string when inside a content stream" do
|
29
|
+
s = "I can has a string"
|
30
|
+
PDF::Inspector.parse(PDF::Core::PdfObject(s, true)).should == s
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should convert a Ruby string to a UTF-16 PDF string when outside a content stream" do
|
34
|
+
s = "I can has a string"
|
35
|
+
s_utf16 = "\xFE\xFF" + s.unpack("U*").pack("n*")
|
36
|
+
PDF::Inspector.parse(PDF::Core::PdfObject(s, false)).should == s_utf16
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should convert a Ruby string with characters outside the BMP to its " +
|
40
|
+
"UTF-16 representation with a BOM" do
|
41
|
+
# U+10192 ROMAN SEMUNCIA SIGN
|
42
|
+
semuncia = [65938].pack("U")
|
43
|
+
PDF::Core::PdfObject(semuncia, false).upcase.should == "<FEFFD800DD92>"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should pass through bytes regardless of content stream status for ByteString" do
|
47
|
+
PDF::Core::PdfObject(PDF::Core::ByteString.new("\xDE\xAD\xBE\xEF")).upcase.
|
48
|
+
should == "<DEADBEEF>"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should escape parens when converting from Ruby string to PDF" do
|
52
|
+
s = 'I )(can has a string'
|
53
|
+
PDF::Inspector.parse(PDF::Core::PdfObject(s, true)).should == s
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should handle ruby escaped parens when converting to PDF string" do
|
57
|
+
s = 'I can \\)( has string'
|
58
|
+
PDF::Inspector.parse(PDF::Core::PdfObject(s, true)).should == s
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should escape various strings correctly when converting a LiteralString" do
|
62
|
+
ls = PDF::Core::LiteralString.new("abc")
|
63
|
+
PDF::Core::PdfObject(ls).should == "(abc)"
|
64
|
+
|
65
|
+
ls = PDF::Core::LiteralString.new("abc\x0Ade") # should escape \n
|
66
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x0Ade)"
|
67
|
+
|
68
|
+
ls = PDF::Core::LiteralString.new("abc\x0Dde") # should escape \r
|
69
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x0Dde)"
|
70
|
+
|
71
|
+
ls = PDF::Core::LiteralString.new("abc\x09de") # should escape \t
|
72
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x09de)"
|
73
|
+
|
74
|
+
ls = PDF::Core::LiteralString.new("abc\x08de") # should escape \b
|
75
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x08de)"
|
76
|
+
|
77
|
+
ls = PDF::Core::LiteralString.new("abc\x0Cde") # should escape \f
|
78
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x0Cde)"
|
79
|
+
|
80
|
+
ls = PDF::Core::LiteralString.new("abc(de") # should escape \(
|
81
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C(de)"
|
82
|
+
|
83
|
+
ls = PDF::Core::LiteralString.new("abc)de") # should escape \)
|
84
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C)de)"
|
85
|
+
|
86
|
+
ls = PDF::Core::LiteralString.new("abc\x5Cde") # should escape \\
|
87
|
+
PDF::Core::PdfObject(ls).should == "(abc\x5C\x5Cde)"
|
88
|
+
PDF::Core::PdfObject(ls).size.should == 9
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should escape strings correctly when converting a LiteralString that is not utf-8" do
|
92
|
+
data = "\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\xaf\xd0"
|
93
|
+
ls = PDF::Core::LiteralString.new(data)
|
94
|
+
PDF::Core::PdfObject(ls).should == "(\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\x5c\xaf\xd0)"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should convert a Ruby symbol to PDF name" do
|
98
|
+
PDF::Core::PdfObject(:my_symbol).should == "/my_symbol"
|
99
|
+
PDF::Core::PdfObject(:"A;Name_With-Various***Characters?").should ==
|
100
|
+
"/A;Name_With-Various***Characters?"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should convert a whitespace or delimiter containing Ruby symbol to a PDF name" do
|
104
|
+
PDF::Core::PdfObject(:"my symbol").should == "/my#20symbol"
|
105
|
+
PDF::Core::PdfObject(:"my#symbol").should == "/my#23symbol"
|
106
|
+
PDF::Core::PdfObject(:"my/symbol").should == "/my#2Fsymbol"
|
107
|
+
PDF::Core::PdfObject(:"my(symbol").should == "/my#28symbol"
|
108
|
+
PDF::Core::PdfObject(:"my)symbol").should == "/my#29symbol"
|
109
|
+
PDF::Core::PdfObject(:"my<symbol").should == "/my#3Csymbol"
|
110
|
+
PDF::Core::PdfObject(:"my>symbol").should == "/my#3Esymbol"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should convert a Ruby array to PDF Array when inside a content stream" do
|
114
|
+
PDF::Core::PdfObject([1,2,3]).should == "[1 2 3]"
|
115
|
+
PDF::Inspector.parse(PDF::Core::PdfObject([[1,2],:foo,"Bar"], true)).should ==
|
116
|
+
[[1,2],:foo, "Bar"]
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should convert a Ruby array to PDF Array when outside a content stream" do
|
120
|
+
bar = "\xFE\xFF" + "Bar".unpack("U*").pack("n*")
|
121
|
+
PDF::Core::PdfObject([1,2,3]).should == "[1 2 3]"
|
122
|
+
PDF::Inspector.parse(PDF::Core::PdfObject([[1,2],:foo,"Bar"], false)).should ==
|
123
|
+
[[1,2],:foo, bar]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should convert a Ruby hash to a PDF Dictionary when inside a content stream" do
|
127
|
+
dict = PDF::Core::PdfObject( {:foo => :bar,
|
128
|
+
"baz" => [1,2,3],
|
129
|
+
:bang => {:a => "what", :b => [:you, :say] }}, true )
|
130
|
+
|
131
|
+
res = PDF::Inspector.parse(dict)
|
132
|
+
|
133
|
+
res[:foo].should == :bar
|
134
|
+
res[:baz].should == [1,2,3]
|
135
|
+
res[:bang].should == { :a => "what", :b => [:you, :say] }
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should convert a Ruby hash to a PDF Dictionary when outside a content stream" do
|
140
|
+
what = "\xFE\xFF" + "what".unpack("U*").pack("n*")
|
141
|
+
dict = PDF::Core::PdfObject( {:foo => :bar,
|
142
|
+
"baz" => [1,2,3],
|
143
|
+
:bang => {:a => "what", :b => [:you, :say] }}, false )
|
144
|
+
|
145
|
+
res = PDF::Inspector.parse(dict)
|
146
|
+
|
147
|
+
res[:foo].should == :bar
|
148
|
+
res[:baz].should == [1,2,3]
|
149
|
+
res[:bang].should == { :a => what, :b => [:you, :say] }
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not allow keys other than strings or symbols for PDF dicts" do
|
154
|
+
lambda { PDF::Core::PdfObject(:foo => :bar, :baz => :bang, 1 => 4) }.
|
155
|
+
should raise_error(PDF::Core::Errors::FailedObjectConversion)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should convert a Prawn::Reference to a PDF indirect object reference" do
|
159
|
+
ref = PDF::Core::Reference(1,true)
|
160
|
+
PDF::Core::PdfObject(ref).should == ref.to_s
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should convert a NameTree::Node to a PDF hash" do
|
164
|
+
# FIXME: Soft dependench on Prawn::Document exists in Node
|
165
|
+
node = PDF::Core::NameTree::Node.new(nil, 10)
|
166
|
+
node.add "hello", 1.0
|
167
|
+
node.add "world", 2.0
|
168
|
+
data = PDF::Core::PdfObject(node)
|
169
|
+
res = PDF::Inspector.parse(data)
|
170
|
+
res.should == {:Names => ["hello", 1.0, "world", 2.0]}
|
171
|
+
end
|
172
|
+
end
|