combine_pdf 1.0.16 → 1.0.26

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d071703a8903bc5a11d7beb5a0bcb284a8bced5763705de3a7dd9ae6be35b64d
4
- data.tar.gz: 898069ad7ec79ad4fadea5383a721f28c5dfc3632fc20aaa40624954bfe70170
3
+ metadata.gz: fc482ee9da31ce7fc01e92da3936e44407e4879c7058817bb4a57ba0fc0a4165
4
+ data.tar.gz: 1dd52423ee639783510a9ad9aa347e9597e2e14d38a11914d05a03b5116006f2
5
5
  SHA512:
6
- metadata.gz: d52868ff7a021801207ff17a1e87aca8fa1bd82e6fd0dacf91d39d57695b07b87238898238fa90755bfaaec65cb4df384b6db97f3f4e3bf70da7d3d808e55daa
7
- data.tar.gz: f68133d14d5eb5f0428097b4421976da49471eed61f4ac0e574c4718b588458f6971fd107ccc397be004997f3c31ac6bfc122675992412fd521a7910d6f2abd9
6
+ metadata.gz: f6ac66c289762c5f2b6473f450e8808e79d9ca9f927b68f083204a93b7f213a433a6fc4076cd3241ff1a17ac7c08297087ab1bf76e58b0dad12e7a0eebc34628
7
+ data.tar.gz: a39c619af345d61d7d40ba0d0b0a32438caace2b05512273afe1f21b737de6324dcc483f34234c5123c9ed0508a0db481b4bf90ffc06fce2484922f2c6c7abe0
@@ -0,0 +1,28 @@
1
+ name: Main
2
+ on:
3
+ push:
4
+
5
+ jobs:
6
+ tests:
7
+ name: Tests
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: ["2.7", "3.0", "3.1", "3.2"]
13
+
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v3
17
+
18
+ - name: Setup Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ bundler-cache: true
23
+
24
+ - name: Generate lockfile
25
+ run: bundle lock
26
+
27
+ - name: Run tests
28
+ run: bundle exec rake test
data/.travis.yml ADDED
@@ -0,0 +1 @@
1
+ language: ruby
data/CHANGELOG.md CHANGED
@@ -1,6 +1,52 @@
1
1
  # Change Log
2
2
 
