hexapdf 0.11.3 → 0.11.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +51 -0
- data/lib/hexapdf/cli/image2pdf.rb +3 -3
- data/lib/hexapdf/document.rb +5 -0
- data/lib/hexapdf/document/pages.rb +4 -0
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +22 -5
- data/lib/hexapdf/font/true_type/table/hmtx.rb +15 -5
- data/lib/hexapdf/image_loader/png.rb +3 -3
- data/lib/hexapdf/layout/text_box.rb +8 -3
- data/lib/hexapdf/layout/text_layouter.rb +1 -0
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +10 -3
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +4 -4
- data/test/hexapdf/font/true_type/table/test_hmtx.rb +5 -5
- data/test/hexapdf/layout/test_text_box.rb +20 -2
- data/test/hexapdf/layout/test_text_layouter.rb +30 -11
- data/test/hexapdf/task/test_optimize.rb +24 -8
- data/test/hexapdf/test_serializer.rb +3 -3
- data/test/hexapdf/test_writer.rb +2 -2
- metadata +3 -7
- data/CONTRIBUTERS +0 -5
- data/VERSION +0 -1
- data/man/man1/hexapdf.1 +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: baa354ef4d01aa8a9348cfb584d9e255ee253c04b0f927ea16361c45ca904d46
         | 
| 4 | 
            +
              data.tar.gz: 2be95e4cd431bf772815ce4788f7ca25b132de2faec665bbdaf0982f73fea489
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 3e1bf0748678d022163457de1df628e080f7df261e5cb01ac09bae7f8560f05477f901a5e7b17c04111aea958458e0c0ff3c8d3beeda7119ddcd2913e906915b
         | 
| 7 | 
            +
              data.tar.gz: 792ebec34b3f1010ae53867b2e4cce93bb2b472f504606a87f0f8fe651d8cae94c8d4bb99b69e972e9813955a76d9401319dbbb01084b67ea352d210d2656b73
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,54 @@ | |
| 1 | 
            +
            ## 0.11.8 - 2020-06-11
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ### Fixed
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Serialization of special `/` (zero-length name) object in dictionaries and
         | 
| 6 | 
            +
              arrays
         | 
| 7 | 
            +
             | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## 0.11.7 - 2020-06-10
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ### Fixed
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * Deletion of object streams in [HexaPDF::Task::Optimize] to avoid accessing
         | 
| 14 | 
            +
              then invalid object streams
         | 
| 15 | 
            +
            * [HexaPDF::Task::Optimize] to work correctly when deleting object streams and
         | 
| 16 | 
            +
              generating xref streams
         | 
| 17 | 
            +
             | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## 0.11.6 - 2020-05-27
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Fixed
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            * [HexaPDF::Layout::TextBox] to respect the set width and height when fitting
         | 
| 24 | 
            +
              and splitting the box
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            ## 0.11.5 - 2020-01-27
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            ### Changed
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            * [HexaPDF::Font::TrueType::Table::CmapSubtable] to lazily parse the subtable
         | 
| 32 | 
            +
            * [HexaPDF::Font::TrueType::Table::Hmtx] to lazily parse the width data
         | 
| 33 | 
            +
            * CLI command `hexapdf image2pdf` to use the last argument as output file
         | 
| 34 | 
            +
              instead of the first (same order as `merge`)
         | 
| 35 | 
            +
            * Automatically require the HexaPDF C extension if it is installed
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            ### Fixed
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            * Wrong line length calculation for variable width layouting when a text box is
         | 
| 40 | 
            +
              too wide and needs to be broken into parts
         | 
| 41 | 
            +
            * CLI command `hexapdf image2pdf` so that treating a PDF as image works
         | 
| 42 | 
            +
             | 
| 43 | 
            +
             | 
| 44 | 
            +
            ## 0.11.4 - 2019-12-28
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            ### Fixed
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            * Memory consumption problem of PNG image loader when using images with alpha
         | 
| 49 | 
            +
              channel
         | 
| 50 | 
            +
             | 
| 51 | 
            +
             | 
| 1 52 | 
             
            ## 0.11.3 - 2019-11-27
         | 
| 2 53 |  | 
| 3 54 | 
             
            ### Fixed
         | 
| @@ -99,15 +99,15 @@ module HexaPDF | |
| 99 99 | 
             
                    @margins = [0, 0, 0, 0]
         | 
| 100 100 | 
             
                  end
         | 
