hexapdf 0.15.6 → 0.16.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcffb10babdbf723a478ea40721d9515222adf8d12ba9bd799f7b95fa66bc408
4
- data.tar.gz: d5929900ab1b010a39964edc366ea223ef8a2ee9bcd1e9a5873874b4d5a8ecc5
3
+ metadata.gz: 5b2303787fd50c2407bb99336c3315643c4a9401a84a508462715d18a378788c
4
+ data.tar.gz: 675bb953973762670c598f93ed15fcaa4387f962c0cbdc9d27060bd06de4f5ae
5
5
  SHA512:
6
- metadata.gz: d12bbd49204c28675d399477ce0249140bf6ead3fe9332541128802f0edc3ebb2b187752b464b9acd3b71ca4ce6cb5cba33caf19282bd5a15020cec3c6e20297
7
- data.tar.gz: 8df3586c8069db615bf317f22b28069f4bfd1395d31c285bb5c4a63b1b46ec60b088082a5d461adafd590718df6307734361e1e61fe3210009d158fc95c558be
6
+ metadata.gz: 81715891b39fc35606baae317fc44a4be4d7710b2a1488f682425620771c2b563ecdfa8ba8ff0028a5226904d511c79b9507c1fed7170fdfd2c7a29aa4706127
7
+ data.tar.gz: f24fb2cdd07da0c2afde7511c40880e66fd65d87d2fd6035524202fbf8f1040d1e64576b3b080f6aa0d006d5938fc61c399c062d8687b33b3f3a5e9966b3917d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,35 @@
1
+ ## 0.16.0 - 2021-09-28
2
+
3
+ ## Added
4
+
5
+ * Support for RGB color values of the form "RGB" in addition to "RRGGBB" and for
6
+ CSS color module level 3 color names
7
+ * Conversion module for Integer fields to fix certain invalid PDF files
8
+
9
+
10
+ ## 0.15.9 - 2021-09-04
11
+
12
+ ### Fixed
13
+
14
+ * Handling of files that contain stream length values that are indirect objects
15
+ not referring to a number
16
+
17
+
18
+ ## 0.15.8 - 2021-08-16
19
+
20
+ ### Fixed
21
+
22
+ * Regression when using `-v` with the hexapdf command line tool
23
+
24
+
25
+ ## 0.15.7 - 2021-07-17
26
+
27
+ ### Fixed
28
+
29
+ * Infinite loop while parsing PDF array due to missing closing bracket
30
+ * Handling of invalid files with missing or corrupted trailer dictionary
31
+
32
+
1
33
  ## 0.15.6 - 2021-07-16
2
34
 
3
35
  ### Fixed
@@ -119,7 +119,7 @@ module HexaPDF
119
119
  # Writes the document to the given file or does nothing if +out_file+ is +nil+.
120
120
  def write_document(doc, out_file, incremental: false)
121
121
  if out_file
122
- doc.validate(auto_correct: true) do |object, msg, correctable|
122
+ doc.validate(auto_correct: true) do |msg, correctable, object|
123
123
  if command_parser.strict && !correctable
124
124
  raise "Validation error for object (#{object.oid},#{object.gen}): #{msg}"
125
125
  elsif command_parser.verbosity_info?
@@ -245,7 +245,7 @@ module HexaPDF
245
245
  # Defines a mapping from font names and variants to font files.
246
246
  #
247
247
  # The value needs to be a hash of the form:
248
- # {"font_name": {variant: file_name, variant2: file_name2, ...}, ...}
248
+ # {"font_name" => {variant: file_name, variant2: file_name2, ...}, ...}
249
249
  #
250
250
  # Once a font is registered in this way, the font name together with a variant name can be used
251
251
  # with the HexaPDF::Document::Fonts#add method to load the font.
@@ -675,6 +675,10 @@ module HexaPDF
675
675
  # * Three numeric arguments specify an RGB color (see Content::ColorSpace::DeviceRGB::Color).
676
676
  # * A string in the format "RRGGBB" where "RR" is the hexadecimal number for the red, "GG"
677
677
  # for the green and "BB" for the blue color value also specifies an RGB color.
