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.
- checksums.yaml +4 -4
- data/lib/pdfrb/annotation/base.rb +2 -2
- data/lib/pdfrb/appearance/generator.rb +1 -1
- data/lib/pdfrb/cli/images.rb +1 -1
- data/lib/pdfrb/cli.rb +3 -3
- data/lib/pdfrb/color/default_profile.rb +1 -1
- data/lib/pdfrb/conformance/ltv.rb +1 -1
- data/lib/pdfrb/conformance/pades.rb +4 -4
- data/lib/pdfrb/conformance/pdf_2_af.rb +2 -2
- data/lib/pdfrb/conformance/pdf_a.rb +1 -1
- data/lib/pdfrb/conformance/pdf_x.rb +3 -3
- data/lib/pdfrb/conformance/tagged_pdf.rb +1 -1
- data/lib/pdfrb/content/canvas.rb +1 -1
- data/lib/pdfrb/content/hidden_text_detector.rb +1 -1
- data/lib/pdfrb/content/shading/base.rb +1 -1
- data/lib/pdfrb/content/tiling_pattern.rb +1 -1
- data/lib/pdfrb/digital_signature/signing.rb +2 -2
- data/lib/pdfrb/document/annotations.rb +10 -10
- data/lib/pdfrb/document/associated_files.rb +2 -2
- data/lib/pdfrb/document/colors.rb +1 -1
- data/lib/pdfrb/document/destinations.rb +4 -4
- data/lib/pdfrb/document/encryption.rb +1 -1
- data/lib/pdfrb/document/files.rb +5 -5
- data/lib/pdfrb/document/fonts/subsetting.rb +87 -0
- data/lib/pdfrb/document/fonts.rb +10 -80
- data/lib/pdfrb/document/form.rb +9 -9
- data/lib/pdfrb/document/form_xobject.rb +1 -1
- data/lib/pdfrb/document/graphics_state.rb +1 -1
- data/lib/pdfrb/document/images.rb +1 -6
- data/lib/pdfrb/document/info.rb +1 -1
- data/lib/pdfrb/document/layers.rb +1 -1
- data/lib/pdfrb/document/metadata.rb +1 -1
- data/lib/pdfrb/document/outline.rb +8 -8
- data/lib/pdfrb/document/output_intents.rb +3 -3
- data/lib/pdfrb/document/pages.rb +19 -8
- data/lib/pdfrb/document/pdf_a.rb +1 -1
- data/lib/pdfrb/document/portfolio.rb +3 -3
- data/lib/pdfrb/document/shadings.rb +2 -9
- data/lib/pdfrb/document/stamps.rb +2 -2
- data/lib/pdfrb/document/structure.rb +9 -9
- data/lib/pdfrb/document.rb +10 -3
- data/lib/pdfrb/encryption/security_handler.rb +1 -2
- data/lib/pdfrb/font/cff/subsetter.rb +0 -0
- data/lib/pdfrb/font/sfnt.rb +73 -0
- data/lib/pdfrb/font/true_type/subsetter.rb +1 -57
- data/lib/pdfrb/font/true_type/wrapper.rb +3 -3
- data/lib/pdfrb/font.rb +1 -0
- data/lib/pdfrb/font_loader/true_type.rb +2 -2
- data/lib/pdfrb/font_loader/type3.rb +1 -1
- data/lib/pdfrb/importer.rb +3 -3
- data/lib/pdfrb/linearization/writer.rb +1 -1
- data/lib/pdfrb/model/object.rb +7 -0
- data/lib/pdfrb/model/type/action_hide.rb +1 -1
- data/lib/pdfrb/model/type/action_sound.rb +2 -2
- data/lib/pdfrb/model/type/add_action_catalog.rb +1 -1
- data/lib/pdfrb/model/type/add_action_form_field.rb +1 -1
- data/lib/pdfrb/model/type/add_action_page_object.rb +1 -1
- data/lib/pdfrb/model/type/add_action_screen_annotation.rb +1 -1
- data/lib/pdfrb/model/type/add_action_widget_annotation.rb +1 -1
- data/lib/pdfrb/model/type/alternate_image.rb +2 -2
- data/lib/pdfrb/model/type/bead.rb +4 -4
- data/lib/pdfrb/model/type/catalog.rb +1 -1
- data/lib/pdfrb/model/type/color_space.rb +5 -31
- data/lib/pdfrb/model/type/crypt_filter.rb +6 -6
- data/lib/pdfrb/model/type/d_part.rb +4 -4
- data/lib/pdfrb/model/type/destination.rb +2 -18
- data/lib/pdfrb/model/type/document_security_store.rb +1 -1
- data/lib/pdfrb/model/type/dss.rb +1 -1
- data/lib/pdfrb/model/type/font_multiple_master.rb +3 -12
- data/lib/pdfrb/model/type/function_stitching.rb +1 -1
- data/lib/pdfrb/model/type/generic_appearance.rb +1 -1
- data/lib/pdfrb/model/type/misc_extras.rb +2 -7
- data/lib/pdfrb/model/type/name_map.rb +33 -0
- data/lib/pdfrb/model/type/opt_content_ext.rb +2 -2
- data/lib/pdfrb/model/type/optional_content_membership.rb +2 -2
- data/lib/pdfrb/model/type/page.rb +5 -7
- data/lib/pdfrb/model/type/page_tree_node.rb +2 -2
- data/lib/pdfrb/model/type/pattern.rb +2 -18
- data/lib/pdfrb/model/type/rich_media_configuration.rb +1 -1
- data/lib/pdfrb/model/type/shading.rb +2 -18
- data/lib/pdfrb/model/type/signature_extras.rb +6 -21
- data/lib/pdfrb/model/type/soft_mask.rb +1 -13
- data/lib/pdfrb/model/type/struct_elem.rb +2 -2
- data/lib/pdfrb/model/type/struct_tree_root.rb +2 -2
- data/lib/pdfrb/model/type/structure_attributes.rb +5 -18
- data/lib/pdfrb/model/type/thread.rb +3 -3
- data/lib/pdfrb/model/type/three_d_stream.rb +1 -1
- data/lib/pdfrb/model/type/viewport.rb +1 -1
- data/lib/pdfrb/model/type/vri.rb +1 -1
- data/lib/pdfrb/model/type/web_capture_command.rb +1 -1
- data/lib/pdfrb/model/type/web_capture_image_set.rb +1 -1
- data/lib/pdfrb/model/type/web_capture_page_set.rb +2 -2
- data/lib/pdfrb/model/type/xobject_form.rb +1 -13
- data/lib/pdfrb/model/type.rb +2 -0
- data/lib/pdfrb/task/extract_images.rb +1 -2
- data/lib/pdfrb/task/extract_text.rb +1 -1
- data/lib/pdfrb/task/merge.rb +3 -3
- data/lib/pdfrb/task/thumbnail.rb +1 -1
- data/lib/pdfrb/version.rb +1 -1
- data/lib/pdfrb/writer.rb +4 -5
- data/lib/pdfrb/xmp.rb +2 -2
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04a819d2ed2b54eb4ca8c0ac17ceb14cc1c45a79e359bb51c6b5194e2fdb7025
|
|
4
|
+
data.tar.gz: bcb6a670c04b7e68b20b90f8ac344ac0672a76f1fd3e16306ac46b4c44f728ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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:
|
|
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 =
|
|
67
|
+
ref = annot.ref
|
|
68
68
|
if annots.nil?
|
|
69
69
|
page.value[:Annots] = [ref]
|
|
70
70
|
elsif annots.is_a?(::Array)
|
data/lib/pdfrb/cli/images.rb
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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] =
|
|
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] =
|
|
367
|
+
doc.trailer[:Encrypt] = encrypt_dict.ref
|
|
368
368
|
doc.config["encryption.password"] = user_pw
|
|
369
369
|
end
|
|
370
370
|
|
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
156
|
+
resolved = document.resolve(e)
|
|
157
157
|
next unless resolved && resolved.value[:Type] == :FileSpec
|
|
158
158
|
|
|
159
159
|
yield container, resolved
|
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
148
|
+
root = document.resolve(root_ref)
|
|
149
149
|
return unless root
|
|
150
150
|
|
|
151
151
|
first_kids = structure_kids(root, document)
|
data/lib/pdfrb/content/canvas.rb
CHANGED
|
@@ -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 =
|
|
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?
|
|
@@ -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:
|
|
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
|
-
|
|
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:
|
|
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 <<
|
|
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] =
|
|
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:
|
|
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 <<
|
|
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:
|
|
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 <<
|
|
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:
|
|
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 <<
|
|
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 =
|
|
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 =
|
|
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 =
|
|
98
|
+
obj = document.resolve(ref)
|
|
99
99
|
obj if obj.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
100
100
|
end
|
|
101
101
|
end
|
|
@@ -79,7 +79,7 @@ module Pdfrb
|
|
|
79
79
|
d = catalog.value[:Dests]
|
|
80
80
|
return nil unless d
|
|
81
81
|
|
|
82
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
data/lib/pdfrb/document/files.rb
CHANGED
|
@@ -42,8 +42,8 @@ module Pdfrb
|
|
|
42
42
|
{
|
|
43
43
|
Type: :FileSpec,
|
|
44
44
|
UF: name.to_s,
|
|
45
|
-
EF: { UF:
|
|
46
|
-
F:
|
|
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 =
|
|
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 <<
|
|
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 =
|
|
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
|