| 101 101 |  | 
| 102 | 
            -
                  def execute( | 
| 102 | 
            +
                  def execute(*images, out_file) #:nodoc:
         | 
| 103 103 | 
             
                    maybe_raise_on_existing_file(out_file)
         | 
| 104 104 |  | 
| 105 105 | 
             
                    out = HexaPDF::Document.new
         | 
| 106 106 |  | 
| 107 107 | 
             
                    images.each do |image_file|
         | 
| 108 108 | 
             
                      image = out.images.add(image_file)
         | 
| 109 | 
            -
                      iw = image. | 
| 110 | 
            -
                      ih = image. | 
| 109 | 
            +
                      iw = image.width.to_f
         | 
| 110 | 
            +
                      ih = image.height.to_f
         | 
| 111 111 | 
             
                      if @scale != :fit
         | 
| 112 112 | 
             
                        iw *= 72 / @scale
         | 
| 113 113 | 
             
                        ih *= 72 / @scale
         | 
    
        data/lib/hexapdf/document.rb
    CHANGED
    
    | @@ -52,6 +52,11 @@ require 'hexapdf/image_loader' | |
| 52 52 | 
             
            require 'hexapdf/font_loader'
         | 
| 53 53 | 
             
            require 'hexapdf/layout'
         | 
| 54 54 |  | 
| 55 | 
            +
            begin
         | 
| 56 | 
            +
              require 'hexapdf/cext'
         | 
| 57 | 
            +
            rescue LoadError
         | 
| 58 | 
            +
            end
         | 
| 59 | 
            +
             | 
| 55 60 | 
             
            # == HexaPDF API Documentation
         | 
| 56 61 | 
             
            #
         | 
| 57 62 | 
             
            # Here are some pointers to more in depth information:
         | 
| @@ -107,6 +107,8 @@ module HexaPDF | |
| 107 107 | 
             
                  # Deletes the given page object from the document's page tree (but *not* from the document).
         | 
| 108 108 | 
             
                  #
         | 
| 109 109 | 
             
                  # Returns the page object, or +nil+ if the page object was not in the page tree.
         | 
| 110 | 
            +
                  #
         | 
| 111 | 
            +
                  # Also see: HexaPDF::Type::PageTreeNode#delete_page
         | 
| 110 112 | 
             
                  def delete(page)
         | 
| 111 113 | 
             
                    @document.catalog.pages.delete_page(page)
         | 
| 112 114 | 
             
                  end
         | 
| @@ -118,6 +120,8 @@ module HexaPDF | |
| 118 120 | 
             
                  # document).
         | 
| 119 121 | 
             
                  #
         | 
| 120 122 | 
             
                  # Returns the page object, or +nil+ if the index was invalid.
         | 
| 123 | 
            +
                  #
         | 
| 124 | 
            +
                  # Also see: HexaPDF::Type::PageTreeNode#delete_page
         | 
| 121 125 | 
             
                  def delete_at(index)
         | 
| 122 126 | 
             
                    @document.catalog.pages.delete_page(index)
         | 
| 123 127 | 
             
                  end
         | 
| @@ -73,9 +73,14 @@ module HexaPDF | |
| 73 73 | 
             
                      attr_accessor :language
         | 
| 74 74 |  | 
| 75 75 | 
             
                      # The complete code map.
         | 
| 76 | 
            +
                      #
         | 
| 77 | 
            +
                      # Is only fully initialized for existing fonts when a mapping is first accessed via #[].
         | 
| 76 78 | 
             
                      attr_accessor :code_map
         | 
| 77 79 |  | 
| 78 80 | 
             
                      # The complete gid map.
         | 
| 81 | 
            +
                      #
         | 
| 82 | 
            +
                      # Is only fully initialized for existing fonts when a mapping is first accessed via
         | 
| 83 | 
            +
                      # #gid_to_code.
         | 
| 79 84 | 
             
                      attr_accessor :gid_map
         | 
| 80 85 |  | 
| 81 86 | 
             
                      # Creates a new subtable.
         | 
| @@ -127,7 +132,22 @@ module HexaPDF | |
| 127 132 | 
             
                        elsif [0, 2, 4, 6].include?(@format)
         | 
| 128 133 | 
             
                          length, @language = io.read(4).unpack('n2')
         | 
| 129 134 | 
             
                        end
         | 
| 130 | 
            -
             | 
| 135 | 
            +
             | 
| 136 | 
            +
                        return false unless [0, 2, 4, 6, 10, 12].include?(@format)
         | 
| 137 | 
            +
                        offset = io.pos
         | 
| 138 | 
            +
                        @code_map = lambda do |code|
         | 
| 139 | 
            +
                          parse_mapping(io, offset, length)
         | 
| 140 | 
            +
                          @code_map[code]
         | 
| 141 | 
            +
                        end
         | 
| 142 | 
            +
                        @gid_map = lambda do |gid|
         | 
| 143 | 
            +
                          parse_mapping(io, offset, length)
         | 
| 144 | 
            +
                          @gid_map[gid]
         | 
| 145 | 
            +
                        end
         | 
| 146 | 
            +
                        true
         | 
| 147 | 
            +
                      end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                      def parse_mapping(io, offset, length)
         | 
| 150 | 
            +
                        io.pos = offset
         | 
| 131 151 | 
             
                        @code_map, @gid_map = case @format
         | 
| 132 152 | 
             
                                              when 0 then Format0.parse(io, length)
         | 
| 133 153 | 
             
                                              when 2 then Format2.parse(io, length)
         | 
| @@ -135,12 +155,9 @@ module HexaPDF | |
| 135 155 | 
             
                                              when 6 then Format6.parse(io, length)
         | 
| 136 156 | 
             
                                              when 10 then Format10.parse(io, length)
         | 
| 137 157 | 
             
                                              when 12 then Format12.parse(io, length)
         | 
| 138 | 
            -
                                              else
         | 
| 139 | 
            -
                                                supported = false
         | 
| 140 | 
            -
                                                [{}, {}]
         | 
| 141 158 | 
             
                                              end
         | 
| 142 | 
            -
                        supported
         | 
| 143 159 | 
             
                      end
         | 
| 160 | 
            +
                      private :parse_mapping
         | 
| 144 161 |  | 
| 145 162 | 
             
                      def inspect #:nodoc:
         | 
| 146 163 | 
             
                        "#<#{self.class.name} (#{platform_id}, #{encoding_id}, #{language}, " \
         | 
| @@ -51,7 +51,7 @@ module HexaPDF | |
| 51 51 | 
             
                      # the :left_side_bearing.
         | 
| 52 52 | 
             
                      Metric = Struct.new(:advance_width, :left_side_bearing)
         | 
| 53 53 |  | 
| 54 | 
            -
                      #  | 
| 54 | 
            +
                      # A hash of glyph ID to Metric objects mapping.
         | 
| 55 55 | 
             
                      attr_accessor :horizontal_metrics
         | 
| 56 56 |  | 
| 57 57 | 
             
                      # Returns the Metric object for the give glyph ID.
         | 
| @@ -63,10 +63,20 @@ module HexaPDF | |
| 63 63 |  | 
| 64 64 | 
             
                      def parse_table #:nodoc:
         | 
| 65 65 | 
             
                        nr_entries = font[:hhea].num_of_long_hor_metrics
         | 
| 66 | 
            -
                         | 
| 67 | 
            -
                         | 
| 68 | 
            -
             | 
| 69 | 
            -
                           | 
| 66 | 
            +
                        max_id = nr_entries + (directory_entry.length - 4 * nr_entries) / 2
         | 
| 67 | 
            +
                        @horizontal_metrics = Hash.new do |hash, glyph_id|
         | 
| 68 | 
            +
                          return nil if glyph_id >= max_id
         | 
| 69 | 
            +
                          if glyph_id >= nr_entries
         | 
| 70 | 
            +
                            with_io_pos(directory_entry.offset + 4 * nr_entries + (glyph_id - nr_entries) * 2) do
         | 
| 71 | 
            +
                              hash[glyph_id] = Metric.new(@horizontal_metrics[nr_entries - 1].advance_width,
         | 
| 72 | 
            +
                                                          *read_formatted(2, 's>'))
         | 
| 73 | 
            +
                            end
         | 
| 74 | 
            +
                          else
         | 
| 75 | 
            +
                            with_io_pos(directory_entry.offset + 4 * glyph_id) do
         | 
| 76 | 
            +
                              hash[glyph_id] = Metric.new(*read_formatted(4, 'ns>'))
         | 
| 77 | 
            +
                            end
         | 
| 78 | 
            +
                          end
         | 
| 79 | 
            +
                          hash[glyph_id]
         | 
| 70 80 | 
             
                        end
         | 
| 71 81 | 
             
                      end
         | 
| 72 82 |  | 
| @@ -361,12 +361,12 @@ module HexaPDF | |
| 361 361 | 
             
                        image_data << data.getbyte(0)
         | 
| 362 362 | 
             
                        mask_data << data.getbyte(0)
         | 
| 363 363 | 
             
                        while i < bytes_per_row
         | 
| 364 | 
            -
                          image_data << data. | 
| 364 | 
            +
                          bytes_per_colors.times {|j| image_data << data.getbyte(i + j) }
         | 
| 365 365 | 
             
                          i += bytes_per_colors
         | 
| 366 | 
            -
                          mask_data << data. | 
| 366 | 
            +
                          bytes_per_alpha.times {|j| mask_data << data.getbyte(i + j) }
         | 
| 367 367 | 
             
                          i += bytes_per_alpha
         | 
| 368 368 | 
             
                        end
         | 
| 369 | 
            -
                        data[ | 
| 369 | 
            +
                        data = data[bytes_per_row..-1]
         | 
| 370 370 | 
             
                      end
         | 
| 371 371 | 
             
                    end
         | 
| 372 372 |  | 
| @@ -64,6 +64,9 @@ module HexaPDF | |
| 64 64 | 
             
                  #
         | 
| 65 65 | 
             
                  # Also see TextLayouter#style for other style properties taken into account.
         | 
| 66 66 | 
             
                  def fit(available_width, available_height, frame)
         | 
| 67 | 
            +
                    return false if (@initial_width > 0 && @initial_width > available_width) ||
         | 
| 68 | 
            +
                      (@initial_height > 0 && @initial_height > available_height)
         | 
| 69 | 
            +
             | 
| 67 70 | 
             
                    @width = @height = 0
         | 
| 68 71 | 
             
                    @result = if style.position == :flow
         | 
| 69 72 | 
             
                                @tl.fit(@items, frame.width_specification, frame.contour_line.bbox.height)
         | 
| @@ -74,8 +77,8 @@ module HexaPDF | |
| 74 77 | 
             
                                height = (@initial_height > 0 ? @initial_height : available_height) - @height
         | 
| 75 78 | 
             
                                @tl.fit(@items, width, height)
         | 
| 76 79 | 
             
                              end
         | 
| 77 | 
            -
                    @width += @result.lines.max_by(&:width)&.width || 0
         | 
| 78 | 
            -
                    @height += @result.height
         | 
| 80 | 
            +
                    @width += (@initial_width > 0 ? width : @result.lines.max_by(&:width)&.width || 0)
         | 
| 81 | 
            +
                    @height += (@initial_height > 0 ? height : @result.height)
         | 
| 79 82 | 
             
                    if style.last_line_gap && @result.lines.last
         | 
| 80 83 | 
             
                      @height += style.line_spacing.gap(@result.lines.last, @result.lines.last)
         | 
| 81 84 | 
             
                    end
         | 
| @@ -86,7 +89,9 @@ module HexaPDF | |
| 86 89 | 
             
                  # Splits the text box into two boxes if necessary and possible.
         | 
| 87 90 | 
             
                  def split(available_width, available_height, frame)
         | 
| 88 91 | 
             
                    fit(available_width, available_height, frame) unless @result
         | 
| 89 | 
            -
                    if @ | 
| 92 | 
            +
                    if @width > available_width || @height > available_height
         | 
| 93 | 
            +
                      [nil, self]
         | 
| 94 | 
            +
                    elsif @result.remaining_items.empty?
         | 
| 90 95 | 
             
                      [self]
         | 
| 91 96 | 
             
                    elsif @result.lines.empty?
         | 
| 92 97 | 
             
                      [nil, self]
         | 
    
        data/lib/hexapdf/serializer.rb
    CHANGED
    
    
| @@ -127,13 +127,18 @@ module HexaPDF | |
| 127 127 | 
             
                    when :delete
         | 
| 128 128 | 
             
                      doc.revisions.each_with_index do |rev, rev_index|
         | 
| 129 129 | 
             
                        xref_stream = false
         | 
| 130 | 
            +
                        objects_to_delete = []
         | 
| 130 131 | 
             
                        rev.each do |obj|
         | 
| 131 | 
            -
                          if obj.type == :ObjStm | 
| 132 | 
            -
                             | 
| 132 | 
            +
                          if obj.type == :ObjStm
         | 
| 133 | 
            +
                            objects_to_delete << obj
         | 
| 134 | 
            +
                          elsif obj.type == :XRef
         | 
| 135 | 
            +
                            xref_stream = true
         | 
| 136 | 
            +
                            objects_to_delete << obj if xref_streams == :delete
         | 
| 133 137 | 
             
                          else
         | 
| 134 138 | 
             
                            delete_fields_with_defaults(obj)
         | 
| 135 139 | 
             
                          end
         | 
| 136 140 | 
             
                        end
         | 
| 141 | 
            +
                        objects_to_delete.each {|obj| rev.delete(obj) }
         | 
| 137 142 | 
             
                        if xref_streams == :generate && !xref_stream
         | 
| 138 143 | 
             
                          doc.add({Type: :XRef}, revision: rev_index)
         | 
| 139 144 | 
             
                        end
         | 
| @@ -143,11 +148,12 @@ module HexaPDF | |
| 143 148 | 
             
                        xref_stream = false
         | 
| 144 149 | 
             
                        count = 0
         | 
| 145 150 | 
             
                        objstms = [doc.wrap({Type: :ObjStm})]
         | 
| 151 | 
            +
                        old_objstms = []
         | 
| 146 152 | 
             
                        rev.each do |obj|
         | 
| 147 153 | 
             
                          if obj.type == :XRef
         | 
| 148 154 | 
             
                            xref_stream = true
         | 
| 149 155 | 
             
                          elsif obj.type == :ObjStm
         | 
| 150 | 
            -
                             | 
| 156 | 
            +
                            old_objstms << obj
         | 
| 151 157 | 
             
                          end
         | 
| 152 158 | 
             
                          delete_fields_with_defaults(obj)
         | 
| 153 159 |  | 
| @@ -160,6 +166,7 @@ module HexaPDF | |
| 160 166 | 
             
                            count = 0
         | 
| 161 167 | 
             
                          end
         | 
| 162 168 | 
             
                        end
         | 
| 169 | 
            +
                        old_objstms.each {|objstm| rev.delete(objstm) }
         | 
| 163 170 | 
             
                        objstms.each {|objstm| doc.add(objstm, revision: rev_index) }
         | 
| 164 171 | 
             
                        doc.add({Type: :XRef}, revision: rev_index) unless xref_stream
         | 
| 165 172 | 
             
                      end
         | 
    
        data/lib/hexapdf/version.rb
    CHANGED
    
    
| @@ -43,14 +43,14 @@ describe HexaPDF::Font::TrueType::Table::CmapSubtable do | |
| 43 43 |  | 
| 44 44 | 
             
                it "works for format 0" do
         | 
| 45 45 | 
             
                  t = table([0, 262, 0].pack('n3') + [255].pack('C*') + (0..254).to_a.pack('C*'))
         | 
| 46 | 
            +
                  assert_equal(0, t.gid_to_code(255))
         | 
| 47 | 
            +
                  assert_equal(234, t.gid_to_code(233))
         | 
| 48 | 
            +
             | 
| 46 49 | 
             
                  assert_equal(255, t[0])
         | 
| 47 50 | 
             
                  assert_equal(233, t[234])
         | 
| 48 51 | 
             
                  assert_nil(t[256])
         | 
| 49 52 |  | 
| 50 | 
            -
                   | 
| 51 | 
            -
                  assert_equal(234, t.gid_to_code(233))
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  assert_raises(HexaPDF::Error) { table([0, 20, 0].pack('n3') + "a" * 20) }
         | 
| 53 | 
            +
                  assert_raises(HexaPDF::Error) { table([0, 20, 0].pack('n3') + "a" * 20)[0] }
         | 
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 56 | 
             
                it "works for format 2" do
         | 
| @@ -5,7 +5,7 @@ require_relative 'common' | |
| 5 5 | 
             
            require 'hexapdf/font/true_type/table/hhea'
         | 
| 6 6 | 
             
            require 'hexapdf/font/true_type/table/hmtx'
         | 
| 7 7 |  | 
| 8 | 
            -
            describe HexaPDF::Font::TrueType::Table:: | 
| 8 | 
            +
            describe HexaPDF::Font::TrueType::Table::Hmtx do
         | 
| 9 9 | 
             
              before do
         | 
| 10 10 | 
             
                data = [1, -2, 3, -4, 5, -6].pack('ns>ns>s>2')
         | 
| 11 11 | 
             
                set_up_stub_true_type_font(data)
         | 
| @@ -17,14 +17,14 @@ describe HexaPDF::Font::TrueType::Table::Hhea do | |
| 17 17 | 
             
              describe "initialize" do
         | 
| 18 18 | 
             
                it "reads the data from the associated file" do
         | 
| 19 19 | 
             
                  table = create_table(:Hmtx)
         | 
| 20 | 
            -
                  assert_equal(1, table[0].advance_width)
         | 
| 21 | 
            -
                  assert_equal(-2, table[0].left_side_bearing)
         | 
| 22 | 
            -
                  assert_equal(3, table[1].advance_width)
         | 
| 23 | 
            -
                  assert_equal(-4, table[1].left_side_bearing)
         | 
| 24 20 | 
             
                  assert_equal(3, table[2].advance_width)
         | 
| 25 21 | 
             
                  assert_equal(5, table[2].left_side_bearing)
         | 
| 26 22 | 
             
                  assert_equal(3, table[3].advance_width)
         | 
| 27 23 | 
             
                  assert_equal(-6, table[3].left_side_bearing)
         | 
| 24 | 
            +
                  assert_equal(1, table[0].advance_width)
         | 
| 25 | 
            +
                  assert_equal(-2, table[0].left_side_bearing)
         | 
| 26 | 
            +
                  assert_equal(3, table[1].advance_width)
         | 
| 27 | 
            +
                  assert_equal(-4, table[1].left_side_bearing)
         | 
| 28 28 | 
             
                end
         | 
| 29 29 | 
             
              end
         | 
| 30 30 | 
             
            end
         | 
| @@ -31,11 +31,11 @@ describe HexaPDF::Layout::TextBox do | |
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 33 | 
             
                it "respects the set width and height" do
         | 
| 34 | 
            -
                  box = create_box([@inline_box] | 
| 34 | 
            +
                  box = create_box([@inline_box], width: 40, height: 50, style: {padding: 10})
         | 
| 35 35 | 
             
                  assert(box.fit(100, 100, @frame))
         | 
| 36 36 | 
             
                  assert_equal(40, box.width)
         | 
| 37 37 | 
             
                  assert_equal(50, box.height)
         | 
| 38 | 
            -
                  assert_equal([ | 
| 38 | 
            +
                  assert_equal([10], box.instance_variable_get(:@result).lines.map(&:width))
         | 
| 39 39 | 
             
                end
         | 
| 40 40 |  | 
| 41 41 | 
             
                it "fits into the frame's outline" do
         | 
| @@ -52,6 +52,16 @@ describe HexaPDF::Layout::TextBox do | |
| 52 52 | 
             
                  assert_equal(50, box.width)
         | 
| 53 53 | 
             
                  assert_equal(20, box.height)
         | 
| 54 54 | 
             
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                it "can't fit the text box if the set width is bigger than the available width" do
         | 
| 57 | 
            +
                  box = create_box([@inline_box], width: 101)
         | 
| 58 | 
            +
                  refute(box.fit(100, 100, @frame))
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                it "can't fit the text box if the set height is bigger than the available height" do
         | 
| 62 | 
            +
                  box = create_box([@inline_box], height: 101)
         | 
| 63 | 
            +
                  refute(box.fit(100, 100, @frame))
         | 
| 64 | 
            +
                end
         | 
| 55 65 | 
             
              end
         | 
| 56 66 |  | 
| 57 67 | 
             
              describe "split" do
         | 
| @@ -70,6 +80,14 @@ describe HexaPDF::Layout::TextBox do | |
| 70 80 | 
             
                  assert_equal([nil, box], box.split(5, 20, @frame))
         | 
| 71 81 | 
             
                end
         | 
| 72 82 |  | 
| 83 | 
            +
                it "works if the whole text box doesn't fits" do
         | 
| 84 | 
            +
                  box = create_box([@inline_box], width: 102)
         | 
| 85 | 
            +
                  assert_equal([nil, box], box.split(100, 100, @frame))
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  box = create_box([@inline_box], height: 102)
         | 
| 88 | 
            +
                  assert_equal([nil, box], box.split(100, 100, @frame))
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 73 91 | 
             
                it "splits the box if necessary" do
         | 
| 74 92 | 
             
                  box = create_box([@inline_box] * 10)
         | 
| 75 93 | 
             
                  boxes = box.split(50, 10, @frame)
         | 
| @@ -556,18 +556,37 @@ describe HexaPDF::Layout::TextLayouter do | |
| 556 556 | 
             
                  end
         | 
| 557 557 | 
             
                end
         | 
| 558 558 |  | 
| 559 | 
            -
                 | 
| 560 | 
            -
                   | 
| 561 | 
            -
             | 
| 562 | 
            -
             | 
| 563 | 
            -
                   | 
| 564 | 
            -
                  assert_equal(:success, result.status)
         | 
| 565 | 
            -
                  assert_equal(str.strip.length, result.lines.sum {|l| l.items.sum {|i| i.items.count } })
         | 
| 566 | 
            -
                  assert_equal(45, result.height)
         | 
| 559 | 
            +
                describe "breaks a text fragment into parts if it is wider than the available width" do
         | 
| 560 | 
            +
                  before do
         | 
| 561 | 
            +
                    @str = " This is averylongstring"
         | 
| 562 | 
            +
                    @frag = HexaPDF::Layout::TextFragment.create(@str, font: @font)
         | 
| 563 | 
            +
                  end
         | 
| 567 564 |  | 
| 568 | 
            -
                   | 
| 569 | 
            -
             | 
| 570 | 
            -
             | 
| 565 | 
            +
                  it "works with fixed width" do
         | 
| 566 | 
            +
                    result = @layouter.fit([@frag], 20, 100)
         | 
| 567 | 
            +
                    assert(result.remaining_items.empty?)
         | 
| 568 | 
            +
                    assert_equal(:success, result.status)
         | 
| 569 | 
            +
                    assert_equal(@str.delete(" ").length, result.lines.sum {|l| l.items.sum {|i| i.items.count } })
         | 
| 570 | 
            +
                    assert_equal(54, result.height)
         | 
| 571 | 
            +
             | 
| 572 | 
            +
                    result = @layouter.fit([@frag], 1, 100)
         | 
| 573 | 
            +
                    assert_equal(8, result.remaining_items.count)
         | 
| 574 | 
            +
                    assert_equal(:box_too_wide, result.status)
         | 
| 575 | 
            +
                  end
         | 
| 576 | 
            +
             | 
| 577 | 
            +
                  it "works with variable width" do
         | 
| 578 | 
            +
                    width_block = lambda do |height, line_height|
         | 
| 579 | 
            +
                      # 'averylongstring' would fit when only considering height but not height + line_height
         | 
| 580 | 
            +
                      if height + line_height < 15
         | 
| 581 | 
            +
                        63
         | 
| 582 | 
            +
                      else
         | 
| 583 | 
            +
                        10
         | 
| 584 | 
            +
                      end
         | 
| 585 | 
            +
                    end
         | 
| 586 | 
            +
                    result = @layouter.fit([@frag], width_block, 30)
         | 
| 587 | 
            +
                    assert_equal(:height, result.status)
         | 
| 588 | 
            +
                    assert_equal([26.95, 9.44, 7.77], result.lines.map {|l| l.width.round(3) })
         | 
| 589 | 
            +
                  end
         | 
| 571 590 | 
             
                end
         | 
| 572 591 |  | 
| 573 592 | 
             
                describe "horizontal alignment" do
         | 
| @@ -7,13 +7,15 @@ require 'hexapdf/task/optimize' | |
| 7 7 | 
             
            describe HexaPDF::Task::Optimize do
         | 
| 8 8 | 
             
              class TestType < HexaPDF::Dictionary
         | 
| 9 9 |  | 
| 10 | 
            +
                define_type :Test
         | 
| 10 11 | 
             
                define_field :Optional, type: Symbol, default: :Optional
         | 
| 11 12 |  | 
| 12 13 | 
             
              end
         | 
| 13 14 |  | 
| 14 15 | 
             
              before do
         | 
| 16 | 
            +
                HexaPDF::GlobalConfiguration['object.type_map'][:Test] = TestType
         | 
| 15 17 | 
             
                @doc = HexaPDF::Document.new
         | 
| 16 | 
            -
                @obj1 = @doc.add( | 
| 18 | 
            +
                @obj1 = @doc.add({Type: :Test, Optional: :Optional})
         | 
| 17 19 | 
             
                @doc.trailer[:Test] = @doc.wrap(@obj1)
         | 
| 18 20 | 
             
                @doc.revisions.add
         | 
| 19 21 | 
             
                @obj2 = @doc.add({Type: :UsedEntry})
         | 
| @@ -22,6 +24,10 @@ describe HexaPDF::Task::Optimize do | |
| 22 24 | 
             
                @obj1[:Test] = @doc.wrap(@obj4, type: TestType)
         | 
| 23 25 | 
             
              end
         | 
| 24 26 |  | 
| 27 | 
            +
              after do
         | 
| 28 | 
            +
                HexaPDF::GlobalConfiguration['object.type_map'].delete(:Test)
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 25 31 | 
             
              def assert_objstms_generated
         | 
| 26 32 | 
             
                assert(@doc.revisions.all? {|rev| rev.any? {|obj| obj.type == :ObjStm } })
         | 
| 27 33 | 
             
                assert(@doc.revisions.all? {|rev| rev.any? {|obj| obj.type == :XRef } })
         | 
| @@ -40,7 +46,7 @@ describe HexaPDF::Task::Optimize do | |
| 40 46 | 
             
              end
         | 
| 41 47 |  | 
| 42 48 | 
             
              def assert_default_deleted
         | 
| 43 | 
            -
                refute(@ | 
| 49 | 
            +
                refute(@doc.object(1).key?(:Optional))
         | 
| 44 50 | 
             
              end
         | 
| 45 51 |  | 
| 46 52 | 
             
              describe "compact" do
         | 
| @@ -84,21 +90,29 @@ describe HexaPDF::Task::Optimize do | |
| 84 90 | 
             
              end
         | 
| 85 91 |  | 
| 86 92 | 
             
              describe "object_streams" do
         | 
| 87 | 
            -
                 | 
| 93 | 
            +
                def reload_document_with_objstm_from_io
         | 
| 94 | 
            +
                  io = StringIO.new
         | 
| 88 95 | 
             
                  objstm = @doc.add({Type: :ObjStm})
         | 
| 89 | 
            -
                   | 
| 96 | 
            +
                  @doc.add({Type: :XRef})
         | 
| 97 | 
            +
                  objstm.add_object(@doc.add({Type: :Test}))
         | 
| 98 | 
            +
                  @doc.write(io)
         | 
| 99 | 
            +
                  io.rewind
         | 
| 100 | 
            +
                  @doc = HexaPDF::Document.new(io: io)
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                it "generates object streams" do
         | 
| 90 104 | 
             
                  210.times { @doc.add(5) }
         | 
| 105 | 
            +
                  objstm = @doc.add({Type: :ObjStm})
         | 
| 106 | 
            +
                  reload_document_with_objstm_from_io
         | 
| 91 107 | 
             
                  @doc.task(:optimize, object_streams: :generate)
         | 
| 92 108 | 
             
                  assert_objstms_generated
         | 
| 93 109 | 
             
                  assert_default_deleted
         | 
| 94 110 | 
             
                  assert_nil(@doc.object(objstm).value)
         | 
| 95 | 
            -
                   | 
| 96 | 
            -
                  assert([xref], @doc.revisions.current.find_all {|obj| obj.type == :XRef })
         | 
| 111 | 
            +
                  assert_equal(2, @doc.revisions.current.find_all {|obj| obj.type == :ObjStm }.size)
         | 
| 97 112 | 
             
                end
         | 
| 98 113 |  | 
| 99 114 | 
             
                it "deletes object and xref streams" do
         | 
| 100 | 
            -
                   | 
| 101 | 
            -
                  @doc.add({Type: :XRef})
         | 
| 115 | 
            +
                  reload_document_with_objstm_from_io
         | 
| 102 116 | 
             
                  @doc.task(:optimize, object_streams: :delete, xref_streams: :delete)
         | 
| 103 117 | 
             
                  assert_no_objstms
         | 
| 104 118 | 
             
                  assert_no_xrefstms
         | 
| @@ -107,9 +121,11 @@ describe HexaPDF::Task::Optimize do | |
| 107 121 |  | 
| 108 122 | 
             
                it "deletes object and generates xref streams" do
         | 
| 109 123 | 
             
                  @doc.add({Type: :ObjStm})
         | 
| 124 | 
            +
                  xref = @doc.add({Type: :XRef})
         | 
| 110 125 | 
             
                  @doc.task(:optimize, object_streams: :delete, xref_streams: :generate)
         | 
| 111 126 | 
             
                  assert_no_objstms
         | 
| 112 127 | 
             
                  assert_xrefstms_generated
         | 
| 128 | 
            +
                  assert_equal([xref], @doc.revisions.current.find_all {|obj| obj.type == :XRef })
         | 
| 113 129 | 
             
                  assert_default_deleted
         | 
| 114 130 | 
             
                end
         | 
| 115 131 | 
             
              end
         | 
| @@ -75,18 +75,18 @@ describe HexaPDF::Serializer do | |
| 75 75 | 
             
                assert_serialized('/lime#20Green', 'lime Green'.intern)
         | 
| 76 76 | 
             
                assert_serialized('/paired#28#29parentheses', 'paired()parentheses'.intern)
         | 
| 77 77 | 
             
                assert_serialized('/The_Key_of_F#23_Minor', 'The_Key_of_F#_Minor'.intern)
         | 
| 78 | 
            -
                assert_serialized('/', ''.intern)
         | 
| 78 | 
            +
                assert_serialized('/ ', ''.intern)
         | 
| 79 79 | 
             
                assert_serialized('/H#c3#b6#c3#9fgang', "Hößgang".intern)
         | 
| 80 80 | 
             
                assert_serialized('/H#e8lp', "H\xE8lp".force_encoding('BINARY').intern)
         | 
| 81 81 | 
             
              end
         | 
| 82 82 |  | 
| 83 83 | 
             
              it "serializes arrays" do
         | 
| 84 | 
            -
                assert_serialized("[-12 | 
| 84 | 
            +
                assert_serialized("[-12/  2.4321/Name true(345)true]", [-12, :"", 2.4321, :Name, true, '345', true])
         | 
| 85 85 | 
             
                assert_serialized("[]", [])
         | 
| 86 86 | 
             
              end
         | 
| 87 87 |  | 
| 88 88 | 
             
              it "serializes hashes" do
         | 
| 89 | 
            -
                assert_serialized("<</hallo 5/other true/name[5]>>", hallo: 5, other: true, name: [5])
         | 
| 89 | 
            +
                assert_serialized("<</hallo 5/  true/other true/name[5]>>", hallo: 5, "": true, other: true, name: [5])
         | 
| 90 90 | 
             
                assert_serialized("<<>>", {})
         | 
| 91 91 | 
             
              end
         | 
| 92 92 |  | 
    
        data/test/hexapdf/test_writer.rb
    CHANGED
    
    | @@ -40,7 +40,7 @@ describe HexaPDF::Writer do | |
| 40 40 | 
             
                  219
         | 
| 41 41 | 
             
                  %%EOF
         | 
| 42 42 | 
             
                  3 0 obj
         | 
| 43 | 
            -
                  <</Producer(HexaPDF version 0.11. | 
| 43 | 
            +
                  <</Producer(HexaPDF version 0.11.8)>>
         | 
| 44 44 | 
             
                  endobj
         | 
| 45 45 | 
             
                  xref
         | 
| 46 46 | 
             
                  3 1
         | 
| @@ -72,7 +72,7 @@ describe HexaPDF::Writer do | |
| 72 72 | 
             
                  141
         | 
| 73 73 | 
             
                  %%EOF
         | 
| 74 74 | 
             
                  6 0 obj
         | 
| 75 | 
            -
                  <</Producer(HexaPDF version 0.11. | 
| 75 | 
            +
                  <</Producer(HexaPDF version 0.11.8)>>
         | 
| 76 76 | 
             
                  endobj
         | 
| 77 77 | 
             
                  2 0 obj
         | 
| 78 78 | 
             
                  <</Length 10>>stream
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: hexapdf
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.11. | 
| 4 | 
            +
              version: 0.11.8
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Thomas Leitner
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2020-06-11 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: cmdparse
         | 
| @@ -102,11 +102,9 @@ extensions: [] | |
| 102 102 | 
             
            extra_rdoc_files: []
         | 
| 103 103 | 
             
            files:
         | 
| 104 104 | 
             
            - CHANGELOG.md
         | 
| 105 | 
            -
            - CONTRIBUTERS
         | 
| 106 105 | 
             
            - LICENSE
         | 
| 107 106 | 
             
            - README.md
         | 
| 108 107 | 
             
            - Rakefile
         | 
| 109 | 
            -
            - VERSION
         | 
| 110 108 | 
             
            - agpl-3.0.txt
         | 
| 111 109 | 
             
            - bin/hexapdf
         | 
| 112 110 | 
             
            - data/hexapdf/afm/Courier-Bold.afm
         | 
| @@ -401,7 +399,6 @@ files: | |
| 401 399 | 
             
            - lib/hexapdf/version.rb
         | 
| 402 400 | 
             
            - lib/hexapdf/writer.rb
         | 
| 403 401 | 
             
            - lib/hexapdf/xref_section.rb
         | 
| 404 | 
            -
            - man/man1/hexapdf.1
         | 
| 405 402 | 
             
            - test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz
         | 
| 406 403 | 
             
            - test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz
         | 
| 407 404 | 
             
            - test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz
         | 
| @@ -637,8 +634,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 637 634 | 
             
                - !ruby/object:Gem::Version
         | 
| 638 635 | 
             
                  version: '0'
         | 
| 639 636 | 
             
            requirements: []
         | 
| 640 | 
            -
             | 
| 641 | 
            -
            rubygems_version: 2.6.14.4
         | 
| 637 | 
            +
            rubygems_version: 3.0.3
         | 
| 642 638 | 
             
            signing_key: 
         | 
| 643 639 | 
             
            specification_version: 4
         | 
| 644 640 | 
             
            summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
         | 
    
        data/CONTRIBUTERS
    DELETED
    
    
    
        data/VERSION
    DELETED
    
    | @@ -1 +0,0 @@ | |
| 1 | 
            -
            0.11.3
         | 
    
        data/man/man1/hexapdf.1
    DELETED
    
    | 
            File without changes
         |