3
- ***
3
+ #### Change log v.1.0.26 (2023-12-22)
4
+
5
+ **Performance**: possible performance bump. Credit to @denislavski (Denislav Naydenov) for opening PR #235.
6
+
7
+ #### Change log v.1.0.25 (2023-12-19)
8
+
9
+ **Fix**: possible improve memory usage. Credit to @denislavski (Denislav Naydenov) for opening PR #233 and suggesting this change.
10
+
11
+ #### Change log v.1.0.24 (2023-10-19)
12
+
13
+ **Fix**: possible `nil` in loop. Credit to @jkowens for PR #231 and adding a quick fix using a simple guard.
14
+
15
+ **Fix**: preserve file creation date metadata where relevant.
16
+
17
+ #### Change log v.1.0.23 (2023-04-04)
18
+
19
+ **Feature**: merged PR #177 for the `raise_on_encrypted: true` option support. Credit to @leviwilson and @kimyu92 for the PR.
20
+
21
+ #### Change log v.1.0.22
22
+
23
+ **Fix**: fix `fonts` dereferencing issue (#203), credit to @MarcWeber (Marc Weber) for identifying the issue.
24
+
25
+ **Fix**: fix `metrix` dependency, credit to @casperisfine (Jean byroot Boussier) for PR #195.
26
+
27
+ #### Change log v.1.0.21
28
+
29
+ **Fix**: possible fix for issue #184, where nested PDF files within an object stream could break the parser. Credit to Greg Sparrow (@hazelsparrow) for exposng the issue.
30
+
31
+ #### Change log v.1.0.20
32
+
33
+ **Fix**: merges PR #180, `TypeError: can't dup NilClass`. Credit to Adam Trepanier (@adam-e-trepanier) for the merge.
34
+
35
+ #### Change log v.1.0.19
36
+
37
+ **Fix**: fixes font height and width detection issue. Issue #179. Credit to @5anchezzz for opening the issue.
38
+
39
+ **Fix**: fixes an indentation warning. Issue #173. Credit to @rubyFeedback for exposing this issue.
40
+
41
+ #### Change log v.1.0.18
42
+
43
+ **Fix**: fixed issue with the 1.0.17 release where `ProcSet` PDF Arrays should have been expected but where ignored and a PDF Object was assumed instead (issue #171) - credit to @chuchiperriman (Jesús Barbero Rodríguez).
44
+
45
+ #### Change log v.1.0.17
46
+
47
+ NB: yanked from RubyGems.org.
48
+
49
+ **Fix**: fixed issue where nested structure equality tests might provide false positives, resulting in lost data (issue #166) - credit to @cschilbe (Conrad Schilbe).
4
50
 
5
51
  #### Change log v.1.0.16
6
52
 
data/README.md CHANGED
@@ -1,27 +1,29 @@
1
1
  # CombinePDF - the ruby way for merging PDF files
2
2
  [![Gem Version](https://badge.fury.io/rb/combine_pdf.svg)](http://badge.fury.io/rb/combine_pdf)
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-Open%20Source-blue.svg)](https://github.com/boazsegev/combine_pdf)
4
+ [![Documentation](http://inch-ci.org/github/boazsegev/combine_pdf.svg?branch=master)](https://www.rubydoc.info/github/boazsegev/combine_pdf)
4
5
  [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/pickhardt/maintainers-wanted)
5
6
 
7
+
6
8
  CombinePDF is a nifty model, written in pure Ruby, to parse PDF files and combine (merge) them with other PDF files, watermark them or stamp them (all using the PDF file format and pure Ruby code).
7
9
 
8
- ## Install
10
+ ## Unmaintained - Help Wanted(!)
9
11
 
10
- Install with ruby gems:
12
+ I decided to stop maintaining this gem and hope someone could take over the PR reviews and maintenance of this gem (or simply open a successful fork).
11
13
 
12
- ```ruby
13
- gem install combine_pdf
14
- ```
14
+ I wrote this gem because I needed to solve an issue with bates-numbering existing PDF documents.
15
15
 
16
- ## Help Wanted
16
+ However, since 2014 I have been maintaining the gem for free and for no reason at all, except that I enjoyed sharing it with the community.
17
17
 
18
- I need help maintaining the CombinePDF Ruby gem.
18
+ I love this gem, but I cannot keep maintaining it as I have my own projects to focus own and I need both the time and (more importantly) the mindspace.
19
19
 
20
- I wrote this gem because I needed to solve an issue with bates-numbering existing PDF documents. However, during the last three years or so I have been maintaining the project for no reason at all, except that I enjoyed sharing it with the community.
20
+ ## Install
21
21
 
22
- I love this gem, but I feel it's time I took a step back from maintaining it and concentrate on my music and other things I want to develop.
22
+ Install with ruby gems:
23
23
 
24
- Please hit me up if you would like to join in and eventually take over.
24
+ ```ruby
25
+ gem install combine_pdf
26
+ ```
25
27
 
26
28
  ## Known Limitations
27
29
 
@@ -37,10 +39,12 @@ Quick rundown:
37
39
 
38
40
  Some links will be lost when ripping pages out of PDF files and merging them with another PDF.
39
41
 
40
- * Some encrypted PDF files (usually the ones you can't view without a password) will fail quietly instead of noisily.
42
+ * Some encrypted PDF files (usually the ones you can't view without a password) will fail quietly instead of noisily. If you prefer to choose the noisy route, you can specify the `raise_on_encrypted` option using `CombinePDF.load(pdf_file, raise_on_encrypted: true)` which will raise a `CombinePDF::EncryptionError`.
41
43
 
42
44
  * Sometimes the CombinePDF will raise an exception even if the PDF could be parsed (i.e., when PDF optional content exists)... I find it better to err on the side of caution, although for optional content PDFs an exception is avoidable using `CombinePDF.load(pdf_file, allow_optional_content: true)`.
43
45
 
46
+ * The CombinePDF gem runs recursive code to both parse and format the PDF files. Hence, PDF files that have heavily nested objects, as well as those that where combined in a way that results in cyclic nesting, might explode the stack - resulting in an exception or program failure.
47
+
44
48
  CombinePDF is written natively in Ruby and should (presumably) work on all Ruby platforms that follow Ruby 2.0 compatibility.
45
49
 
46
50
  However, PDF files are quite complex creatures and no guaranty is provided.
@@ -112,7 +116,42 @@ pdf.number_pages
112
116
  pdf.save "file_with_numbering.pdf"
113
117
  ```
114
118
 
115
- Numbering can be done with many different options, with different formating, with or without a box object, and even with opacity values - see documentation.
119
+ Numbering can be done with many different options, with different formating, with or without a box object, and even with opacity values - [see documentation](https://www.rubydoc.info/github/boazsegev/combine_pdf/CombinePDF/PDF#number_pages-instance_method).
120
+
121
+ For example, should you prefer to place the page number on the bottom right side of all PDF pages, do:
122
+
123
+ ```ruby
124
+ pdf.number_pages(location: [:bottom_right])
125
+ ```
126
+
127
+ As another example, the dashes around the number are removed and a box is placed around it. The numbering is semi-transparent and the first 3 pages are numbered using letters (a,b,c) rather than numbers:
128
+
129
+
130
+ ```ruby
131
+ # number first 3 pages as "a", "b", "c"
132
+ pdf.number_pages(number_format: " %s ",
133
+ location: [:top, :bottom, :top_left, :top_right, :bottom_left, :bottom_right],
134
+ start_at: "a",
135
+ page_range: (0..2),
136
+ box_color: [0.8,0.8,0.8],
137
+ border_color: [0.4, 0.4, 0.4],
138
+ border_width: 1,
139
+ box_radius: 6,
140
+ opacity: 0.75)
141
+ # number the rest of the pages as 4, 5, ... etc'
142
+ pdf.number_pages(number_format: " %s ",
143
+ location: [:top, :bottom, :top_left, :top_right, :bottom_left, :bottom_right],
144
+ start_at: 4,
145
+ page_range: (3..-1),
146
+ box_color: [0.8,0.8,0.8],
147
+ border_color: [0.4, 0.4, 0.4],
148
+ border_width: 1,
149
+ box_radius: 6,
150
+ opacity: 0.75)
151
+ ```
152
+
153
+ pdf.number_pages(number_format: " %s ", location: :bottom_right, font_size: 44)
154
+
116
155
 
117
156
  ## Loading and Parsing PDF data
118
157
 
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task default: 'test'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
2
9
 
data/combine_pdf.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "combine_pdf"
8
8
  spec.version = CombinePDF::VERSION
9
9
  spec.authors = ["Boaz Segev"]
10
- spec.email = ["boaz@2be.co.il"]
10
+ spec.email = ["bo@bowild.com"]
11
11
  spec.summary = %q{Combine, stamp and watermark PDF files in pure Ruby.}
12
12
  spec.description = %q{A nifty gem, in pure Ruby, to parse PDF files and combine (merge) them with other PDF files, number the pages, watermark them or stamp them, create tables, add basic text objects etc` (all using the PDF file format).}
13
13
  spec.homepage = "https://github.com/boazsegev/combine_pdf"
@@ -19,8 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_runtime_dependency 'ruby-rc4', '>= 0.1.5'
22
+ spec.add_runtime_dependency 'matrix'
22
23
 
23
24
  # spec.add_development_dependency "bundler", ">= 1.7"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rake", ">= 12.3.3"
25
26
  spec.add_development_dependency "minitest"
27
+ spec.add_development_dependency "minitest-around"
26
28
  end
@@ -24,11 +24,11 @@ module CombinePDF
24
24
  raise TypeError, "couldn't create PDF object, expecting type String" unless string.is_a?(String) || string.is_a?(Pathname)
25
25
  begin
26
26
  (begin
27
- File.file? string
28
- rescue
29
- false
30
- end) ? load(string) : parse(string)
31
- rescue => _e
27
+ File.file? string
28
+ rescue
29
+ false
30
+ end) ? load(string) : parse(string)
31
+ rescue => _e
32
32
  raise 'General PDF error - Use CombinePDF.load or CombinePDF.parse for a non-general error message (the requested file was not found OR the string received is not a valid PDF stream OR the file was found but not valid).'
33
33
  end
34
34
  end
@@ -138,12 +138,21 @@ module CombinePDF
138
138
  text.each_char do |c|
139
139
  metrics_array << (merged_metrics[c] || { wx: 0, boundingbox: [0, 0, 0, 0] })
140
140
  end
141
- height = metrics_array.map { |m| m ? m[:boundingbox][3] : 0 } .max
142
- height -= (metrics_array.map { |m| m ? m[:boundingbox][1] : 0 }).min
141
+ metrics_array_mapped_top = [].dup
142
+ metrics_array_mapped_bottom = [].dup
143
143
  width = 0.0
144
144
  metrics_array.each do |m|
145
- width += (m[:wx] || m[:wy])
145
+ if (m && m[:boundingbox])
146
+ metrics_array_mapped_top << m[:boundingbox][3]
147
+ metrics_array_mapped_bottom << m[:boundingbox][1]
148
+ else
149
+ metrics_array_mapped_top << 0
150
+ metrics_array_mapped_bottom << 0
151
+ end
152
+ width += (m[:wx] || m[:wy] || 0) if m
146
153
  end
154
+ height = metrics_array_mapped_top.max
155
+ height -=metrics_array_mapped_bottom.min
147
156
  return [height.to_f / 1000 * size, width.to_f / 1000 * size] if metrics_array[0][:wy]
148
157
  [width.to_f / 1000 * size, height.to_f / 1000 * size]
149
158
  end
@@ -94,7 +94,7 @@ module CombinePDF
94
94
  # end
95
95
 
96
96
  # set ProcSet to recommended value
97
- resources[:ProcSet] = [:PDF, :Text, :ImageB, :ImageC, :ImageI] # this was recommended by the ISO. 32000-1:2008
97
+ resources[:ProcSet] ||= [:PDF, :Text, :ImageB, :ImageC, :ImageI] # this was recommended by the ISO. 32000-1:2008
98
98
 
99
99
  if top # if this is a stamp (overlay)
100
100
  insert_content CONTENT_CONTAINER_START, 0
@@ -147,7 +147,7 @@ module CombinePDF
147
147
 
148
148
  # This method adds a simple text box to the Page represented by the PDFWriter class.
149
149
  # This function takes two values:
150
- # text:: the text to potin the box.
150
+ # text:: the text to write in the box.
151
151
  # properties:: a Hash of box properties.
152
152
  # the symbols and values in the properties Hash could be any or all of the following:
153
153
  # x:: the left position of the box.
@@ -33,7 +33,7 @@ module CombinePDF
33
33
  # they are mainly to used to know if the file is (was) encrypted and to get more details.
34
34
  attr_reader :info_object, :root_object, :names_object, :forms_object, :outlines_object, :metadata
35
35
 
36
- attr_reader :allow_optional_content
36
+ attr_reader :allow_optional_content, :raise_on_encrypted
37
37
  # when creating a parser, it is important to set the data (String) we wish to parse.
38
38
  #
39
39
  # <b>the data is required and it is not possible to set the data at a later stage</b>
@@ -58,6 +58,7 @@ module CombinePDF
58
58
  @version = nil
59
59
  @scanner = nil
60
60
  @allow_optional_content = options[:allow_optional_content]
61
+ @raise_on_encrypted = options[:raise_on_encrypted]
61
62
  end
62
63
 
63
64
  # parse the data in the new parser (the data already set through the initialize / new method)
@@ -96,6 +97,7 @@ module CombinePDF
96
97
  end
97
98
 
98
99
  if @root_object[:Encrypt]
100
+ raise EncryptionError, 'the file is encrypted' if @raise_on_encrypted
99
101
  # change_references_to_actual_values @root_object
100
102
  warn 'PDF is Encrypted! Attempting to decrypt - not yet fully supported.'
101
103
  decryptor = PDFDecrypt.new @parsed, @root_object
@@ -233,16 +235,18 @@ module CombinePDF
233
235
  # all characters that aren't white space or special: /[^\x00\x09\x0a\x0c\x0d\x20\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+
234
236
  elsif str = @scanner.scan(/\/[^\x00\x09\x0a\x0c\x0d\x20\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]*/)
235
237
  out << (str[1..-1].gsub(/\#[0-9a-fA-F]{2}/) { |a| a[1..2].hex.chr }).to_sym
238
+ # warn "CombinePDF detected name: #{out.last.to_s}"
236
239
  ##########################################
237
240
  ## Parse a Number
238
241
  ##########################################
239
242
  elsif str = @scanner.scan(/[\+\-\.\d]+/)
240
243
  str =~ /\./ ? (out << str.to_f) : (out << str.to_i)
244
+ # warn "CombinePDF detected number: #{out.last.to_s}"
241
245
  ##########################################
242
246
  ## parse a Hex String
243
247
  ##########################################
244
248
  elsif str = @scanner.scan(/\<[0-9a-fA-F]*\>/)
245
- # warn "Found a hex string"
249
+ # warn "Found a hex string #{str}"
246
250
  str = str.slice(1..-2).force_encoding(Encoding::ASCII_8BIT)
247
251
  # str = "0#{str}" if str.length.odd?
248
252
  out << unify_string([str].pack('H*').force_encoding(Encoding::ASCII_8BIT))
@@ -319,8 +323,8 @@ module CombinePDF
319
323
  str << 12
320
324
  when 48..57 # octal notation for byte?
321
325
  rep -= 48
322
- rep = (rep << 3) + (str_bytes.shift-48) if str_bytes[0].between?(48, 57)
323
- rep = (rep << 3) + (str_bytes.shift-48) if str_bytes[0].between?(48, 57) && (((rep << 3) + (str_bytes[0] - 48)) <= 255)
326
+ rep = (rep << 3) + (str_bytes.shift-48) if str_bytes[0]&.between?(48, 57)
327
+ rep = (rep << 3) + (str_bytes.shift-48) if str_bytes[0]&.between?(48, 57) && (((rep << 3) + (str_bytes[0] - 48)) <= 255)
324
328
  str << rep
325
329
  when 10 # new line, ignore
326
330
  str_bytes.shift if str_bytes[0] == 13
@@ -336,6 +340,7 @@ module CombinePDF
336
340
  end
337
341
  end
338
342
  out << unify_string(str.pack('C*').force_encoding(Encoding::ASCII_8BIT))
343
+ # warn "Found Literal String: #{out.last}"
339
344
  ##########################################
340
345
  ## parse a Dictionary
341
346
  ##########################################
@@ -348,29 +353,42 @@ module CombinePDF
348
353
  ## return content of array or dictionary
349
354
  ##########################################
350
355
  elsif @scanner.scan(/\]/) || @scanner.scan(/>>/)
356
+ # warn "Dictionary / Array ended with #{@scanner.peek(5)}"
351
357
  return out
352
358
  ##########################################
353
359
  ## parse a Stream
354
360
  ##########################################
355
361
  elsif @scanner.scan(/stream[ \t]*[\r\n]/)
356
362
  @scanner.pos += 1 if @scanner.peek(1) == "\n".freeze && @scanner.matched[-1] != "\n".freeze
363
+ # advance by the publshed stream length (if any)
364
+ old_pos = @scanner.pos
365
+ if(out.last.is_a?(Hash) && out.last[:Length].is_a?(Integer) && out.last[:Length] > 2)
366
+ @scanner.pos += out.last[:Length] - 2
367
+ end
368
+
357
369
  # the following was dicarded because some PDF files didn't have an EOL marker as required
358
370
  # str = @scanner.scan_until(/(\r\n|\r|\n)endstream/)
359
371
  # instead, a non-strict RegExp is used:
360
- str = @scanner.scan_until(/endstream/)
372
+
361
373
 
362
374
  # raise error if the stream doesn't end.
363
- unless str
375
+ unless @scanner.skip_until(/endstream/)
364
376
  raise ParsingError, "Parsing Error: PDF file error - a stream object wasn't properly closed using 'endstream'!"
365
377
  end
378
+ length = @scanner.pos - (old_pos + 9)
379
+ length = 0 if(length < 0)
380
+ length -= 1 if(@scanner.string[old_pos + length - 1] == "\n")
381
+ length -= 1 if(@scanner.string[old_pos + length - 1] == "\r")
382
+ str = (length > 0) ? @scanner.string.slice(old_pos, length) : ''
383
+
384
+ # warn "CombinePDF parser: detected Stream #{str.length} bytes long #{str[0..3]}...#{str[-4..-1]}"
366
385
 
367
386
  # need to remove end of stream
368
387
  if out.last.is_a? Hash
369
- # out.last[:raw_stream_content] = str[0...-10] #cuts only one EON char (\n or \r)
370
- out.last[:raw_stream_content] = unify_string str.sub(/(\r\n|\n|\r)?endstream\z/, '').force_encoding(Encoding::ASCII_8BIT)
388
+ out.last[:raw_stream_content] = unify_string str.force_encoding(Encoding::ASCII_8BIT)
371
389
  else
372
390
  warn 'Stream not attached to dictionary!'
373
- out << str.sub(/(\r\n|\n|\r)?endstream\z/, '').force_encoding(Encoding::ASCII_8BIT)
391
+ out << str.force_encoding(Encoding::ASCII_8BIT)
374
392
  end
375
393
  ##########################################
376
394
  ## parse an Object after finished
@@ -528,6 +546,14 @@ module CombinePDF
528
546
  inheritance_hash[:Resources] ||= { referenced_object: {}, is_reference_only: true }.dup
529
547
  (inheritance_hash[:Resources][:referenced_object] || inheritance_hash[:Resources]).update((catalogs[:Resources][:referenced_object] || catalogs[:Resources]), &HASH_UPDATE_PROC_FOR_OLD)
530
548
  end
549
+ if catalogs[:ProcSet].is_a?(Array)
550
+ if(inheritance_hash[:ProcSet])
551
+ inheritance_hash[:ProcSet][:referenced_object].concat(catalogs[:ProcSet])
552
+ inheritance_hash[:ProcSet][:referenced_object].uniq!
553
+ else
554
+ inheritance_hash[:ProcSet] ||= { referenced_object: catalogs[:ProcSet], is_reference_only: true }.dup
555
+ end
556
+ end
531
557
  if catalogs[:ColorSpace]
532
558
  inheritance_hash[:ColorSpace] ||= { referenced_object: {}, is_reference_only: true }.dup
533
559
  (inheritance_hash[:ColorSpace][:referenced_object] || inheritance_hash[:ColorSpace]).update((catalogs[:ColorSpace][:referenced_object] || catalogs[:ColorSpace]), &HASH_UPDATE_PROC_FOR_OLD)
@@ -556,6 +582,18 @@ module CombinePDF
556
582
  catalogs[:ColorSpace] = { referenced_object: catalogs[:ColorSpace], is_reference_only: true } unless catalogs[:ColorSpace][:referenced_object]
557
583
  catalogs[:ColorSpace][:referenced_object].update((inheritance_hash[:ColorSpace][:referenced_object] || inheritance_hash[:ColorSpace]), &HASH_UPDATE_PROC_FOR_OLD)
558
584
  end
585
+ if inheritance_hash[:ProcSet]
586
+ if(catalogs[:ProcSet])
587
+ if catalogs[:ProcSet].is_a?(Array)
588
+ catalogs[:ProcSet] = { referenced_object: catalogs[:ProcSet], is_reference_only: true }
589
+ end
590
+ catalogs[:ProcSet][:referenced_object].concat(inheritance_hash[:ProcSet][:referenced_object])
591
+ catalogs[:ProcSet][:referenced_object].uniq!
592
+ else
593
+ catalogs[:ProcSet] = { is_reference_only: true }.dup
594
+ catalogs[:ProcSet][:referenced_object] = []
595
+ end
596
+ end
559
597
  # (catalogs[:ColorSpace] ||= {}).update(inheritance_hash[:ColorSpace], &HASH_UPDATE_PROC_FOR_OLD) if inheritance_hash[:ColorSpace]
560
598
  # catalogs[:Order] ||= inheritance_hash[:Order] if inheritance_hash[:Order]
561
599
  # catalogs[:AS] ||= inheritance_hash[:AS] if inheritance_hash[:AS]
@@ -373,16 +373,19 @@ module CombinePDF
373
373
  private
374
374
 
375
375
  def equal_layers obj1, obj2, layer = CombinePDF.eq_depth_limit
376
- return true if(layer == 0)
377
376
  return true if obj1.object_id == obj2.object_id
378
377
  if obj1.is_a? Hash
379
378
  return false unless obj2.is_a? Hash
379
+ return false unless obj1.length == obj2.length
380
380
  keys = obj1.keys;
381
- return false if (keys - obj2.keys).any?
381
+ keys2 = obj2.keys;
382
+ return false if (keys - keys2).any? || (keys2 - keys).any?
383
+ return (warn("CombinePDF nesting limit reached") || true) if(layer == 0)
382
384
  keys.each {|k| return false unless equal_layers( obj1[k], obj2[k], layer-1) }
383
385
  elsif obj1.is_a? Array
384
386
  return false unless obj2.is_a? Array
385
- (obj1-obj2).any?
387
+ return false unless obj1.length == obj2.length
388
+ (obj1-obj2).any? || (obj2-obj1).any?
386
389
  else
387
390
  obj1 == obj2
388
391
  end
@@ -96,6 +96,7 @@ module CombinePDF
96
96
  parser ||= PDFParser.new('')
97
97
  raise TypeError, "initialization error, expecting CombinePDF::PDFParser or nil, but got #{parser.class.name}" unless parser.is_a? PDFParser
98
98
  @objects = parser.parse
99
+
99
100
  # remove any existing id's
100
101
  remove_old_ids
101
102
  # set data from parser
@@ -174,8 +175,12 @@ module CombinePDF
174
175
  def to_pdf(options = {})
175
176
  # reset version if not specified
176
177
  @version = 1.5 if @version.to_f == 0.0
178
+
177
179
  # set info for merged file
178
- @info[:ModDate] = @info[:CreationDate] = Time.now.strftime "D:%Y%m%d%H%M%S%:::z'00"
180
+ unless(@info[:CreationDate].is_a?(String))
181
+ @info[:CreationDate] = Time.now unless @info[:CreationDate].is_a?(Time)
182
+ @info[:CreationDate] = @info[:CreationDate].getgm.strftime("D:%Y%m%d%H%M%S%:::z'00")
183
+ end
179
184
  @info[:Subject] = options[:subject] if options[:subject]
180
185
  @info[:Producer] = options[:producer] if options[:producer]
181
186
  # rebuild_catalog
@@ -201,9 +206,9 @@ module CombinePDF
201
206
  xref_location = loc
202
207
  # xref_location = 0
203
208
  # out.each { |line| xref_location += line.bytesize + 1}
204
- out << "xref\n0 #{indirect_object_count}\n0000000000 65535 f \n"
205
- xref.each { |offset| out << (out.pop + ("%010d 00000 n \n" % offset)) }
206
- out << out.pop + 'trailer'
209
+ out << "xref\n0 #{indirect_object_count}\n0000000000 65535 f "
210
+ xref.each { |offset| out << ("%010d 00000 n ".freeze % offset) }
211
+ out << 'trailer'.freeze
207
212
  out << "<<\n/Root #{false || "#{catalog[:indirect_reference_id]} #{catalog[:indirect_generation_number]} R"}"
208
213
  out << "/Size #{indirect_object_count}"
209
214
  out << "/Info #{@info[:indirect_reference_id]} #{@info[:indirect_generation_number]} R"
@@ -257,12 +262,18 @@ module CombinePDF
257
262
  def fonts(limit_to_type0 = false)
258
263
  fonts_array = []
259
264
  pages.each do |pg|
260
- if pg[:Resources][:Font]
261
- pg[:Resources][:Font].values.each do |f|
262
- f = f[:referenced_object] if f[:referenced_object]
263
- if (limit_to_type0 || f[:Subtype] == :Type0) && f[:Type] == :Font && !fonts_array.include?(f)
264
- fonts_array << f
265
- end
265
+ r = pg[:Resources]
266
+ next if !r
267
+ r = r[:referenced_object] if r[:referenced_object]
268
+ r = r[:Font]
269
+ next if !r
270
+ r = r[:referenced_object] if r[:referenced_object]
271
+ r.values.each do |f|
272
+ next if f.class != Hash
273
+ f = f[:referenced_object] if f[:referenced_object]
274
+ next if f.class != Hash
275
+ if (limit_to_type0 || f[:Subtype] == :Type0) && f[:Type] == :Font && !fonts_array.include?(f)
276
+ fonts_array << f
266
277
  end
267
278
  end
268
279
  end
@@ -1,3 +1,3 @@
1
1
  module CombinePDF
2
- VERSION = '1.0.16'.freeze
2
+ VERSION = '1.0.26'.freeze
3
3
  end
data/lib/combine_pdf.rb CHANGED
@@ -5,6 +5,7 @@ require 'securerandom'
5
5
  require 'strscan'
6
6
  require 'matrix'
7
7
  require 'set'
8
+ require 'digest'
8
9
 
9
10
  # require the RC4 Gem
10
11
  require 'rc4'
data/test/automated CHANGED
@@ -3,9 +3,10 @@
3
3
  $VERBOSE = true
4
4
 
5
5
  require 'benchmark'
6
- $LOAD_PATH.unshift File.expand_path(File.join('..', '..', 'lib'), __FILE__)
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 "./Ruby/test\ pdfs/filled_form.pdf"
18
- pdf.save '01_check_radio_buttuns.pdf'
19
- pdf = CombinePDF.load "./Ruby/test\ pdfs/filled_form.pdf"
20
- pdf << CombinePDF.load("./Ruby/test\ pdfs/empty_form.pdf")
21
- pdf << CombinePDF.load("./Ruby/test\ pdfs/filled_form.pdf")
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 "./Ruby/test\ pdfs/check_form_data__objstreams_w_versions.pdf"
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 './Ruby/test pdfs/share-font-background.pdf'
29
- pdf2 = CombinePDF.load './Ruby/test pdfs/share-font-foreground.pdf'
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 './Ruby/test pdfs/nil_1.pdf'
35
- pdf2 = CombinePDF.load './Ruby/test pdfs/nil_2.pdf'
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 './Ruby/test pdfs/space_after_streram_keyword.pdf'
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 './Ruby/test pdfs/nested_difference.pdf'
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 './Ruby/test pdfs/names_go_haywire_0.pdf'
46
- pdf << CombinePDF.load('./Ruby/test pdfs/names_go_haywire_1.pdf')
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('./Ruby/test pdfs/outlines/self_merge_err.pdf')
50
- pdf.save '05_x1_scribus_test.pdf'
51
- pdf = CombinePDF.load('./Ruby/test pdfs/outlines/self_merge_err.pdf')
52
- pdf << CombinePDF.load('./Ruby/test pdfs/outlines/self_merge_err.pdf')
53
- pdf.save '05_x2_scribus_test.pdf'
54
- # pdf = CombinePDF.load "./Ruby/test pdfs/named_dest.pdf";nil
55
- # pdf.save '05_check_named_dest_links.pdf' # this will take a while
56
- # pdf = CombinePDF.load "./Ruby/test pdfs/named_dest.pdf";nil
57
- pdf << CombinePDF.load('./Ruby/test pdfs/named_dest.pdf'); nil
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 './Ruby/test pdfs/outline_small.pdf'
61
- pdf << CombinePDF.load('./Ruby/test pdfs/outline_small.pdf')
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(./Ruby/test\ pdfs/outlines/self_merge_err.pdf ./Ruby/test\ pdfs/outlines/big_toc.pdf ./Ruby/test\ pdfs/outlines/bigger_toc.pdf ./Ruby/test\ pdfs/outlines/named_dest_no_toc.pdf ./Ruby/test\ pdfs/outlines/named_dest_no_toc2.pdf ./Ruby/test\ pdfs/outlines/named_dest.pdf ./Ruby/test\ pdfs/outlines/named_dest2.pdf)
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("./Ruby/test\ pdfs/Scribus-unknown_err.pdf").save '08_1-unknown-err-empty-str.pdf'
96
- CombinePDF.load("./Ruby/test\ pdfs/Scribus-unknown_err2.pdf").save '08_2-unknown-err-empty-str.pdf'
97
- CombinePDF.load("./Ruby/test\ pdfs/Scribus-unknown_err3.pdf").save '08_3-unknown-err-empty-str.pdf'
98
- CombinePDF.load("./Ruby/test\ pdfs/xref_in_middle.pdf").save '08_4-xref-in-middle.pdf'
99
- CombinePDF.load("./Ruby/test\ pdfs/xref_split.pdf").save '08_5-xref-fragmented.pdf'
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("/Users/2Be/Ruby/test\ pdfs/nil_object.pdf").save('09_nil_in_parsed_array.pdf')
102
+ CombinePDF.load("../../test\ pdfs/nil_object.pdf").save('../tmp/09_nil_in_parsed_array.pdf')
102
103
 
103
- encrypted = [ "./Ruby/test\ pdfs/pdf-reader/encrypted_version4_revision4_128bit_aes_user_pass_apples_enc_metadata.pdf",
104
- "./Ruby/test\ pdfs/AESv2\ encrypted.pdf",
105
- "./Ruby/test\ pdfs/pdf-reader/encrypted_version2_revision3_128bit_rc4_blank_user_pass.pdf",
106
- "./Ruby/test\ pdfs/AES\ enc.pdf",
107
- "./Ruby/test\ pdfs/RC4\ enc.pdf"]
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
- # "./Ruby/test\ pdfs/AESv2\ encrypted.pdf",
136
- # "./Ruby/test\ pdfs/data-in-comment.pdf",
137
- # "./Ruby/test\ pdfs/file_name.pdf",
138
- # "./Ruby/test\ pdfs/garbage_after_eof.pdf",
139
- # "./Ruby/test\ pdfs/Many\ comments.pdf",
140
- # "./Ruby/test\ pdfs/nested\ contents\ array.PDF",
141
- # "./Ruby/test\ pdfs/nested_resources.pdf",
142
- # "./Ruby/test\ pdfs/original-missing-endobje.pdf",
143
- # "./Ruby/test\ pdfs/original-multi-issue.pdf",
144
- # "./Ruby/test\ pdfs/page_stap_nil_secure.pdf",
145
- # "./Ruby/test\ pdfs/referenced\ decryption.pdf",
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
 
Binary file
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.16
4
+ version: 1.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-22 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-rc4
@@ -24,20 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.1.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: matrix
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - "~>"
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
- version: '10.0'
47
+ version: 12.3.3
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - "~>"
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: 12.3.3
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: minitest
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,16 +66,32 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-around
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description: A nifty gem, in pure Ruby, to parse PDF files and combine (merge) them
56
84
  with other PDF files, number the pages, watermark them or stamp them, create tables,
57
85
  add basic text objects etc` (all using the PDF file format).
58
86
  email:
59
- - boaz@2be.co.il
87
+ - bo@bowild.com
60
88
  executables: []
61
89
  extensions: []
62
90
  extra_rdoc_files: []
63
91
  files:
92
+ - ".github/workflows/main.yml"
64
93
  - ".gitignore"
94
+ - ".travis.yml"
65
95
  - CHANGELOG.md
66
96
  - Gemfile
67
97
  - LICENSE.txt
@@ -82,14 +112,17 @@ files:
82
112
  - lib/combine_pdf/renderer.rb
83
113
  - lib/combine_pdf/version.rb
84
114
  - test/automated
115
+ - test/combine_pdf/load_test.rb
85
116
  - test/combine_pdf/renderer_test.rb
86
117
  - test/console
118
+ - test/fixtures/files/sample_encrypted_pdf.pdf
119
+ - test/fixtures/files/sample_pdf.pdf
87
120
  - test/named_dest
88
121
  homepage: https://github.com/boazsegev/combine_pdf
89
122
  licenses:
90
123
  - MIT
91
124
  metadata: {}
92
- post_install_message:
125
+ post_install_message:
93
126
  rdoc_options: []
94
127
  require_paths:
95
128
  - lib
@@ -104,12 +137,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
137
  - !ruby/object:Gem::Version
105
138
  version: '0'
106
139
  requirements: []
107
- rubygems_version: 3.0.1
108
- signing_key:
140
+ rubygems_version: 3.3.26
141
+ signing_key:
109
142
  specification_version: 4
110
143
  summary: Combine, stamp and watermark PDF files in pure Ruby.
111
144
  test_files:
112
145
  - test/automated
146
+ - test/combine_pdf/load_test.rb
113
147
  - test/combine_pdf/renderer_test.rb
114
148
  - test/console
149
+ - test/fixtures/files/sample_encrypted_pdf.pdf
150
+ - test/fixtures/files/sample_pdf.pdf
115
151
  - test/named_dest