678
+ # * As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
679
+ # hexadecimal numbers for the red, green and blue color values of an RGB color.
680
+ # * Any other string is treated as a CSS Color Module Level 3 color name, see
681
+ # https://www.w3.org/TR/css-color-3/#svg-color.
678
682
  # * Four numeric arguments specify a CMYK color (see Content::ColorSpace::DeviceCMYK::Color).
679
683
  # * A color object is used directly (normally used for color spaces other than DeviceRGB,
680
684
  # DeviceCMYK and DeviceGray).
@@ -1852,7 +1856,7 @@ module HexaPDF
1852
1856
  # on the possible color specifications.
1853
1857
  def color_from_specification(spec)
1854
1858
  if spec.length == 1 && spec[0].kind_of?(String)
1855
- resources.color_space(:DeviceRGB).color(*spec[0].scan(/../).map!(&:hex))
1859
+ ColorSpace.device_color_from_specification(spec)
1856
1860
  elsif spec.length == 1 && spec[0].respond_to?(:color_space)
1857
1861
  spec[0]
1858
1862
  else
@@ -96,6 +96,157 @@ module HexaPDF
96
96
  # See: PDF1.7 s8.6
97
97
  module ColorSpace
98
98
 
99
+ # Mapping of CSS Color Module Level 3 names to RGB values.
100
+ CSS_COLOR_NAMES = {
101
+ "aliceblue" => [240, 248, 255],
102
+ "antiquewhite" => [250, 235, 215],
103
+ "aqua" => [0, 255, 255],
104
+ "aquamarine" => [127, 255, 212],
105
+ "azure" => [240, 255, 255],
106
+ "beige" => [245, 245, 220],
107
+ "bisque" => [255, 228, 196],
108
+ "black" => [0, 0, 0],
109
+ "blanchedalmond" => [255, 235, 205],
110
+ "blue" => [0, 0, 255],
111
+ "blueviolet" => [138, 43, 226],
112
+ "brown" => [165, 42, 42],
113
+ "burlywood" => [222, 184, 135],
114
+ "cadetblue" => [95, 158, 160],
115
+ "chartreuse" => [127, 255, 0],
116
+ "chocolate" => [210, 105, 30],
117
+ "coral" => [255, 127, 80],
118
+ "cornflowerblue" => [100, 149, 237],
119
+ "cornsilk" => [255, 248, 220],
120
+ "crimson" => [220, 20, 60],
121
+ "cyan" => [0, 255, 255],
122
+ "darkblue" => [0, 0, 139],
123
+ "darkcyan" => [0, 139, 139],
124
+ "darkgoldenrod" => [184, 134, 11],
125
+ "darkgray" => [169, 169, 169],
126
+ "darkgreen" => [0, 100, 0],
127
+ "darkgrey" => [169, 169, 169],
128
+ "darkkhaki" => [189, 183, 107],
129
+ "darkmagenta" => [139, 0, 139],
130
+ "darkolivegreen" => [85, 107, 47],
131
+ "darkorange" => [255, 140, 0],
132
+ "darkorchid" => [153, 50, 204],
133
+ "darkred" => [139, 0, 0],
134
+ "darksalmon" => [233, 150, 122],
135
+ "darkseagreen" => [143, 188, 143],
136
+ "darkslateblue" => [72, 61, 139],
137
+ "darkslategray" => [47, 79, 79],
138
+ "darkslategrey" => [47, 79, 79],
139
+ "darkturquoise" => [0, 206, 209],
140
+ "darkviolet" => [148, 0, 211],
141
+ "deeppink" => [255, 20, 147],
142
+ "deepskyblue" => [0, 191, 255],
143
+ "dimgray" => [105, 105, 105],
144
+ "dimgrey" => [105, 105, 105],
145
+ "dodgerblue" => [30, 144, 255],
146
+ "firebrick" => [178, 34, 34],
147
+ "floralwhite" => [255, 250, 240],
148
+ "forestgreen" => [34, 139, 34],
149
+ "fuchsia" => [255, 0, 255],
150
+ "gainsboro" => [220, 220, 220],
151
+ "ghostwhite" => [248, 248, 255],
152
+ "gold" => [255, 215, 0],
153
+ "goldenrod" => [218, 165, 32],
154
+ "gray" => [128, 128, 128],
155
+ "green" => [0, 128, 0],
156
+ "greenyellow" => [173, 255, 47],
157
+ "grey" => [128, 128, 128],
158
+ "honeydew" => [240, 255, 240],
159
+ "hotpink" => [255, 105, 180],
160
+ "indianred" => [205, 92, 92],
161
+ "indigo" => [75, 0, 130],
162
+ "ivory" => [255, 255, 240],
163
+ "khaki" => [240, 230, 140],
164
+ "lavender" => [230, 230, 250],
165
+ "lavenderblush" => [255, 240, 245],
166
+ "lawngreen" => [124, 252, 0],
167
+ "lemonchiffon" => [255, 250, 205],
168
+ "lightblue" => [173, 216, 230],
169
+ "lightcoral" => [240, 128, 128],
170
+ "lightcyan" => [224, 255, 255],
171
+ "lightgoldenrodyellow" => [250, 250, 210],
172
+ "lightgray" => [211, 211, 211],
173
+ "lightgreen" => [144, 238, 144],
174
+ "lightgrey" => [211, 211, 211],
175
+ "lightpink" => [255, 182, 193],
176
+ "lightsalmon" => [255, 160, 122],
177
+ "lightseagreen" => [32, 178, 170],
178
+ "lightskyblue" => [135, 206, 250],
179
+ "lightslategray" => [119, 136, 153],
180
+ "lightslategrey" => [119, 136, 153],
181
+ "lightsteelblue" => [176, 196, 222],
182
+ "lightyellow" => [255, 255, 224],
183
+ "lime" => [0, 255, 0],
184
+ "limegreen" => [50, 205, 50],
185
+ "linen" => [250, 240, 230],
186
+ "magenta" => [255, 0, 255],
187
+ "maroon" => [128, 0, 0],
188
+ "mediumaquamarine" => [102, 205, 170],
189
+ "mediumblue" => [0, 0, 205],
190
+ "mediumorchid" => [186, 85, 211],
191
+ "mediumpurple" => [147, 112, 219],
192
+ "mediumseagreen" => [60, 179, 113],
193
+ "mediumslateblue" => [123, 104, 238],
194
+ "mediumspringgreen" => [0, 250, 154],
195
+ "mediumturquoise" => [72, 209, 204],
196
+ "mediumvioletred" => [199, 21, 133],
197
+ "midnightblue" => [25, 25, 112],
198
+ "mintcream" => [245, 255, 250],
199
+ "mistyrose" => [255, 228, 225],
200
+ "moccasin" => [255, 228, 181],
201
+ "navajowhite" => [255, 222, 173],
202
+ "navy" => [0, 0, 128],
203
+ "oldlace" => [253, 245, 230],
204
+ "olive" => [128, 128, 0],
205
+ "olivedrab" => [107, 142, 35],
206
+ "orange" => [255, 165, 0],
207
+ "orangered" => [255, 69, 0],
208
+ "orchid" => [218, 112, 214],
209
+ "palegoldenrod" => [238, 232, 170],
210
+ "palegreen" => [152, 251, 152],
211
+ "paleturquoise" => [175, 238, 238],
212
+ "palevioletred" => [219, 112, 147],
213
+ "papayawhip" => [255, 239, 213],
214
+ "peachpuff" => [255, 218, 185],
215
+ "peru" => [205, 133, 63],
216
+ "pink" => [255, 192, 203],
217
+ "plum" => [221, 160, 221],
218
+ "powderblue" => [176, 224, 230],
219
+ "purple" => [128, 0, 128],
220
+ "red" => [255, 0, 0],
221
+ "rosybrown" => [188, 143, 143],
222
+ "royalblue" => [65, 105, 225],
223
+ "saddlebrown" => [139, 69, 19],
224
+ "salmon" => [250, 128, 114],
225
+ "sandybrown" => [244, 164, 96],
226
+ "seagreen" => [46, 139, 87],
227
+ "seashell" => [255, 245, 238],
228
+ "sienna" => [160, 82, 45],
229
+ "silver" => [192, 192, 192],
230
+ "skyblue" => [135, 206, 235],
231
+ "slateblue" => [106, 90, 205],
232
+ "slategray" => [112, 128, 144],
233
+ "slategrey" => [112, 128, 144],
234
+ "snow" => [255, 250, 250],
235
+ "springgreen" => [0, 255, 127],
236
+ "steelblue" => [70, 130, 180],
237
+ "tan" => [210, 180, 140],
238
+ "teal" => [0, 128, 128],
239
+ "thistle" => [216, 191, 216],
240
+ "tomato" => [255, 99, 71],
241
+ "turquoise" => [64, 224, 208],
242
+ "violet" => [238, 130, 238],
243
+ "wheat" => [245, 222, 179],
244
+ "white" => [255, 255, 255],
245
+ "whitesmoke" => [245, 245, 245],
246
+ "yellow" => [255, 255, 0],
247
+ "yellowgreen" => [154, 205, 50],
248
+ }.freeze
249
+
99
250
  # :call-seq:
