pdf-core 0.8.1 → 0.10.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/pdf/core/annotations.rb +51 -13
- data/lib/pdf/core/byte_string.rb +3 -2
- data/lib/pdf/core/destinations.rb +64 -24
- data/lib/pdf/core/document_state.rb +100 -17
- data/lib/pdf/core/filter_list.rb +44 -5
- data/lib/pdf/core/filters.rb +26 -7
- data/lib/pdf/core/graphics_state.rb +74 -30
- data/lib/pdf/core/literal_string.rb +9 -10
- data/lib/pdf/core/name_tree.rb +76 -16
- data/lib/pdf/core/object_store.rb +69 -19
- data/lib/pdf/core/outline_item.rb +53 -5
- data/lib/pdf/core/outline_root.rb +18 -2
- data/lib/pdf/core/page.rb +158 -32
- data/lib/pdf/core/page_geometry.rb +4 -58
- data/lib/pdf/core/pdf_object.rb +62 -37
- data/lib/pdf/core/reference.rb +58 -15
- data/lib/pdf/core/renderer.rb +116 -47
- data/lib/pdf/core/stream.rb +43 -7
- data/lib/pdf/core/text.rb +255 -106
- data/lib/pdf/core/utils.rb +10 -1
- data/lib/pdf/core.rb +26 -16
- data/pdf-core.gemspec +31 -27
- data.tar.gz.sig +0 -0
- metadata +36 -101
- metadata.gz.sig +2 -1
- data/Gemfile +0 -5
- data/Rakefile +0 -17
@@ -1,27 +1,28 @@
|
|
1
|
-
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
#
|
5
|
-
# Implements graphics state saving and restoring
|
6
|
-
#
|
7
|
-
# Copyright January 2010, Michael Witrant. All Rights Reserved.
|
8
|
-
#
|
9
|
-
# This is free software. Please see the LICENSE and COPYING files for details
|
10
|
-
#
|
11
|
-
|
12
3
|
module PDF
|
13
4
|
module Core
|
5
|
+
# Graphics state saving and restoring
|
14
6
|
class GraphicStateStack
|
7
|
+
# Graphic state stack
|
15
8
|
attr_accessor :stack
|
16
9
|
|
10
|
+
# @param previous_state [GraphicState, nil]
|
17
11
|
def initialize(previous_state = nil)
|
18
12
|
self.stack = [GraphicState.new(previous_state)]
|
19
13
|
end
|
20
14
|
|
15
|
+
# Pushes graphic state onto stack
|
16
|
+
#
|
17
|
+
# @param graphic_state [GraphicState, nil]
|
18
|
+
# @return [void]
|
21
19
|
def save_graphic_state(graphic_state = nil)
|
22
20
|
stack.push(GraphicState.new(graphic_state || current_state))
|
23
21
|
end
|
24
22
|
|
23
|
+
# Restores previous graphic state
|
24
|
+
#
|
25
|
+
# @return [void]
|
25
26
|
def restore_graphic_state
|
26
27
|
if stack.empty?
|
27
28
|
raise PDF::Core::Errors::EmptyGraphicStateStack,
|
@@ -30,64 +31,107 @@ module PDF
|
|
30
31
|
stack.pop
|
31
32
|
end
|
32
33
|
|
34
|
+
# Current graphic state
|
35
|
+
#
|
36
|
+
# @return [GraphicState]
|
33
37
|
def current_state
|
34
38
|
stack.last
|
35
39
|
end
|
36
40
|
|
41
|
+
# Tells whether there are any saved graphic states
|
42
|
+
#
|
43
|
+
# @return [Boolean]
|
44
|
+
# @see #empty?
|
37
45
|
def present?
|
38
46
|
!stack.empty?
|
39
47
|
end
|
40
48
|
|
49
|
+
# Tells whether there are no saved graphic states
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
# @see #present?
|
41
53
|
def empty?
|
42
54
|
stack.empty?
|
43
55
|
end
|
44
56
|
end
|
45
57
|
|
58
|
+
# Graphics state.
|
59
|
+
# It's a *partial* represenation of PDF graphics state. Only the parts
|
60
|
+
# implemented in Prawn are present here.
|
61
|
+
#
|
46
62
|
# NOTE: This class may be a good candidate for a copy-on-write hash.
|
47
63
|
class GraphicState
|
48
|
-
|
49
|
-
|
64
|
+
# Color space
|
65
|
+
# @return [Hash]
|
66
|
+
attr_accessor :color_space
|
67
|
+
|
68
|
+
# Dash
|
69
|
+
# @return [Hash<[:dash, :space, :phase], [nil, Numeric]>]
|
70
|
+
attr_accessor :dash
|
71
|
+
|
72
|
+
# Line cap
|
73
|
+
# @return [Symbol]
|
74
|
+
attr_accessor :cap_style
|
75
|
+
|
76
|
+
# Line Join
|
77
|
+
# @return [Symbol]
|
78
|
+
attr_accessor :join_style
|
79
|
+
|
80
|
+
# Line width
|
81
|
+
# @return [Numberic]
|
82
|
+
attr_accessor :line_width
|
83
|
+
|
84
|
+
# Fill color
|
85
|
+
# @return [String]
|
86
|
+
attr_accessor :fill_color
|
87
|
+
|
88
|
+
# Stroke color
|
89
|
+
attr_accessor :stroke_color
|
50
90
|
|
91
|
+
# @param previous_state [GraphicState, nil]
|
51
92
|
def initialize(previous_state = nil)
|
52
93
|
if previous_state
|
53
94
|
initialize_copy(previous_state)
|
54
95
|
else
|
55
|
-
@color_space
|
56
|
-
@fill_color
|
96
|
+
@color_space = {}
|
97
|
+
@fill_color = '000000'
|
57
98
|
@stroke_color = '000000'
|
58
|
-
@dash
|
59
|
-
@cap_style
|
60
|
-
@join_style
|
61
|
-
@line_width
|
99
|
+
@dash = { dash: nil, space: nil, phase: 0 }
|
100
|
+
@cap_style = :butt
|
101
|
+
@join_style = :miter
|
102
|
+
@line_width = 1
|
62
103
|
end
|
63
104
|
end
|
64
105
|
|
106
|
+
# PDF representation of dash settings
|
107
|
+
#
|
108
|
+
# @return [String]
|
65
109
|
def dash_setting
|
66
110
|
return '[] 0 d' unless @dash[:dash]
|
67
111
|
|
68
|
-
array =
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
112
|
+
array =
|
113
|
+
if @dash[:dash].is_a?(Array)
|
114
|
+
@dash[:dash]
|
115
|
+
else
|
116
|
+
[@dash[:dash], @dash[:space]]
|
117
|
+
end
|
73
118
|
|
74
|
-
"[#{PDF::Core.real_params(array)}] "
|
75
|
-
"#{PDF::Core.real(@dash[:phase])} d"
|
119
|
+
"[#{PDF::Core.real_params(array)}] #{PDF::Core.real(@dash[:phase])} d"
|
76
120
|
end
|
77
121
|
|
78
122
|
private
|
79
123
|
|
80
124
|
def initialize_copy(other)
|
81
125
|
# mutable state
|
82
|
-
@color_space
|
83
|
-
@fill_color
|
126
|
+
@color_space = other.color_space.dup
|
127
|
+
@fill_color = other.fill_color.dup
|
84
128
|
@stroke_color = other.stroke_color.dup
|
85
|
-
@dash
|
129
|
+
@dash = other.dash.dup
|
86
130
|
|
87
131
|
# immutable state that doesn't need to be duped
|
88
|
-
@cap_style
|
89
|
-
@join_style
|
90
|
-
@line_width
|
132
|
+
@cap_style = other.cap_style
|
133
|
+
@join_style = other.join_style
|
134
|
+
@line_width = other.line_width
|
91
135
|
end
|
92
136
|
end
|
93
137
|
end
|
@@ -1,18 +1,17 @@
|
|
1
|
-
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module PDF
|
5
4
|
module Core
|
6
|
-
# This is used to differentiate strings that must be encoded as
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# This is used to differentiate strings that must be encoded as a *literal*
|
6
|
+
# string, versus those that can be encoded in the PDF hexadecimal format.
|
7
|
+
#
|
8
|
+
# Some features of the PDF format appear to require that literal strings be
|
9
|
+
# used. One such feature is the `Dest` key of a link annotation; if a hex
|
10
|
+
# encoded string is used there, the links do not work (as tested in Mac OS
|
11
|
+
# X Preview, and Adobe Acrobat Reader).
|
9
12
|
#
|
10
|
-
#
|
11
|
-
|
12
|
-
# annotation; if a hex encoded string is used there, the links
|
13
|
-
# do not work (as tested in Mac OS X Preview, and Adobe Acrobat
|
14
|
-
# Reader).
|
15
|
-
class LiteralString < String #:nodoc:
|
13
|
+
# @api private
|
14
|
+
class LiteralString < String
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
data/lib/pdf/core/name_tree.rb
CHANGED
@@ -2,22 +2,37 @@
|
|
2
2
|
|
3
3
|
require 'pdf/core/utils'
|
4
4
|
|
5
|
-
# name_tree.rb : Implements NameTree for PDF
|
6
|
-
#
|
7
|
-
# Copyright November 2008, Jamis Buck. All Rights Reserved.
|
8
|
-
#
|
9
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
10
|
-
#
|
11
5
|
module PDF
|
12
6
|
module Core
|
13
|
-
|
14
|
-
|
7
|
+
# Name Tree for PDF
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module NameTree
|
11
|
+
# Name Tree node
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
class Node
|
15
|
+
# Child nodes
|
16
|
+
# @return [Array<Node>]
|
15
17
|
attr_reader :children
|
18
|
+
|
19
|
+
# Children number limit
|
20
|
+
# @return [Integer]
|
16
21
|
attr_reader :limit
|
22
|
+
|
23
|
+
# @return [Prawn::Document]
|
17
24
|
attr_reader :document
|
25
|
+
|
26
|
+
# Parent node
|
27
|
+
# @return [Node]
|
18
28
|
attr_accessor :parent
|
29
|
+
|
30
|
+
# @return [Reference]
|
19
31
|
attr_accessor :ref
|
20
32
|
|
33
|
+
# @param document [Prawn::Document] owning document
|
34
|
+
# @param limit [Integer] Children limit
|
35
|
+
# @param parent [Node] Parent node
|
21
36
|
def initialize(document, limit, parent = nil)
|
22
37
|
@document = document
|
23
38
|
@children = []
|
@@ -26,22 +41,37 @@ module PDF
|
|
26
41
|
@ref = nil
|
27
42
|
end
|
28
43
|
|
44
|
+
# Tells whether there are any children nodes
|
45
|
+
#
|
46
|
+
# @return [Boolean]
|
29
47
|
def empty?
|
30
48
|
children.empty?
|
31
49
|
end
|
32
50
|
|
51
|
+
# Number of all (including nested) children nodes
|
52
|
+
#
|
53
|
+
# @return [Integer]
|
33
54
|
def size
|
34
|
-
leaf? ? children.size : children.
|
55
|
+
leaf? ? children.size : children.sum(&:size)
|
35
56
|
end
|
36
57
|
|
58
|
+
# Tells whether this is a leaf node. A leaf node is the one that has no
|
59
|
+
# children or only {Value} children.
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
37
62
|
def leaf?
|
38
63
|
children.empty? || children.first.is_a?(Value)
|
39
64
|
end
|
40
65
|
|
66
|
+
# Adds a value
|
67
|
+
#
|
68
|
+
# @param name [String]
|
69
|
+
# @param value [any]
|
41
70
|
def add(name, value)
|
42
71
|
self << Value.new(name, value)
|
43
72
|
end
|
44
73
|
|
74
|
+
# @return [Hash] a hash representation of this node
|
45
75
|
def to_hash
|
46
76
|
hash = {}
|
47
77
|
|
@@ -55,6 +85,7 @@ module PDF
|
|
55
85
|
hash
|
56
86
|
end
|
57
87
|
|
88
|
+
# @return [String] the least (in lexicographic order) value name
|
58
89
|
def least
|
59
90
|
if leaf?
|
60
91
|
children.first.name
|
@@ -63,6 +94,7 @@ module PDF
|
|
63
94
|
end
|
64
95
|
end
|
65
96
|
|
97
|
+
# @return [String] the greatest (in lexicographic order) value name
|
66
98
|
def greatest
|
67
99
|
if leaf?
|
68
100
|
children.last.name
|
@@ -71,6 +103,10 @@ module PDF
|
|
71
103
|
end
|
72
104
|
end
|
73
105
|
|
106
|
+
# Insert value maintaining order and rebalancing tree if needed.
|
107
|
+
#
|
108
|
+
# @param value [Value]
|
109
|
+
# @return [value]
|
74
110
|
def <<(value)
|
75
111
|
if children.empty?
|
76
112
|
children << value
|
@@ -78,7 +114,7 @@ module PDF
|
|
78
114
|
children.insert(insertion_point(value), value)
|
79
115
|
split! if children.length > limit
|
80
116
|
else
|
81
|
-
fit = children.
|
117
|
+
fit = children.find { |child| child >= value }
|
82
118
|
fit ||= children.last
|
83
119
|
fit << value
|
84
120
|
end
|
@@ -86,10 +122,19 @@ module PDF
|
|
86
122
|
value
|
87
123
|
end
|
88
124
|
|
125
|
+
# This is a compatibility method to allow uniform comparison between
|
126
|
+
# nodes and values.
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
# @return [Boolean]
|
130
|
+
# @see Value#<=>
|
89
131
|
def >=(other)
|
90
132
|
children.empty? || children.last >= other
|
91
133
|
end
|
92
134
|
|
135
|
+
# Split the tree at the node.
|
136
|
+
#
|
137
|
+
# @return [void]
|
93
138
|
def split!
|
94
139
|
if parent
|
95
140
|
parent.split(self)
|
@@ -102,13 +147,13 @@ module PDF
|
|
102
147
|
end
|
103
148
|
|
104
149
|
# Returns a deep copy of this node, without copying expensive things
|
105
|
-
# like the ref to
|
150
|
+
# like the `ref` to `document`.
|
106
151
|
#
|
152
|
+
# @return [Node]
|
107
153
|
def deep_copy
|
108
154
|
node = dup
|
109
|
-
node.instance_variable_set(
|
110
|
-
node.instance_variable_set(
|
111
|
-
node.ref ? node.ref.deep_copy : nil)
|
155
|
+
node.instance_variable_set(:@children, Utils.deep_clone(children))
|
156
|
+
node.instance_variable_set(:@ref, node.ref ? node.ref.deep_copy : nil)
|
112
157
|
node
|
113
158
|
end
|
114
159
|
|
@@ -134,7 +179,7 @@ module PDF
|
|
134
179
|
half = (node.limit + 1) / 2
|
135
180
|
|
136
181
|
left_children = node.children[0...half]
|
137
|
-
right_children = node.children[half
|
182
|
+
right_children = node.children[half..]
|
138
183
|
|
139
184
|
left.children.replace(left_children)
|
140
185
|
right.children.replace(right_children)
|
@@ -153,25 +198,40 @@ module PDF
|
|
153
198
|
end
|
154
199
|
end
|
155
200
|
|
156
|
-
|
201
|
+
# # Name Tree value
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
class Value
|
157
205
|
include Comparable
|
158
206
|
|
207
|
+
# @return [String]
|
159
208
|
attr_reader :name
|
209
|
+
|
210
|
+
# @return [any]
|
160
211
|
attr_reader :value
|
161
212
|
|
213
|
+
# @param name [String]
|
214
|
+
# @param value [any]
|
162
215
|
def initialize(name, value)
|
163
216
|
@name = PDF::Core::LiteralString.new(name)
|
164
217
|
@value = value
|
165
218
|
end
|
166
219
|
|
220
|
+
# @param other [Value]
|
221
|
+
# @return [-1, 0, 1]
|
222
|
+
# @see Object#<=>
|
223
|
+
# @see Enumerable
|
167
224
|
def <=>(other)
|
168
225
|
name <=> other.name
|
169
226
|
end
|
170
227
|
|
228
|
+
# @return [String] a string containing a human-readable representation
|
229
|
+
# of this value object
|
171
230
|
def inspect
|
172
231
|
"#<Value: #{name.inspect} : #{value.inspect}>"
|
173
232
|
end
|
174
233
|
|
234
|
+
# @return [String] a string representation of this value
|
175
235
|
def to_s
|
176
236
|
"#{name} : #{value}"
|
177
237
|
end
|
@@ -1,24 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Implements PDF object repository
|
4
|
-
#
|
5
|
-
# Copyright August 2009, Brad Ediger. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
|
9
3
|
module PDF
|
10
4
|
module Core
|
11
|
-
|
5
|
+
# PDF object repository
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class ObjectStore
|
12
9
|
include Enumerable
|
13
10
|
|
11
|
+
# Minimum PDF version
|
12
|
+
# @return [Float]
|
14
13
|
attr_reader :min_version
|
15
14
|
|
15
|
+
# @param opts [Hash]
|
16
|
+
# @option opts :info [Hash] Documnt info dict
|
17
|
+
# @option opts :print_scaling [:none, nil] (nil) Print scaling viewer
|
18
|
+
# option
|
16
19
|
def initialize(opts = {})
|
17
20
|
@objects = {}
|
18
21
|
@identifiers = []
|
19
22
|
|
20
|
-
@info
|
21
|
-
@root
|
23
|
+
@info ||= ref(opts[:info] || {}).identifier
|
24
|
+
@root ||= ref(Type: :Catalog).identifier
|
22
25
|
if opts[:print_scaling] == :none
|
23
26
|
root.data[:ViewerPreferences] = { PrintScaling: :None }
|
24
27
|
end
|
@@ -27,22 +30,39 @@ module PDF
|
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
30
|
-
|
31
|
-
|
33
|
+
# Wrap an object into a reference.
|
34
|
+
#
|
35
|
+
# @param data [Hash, Array, Numeric, String, Symbol, Date, Time, nil]
|
36
|
+
# object data
|
37
|
+
# @return [Reference]
|
38
|
+
def ref(data)
|
39
|
+
push(size + 1, data)
|
32
40
|
end
|
33
41
|
|
42
|
+
# Document info dict reference
|
43
|
+
#
|
44
|
+
# @return [Reference]
|
34
45
|
def info
|
35
46
|
@objects[@info]
|
36
47
|
end
|
37
48
|
|
49
|
+
# Document root dict reference
|
50
|
+
#
|
51
|
+
# @return [Reference]
|
38
52
|
def root
|
39
53
|
@objects[@root]
|
40
54
|
end
|
41
55
|
|
56
|
+
# Document pages reference
|
57
|
+
#
|
58
|
+
# @return [Reference]
|
42
59
|
def pages
|
43
60
|
root.data[:Pages]
|
44
61
|
end
|
45
62
|
|
63
|
+
# Number of pages in the document
|
64
|
+
#
|
65
|
+
# @return [Integer]
|
46
66
|
def page_count
|
47
67
|
pages.data[:Count]
|
48
68
|
end
|
@@ -51,12 +71,20 @@ module PDF
|
|
51
71
|
# If the object provided is not a PDF::Core::Reference, one is created
|
52
72
|
# from the arguments provided.
|
53
73
|
#
|
54
|
-
|
74
|
+
# @overload push(reference)
|
75
|
+
# @param reference [Reference]
|
76
|
+
# @return [reference]
|
77
|
+
# @overload push(id, data)
|
78
|
+
# @param id [Integer] reference identifier
|
79
|
+
# @param data [Hash, Array, Numeric, String, Symbol, Date, Time, nil]
|
80
|
+
# object data
|
81
|
+
# @return [Reference] - the added reference
|
82
|
+
def push(*args)
|
55
83
|
reference =
|
56
84
|
if args.first.is_a?(PDF::Core::Reference)
|
57
85
|
args.first
|
58
86
|
else
|
59
|
-
PDF::Core::Reference.new(*args
|
87
|
+
PDF::Core::Reference.new(*args)
|
60
88
|
end
|
61
89
|
|
62
90
|
@objects[reference.identifier] = reference
|
@@ -66,36 +94,58 @@ module PDF
|
|
66
94
|
|
67
95
|
alias << push
|
68
96
|
|
97
|
+
# Iterate over document object references.
|
98
|
+
#
|
99
|
+
# @yieldparam ref [Reference]
|
100
|
+
# @return [void]
|
69
101
|
def each
|
70
102
|
@identifiers.each do |id|
|
71
|
-
yield
|
103
|
+
yield(@objects[id])
|
72
104
|
end
|
73
105
|
end
|
74
106
|
|
107
|
+
# Get object reference by its identifier.
|
108
|
+
#
|
109
|
+
# @param id [Integer] object identifier
|
110
|
+
# @return [Reference]
|
75
111
|
def [](id)
|
76
112
|
@objects[id]
|
77
113
|
end
|
78
114
|
|
115
|
+
# Number of object references in the document.
|
116
|
+
#
|
117
|
+
# @return [Integer]
|
79
118
|
def size
|
80
119
|
@identifiers.size
|
81
120
|
end
|
82
121
|
alias length size
|
83
122
|
|
84
|
-
#
|
85
|
-
#
|
123
|
+
# Get page reference identifier by page number.Pages are indexed starting
|
124
|
+
# at 1 (**not 0**).
|
86
125
|
#
|
126
|
+
# @example
|
127
|
+
# !!!ruby
|
87
128
|
# object_id_for_page(1)
|
88
|
-
#
|
129
|
+
# #=> 5
|
89
130
|
# object_id_for_page(10)
|
90
|
-
#
|
131
|
+
# #=> 87
|
91
132
|
# object_id_for_page(-11)
|
92
|
-
#
|
133
|
+
# #=> 17
|
93
134
|
#
|
135
|
+
# @param page [Integer] page number
|
136
|
+
# @return [Integer] page object identifier
|
94
137
|
def object_id_for_page(page)
|
95
138
|
page -= 1 if page.positive?
|
96
139
|
flat_page_ids = get_page_objects(pages).flatten
|
97
140
|
flat_page_ids[page]
|
98
141
|
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# returns an array with the object IDs for all pages
|
146
|
+
def get_page_objects(pages)
|
147
|
+
pages.data[:Kids].map(&:identifier)
|
148
|
+
end
|
99
149
|
end
|
100
150
|
end
|
101
151
|
end
|
@@ -2,10 +2,55 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# Outline item.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
# @see # PDF 1.7 spec, section 8.2.2 Document Outline
|
9
|
+
class OutlineItem
|
10
|
+
# The total number of its open descendants at all lower levels of the
|
11
|
+
# outline hierarchy.
|
12
|
+
# @return [Integer]
|
13
|
+
attr_accessor :count
|
8
14
|
|
15
|
+
# The first of this item’s immediate children in the outline hierarchy.
|
16
|
+
# @return [Reference<PDF::Core::OutlineItem>]
|
17
|
+
attr_accessor :first
|
18
|
+
|
19
|
+
# The last of this item’s immediate children in the outline hierarchy.
|
20
|
+
# @return [Reference<PDF::Core::OutlineItem>]
|
21
|
+
attr_accessor :last
|
22
|
+
|
23
|
+
# The next item at this outline level.
|
24
|
+
# @return [Reference<PDF::Core::OutlineItem>]
|
25
|
+
attr_accessor :next
|
26
|
+
|
27
|
+
# The previous item at this outline level.
|
28
|
+
# @return [Reference<PDF::Core::OutlineItem>]
|
29
|
+
attr_accessor :prev
|
30
|
+
|
31
|
+
# The parent of this item in the outline hierarchy.
|
32
|
+
# @return [Reference<[PDF::Core::OutlineItem, PDF::Core::OutlineRoot]>]
|
33
|
+
attr_accessor :parent
|
34
|
+
|
35
|
+
# The text to be displayed on the screen for this item.
|
36
|
+
# @return [String]
|
37
|
+
attr_accessor :title
|
38
|
+
|
39
|
+
# The destination to be displayed when this item is activated.
|
40
|
+
# @return [String]
|
41
|
+
# @return [Symbol]
|
42
|
+
# @return [Array]
|
43
|
+
# @see Destinations
|
44
|
+
attr_accessor :dest
|
45
|
+
|
46
|
+
# Is this item open or closed.
|
47
|
+
# @return [Boolean]
|
48
|
+
attr_accessor :closed
|
49
|
+
|
50
|
+
# @param title [String]
|
51
|
+
# @param parent [PDF::Core::OutlineRoot, PDF::Core::OutlineItem]
|
52
|
+
# @param options [Hash]
|
53
|
+
# @option options :closed [Boolean]
|
9
54
|
def initialize(title, parent, options)
|
10
55
|
@closed = options[:closed]
|
11
56
|
@title = title
|
@@ -13,15 +58,18 @@ module PDF
|
|
13
58
|
@count = 0
|
14
59
|
end
|
15
60
|
|
61
|
+
# A hash representation of this outline item.
|
62
|
+
#
|
63
|
+
# @return [Hash]
|
16
64
|
def to_hash
|
17
65
|
hash = {
|
18
66
|
Title: title,
|
19
67
|
Parent: parent,
|
20
|
-
Count: closed ? -count : count
|
68
|
+
Count: closed ? -count : count,
|
21
69
|
}
|
22
70
|
[
|
23
71
|
{ First: first }, { Last: last }, { Next: defined?(@next) && @next },
|
24
|
-
{ Prev: prev }, { Dest: dest }
|
72
|
+
{ Prev: prev }, { Dest: dest },
|
25
73
|
].each do |h|
|
26
74
|
unless h.values.first.nil?
|
27
75
|
hash.merge!(h)
|
@@ -2,13 +2,29 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
-
|
6
|
-
|
5
|
+
# Document Outline root.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
# @see # PDF 1.7 spec, section 8.2.2 Document Outline
|
9
|
+
class OutlineRoot
|
10
|
+
# The total number of open items at all levels of the outline.
|
11
|
+
# @return [Integer]
|
12
|
+
attr_accessor :count
|
13
|
+
|
14
|
+
# The first top-level item in the outline.
|
15
|
+
# @return [Reference]
|
16
|
+
attr_accessor :first
|
17
|
+
|
18
|
+
# The last top-level item in the outline.
|
19
|
+
# @return [Reference]
|
20
|
+
attr_accessor :last
|
7
21
|
|
8
22
|
def initialize
|
9
23
|
@count = 0
|
10
24
|
end
|
11
25
|
|
26
|
+
# Hash representation of the outline root
|
27
|
+
# @return [Hash]
|
12
28
|
def to_hash
|
13
29
|
{ Type: :Outlines, Count: count, First: first, Last: last }
|
14
30
|
end
|