Class: Pdfrb::Writer
- Inherits:
-
Object
- Object
- Pdfrb::Writer
- Defined in:
- lib/pdfrb/writer.rb
Overview
Writes a Document to an IO as a complete PDF file: header, indirect objects, xref section, trailer.
Two modes:
* +write+ (default) — full rewrite; assign oids to new objects,
emit every object the document references.
* +write_incremental+ — append a new revision to an existing
byte stream. Only valid when the document was opened from an
IO; the original bytes are preserved verbatim, and a new
xref + trailer are appended with /Prev pointing back.
Constant Summary collapse
- DEFAULT_VERSION =
"1.4"
Instance Attribute Summary collapse
-
#document ⇒ Object
readonly
Returns the value of attribute document.
-
#io ⇒ Object
readonly
Returns the value of attribute io.
-
#serializer ⇒ Object
readonly
Returns the value of attribute serializer.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(document, io) ⇒ Writer
constructor
A new instance of Writer.
-
#serializer_encrypter_opts ⇒ Object
Build the encrypter option for the Serializer from the document's /Encrypt dict.
- #write ⇒ Object
-
#write_incremental ⇒ Object
Append a new revision to the original byte stream.
Constructor Details
#initialize(document, io) ⇒ Writer
Returns a new instance of Writer.
21 22 23 24 25 26 27 28 29 30 |
# File 'lib/pdfrb/writer.rb', line 21 def initialize(document, io) @document = document @io = io @serializer = Serializer.new( compress_streams: document.config["writer.compress_streams"], compress_min_size: document.config["writer.compress_min_size"], **serializer_encrypter_opts ) @xref_offsets = {} end |
Instance Attribute Details
#document ⇒ Object (readonly)
Returns the value of attribute document.
19 20 21 |
# File 'lib/pdfrb/writer.rb', line 19 def document @document end |
#io ⇒ Object (readonly)
Returns the value of attribute io.
19 20 21 |
# File 'lib/pdfrb/writer.rb', line 19 def io @io end |
#serializer ⇒ Object (readonly)
Returns the value of attribute serializer.
19 20 21 |
# File 'lib/pdfrb/writer.rb', line 19 def serializer @serializer end |
Class Method Details
.write(document, io) ⇒ Object
64 65 66 |
# File 'lib/pdfrb/writer.rb', line 64 def self.write(document, io) new(document, io).write end |
.write_incremental(document, io) ⇒ Object
68 69 70 |
# File 'lib/pdfrb/writer.rb', line 68 def self.write_incremental(document, io) new(document, io).write_incremental end |
Instance Method Details
#serializer_encrypter_opts ⇒ Object
Build the encrypter option for the Serializer from the document's /Encrypt dict. If the document isn't encrypted, returns empty hash. The SecurityHandler's encrypt_data method becomes the Serializer's encrypter, which encrypts string/stream payloads per-object.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/pdfrb/writer.rb', line 36 def serializer_encrypter_opts # Use a pre-configured handler if the document provides one # (e.g., set by the encryption CLI). handler = document.config["encryption.handler"] return { encrypter: handler } if handler trailer = document.trailer return {} unless trailer encrypt_ref = trailer[:Encrypt] return {} unless encrypt_ref encrypt_dict = encrypt_ref.is_a?(Pdfrb::Model::Reference) ? document.object(encrypt_ref) : encrypt_ref return {} unless encrypt_dict handler = Pdfrb::Encryption::StandardSecurityHandler.new( Encrypt: encrypt_dict.value, ID: trailer[:ID] ) password = document.config["encryption.password"] || "" handler.verify_user_password(password) { encrypter: handler } rescue StandardError {} end |
#write ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/pdfrb/writer.rb', line 72 def write @io.binmode @io.truncate(0) if @io.is_a?(StringIO) write_header dispatch_before_write use_stream = document.config["writer.use_xref_stream"] pack_objstm = document.config["writer.pack_object_streams"] packed = pack_objstm ? pack_object_streams : {} each_indirect_object do |obj| next if packed.key?(obj.oid) @xref_offsets[obj.oid] = @io.pos @io << @serializer.serialize_indirect(obj) end xref_pos = if use_stream write_xref_stream(packed) else write_xref end if use_stream write_xref_stream_trailer(xref_pos) else write_trailer(xref_pos) end @io.flush self end |
#write_incremental ⇒ Object
Append a new revision to the original byte stream. Requires the document to have been opened from an IO (so we can copy its original bytes verbatim) and the IO the writer is given is the target output.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/pdfrb/writer.rb', line 108 def write_incremental raise Pdfrb::Error, "incremental write requires a source IO" unless document.io @io.binmode # Copy the original bytes verbatim. document.io.seek(0, IO::SEEK_SET) @io << document.io.read dispatch_before_write # Emit only the modified objects. document.each_indirect_object do |obj| next unless obj.indirect? @xref_offsets[obj.oid] = @io.pos @io << @serializer.serialize_indirect(obj) end xref_pos = write_xref(prev: previous_xref_offset) write_trailer(xref_pos, prev: previous_xref_offset) @io.flush self end |