100
251
  # ColorSpace.device_color_from_specification(gray) => color
101
252
  # ColorSpace.device_color_from_specification(r, g, b) => color
@@ -111,6 +262,10 @@ module HexaPDF
111
262
  # * Three numeric arguments specify an RGB color (see DeviceRGB::Color).
112
263
  # * A string in the format "RRGGBB" where "RR" is the hexadecimal number for the red, "GG"
113
264
  # for the green and "BB" for the blue color value also specifies an RGB color.
265
+ # * As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
266
+ # hexadecimal numbers for the red, green and blue color values of an RGB color.
267
+ # * Any other string is treated as a CSS Color Module Level 3 color name, see
268
+ # https://www.w3.org/TR/css-color-3/#svg-color.
114
269
  # * Four numeric arguments specify a CMYK color (see DeviceCMYK::Color).
115
270
  # * An array is treated as if its items were specified separately as arguments.
116
271
  #
@@ -118,7 +273,18 @@ module HexaPDF
118
273
  # values are first normalized - see DeviceGray#color, DeviceRGB#color and DeviceCMYK#color.
119
274
  def self.device_color_from_specification(*spec)
120
275
  spec.flatten!
121
- spec = spec[0].scan(/../).map!(&:hex) if spec.length == 1 && spec[0].kind_of?(String)
276
+ first_item = spec[0]
277
+ if spec.length == 1 && first_item.kind_of?(String)
278
+ spec = if first_item.match?(/\A\h{6}\z/)
279
+ first_item.scan(/../).map!(&:hex)
280
+ elsif first_item.match?(/\A\h{3}\z/)
281
+ first_item.each_char.map {|x| (x*2).hex}
282
+ elsif CSS_COLOR_NAMES.key?(first_item)
283
+ CSS_COLOR_NAMES[first_item]
284
+ else
285
+ raise ArgumentError, "Given string is neither a hex color nor a color name"
286
+ end
287
+ end
122
288
  GlobalConfiguration.constantize('color_space.map', for_components(spec)).new.color(*spec)
