pdf-core 0.9.0 → 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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/pdf/core/annotations.rb +51 -13
- data/lib/pdf/core/byte_string.rb +3 -1
- data/lib/pdf/core/destinations.rb +64 -24
- data/lib/pdf/core/document_state.rb +97 -14
- data/lib/pdf/core/filter_list.rb +30 -1
- data/lib/pdf/core/filters.rb +26 -7
- data/lib/pdf/core/graphics_state.rb +68 -23
- data/lib/pdf/core/literal_string.rb +9 -9
- data/lib/pdf/core/name_tree.rb +74 -13
- data/lib/pdf/core/object_store.rb +69 -19
- data/lib/pdf/core/outline_item.rb +53 -4
- data/lib/pdf/core/outline_root.rb +18 -2
- data/lib/pdf/core/page.rb +148 -23
- data/lib/pdf/core/page_geometry.rb +4 -58
- data/lib/pdf/core/pdf_object.rb +57 -36
- data/lib/pdf/core/reference.rb +50 -14
- data/lib/pdf/core/renderer.rb +115 -44
- data/lib/pdf/core/stream.rb +38 -8
- data/lib/pdf/core/text.rb +242 -102
- data/lib/pdf/core/utils.rb +8 -0
- data/lib/pdf/core.rb +26 -16
- data/pdf-core.gemspec +27 -23
- data.tar.gz.sig +0 -0
- metadata +44 -107
- metadata.gz.sig +2 -2
- data/Gemfile +0 -5
- data/Rakefile +0 -29
@@ -1,26 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# Implements graphics state saving and restoring
|
5
|
-
#
|
6
|
-
# Copyright January 2010, Michael Witrant. All Rights Reserved.
|
7
|
-
#
|
8
|
-
# This is free software. Please see the LICENSE and COPYING files for details
|
9
|
-
#
|
10
|
-
|
11
3
|
module PDF
|
12
4
|
module Core
|
5
|
+
# Graphics state saving and restoring
|
13
6
|
class GraphicStateStack
|
7
|
+
# Graphic state stack
|
14
8
|
attr_accessor :stack
|
15
9
|
|
10
|
+
# @param previous_state [GraphicState, nil]
|
16
11
|
def initialize(previous_state = nil)
|
17
12
|
self.stack = [GraphicState.new(previous_state)]
|
18
13
|
end
|
19
14
|
|
15
|
+
# Pushes graphic state onto stack
|
16
|
+
#
|
17
|
+
# @param graphic_state [GraphicState, nil]
|
18
|
+
# @return [void]
|
20
19
|
def save_graphic_state(graphic_state = nil)
|
21
20
|
stack.push(GraphicState.new(graphic_state || current_state))
|
22
21
|
end
|
23
22
|
|
23
|
+
# Restores previous graphic state
|
24
|
+
#
|
25
|
+
# @return [void]
|
24
26
|
def restore_graphic_state
|
25
27
|
if stack.empty?
|
26
28
|
raise PDF::Core::Errors::EmptyGraphicStateStack,
|
@@ -29,37 +31,81 @@ module PDF
|
|
29
31
|
stack.pop
|
30
32
|
end
|
31
33
|
|
34
|
+
# Current graphic state
|
35
|
+
#
|
36
|
+
# @return [GraphicState]
|
32
37
|
def current_state
|
33
38
|
stack.last
|
34
39
|
end
|
35
40
|
|
41
|
+
# Tells whether there are any saved graphic states
|
42
|
+
#
|
43
|
+
# @return [Boolean]
|
44
|
+
# @see #empty?
|
36
45
|
def present?
|
37
46
|
!stack.empty?
|
38
47
|
end
|
39
48
|
|
49
|
+
# Tells whether there are no saved graphic states
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
# @see #present?
|
40
53
|
def empty?
|
41
54
|
stack.empty?
|
42
55
|
end
|
43
56
|
end
|
44
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
|
+
#
|
45
62
|
# NOTE: This class may be a good candidate for a copy-on-write hash.
|
46
63
|
class GraphicState
|
47
|
-
|
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
|
48
90
|
|
91
|
+
# @param previous_state [GraphicState, nil]
|
49
92
|
def initialize(previous_state = nil)
|
50
93
|
if previous_state
|
51
94
|
initialize_copy(previous_state)
|
52
95
|
else
|
53
|
-
@color_space
|
54
|
-
@fill_color
|
96
|
+
@color_space = {}
|
97
|
+
@fill_color = '000000'
|
55
98
|
@stroke_color = '000000'
|
56
|
-
@dash
|
57
|
-
@cap_style
|
58
|
-
@join_style
|
59
|
-
@line_width
|
99
|
+
@dash = { dash: nil, space: nil, phase: 0 }
|
100
|
+
@cap_style = :butt
|
101
|
+
@join_style = :miter
|
102
|
+
@line_width = 1
|
60
103
|
end
|
61
104
|
end
|
62
105
|
|
106
|
+
# PDF representation of dash settings
|
107
|
+
#
|
108
|
+
# @return [String]
|
63
109
|
def dash_setting
|
64
110
|
return '[] 0 d' unless @dash[:dash]
|
65
111
|
|
@@ -70,23 +116,22 @@ module PDF
|
|
70
116
|
[@dash[:dash], @dash[:space]]
|
71
117
|
end
|
72
118
|
|
73
|
-
"[#{PDF::Core.real_params(array)}] "
|
74
|
-
"#{PDF::Core.real(@dash[:phase])} d"
|
119
|
+
"[#{PDF::Core.real_params(array)}] #{PDF::Core.real(@dash[:phase])} d"
|
75
120
|
end
|
76
121
|
|
77
122
|
private
|
78
123
|
|
79
124
|
def initialize_copy(other)
|
80
125
|
# mutable state
|
81
|
-
@color_space
|
82
|
-
@fill_color
|
126
|
+
@color_space = other.color_space.dup
|
127
|
+
@fill_color = other.fill_color.dup
|
83
128
|
@stroke_color = other.stroke_color.dup
|
84
|
-
@dash
|
129
|
+
@dash = other.dash.dup
|
85
130
|
|
86
131
|
# immutable state that doesn't need to be duped
|
87
|
-
@cap_style
|
88
|
-
@join_style
|
89
|
-
@line_width
|
132
|
+
@cap_style = other.cap_style
|
133
|
+
@join_style = other.join_style
|
134
|
+
@line_width = other.line_width
|
90
135
|
end
|
91
136
|
end
|
92
137
|
end
|
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
-
# This is used to differentiate strings that must be encoded as
|
6
|
-
#
|
7
|
-
# the PDF hexadecimal format.
|
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.
|
8
7
|
#
|
9
|
-
# Some features of the PDF format appear to require that literal
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
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).
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
class LiteralString < String
|
15
15
|
end
|
16
16
|
end
|
17
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
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
|
@@ -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,12 +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(
|
155
|
+
node.instance_variable_set(:@children, Utils.deep_clone(children))
|
156
|
+
node.instance_variable_set(:@ref, node.ref ? node.ref.deep_copy : nil)
|
111
157
|
node
|
112
158
|
end
|
113
159
|
|
@@ -133,7 +179,7 @@ module PDF
|
|
133
179
|
half = (node.limit + 1) / 2
|
134
180
|
|
135
181
|
left_children = node.children[0...half]
|
136
|
-
right_children = node.children[half
|
182
|
+
right_children = node.children[half..]
|
137
183
|
|
138
184
|
left.children.replace(left_children)
|
139
185
|
right.children.replace(right_children)
|
@@ -152,25 +198,40 @@ module PDF
|
|
152
198
|
end
|
153
199
|
end
|
154
200
|
|
155
|
-
|
201
|
+
# # Name Tree value
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
class Value
|
156
205
|
include Comparable
|
157
206
|
|
207
|
+
# @return [String]
|
158
208
|
attr_reader :name
|
209
|
+
|
210
|
+
# @return [any]
|
159
211
|
attr_reader :value
|
160
212
|
|
213
|
+
# @param name [String]
|
214
|
+
# @param value [any]
|
161
215
|
def initialize(name, value)
|
162
216
|
@name = PDF::Core::LiteralString.new(name)
|
163
217
|
@value = value
|
164
218
|
end
|
165
219
|
|
220
|
+
# @param other [Value]
|
221
|
+
# @return [-1, 0, 1]
|
222
|
+
# @see Object#<=>
|
223
|
+
# @see Enumerable
|
166
224
|
def <=>(other)
|
167
225
|
name <=> other.name
|
168
226
|
end
|
169
227
|
|
228
|
+
# @return [String] a string containing a human-readable representation
|
229
|
+
# of this value object
|
170
230
|
def inspect
|
171
231
|
"#<Value: #{name.inspect} : #{value.inspect}>"
|
172
232
|
end
|
173
233
|
|
234
|
+
# @return [String] a string representation of this value
|
174
235
|
def to_s
|
175
236
|
"#{name} : #{value}"
|
176
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,9 +2,55 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
-
|
6
|
-
|
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
|
7
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]
|
8
54
|
def initialize(title, parent, options)
|
9
55
|
@closed = options[:closed]
|
10
56
|
@title = title
|
@@ -12,15 +58,18 @@ module PDF
|
|
12
58
|
@count = 0
|
13
59
|
end
|
14
60
|
|
61
|
+
# A hash representation of this outline item.
|
62
|
+
#
|
63
|
+
# @return [Hash]
|
15
64
|
def to_hash
|
16
65
|
hash = {
|
17
66
|
Title: title,
|
18
67
|
Parent: parent,
|
19
|
-
Count: closed ? -count : count
|
68
|
+
Count: closed ? -count : count,
|
20
69
|
}
|
21
70
|
[
|
22
71
|
{ First: first }, { Last: last }, { Next: defined?(@next) && @next },
|
23
|
-
{ Prev: prev }, { Dest: dest }
|
72
|
+
{ Prev: prev }, { Dest: dest },
|
24
73
|
].each do |h|
|
25
74
|
unless h.values.first.nil?
|
26
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
|