Class: Pdfrb::Writer

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document, io) ⇒ Writer

Returns a new instance of Writer.



21
22
23
24
25
26
27
28
29
# 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"]
  )
  @xref_offsets = {} # oid -> byte offset
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



19
20
21
# File 'lib/pdfrb/writer.rb', line 19

def document
  @document
end

#ioObject (readonly)

Returns the value of attribute io.



19
20
21
# File 'lib/pdfrb/writer.rb', line 19

def io
  @io
end

#serializerObject (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



31
32
33
# File 'lib/pdfrb/writer.rb', line 31

def self.write(document, io)
  new(document, io).write
end

.write_incremental(document, io) ⇒ Object



35
36
37
# File 'lib/pdfrb/writer.rb', line 35

def self.write_incremental(document, io)
  new(document, io).write_incremental
end

Instance Method Details

#writeObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/pdfrb/writer.rb', line 39

def write
  @io.binmode
  @io.truncate(0) if @io.respond_to?(:truncate)
  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_incrementalObject

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.

Raises:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/pdfrb/writer.rb', line 75

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.instance_variable_get(:@objects).each_value 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