pdfrb 0.8.4 → 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 +9 -2
- 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/d_part.rb +4 -4
- 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/function_stitching.rb +1 -1
- data/lib/pdfrb/model/type/generic_appearance.rb +1 -1
- 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/rich_media_configuration.rb +1 -1
- 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/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/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 +3 -1
data/lib/pdfrb/document/fonts.rb
CHANGED
|
@@ -5,6 +5,9 @@ require "stringio"
|
|
|
5
5
|
module Pdfrb
|
|
6
6
|
class Document
|
|
7
7
|
class Fonts
|
|
8
|
+
autoload :Subsetting, "pdfrb/document/fonts/subsetting"
|
|
9
|
+
include Subsetting
|
|
10
|
+
|
|
8
11
|
STANDARDS = %w[
|
|
9
12
|
Helvetica Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique
|
|
10
13
|
Times-Roman Times-Bold Times-Italic Times-BoldItalic
|
|
@@ -152,21 +155,6 @@ module Pdfrb
|
|
|
152
155
|
desc&.value&.key?(:FontFile2)
|
|
153
156
|
end
|
|
154
157
|
|
|
155
|
-
def subset_fonts!
|
|
156
|
-
@font_streams.each do |resource, data|
|
|
157
|
-
next unless valid_font_data?(data)
|
|
158
|
-
|
|
159
|
-
codepoints = @used_codepoints[resource]
|
|
160
|
-
next if codepoints.empty?
|
|
161
|
-
|
|
162
|
-
begin
|
|
163
|
-
subset_font(resource, data, codepoints)
|
|
164
|
-
rescue StandardError
|
|
165
|
-
next
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
158
|
class << self
|
|
171
159
|
def loaders; @loaders ||= []; end
|
|
172
160
|
def register_loader(loader); loaders.unshift(loader); end
|
|
@@ -178,13 +166,13 @@ module Pdfrb
|
|
|
178
166
|
|
|
179
167
|
widths = Array.new(256, DEFAULT_WIDTH)
|
|
180
168
|
tu_stream = build_tounicode(doc)
|
|
181
|
-
tu_ref =
|
|
169
|
+
tu_ref = tu_stream.ref
|
|
182
170
|
fd = doc.add({
|
|
183
171
|
Type: :FontDescriptor, FontName: name.to_sym, Flags: 32,
|
|
184
172
|
FontBBox: [0, 0, 1000, 1000], ItalicAngle: 0,
|
|
185
173
|
Ascent: 800, Descent: -200, CapHeight: 700, StemV: 80
|
|
186
174
|
}, type: Pdfrb::Model::Cos::Dictionary)
|
|
187
|
-
fd_ref =
|
|
175
|
+
fd_ref = fd.ref
|
|
188
176
|
font_hash = {
|
|
189
177
|
Type: :Font, Subtype: :Type1, BaseFont: name.to_sym,
|
|
190
178
|
FirstChar: 0, LastChar: 255, Widths: widths,
|
|
@@ -399,18 +387,6 @@ module Pdfrb
|
|
|
399
387
|
name.to_s.gsub(/[\s()\[\]<>{}\/%]+/, "-")
|
|
400
388
|
end
|
|
401
389
|
|
|
402
|
-
# Generate a deterministic 6-letter subset tag from the font bytes
|
|
403
|
-
# so re-embedding the same font produces the same prefix. Format
|
|
404
|
-
# is six uppercase ASCII letters derived from the SHA-1 of the
|
|
405
|
-
# first 1 KB of the font file (per PDF spec s9.6.4).
|
|
406
|
-
def subset_tag_for(font_bytes)
|
|
407
|
-
require "digest"
|
|
408
|
-
digest = Digest::SHA1.digest(font_bytes.byteslice(0, 1024) || "")
|
|
409
|
-
digest.byteslice(0, 6).bytes.each_with_object(+"") do |b, s|
|
|
410
|
-
s << ((b % 26) + 65).chr
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
390
|
def true_type_subtype(data)
|
|
415
391
|
magic = data&.byteslice(0, 4)
|
|
416
392
|
# Per PDF spec s9.6.2 + s9.9: magic distinguishes the two
|
|
@@ -444,14 +420,14 @@ module Pdfrb
|
|
|
444
420
|
|
|
445
421
|
def default_font(name)
|
|
446
422
|
tu_stream = self.class.build_tounicode(document)
|
|
447
|
-
tu_ref =
|
|
423
|
+
tu_ref = tu_stream.ref
|
|
448
424
|
|
|
449
425
|
fd = document.add({
|
|
450
426
|
Type: :FontDescriptor, FontName: name.to_sym, Flags: 32,
|
|
451
427
|
FontBBox: [0, 0, 1000, 1000], ItalicAngle: 0,
|
|
452
428
|
Ascent: 800, Descent: -200, CapHeight: 700, StemV: 80
|
|
453
429
|
}, type: Pdfrb::Model::Cos::Dictionary)
|
|
454
|
-
fd_ref =
|
|
430
|
+
fd_ref = fd.ref
|
|
455
431
|
|
|
456
432
|
if @pending_io_data && valid_font_data?(@pending_io_data)
|
|
457
433
|
font_file = document.add(
|
|
@@ -466,11 +442,11 @@ module Pdfrb
|
|
|
466
442
|
font_file.value[:Subtype] = :OpenType
|
|
467
443
|
font_file.value[:Length1] = @pending_io_data.bytesize
|
|
468
444
|
fd.value[:FontFile3] =
|
|
469
|
-
|
|
445
|
+
font_file.ref
|
|
470
446
|
else
|
|
471
447
|
font_file.value[:Length1] = @pending_io_data.bytesize
|
|
472
448
|
fd.value[:FontFile2] =
|
|
473
|
-
|
|
449
|
+
font_file.ref
|
|
474
450
|
end
|
|
475
451
|
end
|
|
476
452
|
|
|
@@ -483,58 +459,12 @@ module Pdfrb
|
|
|
483
459
|
}, type: subtype == :TrueType ? Pdfrb::Model::Type::FontTrueType : Pdfrb::Model::Type::FontType1)
|
|
484
460
|
end
|
|
485
461
|
|
|
486
|
-
# Build the subsetted font bytes for +resource+ and replace the
|
|
487
|
-
# descriptor's font-file stream (FontFile2 for TrueType
|
|
488
|
-
# outlines, FontFile3/OpenType for CFF).
|
|
489
|
-
def subset_font(resource, data, codepoints)
|
|
490
|
-
subset, font_file_key =
|
|
491
|
-
if data.byteslice(0, 4) == "OTTO".b
|
|
492
|
-
# CFF outlines: map codepoints to glyph IDs via the OTF
|
|
493
|
-
# cmap (it addresses CFF glyphs too), subset the 'CFF '
|
|
494
|
-
# table, and rebuild the OTF container.
|
|
495
|
-
cmap = Pdfrb::Font::TrueType::File.new(data).cmap
|
|
496
|
-
gids = codepoints.filter_map { |cp| cmap.glyph_id_for(cp) }.uniq
|
|
497
|
-
[Pdfrb::Font::CFF::Subsetter.subset_otf(data, gids), :FontFile3]
|
|
498
|
-
else
|
|
499
|
-
ttf = Pdfrb::Font::TrueType::File.new(data)
|
|
500
|
-
subsetter = Pdfrb::Font::TrueType::Subsetter.new(ttf, codepoints.to_a)
|
|
501
|
-
[subsetter.subset, :FontFile2]
|
|
502
|
-
end
|
|
503
|
-
dict = @font_dicts[resource]
|
|
504
|
-
return unless dict
|
|
505
|
-
|
|
506
|
-
desc_ref = dict.value[:FontDescriptor]
|
|
507
|
-
return unless desc_ref
|
|
508
|
-
|
|
509
|
-
desc = desc_ref.is_a?(Pdfrb::Model::Reference) ? document.object(desc_ref) : desc_ref
|
|
510
|
-
return unless desc
|
|
511
|
-
|
|
512
|
-
# Reuse the add-time stream object in place rather than
|
|
513
|
-
# allocating a replacement — a second stream would leave the
|
|
514
|
-
# full original orphaned in the file (doubling output size).
|
|
515
|
-
fd_stream = desc.value[font_file_key]
|
|
516
|
-
fd_stream = document.object(fd_stream) if fd_stream.is_a?(Pdfrb::Model::Reference)
|
|
517
|
-
if fd_stream.is_a?(Pdfrb::Model::Cos::Stream)
|
|
518
|
-
fd_stream.stream = subset
|
|
519
|
-
fd_stream.value[:Length] = subset.bytesize
|
|
520
|
-
fd_stream.value.delete(:Filter)
|
|
521
|
-
if font_file_key == :FontFile3
|
|
522
|
-
fd_stream.value[:Subtype] = :OpenType
|
|
523
|
-
fd_stream.value[:Length1] = subset.bytesize
|
|
524
|
-
end
|
|
525
|
-
end
|
|
526
|
-
end
|
|
527
|
-
|
|
528
462
|
# Fonts attach to the page-tree ROOT's /Resources so every page
|
|
529
463
|
# inherits them (s7.7.3.2 resource inheritance). Attaching to
|
|
530
464
|
# the Catalog instead — as this used to — produced a stray key
|
|
531
465
|
# no viewer honours, leaving written pages without fonts.
|
|
532
466
|
def attach_to_resources(resource, font_dict)
|
|
533
|
-
|
|
534
|
-
root = document.pages.pages_root
|
|
535
|
-
root.value[:Resources] ||= {}
|
|
536
|
-
root.value[:Resources][:Font] ||= {}
|
|
537
|
-
root.value[:Resources][:Font][resource] = ref
|
|
467
|
+
document.pages.attach_resource(:Font, resource, font_dict.ref)
|
|
538
468
|
end
|
|
539
469
|
end
|
|
540
470
|
end
|
data/lib/pdfrb/document/form.rb
CHANGED
|
@@ -98,7 +98,7 @@ module Pdfrb
|
|
|
98
98
|
|
|
99
99
|
fields = acroform[:Fields] || []
|
|
100
100
|
fields.each do |ref|
|
|
101
|
-
obj =
|
|
101
|
+
obj = document.resolve(ref)
|
|
102
102
|
yield obj if obj
|
|
103
103
|
end
|
|
104
104
|
end
|
|
@@ -165,13 +165,13 @@ module Pdfrb
|
|
|
165
165
|
fields = acroform[:Fields]
|
|
166
166
|
return nil unless fields
|
|
167
167
|
|
|
168
|
-
field_ref =
|
|
168
|
+
field_ref = field.ref
|
|
169
169
|
fields.delete_if { |r| r == field_ref || (r.is_a?(Pdfrb::Model::Reference) && r.oid == field.oid) }
|
|
170
170
|
|
|
171
171
|
# Remove widget annotation from page /Annots
|
|
172
172
|
page_ref = field.value[:P]
|
|
173
173
|
if page_ref
|
|
174
|
-
page =
|
|
174
|
+
page = document.resolve(page_ref)
|
|
175
175
|
annots = page&.value&.[](:Annots)
|
|
176
176
|
annots&.delete_if { |r| r == field_ref || (r.is_a?(Pdfrb::Model::Reference) && r.oid == field.oid) }
|
|
177
177
|
end
|
|
@@ -219,7 +219,7 @@ module Pdfrb
|
|
|
219
219
|
page_ref = field.value[:P]
|
|
220
220
|
return unless page_ref
|
|
221
221
|
|
|
222
|
-
page =
|
|
222
|
+
page = document.resolve(page_ref)
|
|
223
223
|
return unless page
|
|
224
224
|
|
|
225
225
|
name = register_form_on_page(page, form_stream)
|
|
@@ -248,7 +248,7 @@ module Pdfrb
|
|
|
248
248
|
end
|
|
249
249
|
return nil unless target
|
|
250
250
|
|
|
251
|
-
|
|
251
|
+
document.resolve(target)
|
|
252
252
|
end
|
|
253
253
|
|
|
254
254
|
def dictionary?(value)
|
|
@@ -278,7 +278,7 @@ module Pdfrb
|
|
|
278
278
|
resources = page.value[:Resources] = Pdfrb::Model::Cos::Dictionary.new({}) unless resources.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
279
279
|
xobjects = resources.value[:XObject] || {}
|
|
280
280
|
name = unique_xobject_name(xobjects)
|
|
281
|
-
xobjects[name] =
|
|
281
|
+
xobjects[name] = form_stream.ref
|
|
282
282
|
resources.value[:XObject] = xobjects
|
|
283
283
|
name
|
|
284
284
|
end
|
|
@@ -306,7 +306,7 @@ module Pdfrb
|
|
|
306
306
|
Subtype: :Widget,
|
|
307
307
|
T: name,
|
|
308
308
|
Rect: rect,
|
|
309
|
-
P:
|
|
309
|
+
P: page.ref,
|
|
310
310
|
FT: :Tx,
|
|
311
311
|
},
|
|
312
312
|
type: Pdfrb::Model::Type::Annotation
|
|
@@ -317,7 +317,7 @@ module Pdfrb
|
|
|
317
317
|
|
|
318
318
|
def add_annot_to_page(page, widget)
|
|
319
319
|
annots = page.value[:Annots]
|
|
320
|
-
ref =
|
|
320
|
+
ref = widget.ref
|
|
321
321
|
if annots.nil?
|
|
322
322
|
page.value[:Annots] = [ref]
|
|
323
323
|
elsif annots.is_a?(::Array)
|
|
@@ -330,7 +330,7 @@ module Pdfrb
|
|
|
330
330
|
def register_field(field)
|
|
331
331
|
acroform = document.catalog.value[:AcroForm]
|
|
332
332
|
fields = acroform[:Fields]
|
|
333
|
-
ref =
|
|
333
|
+
ref = field.ref
|
|
334
334
|
fields << ref
|
|
335
335
|
end
|
|
336
336
|
end
|
|
@@ -50,7 +50,7 @@ module Pdfrb
|
|
|
50
50
|
resources = page.value[:Resources]
|
|
51
51
|
resources = {} unless resources.is_a?(::Hash)
|
|
52
52
|
xobjects = resources[:XObject] || {}
|
|
53
|
-
xobjects[@name] =
|
|
53
|
+
xobjects[@name] = @stream.ref
|
|
54
54
|
resources[:XObject] = xobjects
|
|
55
55
|
page.value[:Resources] = resources
|
|
56
56
|
end
|
|
@@ -24,7 +24,7 @@ module Pdfrb
|
|
|
24
24
|
def register(page, **params)
|
|
25
25
|
gs = document.add({ Type: :ExtGState, **params },
|
|
26
26
|
type: Pdfrb::Model::Type::GraphicsStateParameter)
|
|
27
|
-
ref =
|
|
27
|
+
ref = gs.ref
|
|
28
28
|
|
|
29
29
|
resources = ensure_resources(page)
|
|
30
30
|
ext_gstate = resources.value[:ExtGState] || {}
|
|
@@ -46,12 +46,7 @@ module Pdfrb
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def attach_to_resources(name, image)
|
|
49
|
-
|
|
50
|
-
# Page-tree root so every page inherits it (s7.7.3.2).
|
|
51
|
-
root = document.pages.pages_root
|
|
52
|
-
root.value[:Resources] ||= {}
|
|
53
|
-
root.value[:Resources][:XObject] ||= {}
|
|
54
|
-
root.value[:Resources][:XObject][name] = ref
|
|
49
|
+
document.pages.attach_resource(:XObject, name, image.ref)
|
|
55
50
|
end
|
|
56
51
|
end
|
|
57
52
|
end
|
data/lib/pdfrb/document/info.rb
CHANGED
|
@@ -29,16 +29,16 @@ module Pdfrb
|
|
|
29
29
|
{ Type: :Outlines },
|
|
30
30
|
type: Pdfrb::Model::Cos::Dictionary
|
|
31
31
|
)
|
|
32
|
-
root_ref =
|
|
32
|
+
root_ref = root.ref
|
|
33
33
|
|
|
34
34
|
prev_dict = nil
|
|
35
35
|
first_ref = nil
|
|
36
36
|
@entries.each do |entry|
|
|
37
37
|
dict = entry.build!(@document)
|
|
38
|
-
ref =
|
|
38
|
+
ref = dict.ref
|
|
39
39
|
|
|
40
40
|
dict.value[:Parent] = root_ref
|
|
41
|
-
dict.value[:Prev] =
|
|
41
|
+
dict.value[:Prev] = prev_dict.ref if prev_dict
|
|
42
42
|
dict.value[:Next] = nil
|
|
43
43
|
prev_dict&.value&.[]=(:Next, ref)
|
|
44
44
|
|
|
@@ -47,7 +47,7 @@ module Pdfrb
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
root.value[:First] = first_ref
|
|
50
|
-
root.value[:Last] =
|
|
50
|
+
root.value[:Last] = prev_dict.ref if prev_dict
|
|
51
51
|
root.value[:Count] = @entries.length
|
|
52
52
|
|
|
53
53
|
@document.catalog.value[:Outlines] = root_ref
|
|
@@ -78,11 +78,11 @@ module Pdfrb
|
|
|
78
78
|
first_ref = nil
|
|
79
79
|
@children.each do |child|
|
|
80
80
|
child_dict = child.build!(document)
|
|
81
|
-
child_ref =
|
|
82
|
-
parent_ref =
|
|
81
|
+
child_ref = child_dict.ref
|
|
82
|
+
parent_ref = dict.ref
|
|
83
83
|
|
|
84
84
|
child_dict.value[:Parent] = parent_ref
|
|
85
|
-
child_dict.value[:Prev] =
|
|
85
|
+
child_dict.value[:Prev] = prev_child_dict.ref if prev_child_dict
|
|
86
86
|
child_dict.value[:Next] = nil
|
|
87
87
|
prev_child_dict&.value&.[]=(:Next, child_ref)
|
|
88
88
|
|
|
@@ -91,7 +91,7 @@ module Pdfrb
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
dict.value[:First] = first_ref
|
|
94
|
-
dict.value[:Last] =
|
|
94
|
+
dict.value[:Last] = prev_child_dict.ref if prev_child_dict
|
|
95
95
|
dict.value[:Count] = @children.length
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -42,7 +42,7 @@ module Pdfrb
|
|
|
42
42
|
)
|
|
43
43
|
catalog = document.catalog
|
|
44
44
|
intents = catalog.value[:OutputIntents]
|
|
45
|
-
ref =
|
|
45
|
+
ref = intent.ref
|
|
46
46
|
if intents.nil?
|
|
47
47
|
catalog.value[:OutputIntents] = [ref]
|
|
48
48
|
elsif intents.is_a?(::Array)
|
|
@@ -63,7 +63,7 @@ module Pdfrb
|
|
|
63
63
|
type: Pdfrb::Model::Cos::Stream
|
|
64
64
|
)
|
|
65
65
|
stream.stream = profile.raw_data
|
|
66
|
-
ref =
|
|
66
|
+
ref = stream.ref
|
|
67
67
|
add(ref, identifier: identifier, condition: condition, registry: registry, subtype: subtype)
|
|
68
68
|
end
|
|
69
69
|
|
|
@@ -74,7 +74,7 @@ module Pdfrb
|
|
|
74
74
|
return self unless intents
|
|
75
75
|
|
|
76
76
|
intents.each do |ref|
|
|
77
|
-
obj =
|
|
77
|
+
obj = document.resolve(ref)
|
|
78
78
|
yield obj if obj
|
|
79
79
|
end
|
|
80
80
|
self
|
data/lib/pdfrb/document/pages.rb
CHANGED
|
@@ -31,9 +31,9 @@ module Pdfrb
|
|
|
31
31
|
# one lazily when it attaches XObjects.
|
|
32
32
|
page_hash = {
|
|
33
33
|
Type: :Page,
|
|
34
|
-
Parent:
|
|
34
|
+
Parent: root.ref,
|
|
35
35
|
MediaBox: media_box,
|
|
36
|
-
Contents:
|
|
36
|
+
Contents: contents.ref
|
|
37
37
|
}
|
|
38
38
|
page_hash[:BleedBox] = bleed_box if bleed_box
|
|
39
39
|
page_hash[:TrimBox] = trim_box if trim_box
|
|
@@ -42,7 +42,7 @@ module Pdfrb
|
|
|
42
42
|
page = document.add(page_hash, type: Pdfrb::Model::Type::Page)
|
|
43
43
|
page.value[:Rotate] = rotate if rotate.nonzero?
|
|
44
44
|
kids = (root.value[:Kids] ||= [])
|
|
45
|
-
kids <<
|
|
45
|
+
kids << page.ref
|
|
46
46
|
root.value[:Count] = (root.value[:Count] || 0) + 1
|
|
47
47
|
page
|
|
48
48
|
end
|
|
@@ -57,7 +57,8 @@ module Pdfrb
|
|
|
57
57
|
|
|
58
58
|
def count
|
|
59
59
|
raw = pages_root[:Count]
|
|
60
|
-
resolved =
|
|
60
|
+
resolved = document.resolve(raw)
|
|
61
|
+
resolved = resolved.value if resolved.is_a?(Pdfrb::Model::Object)
|
|
61
62
|
case resolved
|
|
62
63
|
when Integer then resolved
|
|
63
64
|
when Numeric then resolved.to_i
|
|
@@ -136,6 +137,17 @@ module Pdfrb
|
|
|
136
137
|
end
|
|
137
138
|
end
|
|
138
139
|
|
|
140
|
+
# Attach +ref+ under +category+ (e.g. :Font, :XObject,
|
|
141
|
+
# :Shading) in the page-tree root's /Resources, where every
|
|
142
|
+
# page inherits it (s7.7.3.2). The single seam for resource
|
|
143
|
+
# placement — placement policy changes land here.
|
|
144
|
+
def attach_resource(category, name, ref)
|
|
145
|
+
root = pages_root
|
|
146
|
+
root.value[:Resources] ||= {}
|
|
147
|
+
root.value[:Resources][category] ||= {}
|
|
148
|
+
root.value[:Resources][category][name] = ref
|
|
149
|
+
end
|
|
150
|
+
|
|
139
151
|
# The page-tree root (Catalog /Pages), seeding an empty tree if
|
|
140
152
|
# needed. Resources placed here are inherited by every page
|
|
141
153
|
# (s7.7.3.2).
|
|
@@ -149,7 +161,7 @@ module Pdfrb
|
|
|
149
161
|
# No /Pages yet — seed an empty tree.
|
|
150
162
|
root = document.add({ Type: :Pages, Kids: [], Count: 0 },
|
|
151
163
|
type: Pdfrb::Model::Type::PageTreeNode)
|
|
152
|
-
catalog.value[:Pages] =
|
|
164
|
+
catalog.value[:Pages] = root.ref
|
|
153
165
|
root
|
|
154
166
|
end
|
|
155
167
|
|
|
@@ -163,8 +175,7 @@ module Pdfrb
|
|
|
163
175
|
kids = kids.value if kids.is_a?(Pdfrb::Model::Cos::Dictionary) && !kids.is_a?(::Hash)
|
|
164
176
|
|
|
165
177
|
Array(kids).each do |kid_ref|
|
|
166
|
-
kid =
|
|
167
|
-
document.object(kid_ref) : kid_ref
|
|
178
|
+
kid = document.resolve(kid_ref)
|
|
168
179
|
next unless kid
|
|
169
180
|
|
|
170
181
|
type = kid.is_a?(Pdfrb::Model::Cos::Dictionary) ? kid.value[:Type] : nil
|
|
@@ -181,7 +192,7 @@ module Pdfrb
|
|
|
181
192
|
def ref_to(page)
|
|
182
193
|
return page if page.is_a?(Pdfrb::Model::Reference)
|
|
183
194
|
|
|
184
|
-
|
|
195
|
+
page.ref
|
|
185
196
|
end
|
|
186
197
|
end
|
|
187
198
|
end
|
data/lib/pdfrb/document/pdf_a.rb
CHANGED
|
@@ -100,9 +100,9 @@ module Pdfrb
|
|
|
100
100
|
},
|
|
101
101
|
type: Pdfrb::Model::Cos::Dictionary
|
|
102
102
|
)
|
|
103
|
-
filespec.value[:EF] =
|
|
103
|
+
filespec.value[:EF] = ef.ref
|
|
104
104
|
filespec.value[:AFRelationship] = :Unspecified
|
|
105
|
-
|
|
105
|
+
filespec.ref
|
|
106
106
|
end
|
|
107
107
|
end
|
|
108
108
|
|
|
@@ -112,7 +112,7 @@ module Pdfrb
|
|
|
112
112
|
type: Pdfrb::Model::Cos::Stream
|
|
113
113
|
)
|
|
114
114
|
embedded.stream = item.file_bytes
|
|
115
|
-
|
|
115
|
+
embedded.ref
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
end
|
|
@@ -109,7 +109,7 @@ module Pdfrb
|
|
|
109
109
|
{
|
|
110
110
|
FunctionType: 3,
|
|
111
111
|
Domain: Pdfrb::Model::PdfArray.new([0, 1]),
|
|
112
|
-
Functions: functions.map
|
|
112
|
+
Functions: functions.map(&:ref),
|
|
113
113
|
Bounds: Pdfrb::Model::PdfArray.new(bounds),
|
|
114
114
|
Encode: Pdfrb::Model::PdfArray.new(stops.each_cons(2).map { [0, 1] }.flatten),
|
|
115
115
|
},
|
|
@@ -142,14 +142,7 @@ module Pdfrb
|
|
|
142
142
|
|
|
143
143
|
def register(name, shading_obj)
|
|
144
144
|
@registry[name] = shading_obj
|
|
145
|
-
document.
|
|
146
|
-
# Attach to the page-tree root so every page inherits it
|
|
147
|
-
# (s7.7.3.2); the Catalog has no /Resources key in PDF.
|
|
148
|
-
root = document.pages.pages_root
|
|
149
|
-
root.value[:Resources] ||= {}
|
|
150
|
-
root.value[:Resources][:Shading] ||= {}
|
|
151
|
-
root.value[:Resources][:Shading][name] =
|
|
152
|
-
Pdfrb::Model::Reference.new(shading_obj.oid, shading_obj.gen)
|
|
145
|
+
document.pages.attach_resource(:Shading, name, shading_obj.ref)
|
|
153
146
|
end
|
|
154
147
|
|
|
155
148
|
def next_name
|
|
@@ -19,7 +19,7 @@ module Pdfrb
|
|
|
19
19
|
# @return [Symbol] the resource name (e.g., :St1).
|
|
20
20
|
def stamp_everywhere(form_xobject, at: [0, 0])
|
|
21
21
|
name = next_stamp_name
|
|
22
|
-
ref =
|
|
22
|
+
ref = form_xobject.ref
|
|
23
23
|
|
|
24
24
|
document.pages.each do |page|
|
|
25
25
|
register_xobject_in_resources(page, name, ref)
|
|
@@ -31,7 +31,7 @@ module Pdfrb
|
|
|
31
31
|
# Stamp a Form XObject on a single page.
|
|
32
32
|
def stamp_page(page, form_xobject, at: [0, 0])
|
|
33
33
|
name = next_stamp_name
|
|
34
|
-
ref =
|
|
34
|
+
ref = form_xobject.ref
|
|
35
35
|
register_xobject_in_resources(page, name, ref)
|
|
36
36
|
emit_do_operator(page, name, at)
|
|
37
37
|
name
|
|
@@ -35,13 +35,13 @@ module Pdfrb
|
|
|
35
35
|
)
|
|
36
36
|
catalog = document.catalog
|
|
37
37
|
catalog.value[:StructTreeRoot] =
|
|
38
|
-
|
|
38
|
+
root_elem.ref
|
|
39
39
|
mark_info = catalog.value[:MarkInfo]
|
|
40
40
|
if mark_info.nil?
|
|
41
41
|
mark_info = document.add({ Marked: true },
|
|
42
42
|
type: Pdfrb::Model::Cos::Dictionary)
|
|
43
43
|
catalog.value[:MarkInfo] =
|
|
44
|
-
|
|
44
|
+
mark_info.ref
|
|
45
45
|
end
|
|
46
46
|
@root = root_elem
|
|
47
47
|
end
|
|
@@ -59,7 +59,7 @@ module Pdfrb
|
|
|
59
59
|
page_ref = if page.is_a?(Pdfrb::Model::Reference)
|
|
60
60
|
page
|
|
61
61
|
else
|
|
62
|
-
|
|
62
|
+
page.ref
|
|
63
63
|
end
|
|
64
64
|
elem.value[:Pg] = page_ref
|
|
65
65
|
end
|
|
@@ -166,7 +166,7 @@ module Pdfrb
|
|
|
166
166
|
nums << page_idx
|
|
167
167
|
nums << entries.length
|
|
168
168
|
entries.each do |_mcid, elem| # rubocop:disable Style/HashEachMethods
|
|
169
|
-
nums <<
|
|
169
|
+
nums << elem.ref
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
|
|
@@ -189,7 +189,7 @@ module Pdfrb
|
|
|
189
189
|
return 0 unless page_ref
|
|
190
190
|
|
|
191
191
|
document.pages.each_with_index do |page, idx|
|
|
192
|
-
page_obj =
|
|
192
|
+
page_obj = document.resolve(page)
|
|
193
193
|
return idx if page_obj == page_ref || page == page_ref
|
|
194
194
|
end
|
|
195
195
|
0
|
|
@@ -215,16 +215,16 @@ module Pdfrb
|
|
|
215
215
|
def append_child(parent, child)
|
|
216
216
|
children = parent.value[:K]
|
|
217
217
|
if children.nil?
|
|
218
|
-
parent.value[:K] = [
|
|
218
|
+
parent.value[:K] = [child.ref]
|
|
219
219
|
elsif children.is_a?(::Array)
|
|
220
|
-
children <<
|
|
220
|
+
children << child.ref
|
|
221
221
|
else
|
|
222
222
|
parent.value[:K] = [
|
|
223
223
|
children,
|
|
224
|
-
|
|
224
|
+
child.ref,
|
|
225
225
|
]
|
|
226
226
|
end
|
|
227
|
-
child.value[:P] =
|
|
227
|
+
child.value[:P] = parent.ref
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
public
|
data/lib/pdfrb/document.rb
CHANGED
|
@@ -88,6 +88,13 @@ module Pdfrb
|
|
|
88
88
|
# Resolve a Reference to its Object. New/modified objects take
|
|
89
89
|
# precedence over xref-loaded ones; otherwise consult the
|
|
90
90
|
# ObjectReader (which caches per oid).
|
|
91
|
+
# Resolve a value to the object it denotes: References are
|
|
92
|
+
# dereferenced against this document; anything else is returned
|
|
93
|
+
# unchanged. The single seam for "give me the thing itself".
|
|
94
|
+
def resolve(value)
|
|
95
|
+
value.is_a?(Pdfrb::Model::Reference) ? object(value) : value
|
|
96
|
+
end
|
|
97
|
+
|
|
91
98
|
def object(reference)
|
|
92
99
|
return reference unless reference.is_a?(Pdfrb::Model::Reference)
|
|
93
100
|
|
|
@@ -430,9 +437,9 @@ module Pdfrb
|
|
|
430
437
|
|
|
431
438
|
def seed_empty_structure
|
|
432
439
|
pages = add({ Type: :Pages, Kids: [], Count: 0 })
|
|
433
|
-
catalog = add({ Type: :Catalog, Pages:
|
|
440
|
+
catalog = add({ Type: :Catalog, Pages: pages.ref })
|
|
434
441
|
@catalog = catalog
|
|
435
|
-
@empty_trailer = { Size: @next_oid, Root:
|
|
442
|
+
@empty_trailer = { Size: @next_oid, Root: catalog.ref }
|
|
436
443
|
end
|
|
437
444
|
|
|
438
445
|
def recover_or_raise(error)
|
|
Binary file
|