hexapdf 0.11.4 → 0.11.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0907516ec3eaf3e982a0380bab72ea8923ea18ed3213b426061572913c2c426e'
4
- data.tar.gz: 6541fdd61bfc2000a3bd77e8aa8ebf046e14c56a87d856bace5f89c586042f42
3
+ metadata.gz: 245de775fa069ad91f2fe9f5e72610df40211e8b15a92b376cdf217c63b877fe
4
+ data.tar.gz: 34891827479def7d0efd506c9cd62f10abced99b8e694e39bc0dd06b1fa88bfe
5
5
  SHA512:
6
- metadata.gz: 76a46bb08612f035c0e1159c1644797ecb949933ea73451d4f2e3bb128f5db3fd240bb759ec750ab42469c378b3fc36ec8ff466a6c39682a166b606dca5e7ca1
7
- data.tar.gz: 1368b225b5d638c8cfc36057d983126746df3333e73f2b88d50238c51bdef095de275b9c872653b5c78a3009dbf60d71a7cd0ae7f9e231e6966c590e831de834
6
+ metadata.gz: 0c8bedff161a8aa756d6ffc426c89554e82537198692250a78f0eaad36fa896767681bda681d43bdcd5237f3eba91d25679499bbbe56ff525a16813c06187636
7
+ data.tar.gz: 35f82390333d2110c7ccb3059c93914e7ab03bbcd986c0ca7da1d3425c5a2c619aa42513da15d218423917e01f696b7b4e156f00b1997007c9feb637ae921d20
@@ -1,3 +1,20 @@
1
+ ## 0.11.5 - 2020-01-27
2
+
3
+ ### Changed
4
+
5
+ * [HexaPDF::Font::TrueType::Table::CmapSubtable] to lazily parse the subtable
6
+ * [HexaPDF::Font::TrueType::Table::Hmtx] to lazily parse the width data
7
+ * CLI command `hexapdf image2pdf` to use the last argument as output file
8
+ instead of the first (same order as `merge`)
9
+ * Automatically require the HexaPDF C extension if it is installed
10
+
11
+ ### Fixed
12
+
13
+ * Wrong line length calculation for variable width layouting when a text box is
14
+ too wide and needs to be broken into parts
15
+ * CLI command `hexapdf image2pdf` so that treating a PDF as image works
16
+
17
+
1
18
  ## 0.11.4 - 2019-12-28
2
19
 
3
20
  ### Fixed
@@ -1,5 +1,5 @@
1
1
  Count Name
2
2
  ======= ====
3
- 1097 Thomas Leitner <t_leitner@gmx.at>
3
+ 1104 Thomas Leitner <t_leitner@gmx.at>
4
4
  1 Stanislav (Stas) Katkov <sk@skylup.com>
5
5
  1 Daniel Kraus <bovender@bovender.de>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.4
1
+ 0.11.5
@@ -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:
@@ -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
 
@@ -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
@@ -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.5'
41
41
 
42
42
  end
@@ -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
@@ -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
@@ -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.5)>>
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.5)>>
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.5
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-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -637,7 +637,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
637
637
  - !ruby/object:Gem::Version
638
638
  version: '0'
639
639
  requirements: []
640
- rubygems_version: 3.0.3
640
+ rubygems_version: 3.1.2
641
641
  signing_key:
642
642
  specification_version: 4
643
643
  summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby