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 +4 -4
- data/CHANGELOG.md +50 -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/encryption/security_handler.rb +6 -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/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/encryption/test_security_handler.rb +4 -0
- 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 +2 -5
- 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
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f56bc512ed28de11d43f5b2eb662729086734dc3120e6c8e96b56eab89420da4
|
4
|
+
data.tar.gz: 4b9e75f7d533cc7b3c3a6e297d26ab0358dcaa4ac0f0a5346df3e95c90d9c173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3651a7ed4a7fb305c79a70b0c009441b0e3012188ce5e8baf8847107bce27793e0c48a577ae0bbc9ae3d6bece5356b86955b4deb2abd505d0b7a856053461ab3
|
7
|
+
data.tar.gz: 7cfd77439479567d81133e39243715dd05b3a3b31ccc64fd923ec7391ba745834977011e4618f1f9462cdcb2a682ed1b102c20474a4b3f5d7c69be438c6abd51
|
data/CHANGELOG.md
CHANGED
@@ -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(
|
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
|
@@ -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
|
-
|
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
|
|
@@ -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.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.
|
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
|
+
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:
|
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
|
data/CONTRIBUTERS
DELETED
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.11.4
|
data/man/man1/hexapdf.1
DELETED
File without changes
|