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