combine_pdf 1.0.26 → 1.0.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +6 -2
- data/CHANGELOG.md +10 -0
- data/lib/combine_pdf/api.rb +1 -0
- data/lib/combine_pdf/basic_writer.rb +1 -0
- 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 +1 -0
- data/lib/combine_pdf/page_methods.rb +5 -4
- data/lib/combine_pdf/parser.rb +9 -9
- data/lib/combine_pdf/pdf_protected.rb +21 -19
- data/lib/combine_pdf/pdf_public.rb +4 -3
- data/lib/combine_pdf/renderer.rb +3 -2
- data/lib/combine_pdf/version.rb +3 -1
- data/lib/combine_pdf.rb +14 -13
- data/test/combine_pdf/renderer_test.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1da4a9ad814eebd6f7b976c238a018a19e6cd1106dea1ebf5d3d51ab1b213ad7
|
4
|
+
data.tar.gz: 0fe9ca847a095fb68e2498e03329186d382a856d80e549d83a301f0f0675c9a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ded304e2d225506a354da76d0165e2d31afffae5537cc30bce2c12228c767825093725b191aa03be08f024437ab15d8431e181d6c9abaefd02f832a494e559b3
|
7
|
+
data.tar.gz: c15e1be8a06560ccc966f7e28c4dc84bc05656b33936862dd307afe7744f011bdc17c50107f9595ef44c281e10fc62f1e535f8ef93c24ea438eaa45fc5287e02
|
data/.github/workflows/main.yml
CHANGED
@@ -9,7 +9,11 @@ jobs:
|
|
9
9
|
strategy:
|
10
10
|
fail-fast: false
|
11
11
|
matrix:
|
12
|
-
ruby: ["2.7", "3.0", "3.1", "3.2"]
|
12
|
+
ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"]
|
13
|
+
rubyopt: [""]
|
14
|
+
include:
|
15
|
+
- ruby: "3.3"
|
16
|
+
rubyopt: "--enable-frozen-string-literal --debug-frozen-string-literal"
|
13
17
|
|
14
18
|
steps:
|
15
19
|
- name: Checkout code
|
@@ -25,4 +29,4 @@ jobs:
|
|
25
29
|
run: bundle lock
|
26
30
|
|
27
31
|
- name: Run tests
|
28
|
-
run: bundle exec rake test
|
32
|
+
run: bundle exec rake test RUBYOPT="${{ matrix.rubyopt }}"
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
#### Change log v.1.0.28 (2024-11-12)
|
4
|
+
|
5
|
+
**Fix**: use `require` to load code (instead of `load`). Credit to @casperisfine (Jean byroot Boussier) for PR #216.
|
6
|
+
|
7
|
+
#### Change log v.1.0.27 (2024-11-10)
|
8
|
+
|
9
|
+
**Performance**: fix performance issues with `object_id` usage in Ruby 3+. Credit to @amomchilov (Alexander Momchilov) for PR #241.
|
10
|
+
|
11
|
+
**Performance**: use frozen string literals. Credit to @casperisfine (Jean byroot Boussier) for PR #239.
|
12
|
+
|
3
13
|
#### Change log v.1.0.26 (2023-12-22)
|
4
14
|
|
5
15
|
**Performance**: possible performance bump. Credit to @denislavski (Denislav Naydenov) for opening PR #235.
|
data/lib/combine_pdf/api.rb
CHANGED
data/lib/combine_pdf/decrypt.rb
CHANGED
@@ -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
|
@@ -137,7 +138,7 @@ module CombinePDF
|
|
137
138
|
object_key = @key.dup
|
138
139
|
object_key << [encrypted_id].pack('i')[0..2]
|
139
140
|
object_key << [encrypted_generation].pack('i')[0..1]
|
140
|
-
object_key << 'sAlT'.
|
141
|
+
object_key << 'sAlT'.b
|
141
142
|
key_length = object_key.length < 16 ? object_key.length : 16
|
142
143
|
|
143
144
|
begin
|
data/lib/combine_pdf/filter.rb
CHANGED
data/lib/combine_pdf/fonts.rb
CHANGED
@@ -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
|
@@ -214,7 +215,7 @@ module CombinePDF
|
|
214
215
|
options[:text_padding] = 0 if options[:text_padding].to_f >= 1
|
215
216
|
|
216
217
|
# create box stream
|
217
|
-
box_stream = ''
|
218
|
+
box_stream = +''
|
218
219
|
# set graphic state for box
|
219
220
|
if options[:box_color] || (options[:border_width].to_i > 0 && options[:border_color])
|
220
221
|
# compute x and y position for text
|
@@ -290,7 +291,7 @@ module CombinePDF
|
|
290
291
|
# reset x,y by text alignment - x,y are calculated from the bottom left
|
291
292
|
# each unit (1) is 1/72 Inch
|
292
293
|
# create text stream
|
293
|
-
text_stream = ''
|
294
|
+
text_stream = +''
|
294
295
|
if !text.to_s.empty? && options[:font_size] != 0 && (options[:font_color] || options[:stroke_color])
|
295
296
|
# compute x and y position for text
|
296
297
|
x = options[:x] + (options[:width] * options[:text_padding])
|
@@ -679,7 +680,7 @@ module CombinePDF
|
|
679
680
|
insert_content 'Q'
|
680
681
|
|
681
682
|
# Prep content
|
682
|
-
@contents = ''
|
683
|
+
@contents = +''
|
683
684
|
insert_content @contents
|
684
685
|
@contents
|
685
686
|
end
|
@@ -788,7 +789,7 @@ module CombinePDF
|
|
788
789
|
# add to array
|
789
790
|
if out.last.nil? || out.last[0] != fonts[i]
|
790
791
|
out.last[1] << '>' unless out.last.nil?
|
791
|
-
out << [fonts[i], '<', 0, 0]
|
792
|
+
out << [fonts[i], (+'<'), 0, 0]
|
792
793
|
end
|
793
794
|
out.last[1] << (fonts_array[i].cmap.nil? ? (c.unpack('H*')[0]) : fonts_array[i].cmap[c])
|
794
795
|
if fonts_array[i].metrics[c]
|
data/lib/combine_pdf/parser.rb
CHANGED
@@ -262,7 +262,7 @@ module CombinePDF
|
|
262
262
|
##########################################
|
263
263
|
elsif @scanner.scan(/\(/)
|
264
264
|
# warn "Found a literal string"
|
265
|
-
str = ''.
|
265
|
+
str = ''.b
|
266
266
|
count = 1
|
267
267
|
while count > 0 && @scanner.rest?
|
268
268
|
scn = @scanner.scan_until(/[\(\)]/)
|
@@ -369,7 +369,7 @@ module CombinePDF
|
|
369
369
|
# the following was dicarded because some PDF files didn't have an EOL marker as required
|
370
370
|
# str = @scanner.scan_until(/(\r\n|\r|\n)endstream/)
|
371
371
|
# instead, a non-strict RegExp is used:
|
372
|
-
|
372
|
+
|
373
373
|
|
374
374
|
# raise error if the stream doesn't end.
|
375
375
|
unless @scanner.skip_until(/endstream/)
|
@@ -379,7 +379,7 @@ module CombinePDF
|
|
379
379
|
length = 0 if(length < 0)
|
380
380
|
length -= 1 if(@scanner.string[old_pos + length - 1] == "\n")
|
381
381
|
length -= 1 if(@scanner.string[old_pos + length - 1] == "\r")
|
382
|
-
str = (length > 0) ? @scanner.string.slice(old_pos, length) : ''
|
382
|
+
str = (length > 0) ? @scanner.string.slice(old_pos, length) : +''
|
383
383
|
|
384
384
|
# warn "CombinePDF parser: detected Stream #{str.length} bytes long #{str[0..3]}...#{str[-4..-1]}"
|
385
385
|
|
@@ -632,17 +632,17 @@ module CombinePDF
|
|
632
632
|
#
|
633
633
|
def serialize_objects_and_references
|
634
634
|
obj_dir = {}
|
635
|
-
objid_cache = {}
|
635
|
+
objid_cache = {}.compare_by_identity
|
636
636
|
# create a dictionary for referenced objects (no value resolution at this point)
|
637
637
|
# at the same time, delete duplicates and old versions when objects have multiple versions
|
638
638
|
@parsed.uniq!
|
639
639
|
@parsed.length.times do |i|
|
640
640
|
o = @parsed[i]
|
641
|
-
objid_cache[o
|
641
|
+
objid_cache[o] = i
|
642
642
|
tmp_key = [o[:indirect_reference_id], o[:indirect_generation_number]]
|
643
643
|
if tmp_found = obj_dir[tmp_key]
|
644
644
|
tmp_found.clear
|
645
|
-
@parsed[objid_cache[tmp_found
|
645
|
+
@parsed[objid_cache[tmp_found]] = nil
|
646
646
|
end
|
647
647
|
obj_dir[tmp_key] = o
|
648
648
|
end
|
@@ -765,9 +765,9 @@ module CombinePDF
|
|
765
765
|
# end
|
766
766
|
|
767
767
|
# # run block of code on evey PDF object (PDF objects are class Hash)
|
768
|
-
# def each_object(object, limit_references = true, already_visited = {}, &block)
|
768
|
+
# def each_object(object, limit_references = true, already_visited = {}.compare_by_identity, &block)
|
769
769
|
# unless limit_references
|
770
|
-
# already_visited[object
|
770
|
+
# already_visited[object] = true
|
771
771
|
# end
|
772
772
|
# case
|
773
773
|
# when object.is_a?(Array)
|
@@ -776,7 +776,7 @@ module CombinePDF
|
|
776
776
|
# yield(object)
|
777
777
|
# unless limit_references && object[:is_reference_only]
|
778
778
|
# object.each do |k,v|
|
779
|
-
# each_object(v, limit_references, already_visited, &block) unless already_visited[v
|
779
|
+
# each_object(v, limit_references, already_visited, &block) unless already_visited[v]
|
780
780
|
# end
|
781
781
|
# end
|
782
782
|
# end
|
@@ -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,7 +375,7 @@ module CombinePDF
|
|
373
375
|
private
|
374
376
|
|
375
377
|
def equal_layers obj1, obj2, layer = CombinePDF.eq_depth_limit
|
376
|
-
return true if obj1.
|
378
|
+
return true if obj1.equal?(obj2)
|
377
379
|
if obj1.is_a? Hash
|
378
380
|
return false unless obj2.is_a? Hash
|
379
381
|
return false unless obj1.length == obj2.length
|
@@ -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,7 +94,7 @@ 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
|
99
100
|
|
@@ -216,7 +217,7 @@ module CombinePDF
|
|
216
217
|
# when finished, remove the numbering system and keep only pointers
|
217
218
|
remove_old_ids
|
218
219
|
# output the pdf stream
|
219
|
-
out.join("\n".
|
220
|
+
out.join("\n".b).force_encoding(Encoding::ASCII_8BIT)
|
220
221
|
end
|
221
222
|
|
222
223
|
# this method returns all the pages cataloged in the catalog.
|
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,4 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'zlib'
|
4
5
|
require 'securerandom'
|
@@ -10,21 +11,21 @@ require 'digest'
|
|
10
11
|
# require the RC4 Gem
|
11
12
|
require 'rc4'
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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'
|
24
25
|
|
25
|
-
#
|
26
|
+
# require 'combine_pdf/operations'
|
26
27
|
|
27
|
-
|
28
|
+
require 'combine_pdf/version'
|
28
29
|
|
29
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).
|
30
31
|
#
|
@@ -12,7 +12,7 @@ class CombinePDFRendererTest < Minitest::Test
|
|
12
12
|
|
13
13
|
def test_numeric_array_to_pdf
|
14
14
|
input = [1.234567, 0.000054, 5, -0.000099]
|
15
|
-
expected = "[1.234567 0.000054 5 -0.000099]".
|
15
|
+
expected = "[1.234567 0.000054 5 -0.000099]".b
|
16
16
|
actual = TestRenderer.new.test_object(input)
|
17
17
|
|
18
18
|
assert_equal(expected, actual)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: combine_pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.28
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-rc4
|