pdfrb 0.8.3 → 0.8.5

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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pdfrb/annotation/base.rb +2 -2
  3. data/lib/pdfrb/appearance/generator.rb +1 -1
  4. data/lib/pdfrb/cli/images.rb +1 -1
  5. data/lib/pdfrb/cli.rb +3 -3
  6. data/lib/pdfrb/color/default_profile.rb +1 -1
  7. data/lib/pdfrb/conformance/ltv.rb +1 -1
  8. data/lib/pdfrb/conformance/pades.rb +4 -4
  9. data/lib/pdfrb/conformance/pdf_2_af.rb +2 -2
  10. data/lib/pdfrb/conformance/pdf_a.rb +1 -1
  11. data/lib/pdfrb/conformance/pdf_x.rb +3 -3
  12. data/lib/pdfrb/conformance/tagged_pdf.rb +1 -1
  13. data/lib/pdfrb/content/canvas.rb +1 -1
  14. data/lib/pdfrb/content/hidden_text_detector.rb +1 -1
  15. data/lib/pdfrb/content/shading/base.rb +1 -1
  16. data/lib/pdfrb/content/tiling_pattern.rb +1 -1
  17. data/lib/pdfrb/digital_signature/signing.rb +2 -2
  18. data/lib/pdfrb/document/annotations.rb +10 -10
  19. data/lib/pdfrb/document/associated_files.rb +2 -2
  20. data/lib/pdfrb/document/colors.rb +1 -1
  21. data/lib/pdfrb/document/destinations.rb +4 -4
  22. data/lib/pdfrb/document/encryption.rb +1 -1
  23. data/lib/pdfrb/document/files.rb +5 -5
  24. data/lib/pdfrb/document/fonts/subsetting.rb +87 -0
  25. data/lib/pdfrb/document/fonts.rb +10 -80
  26. data/lib/pdfrb/document/form.rb +9 -9
  27. data/lib/pdfrb/document/form_xobject.rb +1 -1
  28. data/lib/pdfrb/document/graphics_state.rb +1 -1
  29. data/lib/pdfrb/document/images.rb +1 -6
  30. data/lib/pdfrb/document/info.rb +1 -1
  31. data/lib/pdfrb/document/layers.rb +1 -1
  32. data/lib/pdfrb/document/metadata.rb +1 -1
  33. data/lib/pdfrb/document/outline.rb +8 -8
  34. data/lib/pdfrb/document/output_intents.rb +3 -3
  35. data/lib/pdfrb/document/pages.rb +19 -8
  36. data/lib/pdfrb/document/pdf_a.rb +1 -1
  37. data/lib/pdfrb/document/portfolio.rb +3 -3
  38. data/lib/pdfrb/document/shadings.rb +2 -9
  39. data/lib/pdfrb/document/stamps.rb +2 -2
  40. data/lib/pdfrb/document/structure.rb +9 -9
  41. data/lib/pdfrb/document.rb +10 -3
  42. data/lib/pdfrb/encryption/security_handler.rb +1 -2
  43. data/lib/pdfrb/font/cff/subsetter.rb +0 -0
  44. data/lib/pdfrb/font/sfnt.rb +73 -0
  45. data/lib/pdfrb/font/true_type/subsetter.rb +1 -57
  46. data/lib/pdfrb/font/true_type/wrapper.rb +3 -3
  47. data/lib/pdfrb/font.rb +1 -0
  48. data/lib/pdfrb/font_loader/true_type.rb +2 -2
  49. data/lib/pdfrb/font_loader/type3.rb +1 -1
  50. data/lib/pdfrb/importer.rb +3 -3
  51. data/lib/pdfrb/linearization/writer.rb +1 -1
  52. data/lib/pdfrb/model/object.rb +7 -0
  53. data/lib/pdfrb/model/type/action_hide.rb +1 -1
  54. data/lib/pdfrb/model/type/action_sound.rb +2 -2
  55. data/lib/pdfrb/model/type/add_action_catalog.rb +1 -1
  56. data/lib/pdfrb/model/type/add_action_form_field.rb +1 -1
  57. data/lib/pdfrb/model/type/add_action_page_object.rb +1 -1
  58. data/lib/pdfrb/model/type/add_action_screen_annotation.rb +1 -1
  59. data/lib/pdfrb/model/type/add_action_widget_annotation.rb +1 -1
  60. data/lib/pdfrb/model/type/alternate_image.rb +2 -2
  61. data/lib/pdfrb/model/type/bead.rb +4 -4
  62. data/lib/pdfrb/model/type/catalog.rb +1 -1
  63. data/lib/pdfrb/model/type/color_space.rb +5 -31
  64. data/lib/pdfrb/model/type/crypt_filter.rb +6 -6
  65. data/lib/pdfrb/model/type/d_part.rb +4 -4
  66. data/lib/pdfrb/model/type/destination.rb +2 -18
  67. data/lib/pdfrb/model/type/document_security_store.rb +1 -1
  68. data/lib/pdfrb/model/type/dss.rb +1 -1
  69. data/lib/pdfrb/model/type/font_multiple_master.rb +3 -12
  70. data/lib/pdfrb/model/type/function_stitching.rb +1 -1
  71. data/lib/pdfrb/model/type/generic_appearance.rb +1 -1
  72. data/lib/pdfrb/model/type/misc_extras.rb +2 -7
  73. data/lib/pdfrb/model/type/name_map.rb +33 -0
  74. data/lib/pdfrb/model/type/opt_content_ext.rb +2 -2
  75. data/lib/pdfrb/model/type/optional_content_membership.rb +2 -2
  76. data/lib/pdfrb/model/type/page.rb +5 -7
  77. data/lib/pdfrb/model/type/page_tree_node.rb +2 -2
  78. data/lib/pdfrb/model/type/pattern.rb +2 -18
  79. data/lib/pdfrb/model/type/rich_media_configuration.rb +1 -1
  80. data/lib/pdfrb/model/type/shading.rb +2 -18
  81. data/lib/pdfrb/model/type/signature_extras.rb +6 -21
  82. data/lib/pdfrb/model/type/soft_mask.rb +1 -13
  83. data/lib/pdfrb/model/type/struct_elem.rb +2 -2
  84. data/lib/pdfrb/model/type/struct_tree_root.rb +2 -2
  85. data/lib/pdfrb/model/type/structure_attributes.rb +5 -18
  86. data/lib/pdfrb/model/type/thread.rb +3 -3
  87. data/lib/pdfrb/model/type/three_d_stream.rb +1 -1
  88. data/lib/pdfrb/model/type/viewport.rb +1 -1
  89. data/lib/pdfrb/model/type/vri.rb +1 -1
  90. data/lib/pdfrb/model/type/web_capture_command.rb +1 -1
  91. data/lib/pdfrb/model/type/web_capture_image_set.rb +1 -1
  92. data/lib/pdfrb/model/type/web_capture_page_set.rb +2 -2
  93. data/lib/pdfrb/model/type/xobject_form.rb +1 -13
  94. data/lib/pdfrb/model/type.rb +2 -0
  95. data/lib/pdfrb/task/extract_images.rb +1 -2
  96. data/lib/pdfrb/task/extract_text.rb +1 -1
  97. data/lib/pdfrb/task/merge.rb +3 -3
  98. data/lib/pdfrb/task/thumbnail.rb +1 -1
  99. data/lib/pdfrb/version.rb +1 -1
  100. data/lib/pdfrb/writer.rb +4 -5
  101. data/lib/pdfrb/xmp.rb +2 -2
  102. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 386ea091bd58d931bc196bd3df335f26043feb5f70e02e33cd076b30566e157d
