combine_pdf 1.0.13 → 1.0.18

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: 3ca8e3d75a2b167718e3f749076bd5bbbd1701b0218a811fd9fed4dda23c194a
4
- data.tar.gz: 71bae00e5caeba7b1f70d2fc3492a669b5c05fcde8d56a9b58b7bbda2010cec9
3
+ metadata.gz: 95f44419c731c5b1e7625589d159c608ab6948004e347db9ee2380611e10dd6f
4
+ data.tar.gz: d2ee8cf53e111cdf4051886262ad2a4fa216eca36aaaf1b45b7782379f793642
5
5
  SHA512:
6
- metadata.gz: 4c680801b7c0c925e1c6a66459b51de48ff3942c1cf24d5b31dbad55a2fb88f434ac4f67404c81ee422e672c92fc852ba4708835904c1d041cc5537abc13ba87
7
- data.tar.gz: b2cb8a1eecf10d2503193f09802dc25655cd79b8bf41d422c1c45152fb0cf98e2092788bc19e77d139ec5918fa42782a5f97a2e1e9a7f9703de5be5b4479d2ca
6
+ metadata.gz: 7cac17e8c080e0eba10f19efa90c5eb6252f12811218ff5ad8f330ec8977abec677628d6cfaf70d9abc5e2b754e711e9024315cad0de2f32286f1d7dbeabec87
7
+ data.tar.gz: 7e60b19afafa071a6d21ce73da4be142501c0becc4aede5e579706789d0c276903a8193661d0ffa16d0c4c906d0fa6136124011d1de3a8c968a3c1334804d476
@@ -2,6 +2,26 @@
2
2
 
3
3
  ***
4
4
 
