hexapdf 0.11.4 → 0.11.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0907516ec3eaf3e982a0380bab72ea8923ea18ed3213b426061572913c2c426e'
4
- data.tar.gz: 6541fdd61bfc2000a3bd77e8aa8ebf046e14c56a87d856bace5f89c586042f42
3
+ metadata.gz: f56bc512ed28de11d43f5b2eb662729086734dc3120e6c8e96b56eab89420da4
4
+ data.tar.gz: 4b9e75f7d533cc7b3c3a6e297d26ab0358dcaa4ac0f0a5346df3e95c90d9c173
5
5
  SHA512:
6
- metadata.gz: 76a46bb08612f035c0e1159c1644797ecb949933ea73451d4f2e3bb128f5db3fd240bb759ec750ab42469c378b3fc36ec8ff466a6c39682a166b606dca5e7ca1
7
- data.tar.gz: 1368b225b5d638c8cfc36057d983126746df3333e73f2b88d50238c51bdef095de275b9c872653b5c78a3009dbf60d71a7cd0ae7f9e231e6966c590e831de834
6
+ metadata.gz: 3651a7ed4a7fb305c79a70b0c009441b0e3012188ce5e8baf8847107bce27793e0c48a577ae0bbc9ae3d6bece5356b86955b4deb2abd505d0b7a856053461ab3
7
+ data.tar.gz: 7cfd77439479567d81133e39243715dd05b3a3b31ccc64fd923ec7391ba745834977011e4618f1f9462cdcb2a682ed1b102c20474a4b3f5d7c69be438c6abd51
@@ -1,3 +1,53 @@
1
+ ## 0.11.9 - 2020-06-15
2
+
3
+ ### Changed
4
+
5
+ * Encryption dictionaries to always be indirect objects
6
+
7
+
8
+ ## 0.11.8 - 2020-06-11
9
+
10
+ ### Fixed
11
+
12
+ * Serialization of special `/` (zero-length name) object in dictionaries and
13
+ arrays
14
+
15
+
16
+ ## 0.11.7 - 2020-06-10
17
+
18
+ ### Fixed
19
+
20
+ * Deletion of object streams in [HexaPDF::Task::Optimize] to avoid accessing
21
+ then invalid object streams
22
+ * [HexaPDF::Task::Optimize] to work correctly when deleting object streams and
23
+ generating xref streams
24
+
25
+
26
+ ## 0.11.6 - 2020-05-27
27
+
28
+ ### Fixed
29
+
30
+ * [HexaPDF::Layout::TextBox] to respect the set width and height when fitting
31
+ and splitting the box
32
+
33
+
34
+ ## 0.11.5 - 2020-01-27
35
+
36
+ ### Changed
37
+
38
+ * [HexaPDF::Font::TrueType::Table::CmapSubtable] to lazily parse the subtable
39
+ * [HexaPDF::Font::TrueType::Table::Hmtx] to lazily parse the width data
40
+ * CLI command `hexapdf image2pdf` to use the last argument as output file
41
+ instead of the first (same order as `merge`)
42
+ * Automatically require the HexaPDF C extension if it is installed
43
+
44
+ ### Fixed
45
+
46
+ * Wrong line length calculation for variable width layouting when a text box is
47
+ too wide and needs to be broken into parts
48
+ * CLI command `hexapdf image2pdf` so that treating a PDF as image works
49
+
50
+
1
51
  ## 0.11.4 - 2019-12-28
2
52
 
3
53
  ### Fixed
@@ -99,15 +99,15 @@ module HexaPDF
99
99
  @margins = [0, 0, 0, 0]
100
100
  end
101
101
 
102
- def execute(out_file, *images) #:nodoc:
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.info.width.to_f
110
- ih = image.info.height.to_f
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
@@ -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
@@ -59,6 +59,12 @@ module HexaPDF
59
59
  define_field :StrF, type: Symbol, default: :Identity, version: '1.5'
60
60
  define_field :EFF, type: Symbol, version: '1.6'
61
61
 