4
- data.tar.gz: d41d511beef5d357dd5e86f0253cd932f11475dc173e0e29665462bb40fcab61
3
+ metadata.gz: 04a819d2ed2b54eb4ca8c0ac17ceb14cc1c45a79e359bb51c6b5194e2fdb7025
4
+ data.tar.gz: bcb6a670c04b7e68b20b90f8ac344ac0672a76f1fd3e16306ac46b4c44f728ec
5
5
  SHA512:
6
- metadata.gz: 249ca1bde48ee762616405b716b93389fd6eea3950f981a59d8cc18b81620891190c1addae3009b1624065ed7ef3411304761fb1e0cc014bd60c02ba8db01eef
7
- data.tar.gz: 69258188bf5f7cc3a3ffddbb89348b7a3589c54bb5a943fcb46a059c72aded574cdbfb43d212abca82eea0e44375a1f8caf863f51666dc79f95537b3c4f8945d
6
+ metadata.gz: f8eb286788ae52128019b39b18006776c9c9227ab92e76b0a72add85eb92b16daa390704d243627a0f79fcd8b9c0195a606f7f6878953db634ff1c9ad257b0f4
7
+ data.tar.gz: 1940d86297e8e20ae06d33b23bd7b36815d5249fce28eb120262ab33e5350668fa015247444ed905ac1ba5b73295fa092b74d6e477c9fd74a507252a78cb110f
@@ -39,7 +39,7 @@ module Pdfrb
39
39
  Type: :Annot,
