pdf-core 0.8.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|