5
+ #### Change log v.1.0.18
6
+
7
+ **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).
8
+
9
+ #### Change log v.1.0.17
10
+
11
+ **Fix**: fixed issue where nested structure equality tests might provide false positives, resulting in lost data (issue #166) - credit to @cschilbe (Conrad Schilbe).
12
+
13
+ #### Change log v.1.0.16
14
+
15
+ **Fix**: some documentation typos were fixed (PR #147) - credit to @djhopper01 (Derek Hopper).
16
+
17
+ #### Change log v.1.0.15
18
+
19
+ **Fix**: An attempt to fix JRuby compatibility concerns (issue #127).
20
+
21
+ #### Change log v.1.0.14
22
+
23
+ **Fix**: Fixed an issue related to PDF XRef table data, where a malformed EOL marker would cause the parser to fail. Credit to @dangerous (David Rainsford) for exposing this issue in a comment to issue #140.
24
+
5
25
  #### Change log v.1.0.13
6
26
 
7
27
  **Fix**: Fixed an issue related to PDF object streams (version 1.6) where a numerical object at the beginning of the stream might be mis-parsed as an object reference number rather than an object. Credit to @Defoncesko for reporting issue #141.
data/README.md CHANGED
@@ -41,6 +41,8 @@ Quick rundown:
41
41
 
42
42
  * 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
43
 
44
+ * 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.
45
+
44
46
  CombinePDF is written natively in Ruby and should (presumably) work on all Ruby platforms that follow Ruby 2.0 compatibility.
45
47
 
46
48
  However, PDF files are quite complex creatures and no guaranty is provided.
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency 'ruby-rc4', '>= 0.1.5'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.7"
24
- spec.add_development_dependency "rake", "~> 10.0"
23
+ # spec.add_development_dependency "bundler", ">= 1.7"
24
+ spec.add_development_dependency "rake", ">= 12.3.3"
25
25
  spec.add_development_dependency "minitest"
26
26
  end
@@ -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'
@@ -140,7 +140,7 @@ module CombinePDF
140
140
  # this function enables plug-ins to expend the font functionality of CombinePDF.
141
141
  #
142
142
  # font_name:: a Symbol with the name of the font. if the fonts exists in the library, it will be overwritten!
143
- # font_metrics:: a Hash of font metrics, of the format char => {wx: char_width, boundingbox: [left_x, buttom_y, right_x, top_y]} where char == character itself (i.e. " " for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy might be supported in the future, for up to down fonts.
143
+ # font_metrics:: a Hash of font metrics, of the format char => {wx: char_width, boundingbox: [left_x, bottom_y, right_x, top_y]} where char == character itself (i.e. " " for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy might be supported in the future, for up to down fonts.
144
144
  # font_pdf_object:: a Hash in the internal format recognized by CombinePDF, that represents the font object.
145
145
  # font_cmap:: a CMap dictionary Hash) which maps unicode characters to the hex CID for the font (i.e. {"a" => "61", "z" => "7a" }).
146
146
  def register_font(font_name, font_metrics, font_pdf_object, font_cmap = nil)
@@ -100,7 +100,7 @@ module CombinePDF
100
100
 
101
101
  # adds a correctly formatted font object to the font library.
102
102
  # font_name:: a Symbol with the name of the font. if the fonts name exists, the font will be overwritten!
103
- # font_metrics:: a Hash of ont metrics, of the format char => {wx: char_width, boundingbox: [left_x, buttom_y, right_x, top_y]} where i == character code (i.e. 32 for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy will be supported in the future, for up to down fonts.
103
+ # font_metrics:: a Hash of ont metrics, of the format char => {wx: char_width, boundingbox: [left_x, bottom_y, right_x, top_y]} where i == character code (i.e. 32 for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy will be supported in the future, for up to down fonts.
104
104
  # font_pdf_object:: a Hash in the internal format recognized by CombinePDF, that represents the font object.
105
105
  # font_cmap:: a CMap dictionary Hash) which maps unicode characters to the hex CID for the font (i.e. {"a" => "61", "z" => "7a" }).
106
106
  def register_font(font_name, font_metrics, font_pdf_object, font_cmap = nil)
@@ -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,15 +147,15 @@ 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.
154
- # y:: the BUTTOM position of the box.
154
+ # y:: the BOTTOM position of the box.
155
155
  # width:: the width/length of the box. negative values will be computed from edge of page. defaults to 0 (end of page).
156
156
  # height:: the height of the box. negative values will be computed from edge of page. defaults to 0 (end of page).
157
157
  # text_align:: symbol for horizontal text alignment, can be ":center" (default), ":right", ":left"
158
- # text_valign:: symbol for vertical text alignment, can be ":center" (default), ":top", ":buttom"
158
+ # text_valign:: symbol for vertical text alignment, can be ":center" (default), ":top", ":bottom"
159
159
  # text_padding:: a Float between 0 and 1, setting the padding for the text. defaults to 0.05 (5%).
160
160
  # font:: a registered font name or an Array of names. defaults to ":Helvetica". The 14 standard fonts names are:
161
161
  # - :"Times-Roman"
@@ -244,8 +244,8 @@ module CombinePDF
244
244
  half_radius = (radius.to_f / 2).round 4
245
245
  ## set starting point
246
246
  box_stream << "#{options[:x] + radius} #{options[:y]} m\n"
247
- ## buttom and right corner - first line and first corner
248
- box_stream << "#{options[:x] + options[:width] - radius} #{options[:y]} l\n" # buttom
247
+ ## bottom and right corner - first line and first corner
248
+ box_stream << "#{options[:x] + options[:width] - radius} #{options[:y]} l\n" # bottom
249
249
  if options[:box_radius] != 0 # make first corner, if not straight.
250
250
  box_stream << "#{options[:x] + options[:width] - half_radius} #{options[:y]} "
251
251
  box_stream << "#{options[:x] + options[:width]} #{options[:y] + half_radius} "
@@ -265,7 +265,7 @@ module CombinePDF
265
265
  box_stream << "#{options[:x]} #{options[:y] + options[:height] - half_radius} "
266
266
  box_stream << "#{options[:x]} #{options[:y] + options[:height] - radius} c\n"
267
267
  end
268
- ## left and buttom-left corner
268
+ ## left and bottom-left corner
269
269
  box_stream << "#{options[:x]} #{options[:y] + radius} l\n"
270
270
  if options[:box_radius] != 0
271
271
  box_stream << "#{options[:x]} #{options[:y] + half_radius} "
@@ -287,7 +287,7 @@ module CombinePDF
287
287
  end
288
288
  contents << box_stream
289
289
 
290
- # reset x,y by text alignment - x,y are calculated from the buttom left
290
+ # reset x,y by text alignment - x,y are calculated from the bottom left
291
291
  # each unit (1) is 1/72 Inch
292
292
  # create text stream
293
293
  text_stream = ''
@@ -233,16 +233,18 @@ module CombinePDF
233
233
  # 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
234
  elsif str = @scanner.scan(/\/[^\x00\x09\x0a\x0c\x0d\x20\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]*/)
235
235
  out << (str[1..-1].gsub(/\#[0-9a-fA-F]{2}/) { |a| a[1..2].hex.chr }).to_sym
236
+ # warn "CombinePDF detected name: #{out.last.to_s}"
236
237
  ##########################################
237
238
  ## Parse a Number
238
239
  ##########################################
239
240
  elsif str = @scanner.scan(/[\+\-\.\d]+/)
240
241
  str =~ /\./ ? (out << str.to_f) : (out << str.to_i)
242
+ # warn "CombinePDF detected number: #{out.last.to_s}"
241
243
  ##########################################
242
244
  ## parse a Hex String
243
245
  ##########################################
244
246
  elsif str = @scanner.scan(/\<[0-9a-fA-F]*\>/)
245
- # warn "Found a hex string"
247
+ # warn "Found a hex string #{str}"
246
248
  str = str.slice(1..-2).force_encoding(Encoding::ASCII_8BIT)
247
249
  # str = "0#{str}" if str.length.odd?
248
250
  out << unify_string([str].pack('H*').force_encoding(Encoding::ASCII_8BIT))
@@ -336,6 +338,7 @@ module CombinePDF
336
338
  end
337
339
  end
338
340
  out << unify_string(str.pack('C*').force_encoding(Encoding::ASCII_8BIT))
341
+ # warn "Found Literal String: #{out.last}"
339
342
  ##########################################
340
343
  ## parse a Dictionary
341
344
  ##########################################
@@ -348,6 +351,7 @@ module CombinePDF
348
351
  ## return content of array or dictionary
349
352
  ##########################################
350
353
  elsif @scanner.scan(/\]/) || @scanner.scan(/>>/)
354
+ # warn "Dictionary / Array ended with #{@scanner.peek(5)}"
351
355
  return out
352
356
  ##########################################
353
357
  ## parse a Stream
@@ -364,6 +368,8 @@ module CombinePDF
364
368
  raise ParsingError, "Parsing Error: PDF file error - a stream object wasn't properly closed using 'endstream'!"
365
369
  end
366
370
 
371
+ # warn "CombinePDF parser: detected Stream #{str.length} bytes long #{str[0..3]}...#{str[-4..-1]}"
372
+
367
373
  # need to remove end of stream
368
374
  if out.last.is_a? Hash
369
375
  # out.last[:raw_stream_content] = str[0...-10] #cuts only one EON char (\n or \r)
@@ -418,7 +424,7 @@ module CombinePDF
418
424
  ##########################################
419
425
  elsif @scanner.scan(/xref/)
420
426
  # skip list indetifier lines or list lines ([\d] [\d][\r\n]) ot ([\d] [\d] [nf][\r\n])
421
- while @scanner.scan(/[\s]*[\d]+[ \t]+[\d]+[ \t\r]*\n[\r]?/) || @scanner.scan(/[ \t]*[\d]+[ \t]+[\d]+[ \t]+[nf][\s]*/)
427
+ while @scanner.scan(/[\s]*[\d]+[ \t]+[\d]+[ \t]*[\n\r]+/) || @scanner.scan(/[ \t]*[\d]+[ \t]+[\d]+[ \t]+[nf][\s]*/)
422
428
  nil
423
429
  end
424
430
  ##########################################
@@ -528,6 +534,14 @@ module CombinePDF
528
534
  inheritance_hash[:Resources] ||= { referenced_object: {}, is_reference_only: true }.dup
529
535
  (inheritance_hash[:Resources][:referenced_object] || inheritance_hash[:Resources]).update((catalogs[:Resources][:referenced_object] || catalogs[:Resources]), &HASH_UPDATE_PROC_FOR_OLD)
530
536
  end
537
+ if catalogs[:ProcSet].is_a?(Array)
538
+ if(inheritance_hash[:ProcSet])
539
+ inheritance_hash[:ProcSet][:referenced_object].concat(catalogs[:ProcSet])
540
+ inheritance_hash[:ProcSet][:referenced_object].uniq!
541
+ else
542
+ inheritance_hash[:ProcSet] ||= { referenced_object: catalogs[:ProcSet], is_reference_only: true }.dup
543
+ end
544
+ end
531
545
  if catalogs[:ColorSpace]
532
546
  inheritance_hash[:ColorSpace] ||= { referenced_object: {}, is_reference_only: true }.dup
533
547
  (inheritance_hash[:ColorSpace][:referenced_object] || inheritance_hash[:ColorSpace]).update((catalogs[:ColorSpace][:referenced_object] || catalogs[:ColorSpace]), &HASH_UPDATE_PROC_FOR_OLD)
@@ -556,6 +570,18 @@ module CombinePDF
556
570
  catalogs[:ColorSpace] = { referenced_object: catalogs[:ColorSpace], is_reference_only: true } unless catalogs[:ColorSpace][:referenced_object]
557
571
  catalogs[:ColorSpace][:referenced_object].update((inheritance_hash[:ColorSpace][:referenced_object] || inheritance_hash[:ColorSpace]), &HASH_UPDATE_PROC_FOR_OLD)
558
572
  end
573
+ if inheritance_hash[:ProcSet]
574
+ if(catalogs[:ProcSet])
575
+ if catalogs[:ProcSet].is_a?(Array)
576
+ catalogs[:ProcSet] = { referenced_object: catalogs[:ProcSet], is_reference_only: true }
577
+ end
578
+ catalogs[:ProcSet][:referenced_object].concat(inheritance_hash[:ProcSet][:referenced_object])
579
+ catalogs[:ProcSet][:referenced_object].uniq!
580
+ else
581
+ catalogs[:ProcSet] = { is_reference_only: true }.dup
582
+ catalogs[:ProcSet][:referenced_object] = catalogs[:ProcSet][:referenced_object].dup
583
+ end
584
+ end
559
585
  # (catalogs[:ColorSpace] ||= {}).update(inheritance_hash[:ColorSpace], &HASH_UPDATE_PROC_FOR_OLD) if inheritance_hash[:ColorSpace]
560
586
  # catalogs[:Order] ||= inheritance_hash[:Order] if inheritance_hash[:Order]
561
587
  # catalogs[:AS] ||= inheritance_hash[:AS] if inheritance_hash[:AS]
@@ -232,15 +232,42 @@ module CombinePDF
232
232
  # @private
233
233
  # this method reviews a Hash and updates it by merging Hash data,
234
234
  # preffering the new over the old.
235
- def self.hash_merge_new_no_page(_key, old_data, new_data)
236
- return old_data unless new_data
237
- return new_data unless old_data
238
- if old_data.is_a?(Hash) && new_data.is_a?(Hash)
239
- return old_data if (old_data[:Type] == :Page)
240
- old_data.merge(new_data, &(@hash_merge_new_no_page_proc ||= method(:hash_merge_new_no_page)))
235
+ # def self.hash_merge_new_no_page(_key = nil, old_data = nil, new_data = nil)
236
+ # return old_data unless new_data
237
+ # return new_data unless old_data
238
+ # if old_data.is_a?(Hash) && new_data.is_a?(Hash)
239
+ # return old_data if (old_data[:Type] == :Page)
240
+ # old_data.merge(new_data, &(@hash_merge_new_no_page_proc ||= method(:hash_merge_new_no_page)))
241
+ # elsif old_data.is_a? Array
242
+ # return old_data + new_data if new_data.is_a?(Array)
243
+ # return old_data.dup << new_data
244
+ # elsif new_data.is_a? Array
245
+ # new_data + [old_data]
246
+ # else
247
+ # new_data
248
+ # end
249
+ # end
250
+
251
+ # @private
252
+ # JRuby Alternative this method reviews a Hash and updates it by merging Hash data,
253
+ # preffering the new over the old.
254
+ HASH_MERGE_NEW_NO_PAGE = Proc.new do |_key = nil, old_data = nil, new_data = nil|
255
+ if !new_data
256
+ old_data
257
+ elsif !old_data
258
+ new_data
259
+ elsif old_data.is_a?(Hash) && new_data.is_a?(Hash)
260
+ if (old_data[:Type] == :Page)
261
+ old_data
262
+ else
263
+ old_data.merge(new_data, &HASH_MERGE_NEW_NO_PAGE)
264
+ end
241
265
  elsif old_data.is_a? Array
242
- return old_data + new_data if new_data.is_a?(Array)
243
- return old_data.dup << new_data
266
+ if new_data.is_a?(Array)
267
+ old_data + new_data
268
+ else
269
+ old_data.dup << new_data
270
+ end
244
271
  elsif new_data.is_a? Array
245
272
  new_data + [old_data]
246
273
  else
@@ -346,16 +373,19 @@ module CombinePDF
346
373
  private
347
374
 
348
375
  def equal_layers obj1, obj2, layer = CombinePDF.eq_depth_limit
349
- return true if(layer == 0)
350
376
  return true if obj1.object_id == obj2.object_id
351
377
  if obj1.is_a? Hash
352
378
  return false unless obj2.is_a? Hash
379
+ return false unless obj1.length == obj2.length
353
380
  keys = obj1.keys;
354
- 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)
355
384
  keys.each {|k| return false unless equal_layers( obj1[k], obj2[k], layer-1) }
356
385
  elsif obj1.is_a? Array
357
386
  return false unless obj2.is_a? Array
358
- (obj1-obj2).any?
387
+ return false unless obj1.length == obj2.length
388
+ (obj1-obj2).any? || (obj2-obj1).any?
359
389
  else
360
390
  obj1 == obj2
361
391
  end
@@ -306,10 +306,10 @@ module CombinePDF
306
306
  if data.is_a? PDF
307
307
  @version = [@version, data.version].max
308
308
  pages_to_add = data.pages
309
- actual_value(@names ||= {}.dup).update data.names, &self.class.method(:hash_merge_new_no_page)
309
+ actual_value(@names ||= {}.dup).update data.names, &HASH_MERGE_NEW_NO_PAGE
310
310
  merge_outlines((@outlines ||= {}.dup), actual_value(data.outlines), location) unless actual_value(data.outlines).empty?
311
311
  if actual_value(@forms_data)
312
- actual_value(@forms_data).update actual_value(data.forms_data), &self.class.method(:hash_merge_new_no_page) if data.forms_data
312
+ actual_value(@forms_data).update actual_value(data.forms_data), &HASH_MERGE_NEW_NO_PAGE if data.forms_data
313
313
  else
314
314
  @forms_data = data.forms_data
315
315
  end
@@ -358,9 +358,9 @@ module CombinePDF
358
358
  #
359
359
  # options:: a Hash of options setting the behavior and format of the page numbers:
360
360
  # - :number_format a string representing the format for page number. defaults to ' - %s - ' (allows for letter numbering as well, such as "a", "b"...).
361
- # - :location an Array containing the location for the page numbers, can be :top, :buttom, :top_left, :top_right, :bottom_left, :bottom_right or :center (:center == full page). defaults to [:top, :buttom].
361
+ # - :location an Array containing the location for the page numbers, can be :top, :bottom, :top_left, :top_right, :bottom_left, :bottom_right or :center (:center == full page). defaults to [:top, :bottom].
362
362
  # - :start_at an Integer that sets the number for first page number. also accepts a letter ("a") for letter numbering. defaults to 1.
363
- # - :margin_from_height a number (PDF points) for the top and buttom margins. defaults to 45.
363
+ # - :margin_from_height a number (PDF points) for the top and bottom margins. defaults to 45.
364
364
  # - :margin_from_side a number (PDF points) for the left and right margins. defaults to 15.
365
365
  # - :page_range a range of pages to be numbered (i.e. (2..-1) ) defaults to all the pages (nil). Remember to set the :start_at to the correct value.
366
366
  # the options Hash can also take all the options for {Page_Methods#textbox}.
@@ -1,3 +1,3 @@
1
1
  module CombinePDF
2
- VERSION = '1.0.13'.freeze
2
+ VERSION = '1.0.18'.freeze
3
3
  end
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.13
4
+ version: 1.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-11 00:00:00.000000000 Z
11
+ date: 2020-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-rc4
@@ -24,34 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.1.5
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.7'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.7'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
- - - "~>"
31
+ - - ">="
46
32
  - !ruby/object:Gem::Version
47
- version: '10.0'
33
+ version: 12.3.3
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
- - - "~>"
38
+ - - ">="
53
39
  - !ruby/object:Gem::Version
54
- version: '10.0'
40
+ version: 12.3.3
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: minitest
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -118,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
104
  - !ruby/object:Gem::Version
119
105
  version: '0'
120
106
  requirements: []
121
- rubyforge_project:
122
- rubygems_version: 2.7.6
107
+ rubygems_version: 3.1.2
123
108
  signing_key:
124
109
  specification_version: 4
125
110
  summary: Combine, stamp and watermark PDF files in pure Ruby.