Class: Pdfrb::Document
- Inherits:
-
Object
- Object
- Pdfrb::Document
- Defined in:
- lib/pdfrb/document.rb,
lib/pdfrb/document/files.rb,
lib/pdfrb/document/fonts.rb,
lib/pdfrb/document/pages.rb,
lib/pdfrb/document/images.rb,
lib/pdfrb/document/outline.rb,
lib/pdfrb/document/metadata.rb,
lib/pdfrb/document/annotations.rb,
lib/pdfrb/document/destinations.rb
Overview
Top-level PDF document facade. Owns:
* The IO it was read from (or nil for in-memory).
* An oid -> Object table for new/modified objects.
* A wrap() pipeline that upgrades raw Hashes to typed
Dictionary subclasses based on /Type or an explicit type.
* On read: an XrefSection + ObjectReader for lazy resolution.
* A revisions stack (TODO 30 — incremental updates).
Defined Under Namespace
Classes: Annotations, Destinations, Files, Fonts, Images, Metadata, Outline, OutlineEntry, Pages
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#io ⇒ Object
readonly
Returns the value of attribute io.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
-
#xref ⇒ Object
readonly
Returns the value of attribute xref.
Class Method Summary collapse
Instance Method Summary collapse
- #add(value, type: nil) ⇒ Object
- #annotations ⇒ Object
- #catalog ⇒ Object
- #destinations ⇒ Object
- #dispatch_message(message, *args) ⇒ Object
-
#each_indirect_object ⇒ Object
Yield every indirect object in this document: modified/new ones first (they shadow loaded ones), then every loaded entry the xref knows about.
- #files ⇒ Object
- #fonts ⇒ Object
- #images ⇒ Object
-
#initialize(io: nil, config: {}) ⇒ Document
constructor
A new instance of Document.
- #metadata ⇒ Object
-
#object(reference) ⇒ Object
(also: #dereference)
Resolve a Reference to its Object.
- #outline ⇒ Object
-
#pages ⇒ Object
---- Facade accessors (Phase 13) ---- Each returns a memoised helper object that knows how to mutate this document.
- #register_listener(message, &block) ⇒ Object
-
#register_override(obj) ⇒ Object
Replace an indirect object in the @objects table.
-
#trailer ⇒ Object
Convenience accessor for the document Catalog dict.
- #wrap(data, type: nil, oid: 0, gen: 0) ⇒ Object
-
#write(path = nil, io: nil) ⇒ Object
Write this document to
path(or any IO via +io:).
Constructor Details
#initialize(io: nil, config: {}) ⇒ Document
Returns a new instance of Document.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/pdfrb/document.rb', line 23 def initialize(io: nil, config: {}) @config = Configuration.new(config) @io = io @objects = {} # oid -> Pdfrb::Model::Object (modified or new) @next_oid = 1 @listeners = {} # message_name -> [Proc] @xref = nil @object_reader = nil @version = "1.4" @empty_trailer = nil if io read_from_io(io) else seed_empty_structure end end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
41 42 43 |
# File 'lib/pdfrb/document.rb', line 41 def config @config end |
#io ⇒ Object (readonly)
Returns the value of attribute io.
41 42 43 |
# File 'lib/pdfrb/document.rb', line 41 def io @io end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
41 42 43 |
# File 'lib/pdfrb/document.rb', line 41 def version @version end |
#xref ⇒ Object (readonly)
Returns the value of attribute xref.
41 42 43 |
# File 'lib/pdfrb/document.rb', line 41 def xref @xref end |
Class Method Details
.open(path, **opts) ⇒ Object
43 44 45 46 47 48 49 50 51 |
# File 'lib/pdfrb/document.rb', line 43 def self.open(path, **opts) if block_given? File.open(path, "rb") { |f| yield new(io: f, **opts) } else bytes = File.binread(path) require "stringio" new(io: StringIO.new(bytes), **opts) end end |
Instance Method Details
#add(value, type: nil) ⇒ Object
63 64 65 66 67 68 |
# File 'lib/pdfrb/document.rb', line 63 def add(value, type: nil) oid = allocate_oid obj = wrap(value, type: type, oid: oid, gen: 0) register(obj) obj end |
#annotations ⇒ Object
122 123 124 |
# File 'lib/pdfrb/document.rb', line 122 def annotations @annotations ||= Document::Annotations.new(self) end |
#catalog ⇒ Object
155 156 157 158 159 160 161 162 |
# File 'lib/pdfrb/document.rb', line 155 def catalog return @catalog if defined?(@catalog) && @catalog ref = trailer ? trailer[:Root] : nil return nil unless ref @catalog = object(ref) end |
#destinations ⇒ Object
118 119 120 |
# File 'lib/pdfrb/document.rb', line 118 def destinations @destinations ||= Document::Destinations.new(self) end |
#dispatch_message(message, *args) ⇒ Object
88 89 90 91 92 |
# File 'lib/pdfrb/document.rb', line 88 def (, *args) return unless @listeners.key?() @listeners[].each { |blk| blk.call(*args) } end |
#each_indirect_object ⇒ Object
Yield every indirect object in this document: modified/new ones first (they shadow loaded ones), then every loaded entry the xref knows about.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/pdfrb/document.rb', line 167 def each_indirect_object seen = Set.new @objects.each_value do |obj| next unless obj.indirect? seen << obj.oid yield obj end return if @xref.nil? @xref.entries.each_key do |oid| next if seen.include?(oid) next if oid.zero? obj = object(Pdfrb::Model::Reference.new(oid, 0)) next if obj.nil? || !obj.indirect? yield obj end end |
#files ⇒ Object
110 111 112 |
# File 'lib/pdfrb/document.rb', line 110 def files @files ||= Document::Files.new(self) end |
#fonts ⇒ Object
102 103 104 |
# File 'lib/pdfrb/document.rb', line 102 def fonts @fonts ||= Document::Fonts.new(self) end |
#images ⇒ Object
106 107 108 |
# File 'lib/pdfrb/document.rb', line 106 def images @images ||= Document::Images.new(self) end |
#metadata ⇒ Object
114 115 116 |
# File 'lib/pdfrb/document.rb', line 114 def @metadata ||= Document::Metadata.new(self) end |
#object(reference) ⇒ Object Also known as: dereference
Resolve a Reference to its Object. New/modified objects take precedence over xref-loaded ones; otherwise consult the ObjectReader (which caches per oid).
73 74 75 76 77 78 79 80 81 |
# File 'lib/pdfrb/document.rb', line 73 def object(reference) return reference unless reference.is_a?(Pdfrb::Model::Reference) modified = @objects[reference.oid] return modified if modified return nil if @object_reader.nil? @object_reader.load_oid(reference.oid) end |
#outline ⇒ Object
126 127 128 |
# File 'lib/pdfrb/document.rb', line 126 def outline @outline ||= Document::Outline.new(self) end |
#pages ⇒ Object
---- Facade accessors (Phase 13) ---- Each returns a memoised helper object that knows how to mutate this document. Defined under Pdfrb::Document::*.
98 99 100 |
# File 'lib/pdfrb/document.rb', line 98 def pages @pages ||= Document::Pages.new(self) end |
#register_listener(message, &block) ⇒ Object
84 85 86 |
# File 'lib/pdfrb/document.rb', line 84 def register_listener(, &block) (@listeners[] ||= []) << block end |
#register_override(obj) ⇒ Object
Replace an indirect object in the @objects table. Used by the Importer when promoting a Dictionary stub to a Stream (so cycles resolve correctly). Idempotent.
133 134 135 |
# File 'lib/pdfrb/document.rb', line 133 def register_override(obj) @objects[obj.oid] = obj end |
#trailer ⇒ Object
Convenience accessor for the document Catalog dict. Loads from trailer's /Root, which itself is loaded lazily from the xref.
149 150 151 152 153 |
# File 'lib/pdfrb/document.rb', line 149 def trailer return @trailer if defined?(@trailer) && @trailer @trailer = read_trailer end |
#wrap(data, type: nil, oid: 0, gen: 0) ⇒ Object
53 54 55 56 57 58 59 60 61 |
# File 'lib/pdfrb/document.rb', line 53 def wrap(data, type: nil, oid: 0, gen: 0) target_class = resolve_target_class(data, type) value = unwrap_value(data) if target_class <= Pdfrb::Model::Object target_class.new(value, oid: oid, gen: gen, document: self) else target_class.new(value) end end |
#write(path = nil, io: nil) ⇒ Object
Write this document to path (or any IO via +io:).
138 139 140 141 142 143 144 145 |
# File 'lib/pdfrb/document.rb', line 138 def write(path = nil, io: nil) target = io || (path && File.open(path, "wb")) raise ArgumentError, "write needs a path or io:" unless target Pdfrb::Writer.write(self, target) target.close if path && io.nil? && target.respond_to?(:close) self end |