lib/hexapdf/document.rb in hexapdf-0.8.0 vs lib/hexapdf/document.rb in hexapdf-0.9.0
- old
+ new
@@ -55,10 +55,12 @@
# * For information about the command line application, see the HexaPDF::CLI module.
# * HexaPDF::Document provides information about how to work with a PDF file.
# * HexaPDF::Content::Canvas provides the canvas API for drawing/writing on a page or form XObject
module HexaPDF
+ autoload(:Composer, 'hexapdf/composer')
+
# Represents one PDF document.
#
# A PDF document consists of (indirect) objects, so the main job of this class is to provide
# methods for working with these objects. However, since a PDF document may also be
# incrementally updated and can therefore contain one or more revisions, there are also methods
@@ -365,16 +367,17 @@
object
end
end
# :call-seq:
- # doc.each(current: true) {|obj| block } -> doc
- # doc.each(current: true) {|obj, rev| block } -> doc
- # doc.each(current: true) -> Enumerator
+ # doc.each(only_current: true, only_loaded: false) {|obj| block } -> doc
+ # doc.each(only_current: true, only_loaded: false) {|obj, rev| block } -> doc
+ # doc.each(only_current: true, only_loaded: false) -> Enumerator
#
- # Calls the given block once for every object in the PDF document. The block may either accept
- # only the object or the object and the revision it is in.
+ # Calls the given block once for every object, or, if +only_loaded+ is +true+, for every loaded
+ # object in the PDF document. The block may either accept only the object or the object and the
+ # revision it is in.
#
# By default, only the current version of each object is returned which implies that each
# object number is yielded exactly once. If the +current+ option is +false+, all stored
# objects from newest to oldest are returned, not only the current version of each object.
#
@@ -385,18 +388,20 @@
# two (different) objects with oid/gen [3,0].
#
# * Additionally, there may also be objects with the same object number but different
# generation numbers in different revisions, e.g. one object with oid/gen [3,0] and one with
# oid/gen [3,1].
- def each(current: true, &block)
- return to_enum(__method__, current: current) unless block_given?
+ def each(only_current: true, only_loaded: false, &block)
+ unless block_given?
+ return to_enum(__method__, only_current: only_current, only_loaded: only_loaded)
+ end
yield_rev = (block.arity == 2)
oids = {}
@revisions.reverse_each do |rev|
- rev.each do |obj|
- next if current && oids.include?(obj.oid)
+ rev.each(only_loaded: only_loaded) do |obj|
+ next if only_current && oids.include?(obj.oid)
(yield_rev ? yield(obj, rev) : yield(obj))
oids[obj.oid] = true
end
end
self
@@ -551,54 +556,57 @@
# returned.
def security_handler
@security_handler
end
- # :call-seq:
- # doc.validate(auto_correct: true) -> true or false
- # doc.validate(auto_correct: true) {|object, msg, correctable| block } -> true or false
+ # Validates all objects, or, if +only_loaded+ is +true+, only loaded objects, with optional
+ # auto-correction, and returns +true+ if everything is fine.
#
- # Validates all objects of the document, with optional auto-correction, and returns +true+ if
- # everything is fine.
- #
# If a block is given, it is called on validation problems.
#
# See HexaPDF::Object#validate for more information.
- def validate(auto_correct: true)
+ def validate(auto_correct: true, only_loaded: false) #:yield: object, msg, correctable
cur_obj = trailer
block = (block_given? ? lambda {|msg, correctable| yield(cur_obj, msg, correctable) } : nil)
result = trailer.validate(auto_correct: auto_correct, &block)
- each(current: false) do |obj|
+ each(only_current: false, only_loaded: only_loaded) do |obj|
cur_obj = obj
result &&= obj.validate(auto_correct: auto_correct, &block)
end
result
end
# :call-seq:
- # doc.write(filename, validate: true, update_fields: true, optimize: false)
- # doc.write(io, validate: true, update_fields: true, optimize: false)
+ # doc.write(filename, incremental: false, validate: true, update_fields: true, optimize: false)
+ # doc.write(io, incremental: false, validate: true, update_fields: true, optimize: false)
#
# Writes the document to the given file (in case +io+ is a String) or IO stream.
#
# Before the document is written, it is validated using #validate and an error is raised if the
# document is not valid. However, this step can be skipped if needed.
#
# Options:
#
+ # incremental::
+ # Use the incremental writing mode which just adds a new revision to an existing document.
+ # This is needed, for example, when modifying a signed PDF and the original signature should
+ # stay valid.
+ #
+ # See: PDF1.7 s7.5.6
+ #
# validate::
# Validates the document and raises an error if an uncorrectable problem is found.
#
# update_fields::
# Updates the /ID field in the trailer dictionary as well as the /ModDate field in the
# trailer's /Info dictionary so that it is clear that the document has been updated.
#
# optimize::
# Optimize the file size by using object and cross-reference streams. This will raise the PDF
# version to at least 1.5.
- def write(file_or_io, validate: true, update_fields: true, optimize: false)
+ def write(file_or_io, incremental: false, validate: true, update_fields: true, optimize: false)
dispatch_message(:complete_objects)
if update_fields
trailer.update_id
trailer.info[:ModDate] = Time.now
@@ -617,12 +625,12 @@
end
dispatch_message(:before_write)
if file_or_io.kind_of?(String)
- File.open(file_or_io, 'w+') {|file| Writer.write(self, file) }
+ File.open(file_or_io, 'w+') {|file| Writer.write(self, file, incremental: incremental) }
else
- Writer.write(self, file_or_io)
+ Writer.write(self, file_or_io, incremental: incremental)
end
end
end