123
289
  end
124
290
 
@@ -349,9 +349,30 @@ module HexaPDF
349
349
 
350
350
  end
351
351
 
352
+ # Converter module for fields of type Integer.
353
+ module IntegerConverter
354
+
355
+ # This converter is usable if the +type+ is Integer.
356
+ def self.usable_for?(type)
357
+ type == Integer
358
+ end
359
+
360
+ # :nodoc:
361
+ def self.additional_types
362
+ end
363
+
364
+ # Converts a Float value into an Integer if the float is equal to its integer value. Otherwise
365
+ # returns +nil+
366
+ def self.convert(data, _type, _document)
367
+ return unless data.kind_of?(Float) && data == data.to_i
368
+ data.to_i
369
+ end
370
+
371
+ end
372
+
352
373
  Field.converters.replace([FileSpecificationConverter, DictionaryConverter, ArrayConverter,
353
374
  StringConverter, PDFByteStringConverter, DateConverter,
354
- RectangleConverter])
375
+ RectangleConverter, IntegerConverter])
355
376
 
356
377
  end
357
378
 
@@ -165,7 +165,7 @@ module HexaPDF
165
165
  else
166
166
  0
167
167
  end
168
- @tokenizer.pos = pos + length
168
+ @tokenizer.pos = pos + length rescue pos
169
169
 
170
170
  tok = @tokenizer.next_token