62
+ # Returns +true+ because some PDF readers stumble when encountering a non-indirect encryption
63
+ # dictionary.
64
+ def must_be_indirect?
65
+ true
66
+ end
67
+
62
68
  private
63
69
 
64
70
  # Ensures that the encryption dictionary's content is valid.
@@ -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
- supported = true
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
- # An array of Metric objects, one for each glyph in the font.
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
- @horizontal_metrics = Array.new(nr_entries) { Metric.new(*read_formatted(4, 'ns>')) }
67
- last_advance_width = @horizontal_metrics[-1].advance_width
68
- read_formatted(directory_entry.length - 4 * nr_entries, 's>*').map do |lsb|
69
- @horizontal_metrics << Metric.new(last_advance_width, lsb)
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
 
@@ -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 @result.remaining_items.empty?
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]
@@ -751,6 +751,7 @@ module HexaPDF
751
751
 
752
752
  while true
753
753
  too_wide_box = nil
754
+ line_height = 0
754
755
 
755
756
  rest = style.text_line_wrapping_algorithm.call(rest, width_block) do |line, item|
756
757
  # make sure empty lines broken by mandatory paragraph breaks are not empty
@@ -187,7 +187,7 @@ module HexaPDF
187
187
  begin
188
188
  str = obj.to_s.dup.force_encoding(Encoding::BINARY)
189
189
  str.gsub!(NAME_REGEXP, NAME_SUBSTS)
190
- "/#{str}"
190
+ str.empty? ? "/ " : "/#{str}"
191
191
  end
192
192
  end
193
193
 
@@ -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 || (obj.type == :XRef && xref_streams == :delete)
132
- rev.delete(obj)
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
- rev.delete(obj)
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
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.11.4'
40
+ VERSION = '0.11.9'
41
41
 
42
42
  end
@@ -13,6 +13,10 @@ describe HexaPDF::Encryption::EncryptionDictionary do
13
13
  @dict[:V] = 1
14
14
  end
15
15
 
16
+ it "must be an indirect object" do
17
+ assert(@dict.must_be_indirect?)
18
+ end
19
+
16
20
  it "validates the /V value" do
17
21
  @dict[:V] = 1
18
22
  assert(@dict.validate)
@@ -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
- assert_equal(0, t.gid_to_code(255))
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::Hhea do
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] * 5, width: 40, height: 50, style: {padding: 10})
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([20, 20, 10], box.instance_variable_get(:@result).lines.map(&:width))
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
- it "breaks a text fragment into parts if it is wider than the available width" do
560
- str = " Thisisaverylongstring"
561
- frag = HexaPDF::Layout::TextFragment.create(str, font: @font)
562
- result = @layouter.fit([frag], 20, 100)
563
- assert(result.remaining_items.empty?)
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
- result = @layouter.fit([frag], 1, 100)
569
- assert_equal(str.strip.length, result.remaining_items.count)
570
- assert_equal(:box_too_wide, result.status)
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(@doc.wrap({Optional: :Optional}, type: TestType))
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(@obj1.value.key?(:Optional))
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
- it "generates object streams" do
93
+ def reload_document_with_objstm_from_io
94
+ io = StringIO.new
88
95
  objstm = @doc.add({Type: :ObjStm})
89
- xref = @doc.add({Type: :XRef})
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
- assert(3, @doc.revisions.current.find_all {|obj| obj.type == :ObjStm }.size)
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
- @doc.add({Type: :ObjStm})
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 2.4321/Name true(345)true]", [-12, 2.4321, :Name, true, '345', true])
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
 
@@ -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.4)>>
43
+ <</Producer(HexaPDF version 0.11.9)>>
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.4)>>
75
+ <</Producer(HexaPDF version 0.11.9)>>
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
4
+ version: 0.11.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-28 00:00:00.000000000 Z
11
+ date: 2020-06-15 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
@@ -1,5 +0,0 @@
1
- Count Name
2
- ======= ====
3
- 1097 Thomas Leitner <t_leitner@gmx.at>
4
- 1 Stanislav (Stas) Katkov <sk@skylup.com>
5
- 1 Daniel Kraus <bovender@bovender.de>
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.11.4
File without changes