40
40
  Subtype: subtype,
41
41
  Rect: rect,
42
- P: Pdfrb::Model::Reference.new(page.oid, page.gen),
42
+ P: page.ref,
43
43
  Contents: contents,
44
44
  F: flags,
45
45
  }.compact
@@ -64,7 +64,7 @@ module Pdfrb
64
64
 
65
65
  def attach_to_page(page, annot)
66
66
  annots = page.value[:Annots]
67
- ref = Pdfrb::Model::Reference.new(annot.oid, annot.gen)
67
+ ref = annot.ref
68
68
  if annots.nil?
69
69
  page.value[:Annots] = [ref]
70
70
  elsif annots.is_a?(::Array)
@@ -195,7 +195,7 @@ module Pdfrb
195
195
 
196
196
  def set_appearance(field, form, state_name = :Normal)
197
197
  form_stream = form.stream
198
- ref = Pdfrb::Model::Reference.new(form_stream.oid, form_stream.gen)
198
+ ref = form_stream.ref
199
199
 
200
200
  ap = field.value[:AP]
201
201
  if ap.nil?
@@ -18,7 +18,7 @@ module Pdfrb
18
18
 
19
19
  xo = xo.value if xo.is_a?(Pdfrb::Model::Cos::Dictionary)
20
20
  xo&.each do |name, ref|
21
- obj = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
21
+ obj = doc.resolve(ref)
22
22
  next unless obj&.value&.[](:Subtype) == :Image
23
23
 
24
24
  count += 1
data/lib/pdfrb/cli.rb CHANGED
@@ -158,7 +158,7 @@ module Pdfrb
158
158
  return unless fields
159
159
 
160
160
  fields.each do |ref|
161
- field = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
161
+ field = doc.resolve(ref)
162
162
  next unless field
163
163
 
164
164
  name = field[:T] || "(unnamed)"
@@ -330,7 +330,7 @@ module Pdfrb
330
330
  O: o_entry, U: u_entry },
331
331
  type: Pdfrb::Model::Cos::Dictionary
332
332
  )
333
- doc.trailer[:Encrypt] = Pdfrb::Model::Reference.new(encrypt_dict.oid, encrypt_dict.gen)
333
+ doc.trailer[:Encrypt] = encrypt_dict.ref
334
334
 
335
335
  # Set up the handler so Writer can encrypt per-object.
336
336
  handler = Pdfrb::Encryption::StandardSecurityHandler.new(
@@ -364,7 +364,7 @@ module Pdfrb
364
364
  O: o_entry, U: u_entry, OE: "".b, UE: "".b },
365
365
  type: Pdfrb::Model::Cos::Dictionary
366
366
  )
367
- doc.trailer[:Encrypt] = Pdfrb::Model::Reference.new(encrypt_dict.oid, encrypt_dict.gen)
367
+ doc.trailer[:Encrypt] = encrypt_dict.ref
368
368
  doc.config["encryption.password"] = user_pw
369
369
  end
370
370
 
@@ -47,7 +47,7 @@ module Pdfrb
47
47
  type: Pdfrb::Model::Cos::Stream
