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
|