pdf-reader 2.10.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +9 -0
- data/Rakefile +1 -1
- data/lib/pdf/reader/buffer.rb +3 -4
- data/lib/pdf/reader/cid_widths.rb +3 -1
- data/lib/pdf/reader/cmap.rb +2 -2
- data/lib/pdf/reader/encoding.rb +4 -5
- data/lib/pdf/reader/filter/depredict.rb +1 -1
- data/lib/pdf/reader/font.rb +2 -2
- data/lib/pdf/reader/glyph_hash.rb +13 -5
- data/lib/pdf/reader/lzw.rb +1 -1
- data/lib/pdf/reader/no_text_filter.rb +14 -0
- data/lib/pdf/reader/object_hash.rb +7 -5
- data/lib/pdf/reader/object_stream.rb +1 -1
- data/lib/pdf/reader/overlapping_runs_filter.rb +1 -1
- data/lib/pdf/reader/page.rb +23 -6
- data/lib/pdf/reader/page_layout.rb +1 -1
- data/lib/pdf/reader/page_text_receiver.rb +2 -0
- data/lib/pdf/reader/parser.rb +1 -3
- data/lib/pdf/reader/reference.rb +3 -2
- data/lib/pdf/reader/resources.rb +1 -1
- data/lib/pdf/reader/synchronized_cache.rb +1 -1
- data/lib/pdf/reader/text_run.rb +5 -2
- data/lib/pdf/reader/transformation_matrix.rb +8 -8
- data/lib/pdf/reader/xref.rb +3 -3
- data/lib/pdf/reader.rb +5 -10
- data/rbi/pdf-reader.rbi +277 -254
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3b00946c8b23b65d19ace187550b15bb3fd2537e518c778f4c12da28672c9d8
|
4
|
+
data.tar.gz: 4c2ebeb19dada9f257fa65c2add2f2f6d64f011cb13e997533a4b63fc81baa6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99c9ac879424056221f616d7f7299d03dfc9906c6b81c333ad255439780cf56d2dfc0c31a62347a7a163bcdb4075f8d0c914e2deeebb5d78e8ebc34e19cd7abc
|
7
|
+
data.tar.gz: 50ef8b5e1061dd1d6b24a7727b5537664bcb22473757274b4cc2b92c89b9ba5ea7516f055571f5c8b72d678f7cef549858631408c86a6984196ba7d1773daaca
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
v2.12.0 (26th December 2023)
|
2
|
+
- Fix a sorbet method signature (http://github.com/yob/pdf-reader/pull/512)
|
3
|
+
- Reduce allocations when parsing PDFs with hex strings (http://github.com/yob/pdf-reader/pull/528)
|
4
|
+
- Fix text extraction of some rare unicode codepoints (http://github.com/yob/pdf-reader/pull/529)
|
5
|
+
|
6
|
+
v2.11.0 (26th October 2022)
|
7
|
+
- Various bug fixes
|
8
|
+
- Expanded sorbet type annotations
|
9
|
+
|
1
10
|
v2.10.0 (12th May 2022)
|
2
11
|
- Various bug fixes
|
3
12
|
- Expanded sorbet type annotations
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ desc "Run cane to check quality metrics"
|
|
14
14
|
Cane::RakeTask.new(:quality) do |cane|
|
15
15
|
cane.abc_max = 20
|
16
16
|
cane.style_measure = 100
|
17
|
-
cane.max_violations =
|
17
|
+
cane.max_violations = 33
|
18
18
|
|
19
19
|
cane.use Morecane::EncodingCheck, :encoding_glob => "{app,lib,spec}/**/*.rb"
|
20
20
|
end
|
data/lib/pdf/reader/buffer.rb
CHANGED
@@ -300,13 +300,12 @@ class PDF::Reader
|
|
300
300
|
# we find a closing >
|
301
301
|
#
|
302
302
|
def prepare_hex_token
|
303
|
-
finished = :false
|
304
303
|
str = "".dup
|
305
304
|
|
306
|
-
|
305
|
+
loop do
|
307
306
|
byte = @io.getbyte
|
308
307
|
if byte.nil?
|
309
|
-
|
308
|
+
break
|
310
309
|
elsif (48..57).include?(byte) || (65..90).include?(byte) || (97..122).include?(byte)
|
311
310
|
str << byte
|
312
311
|
elsif byte <= 32
|
@@ -315,7 +314,7 @@ class PDF::Reader
|
|
315
314
|
@tokens << str if str.size > 0
|
316
315
|
@tokens << ">" if byte != 0x3E # '>'
|
317
316
|
@tokens << byte.chr
|
318
|
-
|
317
|
+
break
|
319
318
|
end
|
320
319
|
end
|
321
320
|
end
|
@@ -52,7 +52,9 @@ class PDF::Reader
|
|
52
52
|
|
53
53
|
# this is the form 10 20 123 where all index between 10 and 20 have width 123
|
54
54
|
def parse_second_form(first, final, width)
|
55
|
-
|
55
|
+
if first > final
|
56
|
+
raise MalformedPDFError, "CidWidths: #{first} must be less than #{final}"
|
57
|
+
end
|
56
58
|
|
57
59
|
(first..final).inject({}) { |accum, index|
|
58
60
|
accum[index] = width
|
data/lib/pdf/reader/cmap.rb
CHANGED
@@ -118,8 +118,8 @@ class PDF::Reader
|
|
118
118
|
result = []
|
119
119
|
while unpacked_string.any? do
|
120
120
|
if unpacked_string.size >= 2 &&
|
121
|
-
unpacked_string.first.to_i
|
122
|
-
unpacked_string.first.to_i
|
121
|
+
unpacked_string.first.to_i >= 0xD800 &&
|
122
|
+
unpacked_string.first.to_i <= 0xDBFF
|
123
123
|
# this is a Unicode UTF-16 "Surrogate Pair" see Unicode Spec. Chapter 3.7
|
124
124
|
# lets convert to a UTF-32. (the high bit is between 0xD800-0xDBFF, the
|
125
125
|
# low bit is between 0xDC00-0xDFFF) for example: U+1D44E (U+D835 U+DC4E)
|
data/lib/pdf/reader/encoding.rb
CHANGED
@@ -76,9 +76,9 @@ class PDF::Reader
|
|
76
76
|
diff.each do |val|
|
77
77
|
if val.kind_of?(Numeric)
|
78
78
|
byte = val.to_i
|
79
|
-
|
79
|
+
elsif codepoint = glyphlist.name_to_unicode(val)
|
80
80
|
@differences[byte] = val
|
81
|
-
@mapping[byte] =
|
81
|
+
@mapping[byte] = codepoint
|
82
82
|
byte += 1
|
83
83
|
end
|
84
84
|
end
|
@@ -119,7 +119,7 @@ class PDF::Reader
|
|
119
119
|
# => [:A]
|
120
120
|
#
|
121
121
|
def int_to_name(glyph_code)
|
122
|
-
if @enc_name == "Identity-H" || @enc_name == "Identity-V"
|
122
|
+
if @enc_name == :"Identity-H" || @enc_name == :"Identity-V"
|
123
123
|
[]
|
124
124
|
elsif differences[glyph_code]
|
125
125
|
[differences[glyph_code]]
|
@@ -143,7 +143,6 @@ class PDF::Reader
|
|
143
143
|
CONTROL_CHARS.include?(i) ? [i, UNKNOWN_CHAR] : [i,i]
|
144
144
|
}
|
145
145
|
mapping = Hash[tuples]
|
146
|
-
mapping[nil] = UNKNOWN_CHAR
|
147
146
|
mapping
|
148
147
|
end
|
149
148
|
|
@@ -167,7 +166,7 @@ class PDF::Reader
|
|
167
166
|
end
|
168
167
|
|
169
168
|
def convert_to_utf8(str)
|
170
|
-
ret = str.unpack(unpack).map! { |c| @mapping[c] || c }.pack("U*")
|
169
|
+
ret = str.unpack(unpack).map! { |c| @mapping[c.to_i] || c }.pack("U*")
|
171
170
|
ret.force_encoding("UTF-8")
|
172
171
|
ret
|
173
172
|
end
|
data/lib/pdf/reader/font.rb
CHANGED
@@ -82,8 +82,8 @@ class PDF::Reader
|
|
82
82
|
glyph_width_in_glyph_space = glyph_width(code_point)
|
83
83
|
|
84
84
|
if @subtype == :Type3
|
85
|
-
x1,
|
86
|
-
x2,
|
85
|
+
x1, _y1 = font_matrix_transform(0,0)
|
86
|
+
x2, _y2 = font_matrix_transform(glyph_width_in_glyph_space, 0)
|
87
87
|
(x2 - x1).abs.round(2)
|
88
88
|
else
|
89
89
|
glyph_width_in_glyph_space / 1000.0
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
################################################################################
|
@@ -33,10 +33,18 @@ class PDF::Reader
|
|
33
33
|
#
|
34
34
|
class GlyphHash # :nodoc:
|
35
35
|
def initialize
|
36
|
+
@@by_codepoint_cache ||= nil
|
37
|
+
@@by_name_cache ||= nil
|
38
|
+
|
36
39
|
# only parse the glyph list once, and cache the results (for performance)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
if @@by_codepoint_cache != nil && @@by_name_cache != nil
|
41
|
+
@by_name = @@by_name_cache
|
42
|
+
@by_codepoint = @@by_codepoint_cache
|
43
|
+
else
|
44
|
+
by_name, by_codepoint = load_adobe_glyph_mapping
|
45
|
+
@by_name = @@by_name_cache ||= by_name
|
46
|
+
@by_codepoint = @@by_codepoint_cache ||= by_codepoint
|
47
|
+
end
|
40
48
|
end
|
41
49
|
|
42
50
|
# attempt to convert a PDF Name to a unicode codepoint. Returns nil
|
@@ -127,7 +135,7 @@ class PDF::Reader
|
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
130
|
-
|
138
|
+
return keyed_by_name.freeze, keyed_by_codepoint.freeze
|
131
139
|
end
|
132
140
|
|
133
141
|
end
|
data/lib/pdf/reader/lzw.rb
CHANGED
@@ -42,7 +42,7 @@ module PDF
|
|
42
42
|
while bits_left_in_chunk > 0 and @current_pos < @data.size
|
43
43
|
chunk = 0 if chunk < 0
|
44
44
|
codepoint = @data[@current_pos, 1].to_s.unpack("C*")[0].to_i
|
45
|
-
current_byte = codepoint & (2**@bits_left_in_byte - 1) #clear consumed bits
|
45
|
+
current_byte = codepoint & (2**@bits_left_in_byte - 1).to_i #clear consumed bits
|
46
46
|
dif = bits_left_in_chunk - @bits_left_in_byte
|
47
47
|
if dif > 0 then current_byte <<= dif
|
48
48
|
elsif dif < 0 then current_byte >>= dif.abs
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# typed: strict
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
class PDF::Reader
|
6
|
+
# There's no point rendering zero-width characters
|
7
|
+
class NoTextFilter
|
8
|
+
|
9
|
+
def self.exclude_empty_strings(runs)
|
10
|
+
runs.reject { |run| run.text.to_s.size == 0 }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -2,6 +2,8 @@
|
|
2
2
|
# typed: true
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
|
+
require 'tempfile'
|
6
|
+
|
5
7
|
class PDF::Reader
|
6
8
|
# Provides low level access to the objects in a PDF file via a hash-like
|
7
9
|
# object.
|
@@ -566,7 +568,7 @@ class PDF::Reader
|
|
566
568
|
end
|
567
569
|
|
568
570
|
def object_streams
|
569
|
-
@
|
571
|
+
@object_streams ||= {}
|
570
572
|
end
|
571
573
|
|
572
574
|
# returns an array of object references for all pages in this object store. The ordering of
|
@@ -591,18 +593,18 @@ class PDF::Reader
|
|
591
593
|
|
592
594
|
def read_version
|
593
595
|
@io.seek(0)
|
594
|
-
_m, version = *@io.read(10).match(/PDF-(\d.\d)/)
|
596
|
+
_m, version = *@io.read(10).to_s.match(/PDF-(\d.\d)/)
|
595
597
|
@io.seek(0)
|
596
598
|
version.to_f
|
597
599
|
end
|
598
600
|
|
599
601
|
def extract_io_from(input)
|
600
|
-
if input.
|
602
|
+
if input.is_a?(IO) || input.is_a?(StringIO) || input.is_a?(Tempfile)
|
601
603
|
input
|
602
604
|
elsif File.file?(input.to_s)
|
603
|
-
StringIO.new read_as_binary(input)
|
605
|
+
StringIO.new read_as_binary(input.to_s)
|
604
606
|
else
|
605
|
-
raise ArgumentError, "input must be an IO-like object or a filename"
|
607
|
+
raise ArgumentError, "input must be an IO-like object or a filename (#{input.class})"
|
606
608
|
end
|
607
609
|
end
|
608
610
|
|
data/lib/pdf/reader/page.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
module PDF
|
@@ -43,10 +43,10 @@ module PDF
|
|
43
43
|
#
|
44
44
|
def initialize(objects, pagenum, options = {})
|
45
45
|
@objects, @pagenum = objects, pagenum
|
46
|
-
@page_object = objects.deref_hash(objects.page_references[pagenum - 1])
|
46
|
+
@page_object = objects.deref_hash(objects.page_references[pagenum - 1]) || {}
|
47
47
|
@cache = options[:cache] || {}
|
48
48
|
|
49
|
-
|
49
|
+
if @page_object.empty?
|
50
50
|
raise InvalidPageError, "Invalid page: #{pagenum}"
|
51
51
|
end
|
52
52
|
end
|
@@ -250,8 +250,8 @@ module PDF
|
|
250
250
|
params = []
|
251
251
|
|
252
252
|
while (token = parser.parse_token(PagesStrategy::OPERATORS))
|
253
|
-
if token.kind_of?(Token)
|
254
|
-
callback(receivers,
|
253
|
+
if token.kind_of?(Token) && method_name = PagesStrategy::OPERATORS[token]
|
254
|
+
callback(receivers, method_name, params)
|
255
255
|
params.clear
|
256
256
|
else
|
257
257
|
params << token
|
@@ -263,9 +263,26 @@ module PDF
|
|
263
263
|
|
264
264
|
# calls the name callback method on each receiver object with params as the arguments
|
265
265
|
#
|
266
|
+
# The silly style here is because sorbet won't let me use splat arguments
|
267
|
+
#
|
266
268
|
def callback(receivers, name, params=[])
|
267
269
|
receivers.each do |receiver|
|
268
|
-
|
270
|
+
if receiver.respond_to?(name)
|
271
|
+
case params.size
|
272
|
+
when 0 then receiver.send(name)
|
273
|
+
when 1 then receiver.send(name, params[0])
|
274
|
+
when 2 then receiver.send(name, params[0], params[1])
|
275
|
+
when 3 then receiver.send(name, params[0], params[1], params[2])
|
276
|
+
when 4 then receiver.send(name, params[0], params[1], params[2], params[3])
|
277
|
+
when 5 then receiver.send(name, params[0], params[1], params[2], params[3], params[4])
|
278
|
+
when 6 then receiver.send(name, params[0], params[1], params[2], params[3], params[4], params[5])
|
279
|
+
when 7 then receiver.send(name, params[0], params[1], params[2], params[3], params[4], params[5], params[6])
|
280
|
+
when 8 then receiver.send(name, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7])
|
281
|
+
when 9 then receiver.send(name, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8])
|
282
|
+
else
|
283
|
+
receiver.send(name, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], params[9])
|
284
|
+
end
|
285
|
+
end
|
269
286
|
end
|
270
287
|
end
|
271
288
|
|
data/lib/pdf/reader/parser.rb
CHANGED
@@ -173,9 +173,7 @@ class PDF::Reader
|
|
173
173
|
|
174
174
|
# add a missing digit if required, as required by the spec
|
175
175
|
str << "0" unless str.size % 2 == 0
|
176
|
-
str.
|
177
|
-
nibbles.join("").hex.chr
|
178
|
-
}.join.force_encoding("binary")
|
176
|
+
[str].pack('H*')
|
179
177
|
end
|
180
178
|
################################################################################
|
181
179
|
# Reads a PDF String from the buffer and converts it to a Ruby String
|
data/lib/pdf/reader/reference.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
################################################################################
|
@@ -31,7 +31,8 @@ class PDF::Reader
|
|
31
31
|
################################################################################
|
32
32
|
# An internal PDF::Reader class that represents an indirect reference to a PDF Object
|
33
33
|
class Reference
|
34
|
-
attr_reader :id
|
34
|
+
attr_reader :id
|
35
|
+
attr_reader :gen
|
35
36
|
################################################################################
|
36
37
|
# Create a new Reference to an object with the specified id and revision number
|
37
38
|
def initialize(id, gen)
|
data/lib/pdf/reader/resources.rb
CHANGED
data/lib/pdf/reader/text_run.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
class PDF::Reader
|
@@ -7,7 +7,10 @@ class PDF::Reader
|
|
7
7
|
class TextRun
|
8
8
|
include Comparable
|
9
9
|
|
10
|
-
attr_reader :origin
|
10
|
+
attr_reader :origin
|
11
|
+
attr_reader :width
|
12
|
+
attr_reader :font_size
|
13
|
+
attr_reader :text
|
11
14
|
|
12
15
|
alias :to_s :text
|
13
16
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
class PDF::Reader
|
@@ -51,7 +51,7 @@ class PDF::Reader
|
|
51
51
|
# displacement to speed up processing documents that use vertical
|
52
52
|
# writing systems
|
53
53
|
#
|
54
|
-
def multiply!(a,b
|
54
|
+
def multiply!(a,b,c, d,e,f)
|
55
55
|
if a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0
|
56
56
|
# the identity matrix, no effect
|
57
57
|
self
|
@@ -164,12 +164,12 @@ class PDF::Reader
|
|
164
164
|
# [ e f 1 ] [ e f 1 ]
|
165
165
|
#
|
166
166
|
def regular_multiply!(a2,b2,c2,d2,e2,f2)
|
167
|
-
newa = (@a * a2) + (@b * c2) + (
|
168
|
-
newb = (@a * b2) + (@b * d2) + (
|
169
|
-
newc = (@c * a2) + (@d * c2) + (
|
170
|
-
newd = (@c * b2) + (@d * d2) + (
|
171
|
-
newe = (@e * a2) + (@f * c2) + (
|
172
|
-
newf = (@e * b2) + (@f * d2) + (
|
167
|
+
newa = (@a * a2) + (@b * c2) + (e2 * 0)
|
168
|
+
newb = (@a * b2) + (@b * d2) + (f2 * 0)
|
169
|
+
newc = (@c * a2) + (@d * c2) + (e2 * 0)
|
170
|
+
newd = (@c * b2) + (@d * d2) + (f2 * 0)
|
171
|
+
newe = (@e * a2) + (@f * c2) + (e2 * 1)
|
172
|
+
newf = (@e * b2) + (@f * d2) + (f2 * 1)
|
173
173
|
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
174
174
|
end
|
175
175
|
|
data/lib/pdf/reader/xref.rb
CHANGED
@@ -73,7 +73,7 @@ class PDF::Reader
|
|
73
73
|
#
|
74
74
|
# ref - a PDF::Reader::Reference object containing an object ID and revision number
|
75
75
|
def [](ref)
|
76
|
-
@xref
|
76
|
+
@xref.fetch(ref.id, {}).fetch(ref.gen)
|
77
77
|
rescue
|
78
78
|
raise InvalidObjectError, "Object #{ref.id}, Generation #{ref.gen} is invalid"
|
79
79
|
end
|
@@ -82,8 +82,8 @@ class PDF::Reader
|
|
82
82
|
def each(&block)
|
83
83
|
ids = @xref.keys.sort
|
84
84
|
ids.each do |id|
|
85
|
-
gen = @xref
|
86
|
-
yield PDF::Reader::Reference.new(id, gen)
|
85
|
+
gen = @xref.fetch(id, {}).keys.sort[-1]
|
86
|
+
yield PDF::Reader::Reference.new(id, gen.to_i)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
################################################################################
|
data/lib/pdf/reader.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
################################################################################
|
@@ -128,7 +128,7 @@ module PDF
|
|
128
128
|
doc_strings_to_utf8(dict)
|
129
129
|
end
|
130
130
|
|
131
|
-
# Return a
|
131
|
+
# Return a String with extra XML metadata provided by the author of the PDF file. Not
|
132
132
|
# always present.
|
133
133
|
#
|
134
134
|
def metadata
|
@@ -182,7 +182,7 @@ module PDF
|
|
182
182
|
#
|
183
183
|
# reader.pages.each do |page|
|
184
184
|
# puts page.fonts
|
185
|
-
# puts page.
|
185
|
+
# puts page.rectangles
|
186
186
|
# puts page.text
|
187
187
|
# end
|
188
188
|
#
|
@@ -272,13 +272,7 @@ module PDF
|
|
272
272
|
end
|
273
273
|
|
274
274
|
def root
|
275
|
-
@root ||=
|
276
|
-
obj = @objects.deref_hash(@objects.trailer[:Root]) || {}
|
277
|
-
unless obj.kind_of?(::Hash)
|
278
|
-
raise MalformedPDFError, "PDF malformed, trailer Root should be a dictionary"
|
279
|
-
end
|
280
|
-
obj
|
281
|
-
end
|
275
|
+
@root ||= @objects.deref_hash(@objects.trailer[:Root]) || {}
|
282
276
|
end
|
283
277
|
|
284
278
|
end
|
@@ -315,6 +309,7 @@ require 'pdf/reader/print_receiver'
|
|
315
309
|
require 'pdf/reader/rectangle'
|
316
310
|
require 'pdf/reader/reference'
|
317
311
|
require 'pdf/reader/register_receiver'
|
312
|
+
require 'pdf/reader/no_text_filter'
|
318
313
|
require 'pdf/reader/null_security_handler'
|
319
314
|
require 'pdf/reader/security_handler_factory'
|
320
315
|
require 'pdf/reader/standard_key_builder'
|