171
171
  unless tok.kind_of?(Tokenizer::Token) && tok == 'endstream'
@@ -447,6 +447,15 @@ module HexaPDF
447
447
 
448
448
  if !trailer || trailer.empty?
449
449
  _, trailer = load_revision(startxref_offset) rescue nil
450
+ unless trailer
451
+ xref.each do |_oid, _gen, xref_entry|
452
+ obj, * = parse_indirect_object(xref_entry.pos) rescue nil
453
+ if obj.kind_of?(Hash) && obj[:Type] == :Catalog
454
+ trailer = {Root: HexaPDF::Reference.new(xref_entry.oid, xref_entry.gen)}
455
+ break
456
+ end
457
+ end
458
+ end
450
459
  unless trailer
451
460
  @in_reconstruct_revision = false
452
461
  raise_malformed("Could not reconstruct malformed PDF because trailer was not found", pos: 0)
@@ -55,6 +55,9 @@ module HexaPDF
55
55
 
56
56
  # This object is returned when there are no more tokens to read.
57
57
  NO_MORE_TOKENS = ::Object.new
58
+ def NO_MORE_TOKENS.to_s
59
+ "EOS - no more tokens"
60
+ end
58
61
 
59
62
  # Characters defined as whitespace.
60
63
  #
@@ -384,7 +387,11 @@ module HexaPDF
384
387
  result = []
385
388
  while true
386
389
  obj = next_object(allow_end_array_token: true)
387
- break if obj.equal?(TOKEN_ARRAY_END)
390
+ if obj.equal?(TOKEN_ARRAY_END)
391
+ break
392
+ elsif obj.equal?(NO_MORE_TOKENS)
393
+ raise HexaPDF::MalformedPDFError.new("Unclosed array found", pos: pos)
394
+ end
388
395
  result << obj
389
396
  end
390
397
  result
@@ -403,7 +410,8 @@ module HexaPDF
403
410
  key = next_token
404
411
  break if key.equal?(TOKEN_DICT_END)
405
412
  unless key.kind_of?(Symbol)
406
- raise HexaPDF::MalformedPDFError.new("Dictionary keys must be PDF name objects", pos: pos)
413
+ raise HexaPDF::MalformedPDFError.new("Dictionary keys must be PDF name objects, " \
414
+ "found '#{key}'", pos: pos)
407
415
  end
408
416
 
409
417
  val = next_object
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.15.6'
40
+ VERSION = '0.16.0'
41
41
 
42
42
  end
@@ -161,6 +161,21 @@ module CommonTokenizerTests
161
161
  assert_raises(HexaPDF::MalformedPDFError) { @tokenizer.next_object }
162
162
  end
163
163
 
164
+ it "next_object: fails for an array without closing bracket, encountering EOS" do
165
+ create_tokenizer("[1 2")
166
+ exception = assert_raises(HexaPDF::MalformedPDFError) { @tokenizer.next_object }
167
+ assert_match(/Unclosed array found/, exception.message)
168
+ end
169
+
170
+ it "next_object: fails for a dictionary without closing bracket, encountering EOS" do
171
+ create_tokenizer("<</Name 5")
172
+ exception = assert_raises(HexaPDF::MalformedPDFError) { @tokenizer.next_object }
173
+ assert_match(/must be PDF name objects.*EOS/, exception.message)
174
+ create_tokenizer("<</Name 5 /Other")
175
+ exception = assert_raises(HexaPDF::MalformedPDFError) { @tokenizer.next_object }
176
+ assert_match(/must be PDF name objects.*EOS/, exception.message)
177
+ end
178
+
164
179
  it "returns the correct position on operations" do
165
180
  create_tokenizer("hallo du" << " " * 50000 << "hallo du")
166
181
  @tokenizer.next_token
@@ -73,10 +73,18 @@ describe HexaPDF::Content::ColorSpace do
73
73
  assert_equal([0.2, 1, 0], @class.device_color_from_specification(51, 255, 0).components)
74
74
  end
75
75
 
76
- it "works for RGB values given as string" do
76
+ it "works for RGB values given as full hex string" do
77
77
  assert_equal([0.2, 1, 0], @class.device_color_from_specification("33FF00").components)
78
78
  end
