pdf-core 0.6.1 → 0.7.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/Rakefile +9 -5
- data/lib/pdf/core.rb +20 -19
- data/lib/pdf/core/annotations.rb +16 -17
- data/lib/pdf/core/byte_string.rb +1 -1
- data/lib/pdf/core/destinations.rb +17 -14
- data/lib/pdf/core/document_state.rb +21 -16
- data/lib/pdf/core/filter_list.rb +4 -4
- data/lib/pdf/core/filters.rb +4 -4
- data/lib/pdf/core/graphics_state.rb +15 -19
- data/lib/pdf/core/name_tree.rb +44 -40
- data/lib/pdf/core/object_store.rb +13 -18
- data/lib/pdf/core/outline_item.rb +11 -6
- data/lib/pdf/core/outline_root.rb +1 -1
- data/lib/pdf/core/page.rb +93 -64
- data/lib/pdf/core/page_geometry.rb +52 -56
- data/lib/pdf/core/pdf_object.rb +41 -41
- data/lib/pdf/core/reference.rb +12 -17
- data/lib/pdf/core/renderer.rb +41 -32
- data/lib/pdf/core/stream.rb +6 -8
- data/lib/pdf/core/text.rb +83 -47
- data/lib/pdf/core/utils.rb +12 -0
- data/pdf-core.gemspec +33 -20
- metadata +79 -24
- metadata.gz.sig +0 -0
- data/spec/decimal_rounding_spec.rb +0 -12
- data/spec/document_state_spec.rb +0 -30
- data/spec/filters_spec.rb +0 -34
- data/spec/name_tree_spec.rb +0 -122
- data/spec/object_store_spec.rb +0 -49
- data/spec/pdf_object_spec.rb +0 -172
- data/spec/reference_spec.rb +0 -62
- data/spec/spec_helper.rb +0 -32
- data/spec/stream_spec.rb +0 -59
data/lib/pdf/core/name_tree.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'pdf/core/utils'
|
4
|
+
|
3
5
|
# name_tree.rb : Implements NameTree for PDF
|
4
6
|
#
|
5
7
|
# Copyright November 2008, Jamis Buck. All Rights Reserved.
|
@@ -16,7 +18,7 @@ module PDF
|
|
16
18
|
attr_accessor :parent
|
17
19
|
attr_accessor :ref
|
18
20
|
|
19
|
-
def initialize(document, limit, parent=nil)
|
21
|
+
def initialize(document, limit, parent = nil)
|
20
22
|
@document = document
|
21
23
|
@children = []
|
22
24
|
@limit = limit
|
@@ -29,7 +31,7 @@ module PDF
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def size
|
32
|
-
leaf? ? children.size : children.
|
34
|
+
leaf? ? children.size : children.map(&:size).reduce(:+)
|
33
35
|
end
|
34
36
|
|
35
37
|
def leaf?
|
@@ -47,10 +49,10 @@ module PDF
|
|
47
49
|
if leaf?
|
48
50
|
hash[:Names] = children if leaf?
|
49
51
|
else
|
50
|
-
hash[:Kids] = children.map
|
52
|
+
hash[:Kids] = children.map(&:ref)
|
51
53
|
end
|
52
54
|
|
53
|
-
|
55
|
+
hash
|
54
56
|
end
|
55
57
|
|
56
58
|
def least
|
@@ -84,15 +86,16 @@ module PDF
|
|
84
86
|
value
|
85
87
|
end
|
86
88
|
|
87
|
-
def >=(
|
88
|
-
children.empty? || children.last >=
|
89
|
+
def >=(other)
|
90
|
+
children.empty? || children.last >= other
|
89
91
|
end
|
90
92
|
|
91
93
|
def split!
|
92
94
|
if parent
|
93
95
|
parent.split(self)
|
94
96
|
else
|
95
|
-
left
|
97
|
+
left = new_node(self)
|
98
|
+
right = new_node(self)
|
96
99
|
split_children(self, left, right)
|
97
100
|
children.replace([left, right])
|
98
101
|
end
|
@@ -103,51 +106,51 @@ module PDF
|
|
103
106
|
#
|
104
107
|
def deep_copy
|
105
108
|
node = dup
|
106
|
-
node.instance_variable_set(
|
107
|
-
|
108
|
-
|
109
|
-
node.ref ? node.ref.deep_copy : nil)
|
109
|
+
node.instance_variable_set('@children', Utils.deep_clone(children))
|
110
|
+
node.instance_variable_set('@ref',
|
111
|
+
node.ref ? node.ref.deep_copy : nil)
|
110
112
|
node
|
111
113
|
end
|
112
114
|
|
113
115
|
protected
|
114
116
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
def split(node)
|
118
|
+
new_child = new_node(self)
|
119
|
+
split_children(node, node, new_child)
|
120
|
+
index = children.index(node)
|
121
|
+
children.insert(index + 1, new_child)
|
122
|
+
split! if children.length > limit
|
123
|
+
end
|
122
124
|
|
123
125
|
private
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
def new_node(parent = nil)
|
128
|
+
node = Node.new(document, limit, parent)
|
129
|
+
node.ref = document.ref!(node)
|
130
|
+
node
|
131
|
+
end
|
130
132
|
|
131
|
-
|
132
|
-
|
133
|
+
def split_children(node, left, right)
|
134
|
+
half = (node.limit + 1) / 2
|
133
135
|
|
134
|
-
|
136
|
+
left_children = node.children[0...half]
|
137
|
+
right_children = node.children[half..-1]
|
135
138
|
|
136
|
-
|
137
|
-
|
139
|
+
left.children.replace(left_children)
|
140
|
+
right.children.replace(right_children)
|
138
141
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
142
|
+
unless node.leaf?
|
143
|
+
left_children.each { |child| child.parent = left }
|
144
|
+
right_children.each { |child| child.parent = right }
|
143
145
|
end
|
146
|
+
end
|
144
147
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
149
|
-
return children.length
|
148
|
+
def insertion_point(value)
|
149
|
+
children.each_with_index do |child, index|
|
150
|
+
return index if child >= value
|
150
151
|
end
|
152
|
+
children.length
|
153
|
+
end
|
151
154
|
end
|
152
155
|
|
153
156
|
class Value #:nodoc:
|
@@ -157,11 +160,12 @@ module PDF
|
|
157
160
|
attr_reader :value
|
158
161
|
|
159
162
|
def initialize(name, value)
|
160
|
-
@name
|
163
|
+
@name = PDF::Core::LiteralString.new(name)
|
164
|
+
@value = value
|
161
165
|
end
|
162
166
|
|
163
|
-
def <=>(
|
164
|
-
name <=>
|
167
|
+
def <=>(other)
|
168
|
+
name <=> other.name
|
165
169
|
end
|
166
170
|
|
167
171
|
def inspect
|
@@ -18,12 +18,12 @@ module PDF
|
|
18
18
|
@identifiers = []
|
19
19
|
|
20
20
|
@info ||= ref(opts[:info] || {}).identifier
|
21
|
-
@root ||= ref(:
|
21
|
+
@root ||= ref(Type: :Catalog).identifier
|
22
22
|
if opts[:print_scaling] == :none
|
23
|
-
root.data[:ViewerPreferences] = {:
|
23
|
+
root.data[:ViewerPreferences] = { PrintScaling: :None }
|
24
24
|
end
|
25
25
|
if pages.nil?
|
26
|
-
root.data[:Pages] = ref(:
|
26
|
+
root.data[:Pages] = ref(Type: :Pages, Count: 0, Kids: [])
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -48,22 +48,23 @@ module PDF
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Adds the given reference to the store and returns the reference object.
|
51
|
-
# If the object provided is not a PDF::Core::Reference, one is created
|
52
|
-
# arguments provided.
|
51
|
+
# If the object provided is not a PDF::Core::Reference, one is created
|
52
|
+
# from the arguments provided.
|
53
53
|
#
|
54
54
|
def push(*args, &block)
|
55
|
-
reference =
|
56
|
-
args.first
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
reference =
|
56
|
+
if args.first.is_a?(PDF::Core::Reference)
|
57
|
+
args.first
|
58
|
+
else
|
59
|
+
PDF::Core::Reference.new(*args, &block)
|
60
|
+
end
|
60
61
|
|
61
62
|
@objects[reference.identifier] = reference
|
62
63
|
@identifiers << reference.identifier
|
63
64
|
reference
|
64
65
|
end
|
65
66
|
|
66
|
-
|
67
|
+
alias << push
|
67
68
|
|
68
69
|
def each
|
69
70
|
@identifiers.each do |id|
|
@@ -78,7 +79,7 @@ module PDF
|
|
78
79
|
def size
|
79
80
|
@identifiers.size
|
80
81
|
end
|
81
|
-
|
82
|
+
alias length size
|
82
83
|
|
83
84
|
# returns the object ID for a particular page in the document. Pages
|
84
85
|
# are indexed starting at 1 (not 0!).
|
@@ -95,12 +96,6 @@ module PDF
|
|
95
96
|
flat_page_ids = get_page_objects(pages).flatten
|
96
97
|
flat_page_ids[k]
|
97
98
|
end
|
98
|
-
|
99
|
-
def is_utf8?(str)
|
100
|
-
str.force_encoding(::Encoding::UTF_8)
|
101
|
-
str.valid_encoding?
|
102
|
-
end
|
103
99
|
end
|
104
100
|
end
|
105
101
|
end
|
106
|
-
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module PDF
|
2
2
|
module Core
|
3
3
|
class OutlineItem #:nodoc:
|
4
|
-
attr_accessor :count, :first, :last, :next, :prev, :parent, :title, :dest,
|
4
|
+
attr_accessor :count, :first, :last, :next, :prev, :parent, :title, :dest,
|
5
|
+
:closed
|
5
6
|
|
6
7
|
def initialize(title, parent, options)
|
7
8
|
@closed = options[:closed]
|
@@ -11,11 +12,15 @@ module PDF
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def to_hash
|
14
|
-
hash = {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
hash = {
|
16
|
+
Title: title,
|
17
|
+
Parent: parent,
|
18
|
+
Count: closed ? -count : count
|
19
|
+
}
|
20
|
+
[
|
21
|
+
{ First: first }, { Last: last }, { Next: defined?(@next) && @next },
|
22
|
+
{ Prev: prev }, { Dest: dest }
|
23
|
+
].each do |h|
|
19
24
|
unless h.values.first.nil?
|
20
25
|
hash.merge!(h)
|
21
26
|
end
|
data/lib/pdf/core/page.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# prawn/core/page.rb : Implements low-level representation of a PDF page
|
4
2
|
#
|
5
3
|
# Copyright February 2010, Gregory Brown. All Rights Reserved.
|
@@ -12,21 +10,48 @@ require_relative 'graphics_state'
|
|
12
10
|
module PDF
|
13
11
|
module Core
|
14
12
|
class Page #:nodoc:
|
15
|
-
attr_accessor :document, :margins, :stack
|
13
|
+
attr_accessor :art_indents, :bleeds, :crops, :document, :margins, :stack,
|
14
|
+
:trims
|
16
15
|
attr_writer :content, :dictionary
|
17
16
|
|
18
|
-
|
17
|
+
ZERO_INDENTS = {
|
18
|
+
left: 0,
|
19
|
+
bottom: 0,
|
20
|
+
right: 0,
|
21
|
+
top: 0
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
def initialize(document, options = {})
|
19
25
|
@document = document
|
20
|
-
@margins = options[:margins] || { :
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
26
|
+
@margins = options[:margins] || { left: 36,
|
27
|
+
right: 36,
|
28
|
+
top: 36,
|
29
|
+
bottom: 36 }
|
30
|
+
@crops = options[:crops] || ZERO_INDENTS
|
31
|
+
@bleeds = options[:bleeds] || ZERO_INDENTS
|
32
|
+
@trims = options[:trims] || ZERO_INDENTS
|
33
|
+
@art_indents = options[:art_indents] || ZERO_INDENTS
|
24
34
|
@stack = GraphicStateStack.new(options[:graphic_state])
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
@size = options[:size] || 'LETTER'
|
36
|
+
@layout = options[:layout] || :portrait
|
37
|
+
|
38
|
+
@stamp_stream = nil
|
39
|
+
@stamp_dictionary = nil
|
40
|
+
|
41
|
+
@content = document.ref({})
|
42
|
+
content << 'q' << "\n"
|
43
|
+
@dictionary = document.ref(
|
44
|
+
Type: :Page,
|
45
|
+
Parent: document.state.store.pages,
|
46
|
+
MediaBox: dimensions,
|
47
|
+
CropBox: crop_box,
|
48
|
+
BleedBox: bleed_box,
|
49
|
+
TrimBox: trim_box,
|
50
|
+
ArtBox: art_box,
|
51
|
+
Contents: content
|
52
|
+
)
|
53
|
+
|
54
|
+
resources[:ProcSet] = [:PDF, :Text, :ImageB, :ImageC, :ImageI]
|
30
55
|
end
|
31
56
|
|
32
57
|
def graphic_state
|
@@ -45,15 +70,15 @@ module PDF
|
|
45
70
|
end
|
46
71
|
|
47
72
|
def size
|
48
|
-
defined?(@size) && @size || dimensions[2,2]
|
73
|
+
defined?(@size) && @size || dimensions[2, 2]
|
49
74
|
end
|
50
75
|
|
51
76
|
def in_stamp_stream?
|
52
|
-
|
77
|
+
!@stamp_stream.nil?
|
53
78
|
end
|
54
79
|
|
55
80
|
def stamp_stream(dictionary)
|
56
|
-
@stamp_stream =
|
81
|
+
@stamp_stream = ''
|
57
82
|
@stamp_dictionary = dictionary
|
58
83
|
graphic_stack_size = stack.stack.size
|
59
84
|
|
@@ -76,7 +101,8 @@ module PDF
|
|
76
101
|
end
|
77
102
|
|
78
103
|
def dictionary
|
79
|
-
defined?(@stamp_dictionary) && @stamp_dictionary ||
|
104
|
+
defined?(@stamp_dictionary) && @stamp_dictionary ||
|
105
|
+
document.state.store[@dictionary]
|
80
106
|
end
|
81
107
|
|
82
108
|
def resources
|
@@ -116,62 +142,67 @@ module PDF
|
|
116
142
|
dictionary.data[:Contents].each do |stream|
|
117
143
|
stream.stream.compress! if document.compression_enabled?
|
118
144
|
end
|
119
|
-
|
120
|
-
content.stream.compress!
|
145
|
+
elsif document.compression_enabled?
|
146
|
+
content.stream.compress!
|
121
147
|
end
|
122
148
|
end
|
123
149
|
|
124
|
-
def imported_page?
|
125
|
-
@imported_page
|
126
|
-
end
|
127
|
-
|
128
150
|
def dimensions
|
129
|
-
return inherited_dictionary_value(:MediaBox) if imported_page?
|
130
|
-
|
131
151
|
coords = PDF::Core::PageGeometry::SIZES[size] || size
|
132
|
-
[0,0] +
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
152
|
+
[0, 0] +
|
153
|
+
case layout
|
154
|
+
when :portrait
|
155
|
+
coords
|
156
|
+
when :landscape
|
157
|
+
coords.reverse
|
158
|
+
else
|
159
|
+
raise PDF::Core::Errors::InvalidPageLayout,
|
160
|
+
'Layout must be either :portrait or :landscape'
|
161
|
+
end
|
141
162
|
end
|
142
163
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
@stamp_stream = nil
|
153
|
-
@stamp_dictionary = nil
|
154
|
-
@imported_page = true
|
164
|
+
def art_box
|
165
|
+
left, bottom, right, top = dimensions
|
166
|
+
[
|
167
|
+
left + art_indents[:left],
|
168
|
+
bottom + art_indents[:bottom],
|
169
|
+
right - art_indents[:right],
|
170
|
+
top - art_indents[:top]
|
171
|
+
]
|
155
172
|
end
|
156
173
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
174
|
+
def bleed_box
|
175
|
+
left, bottom, right, top = dimensions
|
176
|
+
[
|
177
|
+
left + bleeds[:left],
|
178
|
+
bottom + bleeds[:bottom],
|
179
|
+
right - bleeds[:right],
|
180
|
+
top - bleeds[:top]
|
181
|
+
]
|
182
|
+
end
|
164
183
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
184
|
+
def crop_box
|
185
|
+
left, bottom, right, top = dimensions
|
186
|
+
[
|
187
|
+
left + crops[:left],
|
188
|
+
bottom + crops[:bottom],
|
189
|
+
right - crops[:right],
|
190
|
+
top - crops[:top]
|
191
|
+
]
|
192
|
+
end
|
171
193
|
|
172
|
-
|
194
|
+
def trim_box
|
195
|
+
left, bottom, right, top = dimensions
|
196
|
+
[
|
197
|
+
left + trims[:left],
|
198
|
+
bottom + trims[:bottom],
|
199
|
+
right - trims[:right],
|
200
|
+
top - trims[:top]
|
201
|
+
]
|
173
202
|
end
|
174
203
|
|
204
|
+
private
|
205
|
+
|
175
206
|
# some entries in the Page dict can be inherited from parent Pages dicts.
|
176
207
|
#
|
177
208
|
# Starting with the current page dict, this method will walk up the
|
@@ -183,12 +214,10 @@ module PDF
|
|
183
214
|
def inherited_dictionary_value(key, local_dict = nil)
|
184
215
|
local_dict ||= dictionary.data
|
185
216
|
|
186
|
-
if local_dict.
|
217
|
+
if local_dict.key?(key)
|
187
218
|
local_dict[key]
|
188
|
-
elsif local_dict.
|
219
|
+
elsif local_dict.key?(:Parent)
|
189
220
|
inherited_dictionary_value(key, local_dict[:Parent].data)
|
190
|
-
else
|
191
|
-
nil
|
192
221
|
end
|
193
222
|
end
|
194
223
|
end
|