48
48
  )
49
49
  stream.stream = bytes
50
- [:ICCBased, Pdfrb::Model::Reference.new(stream.oid, stream.gen)]
50
+ [:ICCBased, stream.ref]
51
51
  end
52
52
 
53
53
  # ---- Header construction ----
@@ -87,7 +87,7 @@ module Pdfrb
87
87
  fields = Pdfrb::Conformance::Pades.signature_fields(doc)
88
88
  has_archival = fields.any? do |field|
89
89
  v = field[:V]
90
- v_obj = v.is_a?(Pdfrb::Model::Reference) ? doc.object(v) : v
90
+ v_obj = doc.resolve(v)
91
91
  v_obj && v_obj[:Type]&.to_sym == :DocTimeStamp
92
92
  end
93
93
  next nil if has_archival
@@ -52,7 +52,7 @@ module Pdfrb
52
52
  v = field[:V]
53
53
  next unless v
54
54
 
55
- v_obj = v.is_a?(Pdfrb::Model::Reference) ? doc.object(v) : v
55
+ v_obj = doc.resolve(v)
56
56
  next if v_obj && ALLOWED_SIGNATURE_TYPES.include?(v_obj[:Type]&.to_sym)
57
57
 
58
58
  vs << Violation.new(
@@ -81,7 +81,7 @@ module Pdfrb
81
81
  v = field[:V]
82
82
  next unless v
83
83
 
84
- v_obj = v.is_a?(Pdfrb::Model::Reference) ? doc.object(v) : v
84
+ v_obj = doc.resolve(v)
85
85
  has_timestamp = v_obj && (
86
86
  v_obj[:Type]&.to_sym == :DocTimeStamp ||
87
87
  (v_obj[:ByteRange] && timestamp_in_signature?(v_obj))
@@ -134,7 +134,7 @@ module Pdfrb
134
134
  # protecting the DSS.
135
135
  has_archival = signature_fields(doc).any? do |field|
136
136
  v = field[:V]
137
- v_obj = v.is_a?(Pdfrb::Model::Reference) ? doc.object(v) : v
137
+ v_obj = doc.resolve(v)
138
138
  v_obj && v_obj[:Type]&.to_sym == :DocTimeStamp
139
139
  end
140
140
  next nil if has_archival
@@ -173,7 +173,7 @@ module Pdfrb
173
173
  return [] unless fields.is_a?(::Array)
174
174
 
175
175
  fields.filter_map do |ref|
176
- obj = ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
176
+ obj = document.resolve(ref)
177
177
  next nil unless obj
178
178
 
179
179
  obj[:FT]&.to_sym == :Sig ? obj : nil
@@ -131,7 +131,7 @@ module Pdfrb
131
131
  af_value = af.is_a?(Pdfrb::Model::PdfArray) ? af.value : af
132
132
  entries = af_value.is_a?(::Array) ? af_value : [af_value]
133
133
  entries.each do |e|
134
- resolved = e.is_a?(Pdfrb::Model::Reference) ? document.object(e) : e
134
+ resolved = document.resolve(e)
135
135
  yield container, resolved if resolved
136
136
  end
137
137
  end
@@ -153,7 +153,7 @@ module Pdfrb
153
153
  af_value = af.is_a?(Pdfrb::Model::PdfArray) ? af.value : af
154
154
  entries = af_value.is_a?(::Array) ? af_value : [af_value]
155
155
  entries.each do |e|
156
- resolved = e.is_a?(Pdfrb::Model::Reference) ? document.object(e) : e
156
+ resolved = document.resolve(e)
157
157
  next unless resolved && resolved.value[:Type] == :FileSpec
158
158
 
159
159
  yield container, resolved
@@ -65,7 +65,7 @@ module Pdfrb
65
65
  next unless fonts
66
66
 
67
67
  fonts.each_value do |ref|
68
- f = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
68
+ f = doc.resolve(ref)
69
69
  next unless f
70
70
  next if f[:FontDescriptor]
71
71
 
@@ -94,7 +94,7 @@ module Pdfrb
94
94
 
95
95
  fonts_hash = fonts.is_a?(Pdfrb::Model::Cos::Dictionary) ? fonts.value : fonts
96
96
  fonts_hash&.each_value do |ref|
97
- font = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
97
+ font = doc.resolve(ref)
98
98
  next unless font
99
99
 
100
100
  fd = font[:FontDescriptor]
@@ -174,7 +174,7 @@ module Pdfrb
174
174
 
175
175
  intents = [intents] unless intents.is_a?(::Array)
176
176
  intents.any? do |ref|
177
- obj = ref.is_a?(Pdfrb::Model::Reference) ? doc.object(ref) : ref
177
+ obj = doc.resolve(ref)
178
178
  obj && obj.value[:S] == :GTS_PDFX
179
179
  end
180
180
  end
@@ -257,7 +257,7 @@ module Pdfrb
257
257
  else [intents]
258
258
  end
259
259
  has_pdfx = intents_array.any? do |i|
260
- obj = i.is_a?(Pdfrb::Model::Reference) ? doc.object(i) : i
260
+ obj = doc.resolve(i)
261
261
  obj && obj[:S] == :GTS_PDFX
262
262
  end
263
263
  next nil if has_pdfx
@@ -145,7 +145,7 @@ module Pdfrb
145
145
  root_ref = document.catalog[:StructTreeRoot]
146
146
  return unless root_ref
147
147
 
148
- root = root_ref.is_a?(Pdfrb::Model::Reference) ? document.object(root_ref) : root_ref
148
+ root = document.resolve(root_ref)
149
149
  return unless root
150
150
 
151
151
  first_kids = structure_kids(root, document)
@@ -531,7 +531,7 @@ module Pdfrb
531
531
  )
532
532
  r = @stream.value[:Resources] || {}
533
533
  eg = r[:ExtGState] || {}
534
- eg[name] = Pdfrb::Model::Reference.new(gs.oid, gs.gen)
534
+ eg[name] = gs.ref
535
535
  r[:ExtGState] = eg
536
536
  @stream.value[:Resources] = r
537
537
  name
@@ -69,7 +69,7 @@ module Pdfrb
69
69
  end
70
70
 
71
71
  return obj if list.any? do |c|
72
- c_obj = c.is_a?(Pdfrb::Model::Reference) ? @document.object(c) : c
72
+ c_obj = @document.resolve(c)
73
73
  c_obj == stream_obj
74
74
  end
75
75
  end
@@ -31,7 +31,7 @@ module Pdfrb
31
31
  # @return [Symbol] resource name (e.g. :Sh1)
32
32
  def register_on(document, page)
33
33
  shading_obj = document.add(to_dict, type: Pdfrb::Model::Cos::Dictionary)
34
- ref = Pdfrb::Model::Reference.new(shading_obj.oid, shading_obj.gen)
34
+ ref = shading_obj.ref
35
35
  resources = ensure_resources(document, page)
36
36
  shading_dict = resources.value[:Shading]
37
37
  if shading_dict.nil?
@@ -51,7 +51,7 @@ module Pdfrb
51
51
  yield canvas
52
52
  end
53
53
 
54
- ref = Pdfrb::Model::Reference.new(pattern_stream.oid, pattern_stream.gen)
54
+ ref = pattern_stream.ref
55
55
  register_in_resources(document, page, ref)
56
56
  end
57
57
 
@@ -43,12 +43,12 @@ module Pdfrb
43
43
 
44
44
  field = document.add(
45
45
  { Type: :Annot, Subtype: :Widget, FT: :Sig, T: "Signature1",
46
- V: Pdfrb::Model::Reference.new(sig_dict.oid, sig_dict.gen),
46
+ V: sig_dict.ref,
47
47
  Rect: [0, 0, 0, 0] },
48
48
  type: Pdfrb::Model::Cos::Dictionary
49
49
  )
50
50
  catalog.value[:AcroForm][:Fields] <<
51
- Pdfrb::Model::Reference.new(field.oid, field.gen)
51
+ field.ref
52
52
  end
53
53
 
54
54
  def serialize(document)
@@ -16,14 +16,14 @@ module Pdfrb
16
16
  Type: :Annot,
17
17
  Subtype: subtype,
18
18
  Rect: rect,
19
- P: Pdfrb::Model::Reference.new(page.oid, page.gen),
19
+ P: page.ref,
20
20
  Contents: opts[:contents],
21
21
  F: opts[:flags] || 0
22
22
  }.compact,
23
23
  type: Pdfrb::Model::Type::Annotation
24
24
  )
25
25
  annots = (page.value[:Annots] ||= [])
26
- annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
26
+ annots << annot.ref
27
27
  annot
28
28
  end
29
29
 
@@ -45,7 +45,7 @@ module Pdfrb
45
45
  { Type: :Action, S: :URI, URI: uri },
46
46
  type: Pdfrb::Model::Type::Action
47
47
  )
48
- annot.value[:A] = Pdfrb::Model::Reference.new(action.oid, action.gen)
48
+ annot.value[:A] = action.ref
49
49
  end
50
50
  annot
51
51
  end
@@ -55,7 +55,7 @@ module Pdfrb
55
55
  annot = document.add(
56
56
  {
57
57
  Type: :Annot, Subtype: :FreeText, Rect: rect,
58
- P: Pdfrb::Model::Reference.new(page.oid, page.gen),
58
+ P: page.ref,
59
59
  Contents: contents
60
60
  },
61
61
  type: Pdfrb::Model::Type::FreeTextAnnotation
@@ -65,7 +65,7 @@ module Pdfrb
65
65
  da_parts << "#{color.join(' ')} rg" if color
66
66
  annot.value[:DA] = da_parts.join(" ") unless da_parts.empty?
67
67
  annots = (page.value[:Annots] ||= [])
68
- annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
68
+ annots << annot.ref
69
69
  annot
70
70
  end
71
71
 
@@ -75,13 +75,13 @@ module Pdfrb
75
75
  {
76
76
  Type: :Annot, Subtype: :Highlight,
77
77
  QuadPoints: quad_points,
78
- P: Pdfrb::Model::Reference.new(page.oid, page.gen),
78
+ P: page.ref,
79
79
  Contents: contents
80
80
  }.compact,
81
81
  type: Pdfrb::Model::Type::HighlightAnnotation
82
82
  )
83
83
  annots = (page.value[:Annots] ||= [])
84
- annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
84
+ annots << annot.ref
85
85
  annot
86
86
  end
87
87
 
@@ -90,13 +90,13 @@ module Pdfrb
90
90
  annot = document.add(
91
91
  {
92
92
  Type: :Annot, Subtype: :Stamp, Rect: rect, Name: name,
93
- P: Pdfrb::Model::Reference.new(page.oid, page.gen),
93
+ P: page.ref,
94
94
  Contents: contents
95
95
  }.compact,
96
96
  type: Pdfrb::Model::Type::StampAnnotation
97
97
  )
98
98
  annots = (page.value[:Annots] ||= [])
99
- annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
99
+ annots << annot.ref
100
100
  annot
101
101
  end
102
102
 
@@ -114,7 +114,7 @@ module Pdfrb
114
114
  return self unless annots
115
115
 
116
116
  annots.each do |ref|
117
- a = ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
117
+ a = document.resolve(ref)
118
118
  yield a if a
119
119
  end
120
120
  self
@@ -54,7 +54,7 @@ module Pdfrb
54
54
  filespec = document.files.add(data, name: filename,
55
55
  description: description,
56
56
  mime_type: mime_type)
57
- ref = Pdfrb::Model::Reference.new(filespec.oid, filespec.gen)
57
+ ref = filespec.ref
58
58
  filespec.value[:AFRelationship] = relationship
59
59
  add_to_catalog(ref, relationship: relationship)
60
60
  ref
@@ -95,7 +95,7 @@ module Pdfrb
95
95
 
96
96
  refs = af.is_a?(::Array) ? af : [af]
97
97
  refs.filter_map do |ref|
98
- obj = ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
98
+ obj = document.resolve(ref)
99
99
  obj if obj.is_a?(Pdfrb::Model::Cos::Dictionary)
100
100
  end
101
101
  end
@@ -30,7 +30,7 @@ module Pdfrb
30
30
  stream.stream = profile.raw_data
31
31
  Pdfrb::Model::PdfArray.new([
32
32
  :ICCBased,
33
- Pdfrb::Model::Reference.new(stream.oid, stream.gen),
33
+ stream.ref,
34
34
  ])
35
35
  end
36
36
 
@@ -79,7 +79,7 @@ module Pdfrb
79
79
  d = catalog.value[:Dests]
80
80
  return nil unless d
81
81
 
82
- d.is_a?(Pdfrb::Model::Reference) ? document.object(d) : d
82
+ document.resolve(d)
83
83
  end
84
84
 
85
85
  def resolved_name_tree
@@ -93,7 +93,7 @@ module Pdfrb
93
93
  d = names.is_a?(Pdfrb::Model::Cos::Dictionary) ? names.value[:Dests] : names[:Dests]
94
94
  return nil unless d
95
95
 
96
- d.is_a?(Pdfrb::Model::Reference) ? document.object(d) : d
96
+ document.resolve(d)
97
97
  end
98
98
 
99
99
  def lookup_in_name_tree(node, name)
@@ -107,7 +107,7 @@ module Pdfrb
107
107
  arr = node.value[:Kids]
108
108
  arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
109
109
  arr.each do |kid_ref|
110
- kid = kid_ref.is_a?(Pdfrb::Model::Reference) ? document.object(kid_ref) : kid_ref
110
+ kid = document.resolve(kid_ref)
111
111
  result = lookup_in_name_tree(kid, name)
112
112
  return result if result
113
113
  end
@@ -130,7 +130,7 @@ module Pdfrb
130
130
  arr = node.value[:Kids]
131
131
  arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
132
132
  arr.each do |kid_ref|
133
- kid = kid_ref.is_a?(Pdfrb::Model::Reference) ? document.object(kid_ref) : kid_ref
133
+ kid = document.resolve(kid_ref)
134
134
  each_name_tree_key(kid, &block)
135
135
  end
136
136
  elsif node.is_a?(Hash) && node[:Names]
@@ -176,7 +176,7 @@ module Pdfrb
176
176
  def register(encrypt_hash, user_password:, prebuilt_handler: nil)
177
177
  dict = document.add(encrypt_hash,
178
178
  type: Pdfrb::Model::Type::EncryptionStandard)
179
- ref = Pdfrb::Model::Reference.new(dict.oid, dict.gen)
179
+ ref = dict.ref
180
180
  trailer = document.trailer
181
181
  if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
182
182
  trailer.value[:Encrypt] = ref
@@ -42,8 +42,8 @@ module Pdfrb
42
42
  {
43
43
  Type: :FileSpec,
44
44
  UF: name.to_s,
45
- EF: { UF: Pdfrb::Model::Reference.new(ef_stream.oid, ef_stream.gen),
46
- F: Pdfrb::Model::Reference.new(ef_stream.oid, ef_stream.gen) },
45
+ EF: { UF: ef_stream.ref,
46
+ F: ef_stream.ref },
47
47
  },
48
48
  type: Pdfrb::Model::Cos::Dictionary
49
49
  )
@@ -66,7 +66,7 @@ module Pdfrb
66
66
  return self unless names_array
67
67
 
68
68
  names_array.each_slice(2) do |name, ref|
69
- resolved = ref.is_a?(Pdfrb::Model::Reference) ? @document.object(ref) : ref
69
+ resolved = @document.resolve(ref)
70
70
  yield(name.to_s, resolved) if resolved
71
71
  end
72
72
  self
@@ -100,7 +100,7 @@ module Pdfrb
100
100
  ef_tree = names[:EmbeddedFiles] ||= {}
101
101
  names_array = ef_tree[:Names] ||= []
102
102
  names_array << name
103
- names_array << Pdfrb::Model::Reference.new(filespec.oid, filespec.gen)
103
+ names_array << filespec.ref
104
104
  end
105
105
 
106
106
  def embedded_files_names_array
@@ -117,7 +117,7 @@ module Pdfrb
117
117
  end