79
79
 
80
+ it "works for RGB values given as half hex string" do
81
+ assert_equal([0.2, 1, 0], @class.device_color_from_specification("3F0").components)
82
+ end
83
+
84
+ it "works for RGB values given as color names" do
85
+ assert_equal([0, 0, 1], @class.device_color_from_specification("blue").components)
86
+ end
87
+
80
88
  it "works for CMYK values" do
81
89
  assert_equal([0.51, 0.9, 1, 0.5],
82
90
  @class.device_color_from_specification(51, 90, 100, 50).components)
@@ -85,6 +93,10 @@ describe HexaPDF::Content::ColorSpace do
85
93
  it "works when an array is given" do
86
94
  assert_equal([0.2], @class.device_color_from_specification([51]).components)
87
95
  end
96
+
97
+ it "raises an error if an invalid color string is given" do
98
+ assert_raises(ArgumentError) { @class.device_color_from_specification("unknown") }
99
+ end
88
100
  end
89
101
 
90
102
  it "returns a device color object for prenormalized color values" do
@@ -242,4 +242,19 @@ describe HexaPDF::DictionaryFields do
242
242
  doc.verify
243
243
  end
244
244
  end
245
+
246
+ describe "IntegerConverter" do
247
+ before do
248
+ @field = self.class::Field.new(Integer)
249
+ end
250
+
251
+ it "no additional field types allowed" do
252
+ assert_equal([Integer], @field.type)
253
+ end
254
+
255
+ it "allows conversion to an Integer from an equivalent Float value" do
256
+ refute_same(3, @field.convert(3.1, nil))
257
+ assert_same(3, @field.convert(3.0, nil))
258
+ end
259
+ end
245
260
  end
@@ -113,13 +113,21 @@ describe HexaPDF::Parser do
113
113
  assert_nil(object)
114
114
  end
115
115
 
116
- it "recovers from an invalid stream length value" do
116
+ it "recovers from a stream length value that doesn't reflect the correct length" do
117
117
  create_parser("1 0 obj<</Length 4>> stream\n12endstream endobj")
118
118
  obj, _, _, stream = @parser.parse_indirect_object
119
119
  assert_equal(2, obj[:Length])
120
120
  assert_equal('12', TestHelper.collector(stream.fiber))
121
121
  end
122
122
 
123
+ it "recovers from an invalid stream length value" do
124
+ create_parser("1 0 obj<</Length 2 0 R>> stream\n12endstream endobj")
125
+ @document.add([5], oid: 2)
126
+ obj, _, _, stream = @parser.parse_indirect_object
127
+ assert_equal(2, obj[:Length])
128
+ assert_equal('12', TestHelper.collector(stream.fiber))
129
+ end
130
+
123
131
  it "works even if the keyword endobj is missing or mangled" do
124
132
  create_parser("1 0 obj<</Length 4>>5")
125
133
  object, * = @parser.parse_indirect_object
@@ -619,7 +627,12 @@ describe HexaPDF::Parser do
619
627
  assert_equal({Size: 1}, @parser.reconstructed_revision.trailer.value)
620
628
  end
621
629
 
622
- it "fails if no trailer is found and the trailer specified at the startxref position is not valid" do
630
+ it "constructs a trailer with a /Root entry if no valid trailer was found" do
631
+ create_parser("1 0 obj\n<</Type /Catalog/Pages 2 0 R>>\nendobj\nxref trailer <</Size 1/Prev 5\n%%EOF")
632
+ assert_equal({Root: HexaPDF::Reference.new(1, 0)}, @parser.reconstructed_revision.trailer.value)
633
+ end
634
+
635
+ it "fails if no valid trailer is found and couldn't be constructed" do
623
636
  create_parser("1 0 obj\n5\nendobj\nquack trailer <</Size 1>>\nstartxref\n22\n%%EOF")
624
637
  assert_raises(HexaPDF::MalformedPDFError) { @parser.reconstructed_revision.trailer }
625
638
  end
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.15.6)>>
43
+ <</Producer(HexaPDF version 0.16.0)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.15.6)>>
75
+ <</Producer(HexaPDF version 0.16.0)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.6
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-16 00:00:00.000000000 Z
11
+ date: 2021-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse