pdfrb 0.8.5 → 0.8.6

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: 04a819d2ed2b54eb4ca8c0ac17ceb14cc1c45a79e359bb51c6b5194e2fdb7025
4
- data.tar.gz: bcb6a670c04b7e68b20b90f8ac344ac0672a76f1fd3e16306ac46b4c44f728ec
3
+ metadata.gz: 84368b352e856470e7d3f3374071df7724c21d5dba77596842ac5bacc419db59
4
+ data.tar.gz: c0bfb8c0a8803aa74ecf43d1e3e35ff18b17bc457582705c409d8fae89b8f50f
5
5
  SHA512:
6
- metadata.gz: f8eb286788ae52128019b39b18006776c9c9227ab92e76b0a72add85eb92b16daa390704d243627a0f79fcd8b9c0195a606f7f6878953db634ff1c9ad257b0f4
7
- data.tar.gz: 1940d86297e8e20ae06d33b23bd7b36815d5249fce28eb120262ab33e5350668fa015247444ed905ac1ba5b73295fa092b74d6e477c9fd74a507252a78cb110f
6
+ metadata.gz: 4d6aec972d3b32bc66f70098ab1122472fef43c675d4eaba1b77cb4c3b74231a515f9ad877d648c8b28d3dc874b55475327b20ade2b2dcc85d70e3e15712fdbc
7
+ data.tar.gz: 65fd26f6e44e1bcaa18471e86662f53e46ae4c2ac9a91a82fb182adbb10c7ef6616e6ab5505379dbc42c414a6684f848864648c486567a59e2f9aa695de67f57
@@ -96,8 +96,7 @@ module Pdfrb
96
96
 
97
97
  def inventory_fonts(doc)
98
98
  fonts = Set.new
99
- doc.each_indirect_object do |obj|
100
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
99
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
101
100
  next unless obj[:Type] == :Font
102
101
 
103
102
  name = obj[:BaseFont] || obj[:Name] || "Unknown"
@@ -117,8 +116,7 @@ module Pdfrb
117
116
 
118
117
  def count_images(doc)
119
118
  count = 0
120
- doc.each_indirect_object do |obj|
121
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
119
+ doc.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
122
120
  next unless obj[:Subtype] == :Image
123
121
 
124
122
  count += 1
@@ -31,8 +31,7 @@ module Pdfrb
31
31
  id: "6.1-4", description: "JavaScript prohibited",
32
32
  severity: :error, spec_clause: "ISO 19005-1 6.1",
33
33
  check: ->(doc) {
34
- doc.each_indirect_object do |obj|
35
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
34
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
36
35
  if obj.value[:S] == :JavaScript
37
36
  return Violation.new(rule_id: "6.1-4", message: "PDF/A prohibits JavaScript actions",
38
37
  object: "JavaScript action", severity: :error,
@@ -201,8 +200,7 @@ module Pdfrb
201
200
  id: "a1-1", description: "JPEG2000 not allowed in A-1",
202
201
  severity: :error, spec_clause: "ISO 19005-1 6.2.4",
203
202
  check: ->(doc) {
204
- doc.each_indirect_object do |obj|
205
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
203
+ doc.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
206
204
  next unless obj[:Filter] == :JPXDecode
207
205
 
208
206
  return Violation.new(rule_id: "a1-1",
@@ -217,8 +215,7 @@ module Pdfrb
217
215
  id: "a1-2", description: "Object streams not allowed in A-1",
218
216
  severity: :error, spec_clause: "ISO 19005-1 6.2.4",
219
217
  check: ->(doc) {
220
- doc.each_indirect_object do |obj|
221
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
218
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
222
219
  next unless obj.value[:Type] == :ObjStm
223
220
 
224
221
  return Violation.new(rule_id: "a1-2",
@@ -247,9 +244,7 @@ module Pdfrb
247
244
  id: "a1-4", description: "LZWDecode not allowed in A-1",
248
245
  severity: :error, spec_clause: "ISO 19005-1 6.2.4",
249
246
  check: ->(doc) {
250
- doc.each_indirect_object do |obj|
251
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
252
-
247
+ doc.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
253
248
  f = obj[:Filter]
254
249
  fs = f.is_a?(::Array) ? f : [f]
255
250
  next unless fs.include?(:LZWDecode)
@@ -269,8 +264,7 @@ module Pdfrb
269
264
  id: "a2-1", description: "PostScript XObjects prohibited",
270
265
  severity: :warning, spec_clause: "ISO 19005-2 6.2.4",
271
266
  check: ->(doc) {
272
- doc.each_indirect_object do |obj|
273
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
267
+ doc.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
274
268
  next unless [:PS, :PSXObject].include?(obj[:Subtype])
275
269
 
276
270
  return Violation.new(rule_id: "a2-1",
@@ -285,8 +279,7 @@ module Pdfrb
285
279
  id: "a2-2", description: "Embedded files not allowed in A-2",
286
280
  severity: :error, spec_clause: "ISO 19005-2 6.2",
287
281
  check: ->(doc) {
288
- doc.each_indirect_object do |obj|
289
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
282
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
290
283
  next unless obj.value[:Type] == :EmbeddedFile
291
284
 
292
285
  return Violation.new(rule_id: "a2-2",
@@ -316,8 +309,7 @@ module Pdfrb
316
309
  severity: :error, spec_clause: "ISO 19005-3 6.2",
317
310
  check: ->(doc) {
318
311
  vs = []
319
- doc.each_indirect_object do |obj|
320
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
312
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
321
313
  next unless obj.value[:Type] == :Filespec
322
314
  next if obj.value[:AFRelationship]
323
315
 
@@ -348,8 +340,7 @@ module Pdfrb
348
340
  severity: :error, spec_clause: "ISO 19005-4 6.2",
349
341
  check: ->(doc) {
350
342
  vs = []
351
- doc.each_indirect_object do |obj|
352
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
343
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
353
344
  next unless obj.value[:Type] == :Filespec
354
345
  next if obj.value[:AFRelationship]
355
346
 
@@ -366,8 +357,7 @@ module Pdfrb
366
357
  severity: :error, spec_clause: "ISO 19005-4 6.2.3",
367
358
  check: ->(doc) {
368
359
  vs = []
369
- doc.each_indirect_object do |annot|
370
- next unless annot.is_a?(Pdfrb::Model::Cos::Dictionary)
360
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |annot|
371
361
  next unless annot.value[:Type] == :Annot
372
362
 
373
363
  st = annot.value[:Subtype]
@@ -150,9 +150,7 @@ module Pdfrb
150
150
  spec_clause: "ISO 15930 §6.5",
151
151
  check: ->(doc) {
152
152
  violations = []
153
- doc.each_indirect_object do |obj|
154
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
155
-
153
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
156
154
  s = obj[:S]
157
155
  next unless [:JavaScript, :JS, :Launch, :URI].include?(s)
158
156
 
@@ -231,7 +229,7 @@ module Pdfrb
231
229
  spec_clause: "ISO 15930-11 6.1",
232
230
  check: ->(doc) {
233
231
  v = doc.version.to_s
234
- next nil if compare_versions(v, "2.0") >= 0
232
+ next nil if Pdfrb::PdfVersion.compare(v, "2.0") >= 0
235
233
 
236
234
  Violation.new(
237
235
  rule_id: "x6-1",
@@ -280,16 +278,8 @@ module Pdfrb
280
278
  rs.register(X6_OUTPUT_INTENT_RULE)
281
279
  end
282
280
 
283
- def compare_versions(a, b)
284
- aa = a.to_s.split(".").map(&:to_i)
285
- bb = b.to_s.split(".").map(&:to_i)
286
- (aa <=> bb) || 0
287
- end
288
-
289
281
  def scan_color_spaces(doc, &block)
290
- doc.each_indirect_object do |obj|
291
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
292
-
282
+ doc.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
293
283
  cs = obj.value[:ColorSpace]
294
284
  next unless cs
295
285
 
@@ -43,13 +43,11 @@ module Pdfrb
43
43
  end
44
44
 
45
45
  def concat(a, b, c, d, e, f, &)
46
- emit_op Pdfrb::Content::Operator::ConcatMatrix, a, b, c, d, e, f
47
- return self unless block_given?
46
+ return emit_op(Pdfrb::Content::Operator::ConcatMatrix, a, b, c, d, e, f) unless block_given?
48
47
 
49
- begin
48
+ save_graphics_state do
49
+ emit_op(Pdfrb::Content::Operator::ConcatMatrix, a, b, c, d, e, f)
50
50
  yield self
51
- ensure
52
- emit_op Pdfrb::Content::Operator::SaveGraphicsState
53
51
  end
54
52
  self
55
53
  end
@@ -282,41 +280,28 @@ module Pdfrb
282
280
  create_ext_g_state(BM: mode.to_s))
283
281
  end
284
282
 
285
- def with_transparency(opacity: 1.0, blend_mode: nil)
286
- save_graphics_state
287
- self.opacity = opacity if opacity < 1.0
288
- self.blend_mode = blend_mode if blend_mode
289
-
290
- begin
283
+ def with_transparency(opacity: 1.0, blend_mode: nil, &)
284
+ save_graphics_state do
285
+ self.opacity = opacity if opacity < 1.0
286
+ self.blend_mode = blend_mode if blend_mode
291
287
  yield self
292
- ensure
293
- emit_op(Pdfrb::Content::Operator::RestoreGraphicsState)
294
288
  end
295
289
  self
296
290
  end
297
291
 
298
292
  def draw_image(name, at: nil, width: nil, height: nil, matrix: nil)
299
- @used_xobjects[name] = true
300
- save_graphics_state do
301
- if matrix
302
- a, b, c, d, e, f = matrix
303
- concat(a, b, c, d, e, f)
304
- emit_op(Pdfrb::Content::Operator::InvokeXObject, name)
305
- else
306
- translate(at[0], at[1])
307
- concat(width, 0, 0, height, 0, 0)
308
- append(" /#{name} Do\n")
309
- end
293
+ if matrix
294
+ a, b, c, d, e, f = matrix
295
+ invoke_xobject(name, matrix: [a, b, c, d, e, f])
296
+ else
297
+ invoke_xobject(name, matrix: [width, 0, 0, height, 0, 0],
298
+ pre_translate: at)
310
299
  end
311
300
  self
312
301
  end
313
302
 
314
303
  def draw_image_matrix(name, a:, b:, c:, d:, e:, f:)
315
- @used_xobjects[name] = true
316
- save_graphics_state do
317
- concat(a, b, c, d, e, f)
318
- emit_op(Pdfrb::Content::Operator::InvokeXObject, name)
319
- end
304
+ invoke_xobject(name, matrix: [a, b, c, d, e, f])
320
305
  self
321
306
  end
322
307
 
@@ -327,13 +312,20 @@ module Pdfrb
327
312
  # @param at [Array<Numeric>] x, y translation.
328
313
  # @param matrix [Array<Numeric>, nil] 6-element transform matrix.
329
314
  def draw_form_xobject(name, at: [0, 0], matrix: nil)
315
+ translate = matrix.nil? ? at : nil
316
+ invoke_xobject(name, matrix: matrix, pre_translate: translate)
317
+ self
318
+ end
319
+
320
+ # Invoke an XObject (/Do) inside a saved graphics state, applying
321
+ # an optional translation then a 6-element transform matrix.
322
+ def invoke_xobject(name, matrix: nil, pre_translate: nil)
330
323
  @used_xobjects[name] = true
331
324
  save_graphics_state do
325
+ translate(pre_translate[0], pre_translate[1]) if pre_translate
332
326
  if matrix
333
327
  a, b, c, d, e, f = matrix
334
- concat(a, b, c, d, e, f)
335
- elsif at
336
- translate(at[0], at[1])
328
+ emit_op(Pdfrb::Content::Operator::ConcatMatrix, a, b, c, d, e, f)
337
329
  end
338
330
  emit_op(Pdfrb::Content::Operator::InvokeXObject, name)
339
331
  end
@@ -55,8 +55,7 @@ module Pdfrb
55
55
  end
56
56
 
57
57
  def find_page(stream_obj)
58
- @document.each_indirect_object do |obj|
59
- next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
58
+ @document.each_indirect_of(Pdfrb::Model::Cos::Dictionary) do |obj|
60
59
  next unless obj[:Type] == :Page
61
60
 
62
61
  contents = obj[:Contents]
@@ -282,6 +282,16 @@ module Pdfrb
282
282
  end
283
283
  end
284
284
 
285
+ # Yield every indirect object of +klass+ (e.g. all Streams, all
286
+ # Dictionaries). Enumerator when blockless.
287
+ def each_indirect_of(klass)
288
+ return enum_for(:each_indirect_of, klass) unless block_given?
289
+
290
+ each_indirect_object do |obj|
291
+ yield obj if obj.is_a?(klass)
292
+ end
293
+ end
294
+
285
295
  # Walk every revision in the document's incremental-update chain,
286
296
  # from the latest (most recent) revision backward via /Prev.
287
297
  # Each revision yields a (revision_index, xref, trailer) tuple
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ # PDF header version comparisons (ISO 32000-2, s7.2). Version strings
5
+ # are dot-separated numerics ("1.4", "2.0"); comparison is
6
+ # numeric-per-component, never lexical ("1.10" > "1.9").
7
+ module PdfVersion
8
+ module_function
9
+
10
+ # @return [Integer] -1, 0, or 1 as +a+ is earlier, equal, or later
11
+ # than +b+.
12
+ def compare(a, b)
13
+ aa = a.to_s.split(".").map(&:to_i)
14
+ bb = b.to_s.split(".").map(&:to_i)
15
+ (aa <=> bb) || 0
16
+ end
17
+
18
+ # @return [Boolean] whether +version+ meets or exceeds +minimum+.
19
+ def at_least?(version, minimum)
20
+ compare(version, minimum) >= 0
21
+ end
22
+ end
23
+ end
@@ -55,9 +55,7 @@ module Pdfrb
55
55
  # {duplicate_oid => canonical_oid} that was applied.
56
56
  def dedup_streams!(document)
57
57
  canonical_for = {}
58
- document.each_indirect_object do |obj|
59
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
60
- next unless obj.indirect?
58
+ document.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
61
59
  next if obj.value[:Type] == :ObjStm
62
60
 
63
61
  key = stream_dedup_key(obj)
@@ -65,9 +63,7 @@ module Pdfrb
65
63
  end
66
64
 
67
65
  replacements = {}
68
- document.each_indirect_object do |obj|
69
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
70
- next unless obj.indirect?
66
+ document.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
71
67
  next if obj.value[:Type] == :ObjStm
72
68
 
73
69
  key = stream_dedup_key(obj)
data/lib/pdfrb/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pdfrb
4
- VERSION = "0.8.5"
4
+ VERSION = "0.8.6"
5
5
  end
data/lib/pdfrb/writer.rb CHANGED
@@ -392,26 +392,19 @@ module Pdfrb
392
392
  return current unless catalog
393
393
 
394
394
  v = current
395
- if (catalog.value[:AF] || catalog.value[:Collection]) && compare_versions(v, "2.0").negative?
395
+ if (catalog.value[:AF] || catalog.value[:Collection]) && Pdfrb::PdfVersion.compare(v, "2.0").negative?
396
396
  v = "2.0"
397
397
  end
398
- if catalog.value[:OCProperties] && compare_versions(v, "1.5").negative?
398
+ if catalog.value[:OCProperties] && Pdfrb::PdfVersion.compare(v, "1.5").negative?
399
399
  v = "1.5"
400
400
  end
401
401
  document.version = v
402
402
  v
403
403
  end
404
404
 
405
- def compare_versions(a, b)
406
- aa = a.to_s.split(".").map(&:to_i)
407
- bb = b.to_s.split(".").map(&:to_i)
408
- (aa <=> bb) || 0
409
- end
410
-
411
405
  def compress_content_streams
412
406
  require "zlib"
413
- document.each_indirect_object do |obj|
414
- next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
407
+ document.each_indirect_of(Pdfrb::Model::Cos::Stream) do |obj|
415
408
  next if obj.value[:Filter]
416
409
  next unless obj.stream
417
410
  next if obj.value[:Type] == :Metadata
data/lib/pdfrb.rb CHANGED
@@ -18,6 +18,7 @@ module Pdfrb
18
18
  autoload :Configuration, "pdfrb/configuration"
19
19
  autoload :DataDir, "pdfrb/data_dir"
20
20
  autoload :PdfConstants, "pdfrb/pdf_constants"
21
+ autoload :PdfVersion, "pdfrb/pdf_version"
21
22
 
22
23
  autoload :Source, "pdfrb/source"
23
24
  autoload :Model, "pdfrb/model"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdfrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-29 00:00:00.000000000 Z
11
+ date: 2026-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark
@@ -1261,6 +1261,7 @@ files:
1261
1261
  - lib/pdfrb/model/type/xobject_image.rb
1262
1262
  - lib/pdfrb/model/type/xref_stream.rb
1263
1263
  - lib/pdfrb/pdf_constants.rb
1264
+ - lib/pdfrb/pdf_version.rb
1264
1265
  - lib/pdfrb/serializer.rb
1265
1266
  - lib/pdfrb/source.rb
1266
1267
  - lib/pdfrb/source/header_reader.rb