118
118
 
119
119
  def add_to_af(target, filespec, relationship)
120
- ref = Pdfrb::Model::Reference.new(filespec.oid, filespec.gen)
120
+ ref = filespec.ref
121
121
  af_entry = if relationship
122
122
  { Type: :AssociatedFile, AFRelationship: relationship,
123
123
  File: ref }
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ class Document
5
+ class Fonts
6
+ # Font-program subsetting (s9.6.4). Mixed into the Fonts
7
+ # facade; the seam it owns is "replace every embedded font
8
+ # program with a subset covering only the used codepoints",
9
+ # dispatching on the outline format (TrueType vs CFF-in-OTF).
10
+ module Subsetting
11
+ # Entry point, invoked by Document#write. Fonts that were
12
+ # never drawn with (no recorded codepoints) keep their full
13
+ # program; failures fall back to the full font.
14
+ def subset_fonts!
15
+ @font_streams.each do |resource, data|
16
+ next unless valid_font_data?(data)
17
+
18
+ codepoints = @used_codepoints[resource]
19
+ next if codepoints.empty?
20
+
21
+ begin
22
+ subset_font(resource, data, codepoints)
23
+ rescue StandardError
24
+ next
25
+ end
26
+ end
27
+ end
28
+
29
+ protected
30
+
31
+ # Build the subsetted font bytes for +resource+ and replace the
32
+ # descriptor's font-file stream (FontFile2 for TrueType
33
+ # outlines, FontFile3/OpenType for CFF).
34
+ def subset_font(resource, data, codepoints)
35
+ subset, font_file_key =
36
+ if data.byteslice(0, 4) == "OTTO".b
37
+ # CFF outlines: map codepoints to glyph IDs via the OTF
38
+ # cmap (it addresses CFF glyphs too), subset the 'CFF '
39
+ # table, and rebuild the OTF container.
40
+ cmap = Pdfrb::Font::TrueType::File.new(data).cmap
41
+ gids = codepoints.filter_map { |cp| cmap.glyph_id_for(cp) }.uniq
42
+ [Pdfrb::Font::CFF::Subsetter.subset_otf(data, gids), :FontFile3]
43
+ else
44
+ ttf = Pdfrb::Font::TrueType::File.new(data)
45
+ subsetter = Pdfrb::Font::TrueType::Subsetter.new(ttf, codepoints.to_a)
46
+ [subsetter.subset, :FontFile2]
47
+ end
48
+ dict = @font_dicts[resource]
49
+ return unless dict
50
+
51
+ desc_ref = dict.value[:FontDescriptor]
52
+ return unless desc_ref
53
+
54
+ desc = document.resolve(desc_ref)
55
+ return unless desc
56
+
57
+ # Reuse the add-time stream object in place rather than
58
+ # allocating a replacement — a second stream would leave the
59
+ # full original orphaned in the file (doubling output size).
60
+ fd_stream = desc.value[font_file_key]
61
+ fd_stream = document.resolve(fd_stream)
62
+ if fd_stream.is_a?(Pdfrb::Model::Cos::Stream)
63
+ fd_stream.stream = subset
64
+ fd_stream.value[:Length] = subset.bytesize
65
+ fd_stream.value.delete(:Filter)
66
+ if font_file_key == :FontFile3
67
+ fd_stream.value[:Subtype] = :OpenType
68
+ fd_stream.value[:Length1] = subset.bytesize
69
+ end
70
+ end
71
+ end
72
+
73
+ # Generate a deterministic 6-letter subset tag from the font bytes
74
+ # so re-embedding the same font produces the same prefix. Format
75
+ # is six uppercase ASCII letters derived from the SHA-1 of the
76
+ # first 1 KB of the font file (per PDF spec s9.6.4).
77
+ def subset_tag_for(font_bytes)
78
+ require "digest"
79
+ digest = Digest::SHA1.digest(font_bytes.byteslice(0, 1024) || "")
80
+ digest.byteslice(0, 6).bytes.each_with_object(+"") do |b, s|
81
+ s << ((b % 26) + 65).chr
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end