pdf-core 0.4.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/pdf/core/annotations.rb +58 -21
- data/lib/pdf/core/byte_string.rb +6 -3
- data/lib/pdf/core/destinations.rb +77 -34
- data/lib/pdf/core/document_state.rb +121 -30
- data/lib/pdf/core/filter_list.rb +47 -6
- data/lib/pdf/core/filters.rb +31 -12
- data/lib/pdf/core/graphics_state.rb +80 -32
- data/lib/pdf/core/literal_string.rb +11 -10
- data/lib/pdf/core/name_tree.rb +118 -54
- data/lib/pdf/core/object_store.rb +82 -37
- data/lib/pdf/core/outline_item.rb +62 -7
- data/lib/pdf/core/outline_root.rb +21 -3
- data/lib/pdf/core/page.rb +232 -77
- data/lib/pdf/core/page_geometry.rb +56 -112
- data/lib/pdf/core/pdf_object.rb +93 -57
- data/lib/pdf/core/reference.rb +70 -30
- data/lib/pdf/core/renderer.rb +149 -68
- data/lib/pdf/core/stream.rb +48 -12
- data/lib/pdf/core/text.rb +300 -106
- data/lib/pdf/core/utils.rb +21 -0
- data/lib/pdf/core.rb +38 -25
- data/pdf-core.gemspec +43 -24
- data.tar.gz.sig +0 -0
- metadata +56 -64
- metadata.gz.sig +2 -0
- data/Gemfile +0 -3
- data/Rakefile +0 -11
- 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/renderer.rb
CHANGED
|
@@ -1,107 +1,136 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'stringio'
|
|
2
4
|
|
|
3
5
|
module PDF
|
|
4
6
|
module Core
|
|
7
|
+
# Document renderer serializes document into its binary representation.
|
|
5
8
|
class Renderer
|
|
9
|
+
# @param state [PDF::Core::DocumentState]
|
|
6
10
|
def initialize(state)
|
|
7
11
|
@state = state
|
|
8
12
|
@state.populate_pages_from_store(self)
|
|
9
|
-
|
|
13
|
+
|
|
10
14
|
min_version(state.store.min_version) if state.store.min_version
|
|
11
15
|
|
|
12
16
|
@page_number = 0
|
|
13
17
|
end
|
|
14
18
|
|
|
19
|
+
# Document state
|
|
20
|
+
# @return [PDF::Core::DocumentState]
|
|
15
21
|
attr_reader :state
|
|
16
22
|
|
|
17
|
-
# Creates a new Reference and adds it to the Document's object
|
|
18
|
-
# list. The +data+ argument is anything that Prawn::PdfObject() can convert.
|
|
19
|
-
#
|
|
20
|
-
# Returns the identifier which points to the reference in the ObjectStore
|
|
23
|
+
# Creates a new Reference and adds it to the Document's object list.
|
|
21
24
|
#
|
|
25
|
+
# @param data [any] anything that {PDF::Core.pdf_object} can convert.
|
|
26
|
+
# @return [Integer] the identifier of the reference
|
|
22
27
|
def ref(data)
|
|
23
28
|
ref!(data).identifier
|
|
24
29
|
end
|
|
25
30
|
|
|
26
|
-
# Like ref, but returns the actual reference instead of its identifier.
|
|
31
|
+
# Like {ref}, but returns the actual reference instead of its identifier.
|
|
27
32
|
#
|
|
28
33
|
# While you can use this to build up nested references within the object
|
|
29
34
|
# tree, it is recommended to persist only identifiers, and then provide
|
|
30
|
-
# helper methods to look up the actual references in the ObjectStore
|
|
31
|
-
#
|
|
32
|
-
#
|
|
35
|
+
# helper methods to look up the actual references in the {ObjectStore} if
|
|
36
|
+
# needed. If you take this approach, `Document::Snapshot` will probably
|
|
37
|
+
# work with your extension.
|
|
33
38
|
#
|
|
39
|
+
# @param data [any] anything that {PDF::Core.pdf_object} can convert.
|
|
40
|
+
# @return [PDF::Core::Reference]
|
|
34
41
|
def ref!(data)
|
|
35
42
|
state.store.ref(data)
|
|
36
43
|
end
|
|
37
44
|
|
|
38
45
|
# At any stage in the object tree an object can be replaced with an
|
|
39
46
|
# indirect reference. To get access to the object safely, regardless
|
|
40
|
-
# of if it's hidden behind a
|
|
47
|
+
# of if it's hidden behind a {Reference}, wrap it in `deref()`.
|
|
41
48
|
#
|
|
49
|
+
# @param obj [PDF::Core::Reference, any]
|
|
50
|
+
# @return [any]
|
|
42
51
|
def deref(obj)
|
|
43
52
|
obj.is_a?(PDF::Core::Reference) ? obj.data : obj
|
|
44
53
|
end
|
|
45
54
|
|
|
46
55
|
# Appends a raw string to the current page content.
|
|
47
56
|
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
|
|
51
|
-
# pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
|
|
52
|
-
# pdf.add_content("S") # stroke
|
|
57
|
+
# @example Raw line drawing example
|
|
58
|
+
# x1, y1, x2, y2 = 100, 500, 300, 550
|
|
53
59
|
#
|
|
60
|
+
# pdf.add_content("#{PDF::Core.real_params([x1, y1])} m") # move
|
|
61
|
+
# pdf.add_content("#{PDF::Core.real_params([ x2, y2 ])} l") # draw path
|
|
62
|
+
# pdf.add_content('S') # stroke
|
|
63
|
+
#
|
|
64
|
+
# @param str [String]
|
|
65
|
+
# @return [void]
|
|
54
66
|
def add_content(str)
|
|
55
67
|
save_graphics_state if graphic_state.nil?
|
|
56
68
|
state.page.content << str << "\n"
|
|
57
69
|
end
|
|
58
70
|
|
|
59
|
-
# The Name dictionary
|
|
60
|
-
#
|
|
61
|
-
#
|
|
71
|
+
# The Name dictionary for this document. It is lazily initialized, so that
|
|
72
|
+
# documents that do not need a name dictionary do not incur the additional
|
|
73
|
+
# overhead.
|
|
62
74
|
#
|
|
75
|
+
# @return [PDF::Core::Reference<Hash>]
|
|
76
|
+
# @see # PDF 1.7 spec, section 3.6.3 Name Dictionary
|
|
63
77
|
def names
|
|
64
|
-
state.store.root.data[:Names] ||= ref!(:
|
|
78
|
+
state.store.root.data[:Names] ||= ref!(Type: :Names)
|
|
65
79
|
end
|
|
66
80
|
|
|
67
81
|
# Returns true if the Names dictionary is in use for this document.
|
|
68
82
|
#
|
|
83
|
+
# @return [Boolean]
|
|
69
84
|
def names?
|
|
70
|
-
state.store.root.data
|
|
85
|
+
state.store.root.data.key?(:Names)
|
|
71
86
|
end
|
|
72
87
|
|
|
73
88
|
# Defines a block to be called just before the document is rendered.
|
|
74
89
|
#
|
|
90
|
+
# @yieldparam document_state [PDF::Core::DocumentState]
|
|
91
|
+
# @return [void]
|
|
75
92
|
def before_render(&block)
|
|
76
93
|
state.before_render_callbacks << block
|
|
77
94
|
end
|
|
78
95
|
|
|
79
96
|
# Defines a block to be called just before a new page is started.
|
|
80
97
|
#
|
|
98
|
+
# @yieldparam document_state [PDF::Core::DocumentState]
|
|
99
|
+
# @return [void]
|
|
81
100
|
def on_page_create(&block)
|
|
82
|
-
|
|
83
|
-
state.on_page_create_callback = block
|
|
84
|
-
else
|
|
85
|
-
state.on_page_create_callback = nil
|
|
86
|
-
end
|
|
101
|
+
state.on_page_create_callback = block
|
|
87
102
|
end
|
|
88
103
|
|
|
104
|
+
# Create a new page and set it current.
|
|
105
|
+
#
|
|
106
|
+
# @param options [Hash]
|
|
107
|
+
# @option options :size [String, Array<Numeric>]
|
|
108
|
+
# @option options :layout [:portrait, :landscape]
|
|
109
|
+
# @return [void]
|
|
89
110
|
def start_new_page(options = {})
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
last_page = state.page
|
|
112
|
+
if last_page
|
|
113
|
+
last_page_size = last_page.size
|
|
114
|
+
last_page_layout = last_page.layout
|
|
93
115
|
last_page_margins = last_page.margins
|
|
94
116
|
end
|
|
95
117
|
|
|
96
|
-
page_options = {
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
page_options = {
|
|
119
|
+
size: options[:size] || last_page_size,
|
|
120
|
+
layout: options[:layout] || last_page_layout,
|
|
121
|
+
margins: last_page_margins,
|
|
122
|
+
}
|
|
99
123
|
if last_page
|
|
100
|
-
|
|
124
|
+
if last_page.graphic_state
|
|
125
|
+
new_graphic_state = last_page.graphic_state.dup
|
|
126
|
+
end
|
|
101
127
|
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
# Erase the color space so that it gets reset on new page for fussy
|
|
129
|
+
# pdf-readers
|
|
130
|
+
if new_graphic_state
|
|
131
|
+
new_graphic_state.color_space = {}
|
|
132
|
+
end
|
|
133
|
+
page_options[:graphic_state] = new_graphic_state
|
|
105
134
|
end
|
|
106
135
|
|
|
107
136
|
state.page = PDF::Core::Page.new(self, page_options)
|
|
@@ -112,6 +141,9 @@ module PDF
|
|
|
112
141
|
state.on_page_create_action(self)
|
|
113
142
|
end
|
|
114
143
|
|
|
144
|
+
# Number of pages in the document.
|
|
145
|
+
#
|
|
146
|
+
# @return [Integer]
|
|
115
147
|
def page_count
|
|
116
148
|
state.page_count
|
|
117
149
|
end
|
|
@@ -119,16 +151,21 @@ module PDF
|
|
|
119
151
|
# Re-opens the page with the given (1-based) page number so that you can
|
|
120
152
|
# draw on it.
|
|
121
153
|
#
|
|
122
|
-
#
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
# @param page_number [Integer]
|
|
155
|
+
# @return [void]
|
|
156
|
+
# @see # Prawn::Document#number_pages for a sample usage of this capability.
|
|
157
|
+
def go_to_page(page_number)
|
|
158
|
+
@page_number = page_number
|
|
159
|
+
state.page = state.pages[page_number - 1]
|
|
127
160
|
end
|
|
128
161
|
|
|
162
|
+
# Finalize all pages
|
|
163
|
+
#
|
|
164
|
+
# @api private
|
|
165
|
+
# @return [void]
|
|
129
166
|
def finalize_all_page_contents
|
|
130
167
|
(1..page_count).each do |i|
|
|
131
|
-
go_to_page
|
|
168
|
+
go_to_page(i)
|
|
132
169
|
while graphic_stack.present?
|
|
133
170
|
restore_graphics_state
|
|
134
171
|
end
|
|
@@ -136,10 +173,13 @@ module PDF
|
|
|
136
173
|
end
|
|
137
174
|
end
|
|
138
175
|
|
|
139
|
-
#
|
|
176
|
+
# Raise the PDF version of the file we're going to generate.
|
|
140
177
|
# A private method, designed for internal use when the user adds a feature
|
|
141
178
|
# to their document that requires a particular version.
|
|
142
179
|
#
|
|
180
|
+
# @param min [Float]
|
|
181
|
+
# @return [void]
|
|
182
|
+
# @api private
|
|
143
183
|
def min_version(min)
|
|
144
184
|
state.version = min if min > state.version
|
|
145
185
|
end
|
|
@@ -147,35 +187,41 @@ module PDF
|
|
|
147
187
|
# Renders the PDF document to string.
|
|
148
188
|
# Pass an open file descriptor to render to file.
|
|
149
189
|
#
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
190
|
+
# @param output [#<<]
|
|
191
|
+
# @return [String]
|
|
192
|
+
def render(output = nil)
|
|
193
|
+
buffer = StringIO.new.binmode
|
|
194
|
+
|
|
154
195
|
finalize_all_page_contents
|
|
155
196
|
|
|
156
|
-
render_header(
|
|
157
|
-
render_body(
|
|
158
|
-
render_xref(
|
|
159
|
-
render_trailer(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return str
|
|
164
|
-
else
|
|
165
|
-
return nil
|
|
197
|
+
render_header(buffer)
|
|
198
|
+
render_body(buffer)
|
|
199
|
+
render_xref(buffer)
|
|
200
|
+
render_trailer(buffer)
|
|
201
|
+
|
|
202
|
+
if output.respond_to?(:<<)
|
|
203
|
+
output << buffer.string
|
|
166
204
|
end
|
|
205
|
+
|
|
206
|
+
buffer.string
|
|
167
207
|
end
|
|
168
208
|
|
|
169
209
|
# Renders the PDF document to file.
|
|
170
210
|
#
|
|
171
|
-
#
|
|
211
|
+
# @example
|
|
212
|
+
# pdf.render_file 'foo.pdf'
|
|
172
213
|
#
|
|
214
|
+
# @param filename [String, #to_path, Integer]
|
|
215
|
+
# @return [void]
|
|
173
216
|
def render_file(filename)
|
|
174
|
-
File.open(filename,
|
|
217
|
+
File.open(filename, 'wb') { |f| render(f) }
|
|
175
218
|
end
|
|
176
219
|
|
|
177
220
|
# Write out the PDF Header, as per spec 3.4.1
|
|
178
221
|
#
|
|
222
|
+
# @api private
|
|
223
|
+
# @param output [#<<]
|
|
224
|
+
# @return [void]
|
|
179
225
|
def render_header(output)
|
|
180
226
|
state.before_render_actions(self)
|
|
181
227
|
|
|
@@ -188,46 +234,72 @@ module PDF
|
|
|
188
234
|
|
|
189
235
|
# Write out the PDF Body, as per spec 3.4.2
|
|
190
236
|
#
|
|
237
|
+
# @api private
|
|
238
|
+
# @param output [(#<<, #size)]
|
|
239
|
+
# @return [void]
|
|
191
240
|
def render_body(output)
|
|
192
241
|
state.render_body(output)
|
|
193
242
|
end
|
|
194
243
|
|
|
195
244
|
# Write out the PDF Cross Reference Table, as per spec 3.4.3
|
|
196
245
|
#
|
|
246
|
+
# @api private
|
|
247
|
+
# @param output [(#<<, #size)]
|
|
248
|
+
# @return [void]
|
|
197
249
|
def render_xref(output)
|
|
198
250
|
@xref_offset = output.size
|
|
199
251
|
output << "xref\n"
|
|
200
252
|
output << "0 #{state.store.size + 1}\n"
|
|
201
253
|
output << "0000000000 65535 f \n"
|
|
202
254
|
state.store.each do |ref|
|
|
203
|
-
output.printf(
|
|
255
|
+
output.printf('%<offset>010d', offset: ref.offset)
|
|
204
256
|
output << " 00000 n \n"
|
|
205
257
|
end
|
|
206
258
|
end
|
|
207
259
|
|
|
208
260
|
# Write out the PDF Trailer, as per spec 3.4.4
|
|
209
261
|
#
|
|
262
|
+
# @api private
|
|
263
|
+
# @param output [#<<]
|
|
264
|
+
# @return [void]
|
|
210
265
|
def render_trailer(output)
|
|
211
|
-
trailer_hash = {
|
|
212
|
-
|
|
213
|
-
|
|
266
|
+
trailer_hash = {
|
|
267
|
+
Size: state.store.size + 1,
|
|
268
|
+
Root: state.store.root,
|
|
269
|
+
Info: state.store.info,
|
|
270
|
+
}
|
|
214
271
|
trailer_hash.merge!(state.trailer) if state.trailer
|
|
215
272
|
|
|
216
273
|
output << "trailer\n"
|
|
217
|
-
output << PDF::Core
|
|
274
|
+
output << PDF::Core.pdf_object(trailer_hash) << "\n"
|
|
218
275
|
output << "startxref\n"
|
|
219
276
|
output << @xref_offset << "\n"
|
|
220
|
-
output <<
|
|
277
|
+
output << '%%EOF' << "\n"
|
|
221
278
|
end
|
|
222
279
|
|
|
280
|
+
# Open (save) current graphic state in the content stream.
|
|
281
|
+
#
|
|
282
|
+
# @return [void]
|
|
223
283
|
def open_graphics_state
|
|
224
|
-
add_content
|
|
284
|
+
add_content('q')
|
|
225
285
|
end
|
|
226
286
|
|
|
287
|
+
# Close current graphic state (restore previous) in the content stream.
|
|
288
|
+
#
|
|
289
|
+
# @return [void]
|
|
227
290
|
def close_graphics_state
|
|
228
|
-
add_content
|
|
291
|
+
add_content('Q')
|
|
229
292
|
end
|
|
230
293
|
|
|
294
|
+
# Save surrent graphic state both in the graphic state stack and in the
|
|
295
|
+
# page content stream.
|
|
296
|
+
#
|
|
297
|
+
# If a block is given graphic state is automatically restored after the
|
|
298
|
+
# block execution.
|
|
299
|
+
#
|
|
300
|
+
# @param graphic_state [PDF::Core::GraphicState]
|
|
301
|
+
# @yield
|
|
302
|
+
# @return [void]
|
|
231
303
|
def save_graphics_state(graphic_state = nil)
|
|
232
304
|
graphic_stack.save_graphic_state(graphic_state)
|
|
233
305
|
open_graphics_state
|
|
@@ -240,12 +312,15 @@ module PDF
|
|
|
240
312
|
# Returns true if content streams will be compressed before rendering,
|
|
241
313
|
# false otherwise
|
|
242
314
|
#
|
|
315
|
+
# @return [Boolean]
|
|
243
316
|
def compression_enabled?
|
|
244
|
-
|
|
317
|
+
state.compress
|
|
245
318
|
end
|
|
246
319
|
|
|
247
320
|
# Pops the last saved graphics state off the graphics state stack and
|
|
248
321
|
# restores the state to those values
|
|
322
|
+
#
|
|
323
|
+
# @return [void]
|
|
249
324
|
def restore_graphics_state
|
|
250
325
|
if graphic_stack.empty?
|
|
251
326
|
raise PDF::Core::Errors::EmptyGraphicStateStack,
|
|
@@ -255,10 +330,16 @@ module PDF
|
|
|
255
330
|
graphic_stack.restore_graphic_state
|
|
256
331
|
end
|
|
257
332
|
|
|
333
|
+
# Graphic state stack of the current document.
|
|
334
|
+
#
|
|
335
|
+
# @return [PDF::Core::GraphicStateStack]
|
|
258
336
|
def graphic_stack
|
|
259
337
|
state.page.stack
|
|
260
338
|
end
|
|
261
339
|
|
|
340
|
+
# Current graphic state
|
|
341
|
+
#
|
|
342
|
+
# @return [PDF::Core::GraphicState]
|
|
262
343
|
def graphic_state
|
|
263
344
|
save_graphics_state unless graphic_stack.current_state
|
|
264
345
|
graphic_stack.current_state
|
data/lib/pdf/core/stream.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# prawn/core/stream.rb : Implements Stream objects
|
|
4
4
|
#
|
|
@@ -8,59 +8,83 @@
|
|
|
8
8
|
|
|
9
9
|
module PDF
|
|
10
10
|
module Core
|
|
11
|
+
# PDF Stream object
|
|
11
12
|
class Stream
|
|
13
|
+
# Stream filters
|
|
14
|
+
# @return [PDF::Core::FilterList]
|
|
12
15
|
attr_reader :filters
|
|
13
16
|
|
|
17
|
+
# @param io [String] must be mutable
|
|
14
18
|
def initialize(io = nil)
|
|
15
19
|
@filtered_stream = ''
|
|
16
20
|
@stream = io
|
|
17
21
|
@filters = FilterList.new
|
|
18
22
|
end
|
|
19
23
|
|
|
24
|
+
# Append data to stream.
|
|
25
|
+
#
|
|
26
|
+
# @param io [String]
|
|
27
|
+
# @return [self]
|
|
20
28
|
def <<(io)
|
|
21
|
-
(@stream ||= '') << io
|
|
29
|
+
(@stream ||= +'') << io
|
|
22
30
|
@filtered_stream = nil
|
|
23
31
|
self
|
|
24
32
|
end
|
|
25
33
|
|
|
34
|
+
# Set up stream to be compressed when serialized.
|
|
35
|
+
#
|
|
36
|
+
# @return [void]
|
|
26
37
|
def compress!
|
|
27
|
-
unless @filters.names.include?
|
|
38
|
+
unless @filters.names.include?(:FlateDecode)
|
|
28
39
|
@filtered_stream = nil
|
|
29
40
|
@filters << :FlateDecode
|
|
30
41
|
end
|
|
31
42
|
end
|
|
32
43
|
|
|
44
|
+
# Is this stream compressed?
|
|
45
|
+
#
|
|
46
|
+
# @return [Boolean]
|
|
33
47
|
def compressed?
|
|
34
|
-
@filters.names.include?
|
|
48
|
+
@filters.names.include?(:FlateDecode)
|
|
35
49
|
end
|
|
36
50
|
|
|
51
|
+
# Is there any data in this stream?
|
|
52
|
+
#
|
|
53
|
+
# @return [Boolean]
|
|
37
54
|
def empty?
|
|
38
55
|
@stream.nil?
|
|
39
56
|
end
|
|
40
57
|
|
|
58
|
+
# Stream data with filters applied.
|
|
59
|
+
#
|
|
60
|
+
# @return [Stream]
|
|
41
61
|
def filtered_stream
|
|
42
62
|
if @stream
|
|
43
63
|
if @filtered_stream.nil?
|
|
44
64
|
@filtered_stream = @stream.dup
|
|
45
65
|
|
|
46
66
|
@filters.each do |(filter_name, params)|
|
|
47
|
-
|
|
48
|
-
|
|
67
|
+
filter = PDF::Core::Filters.const_get(filter_name)
|
|
68
|
+
if filter
|
|
69
|
+
@filtered_stream = filter.encode(@filtered_stream, params)
|
|
49
70
|
end
|
|
50
71
|
end
|
|
51
72
|
end
|
|
52
73
|
|
|
53
74
|
@filtered_stream
|
|
54
|
-
# XXX Fillter stream
|
|
55
|
-
else
|
|
56
|
-
nil
|
|
57
75
|
end
|
|
58
76
|
end
|
|
59
77
|
|
|
78
|
+
# Size of data in the stream
|
|
79
|
+
#
|
|
80
|
+
# @return [Integer]
|
|
60
81
|
def length
|
|
61
82
|
@stream.length
|
|
62
83
|
end
|
|
63
84
|
|
|
85
|
+
# Serialized stream data
|
|
86
|
+
#
|
|
87
|
+
# @return [String]
|
|
64
88
|
def object
|
|
65
89
|
if filtered_stream
|
|
66
90
|
"stream\n#{filtered_stream}\nendstream\n"
|
|
@@ -69,18 +93,21 @@ module PDF
|
|
|
69
93
|
end
|
|
70
94
|
end
|
|
71
95
|
|
|
96
|
+
# Stream dictionary
|
|
97
|
+
#
|
|
98
|
+
# @return [Hash]
|
|
72
99
|
def data
|
|
73
100
|
if @stream
|
|
74
101
|
filter_names = @filters.names
|
|
75
102
|
filter_params = @filters.decode_params
|
|
76
103
|
|
|
77
104
|
d = {
|
|
78
|
-
:
|
|
105
|
+
Length: filtered_stream.length,
|
|
79
106
|
}
|
|
80
107
|
if filter_names.any?
|
|
81
108
|
d[:Filter] = filter_names
|
|
82
109
|
end
|
|
83
|
-
if filter_params.any? {|f| !f.nil? }
|
|
110
|
+
if filter_params.any? { |f| !f.nil? }
|
|
84
111
|
d[:DecodeParms] = filter_params
|
|
85
112
|
end
|
|
86
113
|
|
|
@@ -90,8 +117,17 @@ module PDF
|
|
|
90
117
|
end
|
|
91
118
|
end
|
|
92
119
|
|
|
120
|
+
# String representation of the stream for debugging purposes.
|
|
121
|
+
#
|
|
122
|
+
# @return [String]
|
|
93
123
|
def inspect
|
|
94
|
-
|
|
124
|
+
format(
|
|
125
|
+
'#<%<class>s:0x%<object_id>014x @stream=%<stream>s, @filters=%<filters>s>',
|
|
126
|
+
class: self.class.name,
|
|
127
|
+
object_id: object_id,
|
|
128
|
+
stream: @stream.inspect,
|
|
129
|
+
filters: @filters.inspect,
|
|
130
|
+
)
|
|
95
131
|
end
|
|
96
132
|
end
|
|
97
133
|
end
|