hexapdf 0.44.0 → 0.46.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 +106 -47
- data/examples/019-acro_form.rb +5 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +12 -11
- data/lib/hexapdf/cli/inspect.rb +5 -0
- data/lib/hexapdf/composer.rb +23 -1
- data/lib/hexapdf/configuration.rb +8 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -0
- data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
- data/lib/hexapdf/document/layout.rb +63 -30
- data/lib/hexapdf/document.rb +24 -2
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/importer.rb +15 -5
- data/lib/hexapdf/layout/box.rb +48 -36
- data/lib/hexapdf/layout/column_box.rb +3 -11
- data/lib/hexapdf/layout/container_box.rb +4 -4
- data/lib/hexapdf/layout/frame.rb +7 -6
- data/lib/hexapdf/layout/inline_box.rb +17 -23
- data/lib/hexapdf/layout/list_box.rb +27 -42
- data/lib/hexapdf/layout/page_style.rb +23 -16
- data/lib/hexapdf/layout/style.rb +5 -5
- data/lib/hexapdf/layout/table_box.rb +14 -10
- data/lib/hexapdf/layout/text_box.rb +60 -36
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -1
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/stream.rb +3 -3
- data/lib/hexapdf/tokenizer.rb +3 -2
- data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/field.rb +8 -0
- data/lib/hexapdf/type/acro_form/form.rb +2 -1
- data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- data/test/hexapdf/digital_signature/common.rb +66 -84
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
- data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
- data/test/hexapdf/digital_signature/test_handler.rb +2 -1
- data/test/hexapdf/document/test_layout.rb +44 -5
- data/test/hexapdf/layout/test_box.rb +23 -5
- data/test/hexapdf/layout/test_frame.rb +21 -2
- data/test/hexapdf/layout/test_inline_box.rb +17 -28
- data/test/hexapdf/layout/test_list_box.rb +8 -8
- data/test/hexapdf/layout/test_page_style.rb +7 -2
- data/test/hexapdf/layout/test_table_box.rb +8 -1
- data/test/hexapdf/layout/test_text_box.rb +51 -29
- data/test/hexapdf/layout/test_text_layouter.rb +0 -3
- data/test/hexapdf/test_composer.rb +14 -5
- data/test/hexapdf/test_document.rb +27 -0
- data/test/hexapdf/test_importer.rb +17 -0
- data/test/hexapdf/test_revisions.rb +54 -41
- data/test/hexapdf/test_serializer.rb +1 -0
- data/test/hexapdf/type/acro_form/test_form.rb +9 -0
- metadata +2 -2
@@ -65,13 +65,13 @@ describe HexaPDF::Layout::ListBox do
|
|
65
65
|
describe "fit" do
|
66
66
|
[:default, :flow].each do |position|
|
67
67
|
it "respects the set initial width, position #{position}" do
|
68
|
-
box = create_box(children: @text_boxes[0, 2], width:
|
69
|
-
check_box(box,
|
68
|
+
box = create_box(children: @text_boxes[0, 2], width: 55, style: {position: position})
|
69
|
+
check_box(box, 55, 80)
|
70
70
|
end
|
71
71
|
|
72
72
|
it "respects the set initial height, position #{position}" do
|
73
|
-
box = create_box(children: @text_boxes[0, 2], height:
|
74
|
-
check_box(box, 100,
|
73
|
+
box = create_box(children: @text_boxes[0, 2], height: 55, style: {position: position})
|
74
|
+
check_box(box, 100, 55)
|
75
75
|
end
|
76
76
|
|
77
77
|
it "respects the set initial height even when it doesn't fit completely" do
|
@@ -123,7 +123,7 @@ describe HexaPDF::Layout::ListBox do
|
|
123
123
|
|
124
124
|
it "fails if not even a part of the first list item fits" do
|
125
125
|
box = create_box(children: @text_boxes[0, 2], height: 5)
|
126
|
-
check_box(box, 100,
|
126
|
+
check_box(box, 100, 5, status: :failure)
|
127
127
|
end
|
128
128
|
|
129
129
|
it "fails for unknown marker types" do
|
@@ -134,13 +134,13 @@ describe HexaPDF::Layout::ListBox do
|
|
134
134
|
|
135
135
|
describe "split" do
|
136
136
|
it "splits before a list item if no part of it will fit" do
|
137
|
-
box = create_box(children: @text_boxes[0,
|
138
|
-
assert(box.fit(100,
|
137
|
+
box = create_box(children: @text_boxes[0, 3])
|
138
|
+
assert(box.fit(100, 22, @frame).overflow?)
|
139
139
|
box_a, box_b = box.split
|
140
140
|
assert_same(box, box_a)
|
141
141
|
assert_equal(:show_first_marker, box_b.split_box?)
|
142
142
|
assert_equal(1, box_a.instance_variable_get(:@results)[0].box_fitter.fit_results.size)
|
143
|
-
assert_equal(
|
143
|
+
assert_equal(2, box_b.children.size)
|
144
144
|
assert_equal(2, box_b.start_number)
|
145
145
|
end
|
146
146
|
|
@@ -44,8 +44,13 @@ describe HexaPDF::Layout::PageStyle do
|
|
44
44
|
|
45
45
|
it "works when no template is set" do
|
46
46
|
style = HexaPDF::Layout::PageStyle.new
|
47
|
-
|
48
|
-
|
47
|
+
page1 = style.create_page(@doc)
|
48
|
+
frame1 = style.frame
|
49
|
+
assert_equal("", page1.contents)
|
50
|
+
assert_equal(523.275591, style.frame.width)
|
51
|
+
|
52
|
+
page2 = style.create_page(@doc)
|
53
|
+
refute_same(frame1, style.frame)
|
49
54
|
end
|
50
55
|
|
51
56
|
it "creates a default frame if none is set beforehand or during template execution" do
|
@@ -116,7 +116,14 @@ describe HexaPDF::Layout::TableBox::Cell do
|
|
116
116
|
assert_equal(12, cell.preferred_height)
|
117
117
|
end
|
118
118
|
|
119
|
-
it "doesn't fit
|
119
|
+
it "doesn't fit children that are too big" do
|
120
|
+
cell = create_cell(children: HexaPDF::Layout::Box.create(width: 300, height: 20))
|
121
|
+
assert(cell.fit(100, 100, @frame).failure?)
|
122
|
+
cell = create_cell(children: [HexaPDF::Layout::Box.create(width: 300, height: 20)])
|
123
|
+
assert(cell.fit(100, 100, @frame).failure?)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "doesn't fit anything if the available width or height are too small even if there are no children" do
|
120
127
|
cell = create_cell(children: nil)
|
121
128
|
assert(cell.fit(10, 100, @frame).failure?)
|
122
129
|
assert(cell.fit(100, 10, @frame).failure?)
|
@@ -42,31 +42,32 @@ describe HexaPDF::Layout::TextBox do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it "respects the set width and height" do
|
45
|
-
box = create_box([@inline_box], width:
|
45
|
+
box = create_box([@inline_box] * 5, width: 44, height: 50,
|
46
|
+
style: {padding: 10, text_align: :right, text_valign: :bottom})
|
46
47
|
assert(box.fit(100, 100, @frame).success?)
|
47
|
-
assert_equal(
|
48
|
+
assert_equal(44, box.width)
|
48
49
|
assert_equal(50, box.height)
|
49
|
-
assert_equal([10], box.instance_variable_get(:@result).lines.map(&:width))
|
50
|
+
assert_equal([20, 20, 10], box.instance_variable_get(:@result).lines.map(&:width))
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
53
|
+
describe "style option last_line_gap" do
|
54
|
+
it "is taken into account" do
|
55
|
+
box = create_box([@inline_box] * 5, style: {last_line_gap: true, line_spacing: :double})
|
56
|
+
assert(box.fit(100, 100, @frame).success?)
|
57
|
+
assert_equal(50, box.width)
|
58
|
+
assert_equal(20, box.height)
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
it "will have no effect for fixed-height boxes" do
|
62
|
+
box = create_box([@inline_box] * 5, height: 40, style: {last_line_gap: true, line_spacing: :double})
|
63
|
+
assert(box.fit(100, 100, @frame).success?)
|
64
|
+
assert_equal(50, box.width)
|
65
|
+
assert_equal(40, box.height)
|
66
|
+
end
|
66
67
|
end
|
67
68
|
|
68
|
-
it "uses the whole available width when aligning to the center or
|
69
|
-
[:center, :right].each do |align|
|
69
|
+
it "uses the whole available width when aligning to the center, right or justified" do
|
70
|
+
[:center, :right, :justify].each do |align|
|
70
71
|
box = create_box([@inline_box], style: {text_align: align})
|
71
72
|
assert(box.fit(100, 100, @frame).success?)
|
72
73
|
assert_equal(100, box.width)
|
@@ -103,6 +104,33 @@ describe HexaPDF::Layout::TextBox do
|
|
103
104
|
assert(box.fit(100, 100, @frame).success?)
|
104
105
|
end
|
105
106
|
|
107
|
+
describe "position :flow" do
|
108
|
+
it "fits into the frame's outline" do
|
109
|
+
@frame.remove_area(Geom2D::Rectangle(0, 80, 20, 20))
|
110
|
+
@frame.remove_area(Geom2D::Rectangle(80, 70, 20, 20))
|
111
|
+
box = create_box([@inline_box] * 20, style: {position: :flow})
|
112
|
+
assert(box.fit(100, 100, @frame).success?)
|
113
|
+
assert_equal(100, box.width)
|
114
|
+
assert_equal(30, box.height)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "respects a set initial height" do
|
118
|
+
box = create_box([@inline_box] * 20, height: 13, style: {position: :flow})
|
119
|
+
assert(box.fit(100, 100, @frame).overflow?)
|
120
|
+
assert_equal(100, box.width)
|
121
|
+
assert_equal(13, box.height)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "respects top/bottom padding/border" do
|
125
|
+
@frame.remove_area(Geom2D::Rectangle(0, 80, 20, 20))
|
126
|
+
box = create_box([@inline_box] * 20, style: {position: :flow, padding: 10, border: {width: 2}})
|
127
|
+
assert(box.fit(100, 100, @frame).success?)
|
128
|
+
assert_equal(124, box.width)
|
129
|
+
assert_equal(54, box.height)
|
130
|
+
assert_equal([80, 100, 20], box.instance_variable_get(:@result).lines.map(&:width))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
106
134
|
it "fails if no item of the text box fits due to the width" do
|
107
135
|
box = create_box([@inline_box])
|
108
136
|
assert(box.fit(5, 20, @frame).failure?)
|
@@ -150,15 +178,12 @@ describe HexaPDF::Layout::TextBox do
|
|
150
178
|
assert_operators(@canvas.contents, [[:save_graphics_state],
|
151
179
|
[:restore_graphics_state],
|
152
180
|
[:save_graphics_state],
|
153
|
-
[:
|
154
|
-
[:save_graphics_state],
|
155
|
-
[:append_rectangle, [0, 0, 10, 10]],
|
181
|
+
[:append_rectangle, [5, 10, 10, 10]],
|
156
182
|
[:clip_path_non_zero],
|
157
183
|
[:end_path],
|
158
|
-
[:append_rectangle, [
|
184
|
+
[:append_rectangle, [5.5, 10.5, 9.0, 9.0]],
|
159
185
|
[:stroke_path],
|
160
186
|
[:restore_graphics_state],
|
161
|
-
[:restore_graphics_state],
|
162
187
|
[:save_graphics_state],
|
163
188
|
[:restore_graphics_state]])
|
164
189
|
end
|
@@ -167,21 +192,18 @@ describe HexaPDF::Layout::TextBox do
|
|
167
192
|
@frame.remove_area(Geom2D::Rectangle(0, 0, 40, 100))
|
168
193
|
box = create_box([@inline_box], style: {position: :flow, border: {width: 1}})
|
169
194
|
box.fit(60, 100, @frame)
|
170
|
-
box.draw(@canvas,
|
195
|
+
box.draw(@canvas, 40, 88)
|
171
196
|
assert_operators(@canvas.contents, [[:save_graphics_state],
|
172
|
-
[:append_rectangle, [40,
|
197
|
+
[:append_rectangle, [40, 88, 12, 12]],
|
173
198
|
[:clip_path_non_zero],
|
174
199
|
[:end_path],
|
175
|
-
[:append_rectangle, [40.5,
|
200
|
+
[:append_rectangle, [40.5, 88.5, 11.0, 11.0]],
|
176
201
|
[:stroke_path],
|
177
202
|
[:restore_graphics_state],
|
178
203
|
[:save_graphics_state],
|
179
204
|
[:restore_graphics_state],
|
180
205
|
[:save_graphics_state],
|
181
206
|
[:concatenate_matrix, [1, 0, 0, 1, 41, 89]],
|
182
|
-
[:save_graphics_state],
|
183
|
-
[:concatenate_matrix, [1, 0, 0, 1, 0, 0]],
|
184
|
-
[:restore_graphics_state],
|
185
207
|
[:restore_graphics_state],
|
186
208
|
[:save_graphics_state],
|
187
209
|
[:restore_graphics_state]])
|
@@ -812,11 +812,8 @@ describe HexaPDF::Layout::TextLayouter do
|
|
812
812
|
[:restore_graphics_state],
|
813
813
|
[:save_graphics_state],
|
814
814
|
[:concatenate_matrix, [1, 0, 0, 1, 10, -40]],
|
815
|
-
[:save_graphics_state],
|
816
|
-
[:concatenate_matrix, [1, 0, 0, 1, 0, 0]],
|
817
815
|
[:set_line_width, [2]],
|
818
816
|
[:restore_graphics_state],
|
819
|
-
[:restore_graphics_state],
|
820
817
|
[:save_graphics_state],
|
821
818
|
[:restore_graphics_state]])
|
822
819
|
end
|
@@ -119,6 +119,13 @@ describe HexaPDF::Composer do
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
describe "styles" do
|
123
|
+
it "delegates to layout.styles" do
|
124
|
+
@composer.styles(base: {font_size: 30}, other: {font_size: 40})
|
125
|
+
assert_equal([:base, :other], @composer.document.layout.styles.keys)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
122
129
|
describe "page_style" do
|
123
130
|
it "returns the page style if no argument or block is given" do
|
124
131
|
page_style = @composer.page_style(:default)
|
@@ -225,8 +232,9 @@ describe HexaPDF::Composer do
|
|
225
232
|
first_page_contents = @composer.canvas.contents
|
226
233
|
@composer.draw_box(create_box(height: 400))
|
227
234
|
|
228
|
-
box = create_box
|
229
|
-
box.define_singleton_method(:
|
235
|
+
box = create_box
|
236
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
237
|
+
box.define_singleton_method(:split_content) do |*|
|
230
238
|
[box, HexaPDF::Layout::Box.new(height: 100) {}]
|
231
239
|
end
|
232
240
|
@composer.draw_box(box)
|
@@ -235,7 +243,7 @@ describe HexaPDF::Composer do
|
|
235
243
|
[:concatenate_matrix, [1, 0, 0, 1, 36, 405.889764]],
|
236
244
|
[:restore_graphics_state],
|
237
245
|
[:save_graphics_state],
|
238
|
-
[:concatenate_matrix, [1, 0, 0, 1, 36,
|
246
|
+
[:concatenate_matrix, [1, 0, 0, 1, 36, 36]],
|
239
247
|
[:restore_graphics_state]])
|
240
248
|
assert_operators(@composer.canvas.contents,
|
241
249
|
[[:save_graphics_state],
|
@@ -273,9 +281,10 @@ describe HexaPDF::Composer do
|
|
273
281
|
box = create_box(height: 400)
|
274
282
|
assert_same(box, @composer.draw_box(box))
|
275
283
|
|
276
|
-
box = create_box(height: 400)
|
277
284
|
split_box = create_box(height: 100)
|
278
|
-
box
|
285
|
+
box = create_box
|
286
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
287
|
+
box.define_singleton_method(:split_content) {|*| [box, split_box] }
|
279
288
|
assert_same(split_box, @composer.draw_box(box))
|
280
289
|
end
|
281
290
|
|
@@ -568,4 +568,31 @@ describe HexaPDF::Document do
|
|
568
568
|
it "can be inspected and the output is not too large" do
|
569
569
|
assert_match(/HexaPDF::Document:\d+/, @doc.inspect)
|
570
570
|
end
|
571
|
+
|
572
|
+
describe "duplicate" do
|
573
|
+
it "creates an in-memory copy" do
|
574
|
+
doc = HexaPDF::Document.new
|
575
|
+
doc.pages.add.canvas.line_width(10)
|
576
|
+
doc.trailer.info[:Author] = 'HexaPDF'
|
577
|
+
doc.dispatch_message(:complete_objects)
|
578
|
+
|
579
|
+
dupped = doc.duplicate
|
580
|
+
assert_equal('HexaPDF', dupped.trailer.info[:Author])
|
581
|
+
doc.pages[0].canvas.line_cap_style(:round)
|
582
|
+
assert_equal("10 w\n", dupped.pages[0].contents)
|
583
|
+
end
|
584
|
+
|
585
|
+
it "doesn't copy the encryption state" do
|
586
|
+
doc = HexaPDF::Document.new
|
587
|
+
doc.pages.add.canvas.line_width(10)
|
588
|
+
doc.encrypt
|
589
|
+
io = StringIO.new
|
590
|
+
doc.write(io)
|
591
|
+
|
592
|
+
doc = HexaPDF::Document.new(io: io)
|
593
|
+
dupped = doc.duplicate
|
594
|
+
assert_equal("10 w\n", dupped.pages[0].contents)
|
595
|
+
refute(dupped.encrypted?)
|
596
|
+
end
|
597
|
+
end
|
571
598
|
end
|
@@ -47,6 +47,13 @@ describe HexaPDF::Importer do
|
|
47
47
|
refute_same(obj1, obj2)
|
48
48
|
refute_same(obj1[:ref], obj2[:ref])
|
49
49
|
end
|
50
|
+
|
51
|
+
it "duplicates the whole document" do
|
52
|
+
trailer = HexaPDF::Importer.copy(@dest, @source.trailer, allow_all: true)
|
53
|
+
refute_same(@source.catalog, trailer[:Root])
|
54
|
+
refute_same(@source.pages.root, trailer[:Root][:Pages])
|
55
|
+
assert_equal(90, trailer[:Root][:Pages][:Kids][0][:Rotate])
|
56
|
+
end
|
50
57
|
end
|
51
58
|
|
52
59
|
describe "import" do
|
@@ -121,6 +128,16 @@ describe HexaPDF::Importer do
|
|
121
128
|
refute_same(dst_obj.data.stream, src_obj.data.stream)
|
122
129
|
end
|
123
130
|
|
131
|
+
it "duplicates the stream if it is a FiberDoubleForString, e.g. when using Canvas" do
|
132
|
+
src_page = @source.pages[0]
|
133
|
+
src_page.canvas.line_width(10)
|
134
|
+
dst_page = @importer.import(src_page)
|
135
|
+
refute_same(dst_page, src_page)
|
136
|
+
refute_same(dst_page[:Contents].data.stream, src_page[:Contents].data.stream)
|
137
|
+
src_page.canvas.line_width(20)
|
138
|
+
assert_equal("10 w\n", dst_page.contents)
|
139
|
+
end
|
140
|
+
|
124
141
|
it "does not import objects of type Catalog or Pages" do
|
125
142
|
@obj[:catalog] = @source.catalog
|
126
143
|
@obj[:pages] = @source.catalog.pages
|
@@ -357,46 +357,59 @@ describe HexaPDF::Revisions do
|
|
357
357
|
end
|
358
358
|
end
|
359
359
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
360
|
+
describe "linearzied PDFs" do
|
361
|
+
before do
|
362
|
+
@io = StringIO.new(<<~EOF)
|
363
|
+
%PDF-1.2
|
364
|
+
5 0 obj
|
365
|
+
<</Linearized 1>>
|
366
|
+
endobj
|
367
|
+
xref
|
368
|
+
5 1
|
369
|
+
0000000009 00000 n
|
370
|
+
trailer
|
371
|
+
<</ID[(a)(b)]/Info 1 0 R/Root 2 0 R/Size 6/Prev 394>>
|
372
|
+
%
|
373
|
+
1 0 obj
|
374
|
+
<</ModDate(D:20221205233910+01'00')/Producer(HexaPDF version 0.27.0)>>
|
375
|
+
endobj
|
376
|
+
2 0 obj
|
377
|
+
<</Type/Catalog/Pages 3 0 R>>
|
378
|
+
endobj
|
379
|
+
3 0 obj
|
380
|
+
<</Type/Pages/Kids[4 0 R]/Count 1>>
|
381
|
+
endobj
|
382
|
+
4 0 obj
|
383
|
+
<</Type/Page/MediaBox[0 0 595 842]/Parent 3 0 R/Resources<<>>>>
|
384
|
+
endobj
|
385
|
+
xref
|
386
|
+
0 5
|
387
|
+
0000000000 65535 f
|
388
|
+
0000000133 00000 n
|
389
|
+
0000000219 00000 n
|
390
|
+
0000000264 00000 n
|
391
|
+
0000000315 00000 n
|
392
|
+
trailer
|
393
|
+
<</ID[(a)(b)]/Info 1 0 R/Root 2 0 R/Size 5>>
|
394
|
+
startxref
|
395
|
+
41
|
396
|
+
%%EOF
|
397
|
+
EOF
|
398
|
+
end
|
399
|
+
|
400
|
+
it "merges the two revisions of a linearized PDF into one" do
|
401
|
+
doc = HexaPDF::Document.new(io: @io, config: {'parser.try_xref_reconstruction' => false})
|
402
|
+
assert(doc.revisions.parser.linearized?)
|
403
|
+
assert_equal(1, doc.revisions.count)
|
404
|
+
assert_same(5, doc.revisions.current.xref_section.max_oid)
|
405
|
+
end
|
406
|
+
|
407
|
+
it "works for a fake linearized PDF where the first xref section isn't actually used" do
|
408
|
+
@io.string[-9..-1] = "394\n%%EOF\n"
|
409
|
+
doc = HexaPDF::Document.new(io: @io, config: {'parser.try_xref_reconstruction' => false})
|
410
|
+
assert(doc.revisions.parser.linearized?)
|
411
|
+
assert_equal(1, doc.revisions.count)
|
412
|
+
assert_same(4, doc.revisions.current.xref_section.max_oid)
|
413
|
+
end
|
401
414
|
end
|
402
415
|
end
|
@@ -89,6 +89,7 @@ describe HexaPDF::Serializer do
|
|
89
89
|
assert_serialized('/ ', :"")
|
90
90
|
assert_serialized('/H#c3#b6#c3#9fgang', :Hößgang)
|
91
91
|
assert_serialized('/H#e8lp', "H\xE8lp".force_encoding('BINARY').intern)
|
92
|
+
assert_serialized('/#00#09#0a#0c#0d#20', :"\x00\t\n\f\r ")
|
92
93
|
end
|
93
94
|
|
94
95
|
it "serializes arrays" do
|
@@ -274,6 +274,15 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
274
274
|
assert(obj.null?)
|
275
275
|
end
|
276
276
|
|
277
|
+
it "deletes a field with an embedded widget annotation" do
|
278
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
279
|
+
assert_equal(widget, @field)
|
280
|
+
refute(@doc.pages[0][:Annots].empty?)
|
281
|
+
@acro_form.delete_field(@field)
|
282
|
+
assert(@doc.pages[0][:Annots].empty?)
|
283
|
+
assert(@field.null?)
|
284
|
+
end
|
285
|
+
|
277
286
|
it "deletes all widget annotations from the document and the annotation array" do
|
278
287
|
widget1 = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
279
288
|
widget2 = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
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.
|
4
|
+
version: 0.46.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Leitner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|