combine_pdf 1.0.16 → 1.0.29
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
- data/.github/workflows/main.yml +32 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +61 -1
- data/README.md +51 -12
- data/Rakefile +8 -1
- data/combine_pdf.gemspec +4 -2
- data/lib/combine_pdf/api.rb +6 -5
- data/lib/combine_pdf/basic_writer.rb +2 -1
- data/lib/combine_pdf/decrypt.rb +2 -1
- data/lib/combine_pdf/exceptions.rb +2 -0
- data/lib/combine_pdf/filter.rb +1 -0
- data/lib/combine_pdf/fonts.rb +13 -3
- data/lib/combine_pdf/page_methods.rb +7 -6
- data/lib/combine_pdf/parser.rb +54 -16
- data/lib/combine_pdf/pdf_protected.rb +27 -22
- data/lib/combine_pdf/pdf_public.rb +25 -13
- data/lib/combine_pdf/renderer.rb +3 -2
- data/lib/combine_pdf/version.rb +3 -1
- data/lib/combine_pdf.rb +15 -13
- data/test/automated +65 -64
- data/test/combine_pdf/load_test.rb +48 -0
- data/test/combine_pdf/renderer_test.rb +1 -3
- data/test/fixtures/files/sample_encrypted_pdf.pdf +0 -0
- data/test/fixtures/files/sample_pdf.pdf +0 -0
- metadata +47 -11
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
########################################################
|
3
4
|
## Thoughts from reading the ISO 32000-1:2008
|
4
5
|
## this file is part of the CombinePDF library and the code
|
@@ -21,19 +22,19 @@ module CombinePDF
|
|
21
22
|
# this is used for internal operations, such as injectng data using the << operator.
|
22
23
|
def add_referenced()
|
23
24
|
# an existing object map
|
24
|
-
resolved = {}.
|
25
|
-
existing = {}
|
26
|
-
should_resolve = []
|
25
|
+
resolved = {}.compare_by_identity
|
26
|
+
existing = {}
|
27
|
+
should_resolve = []
|
27
28
|
#set all existing objects as resolved and register their children for future resolution
|
28
|
-
@objects.each { |obj| existing[obj] = obj ; resolved[obj
|
29
|
+
@objects.each { |obj| existing[obj] = obj ; resolved[obj] = obj; should_resolve << obj.values}
|
29
30
|
# loop until should_resolve is empty
|
30
31
|
while should_resolve.any?
|
31
32
|
obj = should_resolve.pop
|
32
|
-
next if resolved[obj
|
33
|
+
next if resolved[obj] # the object exists
|
33
34
|
if obj.is_a?(Hash)
|
34
35
|
referenced = obj[:referenced_object]
|
35
36
|
if referenced && referenced.any?
|
36
|
-
tmp = resolved[referenced
|
37
|
+
tmp = resolved[referenced]
|
37
38
|
if !tmp && referenced[:raw_stream_content]
|
38
39
|
tmp = existing[referenced[:raw_stream_content]]
|
39
40
|
# Avoid endless recursion by limiting it to a number of layers (default == 2)
|
@@ -42,18 +43,18 @@ module CombinePDF
|
|
42
43
|
if tmp
|
43
44
|
obj[:referenced_object] = tmp
|
44
45
|
else
|
45
|
-
resolved[obj
|
46
|
+
resolved[obj] = referenced
|
46
47
|
# existing[referenced] = referenced
|
47
48
|
existing[referenced[:raw_stream_content]] = referenced
|
48
49
|
should_resolve << referenced
|
49
50
|
@objects << referenced
|
50
51
|
end
|
51
52
|
else
|
52
|
-
resolved[obj
|
53
|
-
obj.keys.each { |k| should_resolve << obj[k] unless !obj[k].is_a?(Enumerable) || resolved[obj[k]
|
53
|
+
resolved[obj] = obj
|
54
|
+
obj.keys.each { |k| should_resolve << obj[k] unless !obj[k].is_a?(Enumerable) || resolved[obj[k]] }
|
54
55
|
end
|
55
56
|
elsif obj.is_a?(Array)
|
56
|
-
resolved[obj
|
57
|
+
resolved[obj] = obj
|
57
58
|
should_resolve.concat obj
|
58
59
|
end
|
59
60
|
end
|
@@ -78,14 +79,14 @@ module CombinePDF
|
|
78
79
|
page_list.concat(with_pages) unless with_pages.empty?
|
79
80
|
|
80
81
|
# duplicate any non-unique pages - This is a special case to resolve Adobe Acrobat Reader issues (see issues #19 and #81)
|
81
|
-
uniqueness = {}.
|
82
|
-
page_list.each { |page| page = page[:referenced_object] || page; page = page.dup if uniqueness[page
|
82
|
+
uniqueness = {}.compare_by_identity
|
83
|
+
page_list.each { |page| page = page[:referenced_object] || page; page = page.dup if uniqueness[page]; uniqueness[page] = page }
|
83
84
|
page_list.clear
|
84
85
|
page_list = uniqueness.values
|
85
86
|
uniqueness.clear
|
86
87
|
|
87
88
|
# build new Pages object
|
88
|
-
page_object_kids = []
|
89
|
+
page_object_kids = []
|
89
90
|
pages_object = { Type: :Pages, Count: page_list.length, Kids: page_object_kids }
|
90
91
|
pages_object_reference = { referenced_object: pages_object, is_reference_only: true }
|
91
92
|
page_list.each { |pg| pg[:Parent] = pages_object_reference; page_object_kids << ({ referenced_object: pg, is_reference_only: true }) }
|
@@ -186,17 +187,18 @@ module CombinePDF
|
|
186
187
|
POSSIBLE_NAME_TREES = [:Dests, :AP, :Pages, :IDS, :Templates, :URLS, :JavaScript, :EmbeddedFiles, :AlternatePresentations, :Renditions].to_set.freeze
|
187
188
|
|
188
189
|
def rebuild_names(name_tree = nil, base = 'CombinePDF_0000000')
|
190
|
+
base = +base
|
189
191
|
if name_tree
|
190
192
|
return nil unless name_tree.is_a?(Hash)
|
191
193
|
name_tree = name_tree[:referenced_object] || name_tree
|
192
194
|
dic = []
|
193
195
|
# map a names tree and return a valid name tree. Do not recourse.
|
194
196
|
should_resolve = [name_tree[:Kids], name_tree[:Names]]
|
195
|
-
resolved =
|
197
|
+
resolved = Set.new.compare_by_identity
|
196
198
|
while should_resolve.any?
|
197
199
|
pos = should_resolve.pop
|
198
200
|
if pos.is_a? Array
|
199
|
-
next if resolved.include?(pos
|
201
|
+
next if resolved.include?(pos)
|
200
202
|
if pos[0].is_a? String
|
201
203
|
(pos.length / 2).times do |i|
|
202
204
|
dic << (pos[i * 2].clear << base.next!)
|
@@ -209,16 +211,16 @@ module CombinePDF
|
|
209
211
|
end
|
210
212
|
elsif pos.is_a? Hash
|
211
213
|
pos = pos[:referenced_object] || pos
|
212
|
-
next if resolved.include?(pos
|
214
|
+
next if resolved.include?(pos)
|
213
215
|
should_resolve << pos[:Kids] if pos[:Kids]
|
214
216
|
should_resolve << pos[:Names] if pos[:Names]
|
215
217
|
end
|
216
|
-
resolved << pos
|
218
|
+
resolved << pos
|
217
219
|
end
|
218
220
|
return { referenced_object: { Names: dic }, is_reference_only: true }
|
219
221
|
end
|
220
222
|
@names ||= @names[:referenced_object]
|
221
|
-
new_names = { Type: :Names }
|
223
|
+
new_names = { Type: :Names }
|
222
224
|
POSSIBLE_NAME_TREES.each do |ntree|
|
223
225
|
if @names[ntree]
|
224
226
|
new_names[ntree] = rebuild_names(@names[ntree], base)
|
@@ -373,16 +375,19 @@ module CombinePDF
|
|
373
375
|
private
|
374
376
|
|
375
377
|
def equal_layers obj1, obj2, layer = CombinePDF.eq_depth_limit
|
376
|
-
return true
|
377
|
-
return true if obj1.object_id == obj2.object_id
|
378
|
+
return true if obj1.equal?(obj2)
|
378
379
|
if obj1.is_a? Hash
|
379
380
|
return false unless obj2.is_a? Hash
|
381
|
+
return false unless obj1.length == obj2.length
|
380
382
|
keys = obj1.keys;
|
381
|
-
|
383
|
+
keys2 = obj2.keys;
|
384
|
+
return false if (keys - keys2).any? || (keys2 - keys).any?
|
385
|
+
return (warn("CombinePDF nesting limit reached") || true) if(layer == 0)
|
382
386
|
keys.each {|k| return false unless equal_layers( obj1[k], obj2[k], layer-1) }
|
383
387
|
elsif obj1.is_a? Array
|
384
388
|
return false unless obj2.is_a? Array
|
385
|
-
|
389
|
+
return false unless obj1.length == obj2.length
|
390
|
+
(obj1-obj2).any? || (obj2-obj1).any?
|
386
391
|
else
|
387
392
|
obj1 == obj2
|
388
393
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
|
2
|
+
## frozen_string_literal: true
|
3
|
+
#######################################################
|
3
4
|
## Thoughts from reading the ISO 32000-1:2008
|
4
5
|
## this file is part of the CombinePDF library and the code
|
5
6
|
## is subject to the same license.
|
@@ -93,9 +94,10 @@ module CombinePDF
|
|
93
94
|
@version = 0
|
94
95
|
@viewer_preferences = {}
|
95
96
|
@info = {}
|
96
|
-
parser ||= PDFParser.new('')
|
97
|
+
parser ||= PDFParser.new(+'')
|
97
98
|
raise TypeError, "initialization error, expecting CombinePDF::PDFParser or nil, but got #{parser.class.name}" unless parser.is_a? PDFParser
|
98
99
|
@objects = parser.parse
|
100
|
+
|
99
101
|
# remove any existing id's
|
100
102
|
remove_old_ids
|
101
103
|
# set data from parser
|
@@ -174,8 +176,12 @@ module CombinePDF
|
|
174
176
|
def to_pdf(options = {})
|
175
177
|
# reset version if not specified
|
176
178
|
@version = 1.5 if @version.to_f == 0.0
|
179
|
+
|
177
180
|
# set info for merged file
|
178
|
-
@info[:
|
181
|
+
unless(@info[:CreationDate].is_a?(String))
|
182
|
+
@info[:CreationDate] = Time.now unless @info[:CreationDate].is_a?(Time)
|
183
|
+
@info[:CreationDate] = @info[:CreationDate].getgm.strftime("D:%Y%m%d%H%M%S%:::z'00")
|
184
|
+
end
|
179
185
|
@info[:Subject] = options[:subject] if options[:subject]
|
180
186
|
@info[:Producer] = options[:producer] if options[:producer]
|
181
187
|
# rebuild_catalog
|
@@ -201,9 +207,9 @@ module CombinePDF
|
|
201
207
|
xref_location = loc
|
202
208
|
# xref_location = 0
|
203
209
|
# out.each { |line| xref_location += line.bytesize + 1}
|
204
|
-
out << "xref\n0 #{indirect_object_count}\n0000000000 65535 f
|
205
|
-
xref.each { |offset| out << (
|
206
|
-
out <<
|
210
|
+
out << "xref\n0 #{indirect_object_count}\n0000000000 65535 f "
|
211
|
+
xref.each { |offset| out << ("%010d 00000 n ".freeze % offset) }
|
212
|
+
out << 'trailer'.freeze
|
207
213
|
out << "<<\n/Root #{false || "#{catalog[:indirect_reference_id]} #{catalog[:indirect_generation_number]} R"}"
|
208
214
|
out << "/Size #{indirect_object_count}"
|
209
215
|
out << "/Info #{@info[:indirect_reference_id]} #{@info[:indirect_generation_number]} R"
|
@@ -211,7 +217,7 @@ module CombinePDF
|
|
211
217
|
# when finished, remove the numbering system and keep only pointers
|
212
218
|
remove_old_ids
|
213
219
|
# output the pdf stream
|
214
|
-
out.join("\n".
|
220
|
+
out.join("\n".b).force_encoding(Encoding::ASCII_8BIT)
|
215
221
|
end
|
216
222
|
|
217
223
|
# this method returns all the pages cataloged in the catalog.
|
@@ -257,12 +263,18 @@ module CombinePDF
|
|
257
263
|
def fonts(limit_to_type0 = false)
|
258
264
|
fonts_array = []
|
259
265
|
pages.each do |pg|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
+
r = pg[:Resources]
|
267
|
+
next if !r
|
268
|
+
r = r[:referenced_object] if r[:referenced_object]
|
269
|
+
r = r[:Font]
|
270
|
+
next if !r
|
271
|
+
r = r[:referenced_object] if r[:referenced_object]
|
272
|
+
r.values.each do |f|
|
273
|
+
next if f.class != Hash
|
274
|
+
f = f[:referenced_object] if f[:referenced_object]
|
275
|
+
next if f.class != Hash
|
276
|
+
if (limit_to_type0 || f[:Subtype] == :Type0) && f[:Type] == :Font && !fonts_array.include?(f)
|
277
|
+
fonts_array << f
|
266
278
|
end
|
267
279
|
end
|
268
280
|
end
|
data/lib/combine_pdf/renderer.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module CombinePDF
|
2
3
|
################################################################
|
3
4
|
## These are common functions, used within the different classes
|
@@ -123,12 +124,12 @@ module CombinePDF
|
|
123
124
|
# if the object is not a simple object, it is a dictionary
|
124
125
|
# A dictionary shall be written as a sequence of key-value pairs enclosed in double angle brackets (<<...>>)
|
125
126
|
# (using LESS-THAN SIGNs (3Ch) and GREATER-THAN SIGNs (3Eh)).
|
126
|
-
out << "<<\n".
|
127
|
+
out << "<<\n".b
|
127
128
|
object.each do |key, value|
|
128
129
|
out << "#{object_to_pdf key} #{object_to_pdf value}\n".force_encoding(Encoding::ASCII_8BIT) unless PDF::PRIVATE_HASH_KEYS.include? key
|
129
130
|
end
|
130
131
|
object.delete :Length
|
131
|
-
out << '>>'.
|
132
|
+
out << '>>'.b
|
132
133
|
out << "\nstream\n#{object[:raw_stream_content]}\nendstream".force_encoding(Encoding::ASCII_8BIT) if object[:raw_stream_content]
|
133
134
|
out << "\nendobj\n" if object[:indirect_reference_id]
|
134
135
|
out.join.force_encoding(Encoding::ASCII_8BIT)
|
data/lib/combine_pdf/version.rb
CHANGED
data/lib/combine_pdf.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'zlib'
|
4
5
|
require 'securerandom'
|
5
6
|
require 'strscan'
|
6
7
|
require 'matrix'
|
7
8
|
require 'set'
|
9
|
+
require 'digest'
|
8
10
|
|
9
11
|
# require the RC4 Gem
|
10
12
|
require 'rc4'
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
require 'combine_pdf/api'
|
15
|
+
require 'combine_pdf/renderer'
|
16
|
+
require 'combine_pdf/page_methods'
|
17
|
+
require 'combine_pdf/basic_writer'
|
18
|
+
require 'combine_pdf/decrypt'
|
19
|
+
require 'combine_pdf/fonts'
|
20
|
+
require 'combine_pdf/filter'
|
21
|
+
require 'combine_pdf/parser'
|
22
|
+
require 'combine_pdf/pdf_public'
|
23
|
+
require 'combine_pdf/pdf_protected'
|
24
|
+
require 'combine_pdf/exceptions'
|
23
25
|
|
24
|
-
#
|
26
|
+
# require 'combine_pdf/operations'
|
25
27
|
|
26
|
-
|
28
|
+
require 'combine_pdf/version'
|
27
29
|
|
28
30
|
# This is a pure ruby library to combine/merge, stmap/overlay and number PDF files - as well as to create tables (ment for indexing combined files).
|
29
31
|
#
|
data/test/automated
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
$VERBOSE = true
|
4
4
|
|
5
5
|
require 'benchmark'
|
6
|
-
|
6
|
+
Dir.chdir File.expand_path(File.join('..', '..', 'lib'), __FILE__)
|
7
|
+
$LOAD_PATH.unshift Dir.pwd
|
7
8
|
require 'combine_pdf'
|
8
|
-
require 'bundler/setup'
|
9
|
+
# require 'bundler/setup'
|
9
10
|
|
10
11
|
# You can add fixtures and/or initialization code here to make experimenting
|
11
12
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -14,54 +15,54 @@ require 'bundler/setup'
|
|
14
15
|
# require "pry"
|
15
16
|
# Pry.start
|
16
17
|
|
17
|
-
pdf = CombinePDF.load "
|
18
|
-
pdf.save '01_check_radio_buttuns.pdf'
|
19
|
-
pdf = CombinePDF.load "
|
20
|
-
pdf << CombinePDF.load("
|
21
|
-
pdf << CombinePDF.load("
|
22
|
-
pdf.save '02_check_form_unification_middle_is_empty.pdf'
|
18
|
+
pdf = CombinePDF.load "../../test\ pdfs/filled_form.pdf"
|
19
|
+
pdf.save '../tmp/01_check_radio_buttuns.pdf'
|
20
|
+
pdf = CombinePDF.load "../../test\ pdfs/filled_form.pdf"
|
21
|
+
pdf << CombinePDF.load("../../test\ pdfs/empty_form.pdf")
|
22
|
+
pdf << CombinePDF.load("../../test\ pdfs/filled_form.pdf")
|
23
|
+
pdf.save '../tmp/02_check_form_unification_middle_is_empty.pdf'
|
23
24
|
|
24
|
-
pdf = CombinePDF.load "
|
25
|
-
pdf.save '02_01_check_form_data_ordering_issue.pdf'
|
25
|
+
pdf = CombinePDF.load "../../test\ pdfs/check_form_data__objstreams_w_versions.pdf"
|
26
|
+
pdf.save '../tmp/02_01_check_form_data_ordering_issue.pdf'
|
26
27
|
|
27
28
|
|
28
|
-
pdf = CombinePDF.load '
|
29
|
-
pdf2 = CombinePDF.load '
|
29
|
+
pdf = CombinePDF.load '../../test pdfs/share-font-background.pdf'
|
30
|
+
pdf2 = CombinePDF.load '../../test pdfs/share-font-foreground.pdf'
|
30
31
|
i = 0
|
31
32
|
pdf.pages.each { |pg| pg << pdf2.pages[i] }
|
32
|
-
pdf.save '03_check_font_conflict.pdf'
|
33
|
+
pdf.save '../tmp/03_check_font_conflict.pdf'
|
33
34
|
|
34
|
-
pdf = CombinePDF.load '
|
35
|
-
pdf2 = CombinePDF.load '
|
35
|
+
pdf = CombinePDF.load '../../test pdfs/nil_1.pdf'
|
36
|
+
pdf2 = CombinePDF.load '../../test pdfs/nil_2.pdf'
|
36
37
|
pdf << pdf2
|
37
|
-
pdf.save '03_01_nil_value_conflict.pdf'
|
38
|
+
pdf.save '../tmp/03_01_nil_value_conflict.pdf'
|
38
39
|
|
39
|
-
pdf = CombinePDF.load '
|
40
|
-
pdf.save '03_02_extra_space_after_stream_keyword.pdf'
|
40
|
+
pdf = CombinePDF.load '../../test pdfs/space_after_streram_keyword.pdf'
|
41
|
+
pdf.save '../tmp/03_02_extra_space_after_stream_keyword.pdf'
|
41
42
|
|
42
|
-
pdf = CombinePDF.load '
|
43
|
-
pdf.save '03_03_nested_difference.pdf'
|
43
|
+
pdf = CombinePDF.load '../../test pdfs/nested_difference.pdf'
|
44
|
+
pdf.save '../tmp/03_03_nested_difference.pdf'
|
44
45
|
|
45
|
-
pdf = CombinePDF.load '
|
46
|
-
pdf << CombinePDF.load('
|
47
|
-
pdf.save '04_check_view_and_names_reference.pdf'
|
46
|
+
pdf = CombinePDF.load '../../test pdfs/names_go_haywire_0.pdf'
|
47
|
+
pdf << CombinePDF.load('../../test pdfs/names_go_haywire_1.pdf')
|
48
|
+
pdf.save '../tmp/04_check_view_and_names_reference.pdf'
|
48
49
|
|
49
|
-
pdf = CombinePDF.load('
|
50
|
-
pdf.save '05_x1_scribus_test.pdf'
|
51
|
-
pdf = CombinePDF.load('
|
52
|
-
pdf << CombinePDF.load('
|
53
|
-
pdf.save '05_x2_scribus_test.pdf'
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
pdf << CombinePDF.load('
|
58
|
-
pdf.save '05_1_timeless_check_named_dest_links.pdf' # never ends... :-(
|
50
|
+
pdf = CombinePDF.load('../../test pdfs/outlines/self_merge_err.pdf')
|
51
|
+
pdf.save '../tmp/05_x1_scribus_test.pdf'
|
52
|
+
pdf = CombinePDF.load('../../test pdfs/outlines/self_merge_err.pdf')
|
53
|
+
pdf << CombinePDF.load('../../test pdfs/outlines/self_merge_err.pdf')
|
54
|
+
pdf.save '../tmp/05_x2_scribus_test.pdf'
|
55
|
+
pdf = CombinePDF.load "../../test pdfs/outlines/named_dest.pdf";nil
|
56
|
+
pdf.save '../tmp/05_check_named_dest_links.pdf' # this will take a while
|
57
|
+
pdf = CombinePDF.load "../../test pdfs/outlines/named_dest.pdf";nil
|
58
|
+
pdf << CombinePDF.load('../../test pdfs/outlines/named_dest.pdf'); nil
|
59
|
+
pdf.save '../tmp/05_1_timeless_check_named_dest_links.pdf' # never ends... :-(
|
59
60
|
|
60
|
-
pdf = CombinePDF.load '
|
61
|
-
pdf << CombinePDF.load('
|
62
|
-
pdf.save '06_check_links_to_second_copy.pdf'
|
61
|
+
pdf = CombinePDF.load '../../test pdfs/outline_small.pdf'
|
62
|
+
pdf << CombinePDF.load('../../test pdfs/outline_small.pdf')
|
63
|
+
pdf.save '../tmp/06_check_links_to_second_copy.pdf'
|
63
64
|
|
64
|
-
lists = %w(
|
65
|
+
lists = %w(../../test\ pdfs/outlines/self_merge_err.pdf ../../test\ pdfs/outlines/big_toc.pdf ../../test\ pdfs/outlines/bigger_toc.pdf ../../test\ pdfs/outlines/named_dest_no_toc.pdf ../../test\ pdfs/outlines/named_dest_no_toc2.pdf ../../test\ pdfs/outlines/named_dest.pdf ../../test\ pdfs/outlines/named_dest2.pdf)
|
65
66
|
|
66
67
|
i = 0
|
67
68
|
lists.each do |n|
|
@@ -76,7 +77,7 @@ lists.each do |n|
|
|
76
77
|
end
|
77
78
|
pdf = CombinePDF.new
|
78
79
|
lists.each { |n| pdf << CombinePDF.load(n) }
|
79
|
-
pdf.save('07_named destinations.pdf')
|
80
|
+
pdf.save('../tmp/07_named destinations.pdf')
|
80
81
|
|
81
82
|
pdf = CombinePDF.new
|
82
83
|
lists.each { |n| pdf << CombinePDF.load(n) }
|
@@ -90,26 +91,26 @@ pdf.number_pages(start_at: 1,
|
|
90
91
|
number_location: [:top, :bottom],
|
91
92
|
opacity: 0.75)
|
92
93
|
|
93
|
-
pdf.save('07_named destinations_numbered.pdf')
|
94
|
+
pdf.save('../tmp/07_named destinations_numbered.pdf')
|
94
95
|
|
95
|
-
CombinePDF.load("
|
96
|
-
CombinePDF.load("
|
97
|
-
CombinePDF.load("
|
98
|
-
CombinePDF.load("
|
99
|
-
CombinePDF.load("
|
96
|
+
CombinePDF.load("../../test\ pdfs/Scribus-unknown_err.pdf").save '../tmp/08_1-unknown-err-empty-str.pdf'
|
97
|
+
CombinePDF.load("../../test\ pdfs/Scribus-unknown_err2.pdf").save '../tmp/08_2-unknown-err-empty-str.pdf'
|
98
|
+
CombinePDF.load("../../test\ pdfs/Scribus-unknown_err3.pdf").save '../tmp/08_3-unknown-err-empty-str.pdf'
|
99
|
+
CombinePDF.load("../../test\ pdfs/xref_in_middle.pdf").save '../tmp/08_4-xref-in-middle.pdf'
|
100
|
+
CombinePDF.load("../../test\ pdfs/xref_split.pdf").save '../tmp/08_5-xref-fragmented.pdf'
|
100
101
|
|
101
|
-
CombinePDF.load("
|
102
|
+
CombinePDF.load("../../test\ pdfs/nil_object.pdf").save('../tmp/09_nil_in_parsed_array.pdf')
|
102
103
|
|
103
|
-
encrypted = [ "
|
104
|
-
"
|
105
|
-
"
|
106
|
-
"
|
107
|
-
"
|
104
|
+
encrypted = [ "../../test\ pdfs/pdf-reader/encrypted_version4_revision4_128bit_aes_user_pass_apples_enc_metadata.pdf",
|
105
|
+
"../../test\ pdfs/AESv2\ encrypted.pdf",
|
106
|
+
"../../test\ pdfs/pdf-reader/encrypted_version2_revision3_128bit_rc4_blank_user_pass.pdf",
|
107
|
+
"../../test\ pdfs/AES\ enc.pdf",
|
108
|
+
"../../test\ pdfs/RC4\ enc.pdf"]
|
108
109
|
|
109
110
|
encrypted.length.times do |i|
|
110
111
|
fname = File.basename encrypted[i]
|
111
112
|
begin
|
112
|
-
CombinePDF.load(encrypted[i]).save "10_#{i}_#{fname}"
|
113
|
+
CombinePDF.load(encrypted[i]).save "../tmp/10_#{i}_#{fname}"
|
113
114
|
rescue => e
|
114
115
|
puts e.class.name, e.message
|
115
116
|
if(i == 0)
|
@@ -125,24 +126,24 @@ IO.binwrite '11_prawn.pdf', (Prawn::Document.new { text 'Hello World!' }).render
|
|
125
126
|
page = CombinePDF.parse((Prawn::Document.new { text 'Hello World!' }).render)
|
126
127
|
pdf = CombinePDF.new
|
127
128
|
pdf << page
|
128
|
-
pdf.save '11_parsed_from_prawn.pdf'
|
129
|
+
pdf.save '../tmp/11_parsed_from_prawn.pdf'
|
129
130
|
pdf = CombinePDF.new
|
130
131
|
pdf << page << page
|
131
|
-
pdf.save('11_AcrobatReader_is_unique_page.pdf')
|
132
|
+
pdf.save('../tmp/11_AcrobatReader_is_unique_page.pdf')
|
132
133
|
|
133
134
|
puts GC.stat.inspect
|
134
135
|
# unify = [
|
135
|
-
# "
|
136
|
-
# "
|
137
|
-
# "
|
138
|
-
# "
|
139
|
-
# "
|
140
|
-
# "
|
141
|
-
# "
|
142
|
-
# "
|
143
|
-
# "
|
144
|
-
# "
|
145
|
-
# "
|
136
|
+
# "../../test\ pdfs/AESv2\ encrypted.pdf",
|
137
|
+
# "../../test\ pdfs/data-in-comment.pdf",
|
138
|
+
# "../../test\ pdfs/file_name.pdf",
|
139
|
+
# "../../test\ pdfs/garbage_after_eof.pdf",
|
140
|
+
# "../../test\ pdfs/Many\ comments.pdf",
|
141
|
+
# "../../test\ pdfs/nested\ contents\ array.PDF",
|
142
|
+
# "../../test\ pdfs/nested_resources.pdf",
|
143
|
+
# "../../test\ pdfs/original-missing-endobje.pdf",
|
144
|
+
# "../../test\ pdfs/original-multi-issue.pdf",
|
145
|
+
# "../../test\ pdfs/page_stap_nil_secure.pdf",
|
146
|
+
# "../../test\ pdfs/referenced\ decryption.pdf",
|
146
147
|
# '',
|
147
148
|
# '',
|
148
149
|
# '',
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'minitest/around/spec'
|
4
|
+
require 'combine_pdf'
|
5
|
+
|
6
|
+
describe 'CombinePDF.load' do
|
7
|
+
let(:options) { {} }
|
8
|
+
|
9
|
+
subject { CombinePDF.load "test/fixtures/files/#{file}", options }
|
10
|
+
|
11
|
+
describe 'raise_on_encrypted option' do
|
12
|
+
let(:file) { 'sample_encrypted_pdf.pdf' }
|
13
|
+
let(:options) { { raise_on_encrypted: raise_on_encrypted } }
|
14
|
+
|
15
|
+
describe 'when raise_on_encrypted: true' do
|
16
|
+
let(:raise_on_encrypted) { true }
|
17
|
+
|
18
|
+
describe 'with encrypted file' do
|
19
|
+
it('raises an CombinePDF::EncryptionError') do
|
20
|
+
error = assert_raises(CombinePDF::EncryptionError) { subject }
|
21
|
+
assert_match 'the file is encrypted', error.message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'with unencrypted file' do
|
26
|
+
let(:file) { 'sample_pdf.pdf' }
|
27
|
+
|
28
|
+
it('has a PDF') { assert_instance_of CombinePDF::PDF, subject }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'when raise_on_encrypted: false' do
|
33
|
+
let(:raise_on_encrypted) { false }
|
34
|
+
|
35
|
+
describe 'with encrypted file' do
|
36
|
+
it('does not raise an CombinePDF::EncryptionError') do
|
37
|
+
assert_instance_of CombinePDF::PDF, subject
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'with unencrypted file' do
|
42
|
+
let(:file) { 'sample_pdf.pdf' }
|
43
|
+
|
44
|
+
it('has a PDF') { assert_instance_of CombinePDF::PDF, subject }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,6 +1,4 @@
|
|
1
|
-
require 'bundler/setup'
|
2
1
|
require 'minitest/autorun'
|
3
|
-
require 'combine_pdf/renderer'
|
4
2
|
|
5
3
|
class CombinePDFRendererTest < Minitest::Test
|
6
4
|
|
@@ -14,7 +12,7 @@ class CombinePDFRendererTest < Minitest::Test
|
|
14
12
|
|
15
13
|
def test_numeric_array_to_pdf
|
16
14
|
input = [1.234567, 0.000054, 5, -0.000099]
|
17
|
-
expected = "[1.234567 0.000054 5 -0.000099]".
|
15
|
+
expected = "[1.234567 0.000054 5 -0.000099]".b
|
18
16
|
actual = TestRenderer.new.test_object(input)
|
19
17
|
|
20
18
|
assert_equal(expected, actual)
|
Binary file
|
Binary file
|