hexapdf 0.22.0 → 0.23.0
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/form.rb +26 -3
- data/lib/hexapdf/cli/inspect.rb +12 -3
- data/lib/hexapdf/cli/modify.rb +23 -3
- data/lib/hexapdf/composer.rb +24 -2
- data/lib/hexapdf/document/destinations.rb +396 -0
- data/lib/hexapdf/document.rb +38 -89
- data/lib/hexapdf/layout/frame.rb +8 -9
- data/lib/hexapdf/layout/style.rb +280 -7
- data/lib/hexapdf/layout/text_box.rb +10 -2
- data/lib/hexapdf/layout/text_layouter.rb +6 -1
- data/lib/hexapdf/revision.rb +8 -1
- data/lib/hexapdf/revisions.rb +151 -50
- data/lib/hexapdf/task/optimize.rb +21 -11
- data/lib/hexapdf/type/acro_form/text_field.rb +8 -0
- data/lib/hexapdf/type/catalog.rb +9 -1
- data/lib/hexapdf/type/names.rb +13 -0
- data/lib/hexapdf/type/xref_stream.rb +2 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +3 -1
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +15 -2
- data/test/hexapdf/document/test_destinations.rb +338 -0
- data/test/hexapdf/encryption/test_security_handler.rb +2 -2
- data/test/hexapdf/layout/test_frame.rb +15 -1
- data/test/hexapdf/layout/test_text_box.rb +16 -0
- data/test/hexapdf/layout/test_text_layouter.rb +7 -0
- data/test/hexapdf/task/test_optimize.rb +17 -4
- data/test/hexapdf/test_composer.rb +24 -1
- data/test/hexapdf/test_document.rb +30 -133
- data/test/hexapdf/test_parser.rb +1 -1
- data/test/hexapdf/test_revision.rb +14 -0
- data/test/hexapdf/test_revisions.rb +137 -29
- data/test/hexapdf/test_writer.rb +43 -14
- data/test/hexapdf/type/acro_form/test_text_field.rb +17 -0
- data/test/hexapdf/type/test_catalog.rb +8 -0
- data/test/hexapdf/type/test_names.rb +20 -0
- data/test/hexapdf/type/test_xref_stream.rb +2 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +11 -1
- metadata +5 -2
@@ -0,0 +1,338 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'hexapdf/document'
|
5
|
+
|
6
|
+
describe HexaPDF::Document::Destinations::Destination do
|
7
|
+
def destination(dest)
|
8
|
+
HexaPDF::Document::Destinations::Destination.new(dest)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can be asked whether the referenced page is in a remote document" do
|
12
|
+
assert(destination([5, :Fit]).remote?)
|
13
|
+
refute(destination([HexaPDF::Dictionary.new({}), :Fit]).remote?)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns the page object" do
|
17
|
+
assert_equal(:page, destination([:page, :Fit]).page)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "type :xyz" do
|
21
|
+
before do
|
22
|
+
@dest = destination([:page, :XYZ, :left, :top, :zoom])
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the type of the destination" do
|
26
|
+
assert_equal(:xyz, @dest.type)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns the argument left" do
|
30
|
+
assert_equal(:left, @dest.left)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns the argument top" do
|
34
|
+
assert_equal(:top, @dest.top)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns the argument zoom" do
|
38
|
+
assert_equal(:zoom, @dest.zoom)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an error if the bottom and right properties are accessed" do
|
42
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
43
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "type :fit_page" do
|
48
|
+
before do
|
49
|
+
@dest = destination([:page, :Fit])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns the type of the destination" do
|
53
|
+
assert_equal(:fit_page, @dest.type)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "raises an error if the top, left, bottom, right, zoom properties are accessed" do
|
57
|
+
assert_raises(HexaPDF::Error) { @dest.top }
|
58
|
+
assert_raises(HexaPDF::Error) { @dest.left }
|
59
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
60
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
61
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "type :fit_page_horizontal" do
|
66
|
+
before do
|
67
|
+
@dest = destination([:page, :FitH, :top])
|
68
|
+
end
|
69
|
+
|
70
|
+
it "returns the type of the destination" do
|
71
|
+
assert_equal(:fit_page_horizontal, @dest.type)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns the argument top" do
|
75
|
+
assert_equal(:top, @dest.top)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "raises an error if the left, bottom, right, zoom properties are accessed" do
|
79
|
+
assert_raises(HexaPDF::Error) { @dest.left }
|
80
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
81
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
82
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "type :fit_page_vertical" do
|
87
|
+
before do
|
88
|
+
@dest = destination([:page, :FitV, :left])
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns the type of the destination" do
|
92
|
+
assert_equal(:fit_page_vertical, @dest.type)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns the argument left" do
|
96
|
+
assert_equal(:left, @dest.left)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "raises an error if the top, bottom, right, zoom properties are accessed" do
|
100
|
+
assert_raises(HexaPDF::Error) { @dest.top }
|
101
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
102
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
103
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "type :fit_rectangle" do
|
108
|
+
before do
|
109
|
+
@dest = destination([:page, :FitR, :left, :bottom, :right, :top])
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns the type of the destination" do
|
113
|
+
assert_equal(:fit_rectangle, @dest.type)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns the argument left" do
|
117
|
+
assert_equal(:left, @dest.left)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns the argument top" do
|
121
|
+
assert_equal(:top, @dest.top)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "returns the argument right" do
|
125
|
+
assert_equal(:right, @dest.right)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "returns the argument bottom" do
|
129
|
+
assert_equal(:bottom, @dest.bottom)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "raises an error if the zoom property is accessed" do
|
133
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "type :fit_bounding_box" do
|
138
|
+
before do
|
139
|
+
@dest = destination([:page, :FitB])
|
140
|
+
end
|
141
|
+
|
142
|
+
it "returns the type of the destination" do
|
143
|
+
assert_equal(:fit_bounding_box, @dest.type)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "raises an error if the bottom and right properties are accessed" do
|
147
|
+
assert_raises(HexaPDF::Error) { @dest.left }
|
148
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
149
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
150
|
+
assert_raises(HexaPDF::Error) { @dest.top }
|
151
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "type :fit_bounding_box_horizontal" do
|
156
|
+
before do
|
157
|
+
@dest = destination([:page, :FitBH, :top])
|
158
|
+
end
|
159
|
+
|
160
|
+
it "returns the type of the destination" do
|
161
|
+
assert_equal(:fit_bounding_box_horizontal, @dest.type)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "returns the argument top" do
|
165
|
+
assert_equal(:top, @dest.top)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "raises an error if the left, bottom, right, zoom properties are accessed" do
|
169
|
+
assert_raises(HexaPDF::Error) { @dest.left }
|
170
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
171
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
172
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "type :fit_bounding_box_vertical::" do
|
177
|
+
before do
|
178
|
+
@dest = destination([:page, :FitBV, :left])
|
179
|
+
end
|
180
|
+
|
181
|
+
it "returns the type of the destination" do
|
182
|
+
assert_equal(:fit_bounding_box_vertical, @dest.type)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "returns the argument left" do
|
186
|
+
assert_equal(:left, @dest.left)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "raises an error if the left, bottom, right, zoom properties are accessed" do
|
190
|
+
assert_raises(HexaPDF::Error) { @dest.top }
|
191
|
+
assert_raises(HexaPDF::Error) { @dest.bottom }
|
192
|
+
assert_raises(HexaPDF::Error) { @dest.right }
|
193
|
+
assert_raises(HexaPDF::Error) { @dest.zoom }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe HexaPDF::Document::Destinations do
|
199
|
+
before do
|
200
|
+
@doc = HexaPDF::Document.new
|
201
|
+
@page = @doc.pages.add
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "create_xyz" do
|
205
|
+
it "creates the destination" do
|
206
|
+
dest = @doc.destinations.create_xyz(@page, left: 1, top: 2, zoom: 3)
|
207
|
+
assert_equal([@page, :XYZ, 1, 2, 3], dest)
|
208
|
+
end
|
209
|
+
|
210
|
+
it "creates the destination and registers it under the given name" do
|
211
|
+
dest = @doc.destinations.create_xyz(@page, name: 'xyz')
|
212
|
+
assert_equal([@page, :XYZ, nil, nil, nil], @doc.destinations[dest])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "create_fit_page" do
|
217
|
+
it "creates the destination" do
|
218
|
+
dest = @doc.destinations.create_fit_page( @page)
|
219
|
+
assert_equal([@page, :Fit], dest)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "creates the destination and registers it under the given name" do
|
223
|
+
dest = @doc.destinations.create_fit_page(@page, name: 'xyz')
|
224
|
+
assert_equal([@page, :Fit], @doc.destinations[dest])
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "create_fit_page_horizontal" do
|
229
|
+
it "creates the destination" do
|
230
|
+
dest = @doc.destinations.create_fit_page_horizontal(@page, top: 2)
|
231
|
+
assert_equal([@page, :FitH, 2], dest)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "creates the destination and registers it under the given name" do
|
235
|
+
dest = @doc.destinations.create_fit_page_horizontal(@page, name: 'xyz')
|
236
|
+
assert_equal([@page, :FitH, nil], @doc.destinations[dest])
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "create_fit_page_vertical" do
|
241
|
+
it "creates the destination" do
|
242
|
+
dest = @doc.destinations.create_fit_page_vertical(@page, left: 2)
|
243
|
+
assert_equal([@page, :FitV, 2], dest)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "creates the destination and registers it under the given name" do
|
247
|
+
dest = @doc.destinations.create_fit_page_vertical(@page, name: 'xyz')
|
248
|
+
assert_equal([@page, :FitV, nil], @doc.destinations[dest])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe "create_fit_rectangle" do
|
253
|
+
it "creates the destination" do
|
254
|
+
dest = @doc.destinations.create_fit_rectangle(@page, left: 1, bottom: 2, right: 3, top: 4)
|
255
|
+
assert_equal([@page, :FitR, 1, 2, 3, 4], dest)
|
256
|
+
end
|
257
|
+
|
258
|
+
it "creates the destination and registers it under the given name" do
|
259
|
+
dest = @doc.destinations.create_fit_rectangle(@page, name: 'xyz', left: 1, bottom: 2, right: 3, top: 4)
|
260
|
+
assert_equal([@page, :FitR, 1, 2, 3, 4], @doc.destinations[dest])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "create_fit_bounding_box" do
|
265
|
+
it "creates the destination" do
|
266
|
+
dest = @doc.destinations.create_fit_bounding_box(@page)
|
267
|
+
assert_equal([@page, :FitB], dest)
|
268
|
+
end
|
269
|
+
|
270
|
+
it "creates the destination and registers it under the given name" do
|
271
|
+
dest = @doc.destinations.create_fit_bounding_box(@page, name: 'xyz')
|
272
|
+
assert_equal([@page, :FitB], @doc.destinations[dest])
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "create_fit_bounding_box_horizontal" do
|
277
|
+
it "creates the destination" do
|
278
|
+
dest = @doc.destinations.create_fit_bounding_box_horizontal(@page, top: 2)
|
279
|
+
assert_equal([@page, :FitBH, 2], dest)
|
280
|
+
end
|
281
|
+
|
282
|
+
it "creates the destination and registers it under the given name" do
|
283
|
+
dest = @doc.destinations.create_fit_bounding_box_horizontal(@page, name: 'xyz')
|
284
|
+
assert_equal([@page, :FitBH, nil], @doc.destinations[dest])
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "create_fit_bounding_box_vertical" do
|
289
|
+
it "creates the destination" do
|
290
|
+
dest = @doc.destinations.create_fit_bounding_box_vertical(@page, left: 2)
|
291
|
+
assert_equal([@page, :FitBV, 2], dest)
|
292
|
+
end
|
293
|
+
|
294
|
+
it "creates the destination and registers it under the given name" do
|
295
|
+
dest = @doc.destinations.create_fit_bounding_box_vertical(@page, name: 'xyz')
|
296
|
+
assert_equal([@page, :FitBV, nil], @doc.destinations[dest])
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
it "adds a destination array to the destinations name tree and allows to retrieve it" do
|
301
|
+
@doc.destinations.add('abc', [:page, :Fit])
|
302
|
+
assert_equal([:page, :Fit], @doc.destinations['abc'])
|
303
|
+
end
|
304
|
+
|
305
|
+
it "deletes a named destination" do
|
306
|
+
@doc.destinations.add('abc', [:page, :Fit])
|
307
|
+
assert(@doc.destinations['abc'])
|
308
|
+
@doc.destinations.delete('abc')
|
309
|
+
refute(@doc.destinations['abc'])
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "each" do
|
313
|
+
before do
|
314
|
+
3.times {|i| @doc.destinations.add("abc#{i}", [:page, :Fit]) }
|
315
|
+
end
|
316
|
+
|
317
|
+
it "returns an enumerator if no block is given" do
|
318
|
+
enum = @doc.destinations.each
|
319
|
+
assert_equal('abc0', enum.next.first)
|
320
|
+
assert_equal('abc1', enum.next.first)
|
321
|
+
assert_equal('abc2', enum.next.first)
|
322
|
+
assert_raises(StopIteration) { enum.next }
|
323
|
+
end
|
324
|
+
|
325
|
+
it "iterates over all name-destination pairs in order" do
|
326
|
+
result = [
|
327
|
+
['abc0', :fit_page],
|
328
|
+
['abc1', :fit_page],
|
329
|
+
['abc2', :fit_page],
|
330
|
+
]
|
331
|
+
@doc.destinations.each do |name, dest|
|
332
|
+
exp_name, exp_type = result.shift
|
333
|
+
assert_equal(exp_name, name)
|
334
|
+
assert_equal(exp_type, dest.type)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
@@ -302,9 +302,9 @@ describe HexaPDF::Encryption::SecurityHandler do
|
|
302
302
|
@handler = TestHandler.new(@document)
|
303
303
|
|
304
304
|
assert_equal("Something",
|
305
|
-
@handler.decrypt(@document.revisions[0].trailer[:Encrypt])[:Key])
|
305
|
+
@handler.decrypt(@document.revisions.all[0].trailer[:Encrypt])[:Key])
|
306
306
|
assert_equal("Otherthing",
|
307
|
-
@handler.decrypt(@document.revisions[1].trailer[:Encrypt])[:Key])
|
307
|
+
@handler.decrypt(@document.revisions.all[1].trailer[:Encrypt])[:Key])
|
308
308
|
end
|
309
309
|
|
310
310
|
it "defers handling encryption to a Crypt filter is specified" do
|
@@ -196,8 +196,15 @@ describe HexaPDF::Layout::Frame do
|
|
196
196
|
[[[10, 10], [110, 10], [110, 60], [60, 60], [60, 110], [10, 110]]])
|
197
197
|
end
|
198
198
|
|
199
|
+
it "draws the box in the center" do
|
200
|
+
check_box({width: 50, height: 50, position: :float, position_hint: :center},
|
201
|
+
[35, 60],
|
202
|
+
[[[10, 10], [110, 10], [110, 110], [85, 110], [85, 60], [35, 60],
|
203
|
+
[35, 110], [10, 110]]])
|
204
|
+
end
|
205
|
+
|
199
206
|
describe "with margin" do
|
200
|
-
[:left, :right].each do |hint|
|
207
|
+
[:left, :center, :right].each do |hint|
|
201
208
|
it "ignores all margins if the box fills the whole frame, with position hint #{hint}" do
|
202
209
|
check_box({margin: 10, position: :float, position_hint: hint},
|
203
210
|
[10, 10], [])
|
@@ -219,6 +226,13 @@ describe HexaPDF::Layout::Frame do
|
|
219
226
|
[[[20, 10], [110, 10], [110, 110], [90, 110], [90, 50], [20, 50]]])
|
220
227
|
end
|
221
228
|
|
229
|
+
it "uses the left and the right margin if aligned center" do
|
230
|
+
check_box({width: 50, height: 50, margin: 10, position: :float, position_hint: :center},
|
231
|
+
[35, 60],
|
232
|
+
[[[10, 10], [110, 10], [110, 110], [95, 110], [95, 50], [25, 50],
|
233
|
+
[25, 110], [10, 110]]])
|
234
|
+
end
|
235
|
+
|
222
236
|
it "ignores the right, but not the left margin if aligned right to the frame border" do
|
223
237
|
check_box({width: 50, height: 50, margin: 10, position: :float, position_hint: :right},
|
224
238
|
[60, 60],
|
@@ -53,6 +53,22 @@ describe HexaPDF::Layout::TextBox do
|
|
53
53
|
assert_equal(20, box.height)
|
54
54
|
end
|
55
55
|
|
56
|
+
it "uses the whole available width when aligning to the center or right" do
|
57
|
+
[:center, :right].each do |align|
|
58
|
+
box = create_box([@inline_box], style: {align: align})
|
59
|
+
assert(box.fit(100, 100, @frame))
|
60
|
+
assert_equal(100, box.width)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "uses the whole available height when vertically aligning to the center or bottom" do
|
65
|
+
[:center, :bottom].each do |valign|
|
66
|
+
box = create_box([@inline_box], style: {valign: valign})
|
67
|
+
assert(box.fit(100, 100, @frame))
|
68
|
+
assert_equal(100, box.height)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
56
72
|
it "can't fit the text box if the set width is bigger than the available width" do
|
57
73
|
box = create_box([@inline_box], width: 101)
|
58
74
|
refute(box.fit(100, 100, @frame))
|
@@ -646,6 +646,13 @@ describe HexaPDF::Layout::TextLayouter do
|
|
646
646
|
assert_equal(100 - 20 * 2 + 20, result.lines[0].y_offset)
|
647
647
|
assert_equal(100, result.height)
|
648
648
|
end
|
649
|
+
|
650
|
+
it "doesn't vertically align when layouting in variable-width mode" do
|
651
|
+
@style.valign = :bottom
|
652
|
+
result = @layouter.fit(@items, proc { 40 }, 100)
|
653
|
+
assert_equal(result.lines[0].y_max, result.lines[0].y_offset)
|
654
|
+
assert_equal(40, result.height)
|
655
|
+
end
|
649
656
|
end
|
650
657
|
|
651
658
|
it "post-processes lines for justification if needed" do
|
@@ -52,7 +52,7 @@ describe HexaPDF::Task::Optimize do
|
|
52
52
|
describe "compact" do
|
53
53
|
it "compacts the document" do
|
54
54
|
@doc.task(:optimize, compact: true)
|
55
|
-
assert_equal(1, @doc.revisions.
|
55
|
+
assert_equal(1, @doc.revisions.count)
|
56
56
|
assert_equal(2, @doc.each(only_current: false).to_a.size)
|
57
57
|
refute_equal(@obj2, @doc.object(@obj2))
|
58
58
|
refute_equal(@obj3, @doc.object(@obj3))
|
@@ -81,8 +81,8 @@ describe HexaPDF::Task::Optimize do
|
|
81
81
|
end
|
82
82
|
|
83
83
|
it "compacts and deletes xref streams" do
|
84
|
-
@doc.add({Type: :XRef},
|
85
|
-
@doc.add({Type: :XRef},
|
84
|
+
@doc.revisions.all[0].add(@doc.wrap({Type: :XRef}, oid: @doc.revisions.next_oid))
|
85
|
+
@doc.revisions.all[1].add(@doc.wrap({Type: :XRef}, oid: @doc.revisions.next_oid))
|
86
86
|
@doc.task(:optimize, compact: true, xref_streams: :delete)
|
87
87
|
assert_no_xrefstms
|
88
88
|
assert_default_deleted
|
@@ -108,7 +108,9 @@ describe HexaPDF::Task::Optimize do
|
|
108
108
|
assert_objstms_generated
|
109
109
|
assert_default_deleted
|
110
110
|
assert_nil(@doc.object(objstm).value)
|
111
|
-
|
111
|
+
objstms = @doc.revisions.current.find_all {|obj| obj.type == :ObjStm }
|
112
|
+
assert_equal(2, objstms.size)
|
113
|
+
assert_equal(400, objstms[0].instance_variable_get(:@objects).size)
|
112
114
|
end
|
113
115
|
|
114
116
|
it "deletes object and xref streams" do
|
@@ -158,6 +160,17 @@ describe HexaPDF::Task::Optimize do
|
|
158
160
|
@doc.task(:optimize, compress_pages: true)
|
159
161
|
assert_equal("10 10 m\nq\nQ\nBI\n/Name 5 ID\ndataEI\n", page.contents)
|
160
162
|
end
|
163
|
+
|
164
|
+
it "uses parser.on_correctable_error to defer a decision regarding invalid operations" do
|
165
|
+
page = @doc.pages.add
|
166
|
+
page.contents = "10 20-30 m"
|
167
|
+
@doc.task(:optimize, compress_pages: true)
|
168
|
+
assert_equal("", page.contents)
|
169
|
+
|
170
|
+
@doc.config['parser.on_correctable_error'] = proc { true }
|
171
|
+
page.contents = "10 20-30 m"
|
172
|
+
assert_raises(HexaPDF::Error) { @doc.task(:optimize, compress_pages: true) }
|
173
|
+
end
|
161
174
|
end
|
162
175
|
|
163
176
|
describe "prune_page_resources" do
|
@@ -90,7 +90,7 @@ describe HexaPDF::Composer do
|
|
90
90
|
it "creates a new style if it does not exist based on the base argument" do
|
91
91
|
@composer.style(:base, font_size: 20)
|
92
92
|
assert_equal(20, @composer.style(:newstyle, subscript: true).font_size)
|
93
|
-
refute(
|
93
|
+
refute(@composer.style(:base).subscript)
|
94
94
|
assert_equal(10, @composer.style(:another_new, base: nil).font_size)
|
95
95
|
assert(@composer.style(:yet_another_new, base: :newstyle).subscript)
|
96
96
|
end
|
@@ -240,6 +240,13 @@ describe HexaPDF::Composer do
|
|
240
240
|
assert(box.style.subscript)
|
241
241
|
assert_same(@composer.document.images.add(image_path), box.image)
|
242
242
|
end
|
243
|
+
|
244
|
+
it "allows using a form XObject" do
|
245
|
+
form = @composer.document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 10, 10]})
|
246
|
+
@composer.image(form, width: 10)
|
247
|
+
assert_equal(796, @composer.y)
|
248
|
+
assert_equal(36, @composer.x)
|
249
|
+
end
|
243
250
|
end
|
244
251
|
|
245
252
|
describe "draw_box" do
|
@@ -318,4 +325,20 @@ describe HexaPDF::Composer do
|
|
318
325
|
end
|
319
326
|
end
|
320
327
|
end
|
328
|
+
|
329
|
+
describe "create_stamp" do
|
330
|
+
it "creates and returns a form XObject" do
|
331
|
+
stamp = @composer.create_stamp(10, 5)
|
332
|
+
assert_kind_of(HexaPDF::Type::Form, stamp)
|
333
|
+
assert_equal(10, stamp.width)
|
334
|
+
assert_equal(5, stamp.height)
|
335
|
+
end
|
336
|
+
|
337
|
+
it "allows using a block to draw on the canvas of the form XObject" do
|
338
|
+
stamp = @composer.create_stamp(10, 10) do |canvas|
|
339
|
+
canvas.line_width(5)
|
340
|
+
end
|
341
|
+
assert_equal("5 w\n", stamp.canvas.contents)
|
342
|
+
end
|
343
|
+
end
|
321
344
|
end
|