hexapdf 0.32.2 → 0.34.0
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 +4 -4
- data/CHANGELOG.md +104 -1
- data/README.md +9 -0
- data/examples/002-graphics.rb +15 -17
- data/examples/003-arcs.rb +9 -9
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +2 -2
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +7 -7
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +8 -7
- data/examples/016-frame_automatic_box_placement.rb +2 -2
- data/examples/017-frame_text_flow.rb +2 -1
- data/examples/018-composer.rb +1 -1
- data/examples/020-column_box.rb +2 -1
- data/examples/025-table_box.rb +46 -0
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +12 -3
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +5 -7
- data/lib/hexapdf/composer.rb +106 -53
- data/lib/hexapdf/configuration.rb +65 -40
- data/lib/hexapdf/content/canvas.rb +445 -267
- data/lib/hexapdf/content/color_space.rb +72 -25
- data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
- data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
- data/lib/hexapdf/content/graphic_object.rb +6 -7
- data/lib/hexapdf/content/graphics_state.rb +54 -45
- data/lib/hexapdf/content/operator.rb +54 -54
- data/lib/hexapdf/content/parser.rb +2 -2
- data/lib/hexapdf/content/processor.rb +15 -15
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +5 -0
- data/lib/hexapdf/dictionary.rb +7 -5
- data/lib/hexapdf/dictionary_fields.rb +43 -16
- data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
- data/lib/hexapdf/digital_signature/signature.rb +6 -6
- data/lib/hexapdf/digital_signature/signatures.rb +13 -12
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
- data/lib/hexapdf/digital_signature/signing.rb +4 -0
- data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
- data/lib/hexapdf/digital_signature.rb +7 -2
- data/lib/hexapdf/document/destinations.rb +12 -11
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/layout.rb +170 -39
- data/lib/hexapdf/document/pages.rb +4 -3
- data/lib/hexapdf/document.rb +96 -55
- data/lib/hexapdf/encryption/aes.rb +5 -5
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +31 -24
- data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
- data/lib/hexapdf/encryption.rb +7 -2
- data/lib/hexapdf/error.rb +18 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +55 -6
- data/lib/hexapdf/font/cmap/parser.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +3 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
- data/lib/hexapdf/font/type1_wrapper.rb +19 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
- data/lib/hexapdf/font_loader/from_file.rb +5 -5
- data/lib/hexapdf/font_loader/standard14.rb +3 -3
- data/lib/hexapdf/font_loader.rb +3 -0
- data/lib/hexapdf/image_loader/jpeg.rb +2 -2
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +13 -0
- data/lib/hexapdf/layout/box.rb +32 -5
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +20 -5
- data/lib/hexapdf/layout/frame.rb +53 -18
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +21 -9
- data/lib/hexapdf/layout/list_box.rb +50 -20
- data/lib/hexapdf/layout/page_style.rb +6 -5
- data/lib/hexapdf/layout/style.rb +64 -9
- data/lib/hexapdf/layout/table_box.rb +684 -0
- data/lib/hexapdf/layout/text_box.rb +12 -3
- data/lib/hexapdf/layout/text_fragment.rb +29 -3
- data/lib/hexapdf/layout/text_layouter.rb +32 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +18 -7
- data/lib/hexapdf/parser.rb +7 -7
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +3 -3
- data/lib/hexapdf/serializer.rb +15 -15
- data/lib/hexapdf/stream.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +14 -14
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +2 -2
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
- data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +1 -1
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +2 -1
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +2 -3
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +11 -2
- data/lib/hexapdf/type/cid_font.rb +18 -4
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +3 -3
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +76 -6
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +46 -21
- data/lib/hexapdf/type/page_label.rb +5 -9
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +4 -4
- data/lib/hexapdf/xref_section.rb +2 -2
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
- data/test/hexapdf/content/test_canvas.rb +49 -1
- data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
- data/test/hexapdf/document/test_files.rb +2 -2
- data/test/hexapdf/document/test_layout.rb +105 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +12 -11
- data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
- data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
- data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
- data/test/hexapdf/layout/test_box.rb +14 -5
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +27 -15
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +84 -33
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +60 -0
- data/test/hexapdf/layout/test_table_box.rb +728 -0
- data/test/hexapdf/layout/test_text_box.rb +26 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +36 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +5 -0
- data/test/hexapdf/test_filter.rb +8 -0
- data/test/hexapdf/test_importer.rb +9 -0
- data/test/hexapdf/test_object.rb +16 -5
- data/test/hexapdf/test_stream.rb +7 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
- data/test/hexapdf/type/acro_form/test_form.rb +4 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +20 -6
- metadata +28 -8
|
@@ -25,6 +25,14 @@ describe HexaPDF::Layout::TextBox do
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
it "returns the text contents as string" do
|
|
29
|
+
doc = HexaPDF::Document.new
|
|
30
|
+
font = doc.fonts.add("Times")
|
|
31
|
+
box = create_box([HexaPDF::Layout::TextFragment.create('Test ', font: font), @inline_box,
|
|
32
|
+
HexaPDF::Layout::TextFragment.create('here', font: font)])
|
|
33
|
+
assert_equal('Test here', box.text)
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
describe "fit" do
|
|
29
37
|
it "fits into a rectangular area" do
|
|
30
38
|
box = create_box([@inline_box] * 5, style: {padding: 10})
|
|
@@ -107,6 +115,14 @@ describe HexaPDF::Layout::TextBox do
|
|
|
107
115
|
assert_equal([nil, box], box.split(100, 100, @frame))
|
|
108
116
|
end
|
|
109
117
|
|
|
118
|
+
it "works if the box fits exactly (+/- float divergence)" do
|
|
119
|
+
box = create_box([@inline_box] * 5)
|
|
120
|
+
box.fit(50, 10, @frame)
|
|
121
|
+
box.instance_variable_set(:@width, 50.00000000006)
|
|
122
|
+
box.instance_variable_set(:@height, 10.00000000003)
|
|
123
|
+
assert_equal([box], box.split(50, 10, @frame))
|
|
124
|
+
end
|
|
125
|
+
|
|
110
126
|
it "splits the box if necessary when using non-flowing text" do
|
|
111
127
|
box = create_box([@inline_box] * 10)
|
|
112
128
|
boxes = box.split(50, 10, @frame)
|
|
@@ -125,6 +141,16 @@ describe HexaPDF::Layout::TextBox do
|
|
|
125
141
|
assert_equal(box, boxes[0])
|
|
126
142
|
assert_equal(5, boxes[1].instance_variable_get(:@items).length)
|
|
127
143
|
end
|
|
144
|
+
|
|
145
|
+
it "correctly handles text indentation for split boxes" do
|
|
146
|
+
[{}, {position: :flow}].each do |styles|
|
|
147
|
+
box = create_box([@inline_box] * 202, style: {text_indent: 50, **styles})
|
|
148
|
+
boxes = box.split(100, 100, @frame)
|
|
149
|
+
assert_equal(107, boxes[1].instance_variable_get(:@items).length)
|
|
150
|
+
boxes = boxes[1].split(100, 100, @frame)
|
|
151
|
+
assert_equal(7, boxes[1].instance_variable_get(:@items).length)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
128
154
|
end
|
|
129
155
|
|
|
130
156
|
describe "draw" do
|
|
@@ -51,6 +51,10 @@ describe HexaPDF::Layout::TextFragment do
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
it "returns the text value of the items as string" do
|
|
55
|
+
assert_equal("Hal lo\u{00a0}d\n", setup_fragment(@font.decode_utf8("Hal lo\u{00a0}d\n")).text)
|
|
56
|
+
end
|
|
57
|
+
|
|
54
58
|
it "allows duplicating with only its attributes while also setting new items" do
|
|
55
59
|
setup_fragment([20])
|
|
56
60
|
@fragment.properties['key'] = :value
|
|
@@ -392,6 +396,35 @@ describe HexaPDF::Layout::TextFragment do
|
|
|
392
396
|
end
|
|
393
397
|
end
|
|
394
398
|
|
|
399
|
+
describe "fill_horizontal!" do
|
|
400
|
+
before do
|
|
401
|
+
@fragment = HexaPDF::Layout::TextFragment.create('ab', fill_horizontal: 1, font: @font)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it "returns the fragment if the given width is too small" do
|
|
405
|
+
assert_same(@fragment, @fragment.fill_horizontal!(0.1))
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
it "repeats all items of the fragment" do
|
|
409
|
+
fragment = @fragment.fill_horizontal!(@fragment.width * 2)
|
|
410
|
+
assert_equal([*(@fragment.items * 2), 0], fragment.items)
|
|
411
|
+
assert_in_delta(@fragment.width * 2, fragment.width)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
it "adds, after repeating, items from the start of the fragment to fill the available space" do
|
|
415
|
+
fragment = @fragment.fill_horizontal!(90)
|
|
416
|
+
assert_equal([*(@fragment.items * 9), @fragment.items[0], 3.3333333333332673], fragment.items)
|
|
417
|
+
assert_in_delta(90, fragment.width)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it "sets the character spacing correctly to account for the remaining space after filling with items" do
|
|
421
|
+
fragment = @fragment.fill_horizontal!(90)
|
|
422
|
+
refute_same(@fragment.style, fragment.style)
|
|
423
|
+
assert_equal(0.033333333333332674, fragment.style.character_spacing)
|
|
424
|
+
assert_in_delta(90, fragment.width)
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
395
428
|
it "can be inspected" do
|
|
396
429
|
frag = setup_fragment(@font.decode_utf8("H") << 5)
|
|
397
430
|
assert_match(/:H/, frag.inspect)
|
|
@@ -262,7 +262,7 @@ module CommonLineWrappingTests
|
|
|
262
262
|
end
|
|
263
263
|
|
|
264
264
|
it "handles prohibited breakpoint penalties with non-zero width" do
|
|
265
|
-
item = boxes(20).first
|
|
265
|
+
item = boxes(20).first.item
|
|
266
266
|
result = call(boxes(70) + [glue(10)] + boxes(10) + [penalty(5000, item)] + boxes(30))
|
|
267
267
|
assert_line_wrapping(result, [70, 60])
|
|
268
268
|
end
|
|
@@ -295,11 +295,34 @@ module CommonLineWrappingTests
|
|
|
295
295
|
assert_equal(2, lines.count)
|
|
296
296
|
end
|
|
297
297
|
|
|
298
|
+
it "handles items with fill_horizontal correctly" do
|
|
299
|
+
doc = HexaPDF::Document.new
|
|
300
|
+
font = doc.fonts.add("Times")
|
|
301
|
+
box1 = HexaPDF::Layout::TextLayouter::Box.new(
|
|
302
|
+
HexaPDF::Layout::TextFragment.create('.', font: font, fill_horizontal: 1)
|
|
303
|
+
)
|
|
304
|
+
box2 = HexaPDF::Layout::TextLayouter::Box.new(
|
|
305
|
+
HexaPDF::Layout::TextFragment.create('.', font: font, fill_horizontal: 2)
|
|
306
|
+
)
|
|
307
|
+
items = [box1, *boxes(10), box2]
|
|
308
|
+
rest, lines = call(items, 40)
|
|
309
|
+
assert_equal(0, rest.size)
|
|
310
|
+
assert_equal(1, lines.size)
|
|
311
|
+
|
|
312
|
+
line = lines.first
|
|
313
|
+
refute_same(items[0].item, line.items[0])
|
|
314
|
+
assert_same(items[1].item, line.items[1])
|
|
315
|
+
refute_same(items[2].item, line.items[2])
|
|
316
|
+
assert_equal(10, line.items[0].width)
|
|
317
|
+
assert_equal(10, line.items[1].width)
|
|
318
|
+
assert_equal(20, line.items[2].width)
|
|
319
|
+
end
|
|
298
320
|
end
|
|
299
321
|
|
|
300
322
|
describe HexaPDF::Layout::TextLayouter::SimpleLineWrapping do
|
|
301
323
|
before do
|
|
302
324
|
@obj = HexaPDF::Layout::TextLayouter::SimpleLineWrapping
|
|
325
|
+
@mock_frame = nil
|
|
303
326
|
end
|
|
304
327
|
|
|
305
328
|
describe "fixed width wrapping" do
|
|
@@ -308,7 +331,9 @@ describe HexaPDF::Layout::TextLayouter::SimpleLineWrapping do
|
|
|
308
331
|
def call(items, width = 100, &block)
|
|
309
332
|
lines = []
|
|
310
333
|
block ||= proc { true }
|
|
311
|
-
rest = @obj.call(items, proc { width })
|
|
334
|
+
rest = @obj.call(items, proc { width }, @mock_frame) do |line, item|
|
|
335
|
+
lines << line; block.call(line, item)
|
|
336
|
+
end
|
|
312
337
|
[rest, lines]
|
|
313
338
|
end
|
|
314
339
|
end
|
|
@@ -319,7 +344,9 @@ describe HexaPDF::Layout::TextLayouter::SimpleLineWrapping do
|
|
|
319
344
|
def call(items, width = 100, &block)
|
|
320
345
|
lines = []
|
|
321
346
|
block ||= proc { true }
|
|
322
|
-
rest = @obj.call(items, proc {|_| width })
|
|
347
|
+
rest = @obj.call(items, proc {|_| width }, @mock_frame) do |line, i|
|
|
348
|
+
lines << line; block.call(line, i)
|
|
349
|
+
end
|
|
323
350
|
[rest, lines]
|
|
324
351
|
end
|
|
325
352
|
|
|
@@ -334,7 +361,7 @@ describe HexaPDF::Layout::TextLayouter::SimpleLineWrapping do
|
|
|
334
361
|
end
|
|
335
362
|
end
|
|
336
363
|
lines = []
|
|
337
|
-
rest = @obj.call(boxes([20, 10], [10, 10], [20, 15], [40, 10]), width_block) do |line|
|
|
364
|
+
rest = @obj.call(boxes([20, 10], [10, 10], [20, 15], [40, 10]), width_block, @mock_frame) do |line|
|
|
338
365
|
height += line.height
|
|
339
366
|
lines << line
|
|
340
367
|
true
|
|
@@ -357,7 +384,7 @@ describe HexaPDF::Layout::TextLayouter::SimpleLineWrapping do
|
|
|
357
384
|
lines = []
|
|
358
385
|
item = HexaPDF::Layout::InlineBox.create(width: 20, height: 10) {}
|
|
359
386
|
items = boxes([20, 10]) + [penalty(0, item)] + boxes([40, 15])
|
|
360
|
-
rest = @obj.call(items, width_block) do |line|
|
|
387
|
+
rest = @obj.call(items, width_block, @mock_frame) do |line|
|
|
361
388
|
height += line.height
|
|
362
389
|
lines << line
|
|
363
390
|
true
|
|
@@ -419,6 +446,10 @@ describe HexaPDF::Layout::TextLayouter do
|
|
|
419
446
|
assert(result.remaining_items.empty?)
|
|
420
447
|
assert_equal(:success, result.status)
|
|
421
448
|
end
|
|
449
|
+
|
|
450
|
+
result = @layouter.fit(boxes([20, 20], [20, 20], [20, 20], [20, 20]), 60, 200,
|
|
451
|
+
apply_first_text_indent: false)
|
|
452
|
+
assert_equal([60, 20], result.lines.map(&:width))
|
|
422
453
|
end
|
|
423
454
|
|
|
424
455
|
it "fits using a limited height" do
|
|
@@ -243,6 +243,16 @@ describe HexaPDF::Composer do
|
|
|
243
243
|
[:restore_graphics_state]])
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
+
it "returns the last drawn box" do
|
|
247
|
+
box = create_box(height: 400)
|
|
248
|
+
assert_same(box, @composer.draw_box(box))
|
|
249
|
+
|
|
250
|
+
box = create_box(height: 400)
|
|
251
|
+
split_box = create_box(height: 100)
|
|
252
|
+
box.define_singleton_method(:split) {|*| [box, split_box] }
|
|
253
|
+
assert_same(split_box, @composer.draw_box(box))
|
|
254
|
+
end
|
|
255
|
+
|
|
246
256
|
it "raises an error if a box doesn't fit onto an empty page" do
|
|
247
257
|
assert_raises(HexaPDF::Error) do
|
|
248
258
|
@composer.draw_box(create_box(height: 800))
|
|
@@ -94,6 +94,16 @@ describe HexaPDF::Dictionary do
|
|
|
94
94
|
obj = @test_class.new(nil)
|
|
95
95
|
assert_equal(:MyType, obj.value[:Type])
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
it "doesn't set the default values for required fields if the type class might be wrong" do
|
|
99
|
+
@test_class.define_type(:MyType)
|
|
100
|
+
obj = @test_class.new({})
|
|
101
|
+
assert_equal([], obj.value[:Array])
|
|
102
|
+
obj = @test_class.new({Type: :MyType})
|
|
103
|
+
assert_equal([], obj.value[:Array])
|
|
104
|
+
obj = @test_class.new({Type: :OtherType})
|
|
105
|
+
refute(obj.key?(:Array))
|
|
106
|
+
end
|
|
97
107
|
end
|
|
98
108
|
|
|
99
109
|
describe "[]" do
|
|
@@ -188,8 +188,11 @@ describe HexaPDF::DictionaryFields do
|
|
|
188
188
|
["D:19981223-08'00'", [1998, 12, 23, 00, 00, 00, "-08:00"]],
|
|
189
189
|
["D:199812-08'00'", [1998, 12, 01, 00, 00, 00, "-08:00"]],
|
|
190
190
|
["D:1998-08'00'", [1998, 01, 01, 00, 00, 00, "-08:00"]],
|
|
191
|
+
["D:19981223195210Z", [1998, 12, 23, 19, 52, 10, "+00:00"]],
|
|
192
|
+
["D:19981223195210Z00", [1998, 12, 23, 19, 52, 10, "+00:00"]],
|
|
193
|
+
["D:19981223195210Z00'00", [1998, 12, 23, 19, 52, 10, "+00:00"]],
|
|
191
194
|
["D:19981223195210-08", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
|
|
192
|
-
["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], #
|
|
195
|
+
["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], # no trailing ', as per PDF 2.0
|
|
193
196
|
["D:19981223195210-54'00", [1998, 12, 23, 19, 52, 10, "-23:59:59"]], # TZ hour too large
|
|
194
197
|
["D:19981223195210+10'65", [1998, 12, 23, 19, 52, 10, "+11:05"]], # TZ min too large
|
|
195
198
|
["D:19982423195210-08'00'", [1998, 12, 23, 19, 52, 10, "-08:00"]], # months too large
|
|
@@ -240,6 +240,7 @@ describe HexaPDF::Document do
|
|
|
240
240
|
assert_kind_of(@myclass2, @doc.wrap({Subtype: :Global, Test: "true"}))
|
|
241
241
|
assert_kind_of(@myclass2, @doc.wrap({Type: :MyClass, S: :TheSecond}))
|
|
242
242
|
assert_kind_of(@myclass, @doc.wrap({Type: :MyClass, Subtype: :TheThird}))
|
|
243
|
+
assert_kind_of(HexaPDF::Type::FontTrueType, @doc.wrap({Subtype: :TrueType, BaseFont: :Help}))
|
|
243
244
|
end
|
|
244
245
|
|
|
245
246
|
it "respects the given type/subtype arguments" do
|
|
@@ -560,6 +561,10 @@ describe HexaPDF::Document do
|
|
|
560
561
|
assert_kind_of(HexaPDF::Type::Outline, @doc.outline)
|
|
561
562
|
end
|
|
562
563
|
|
|
564
|
+
it "returns the optional content properties" do
|
|
565
|
+
assert_kind_of(HexaPDF::Type::OptionalContentProperties, @doc.optional_content)
|
|
566
|
+
end
|
|
567
|
+
|
|
563
568
|
it "can be inspected and the output is not too large" do
|
|
564
569
|
assert_match(/HexaPDF::Document:\d+/, @doc.inspect)
|
|
565
570
|
end
|
data/test/hexapdf/test_filter.rb
CHANGED
|
@@ -12,6 +12,14 @@ describe HexaPDF::Filter do
|
|
|
12
12
|
40.times { @str << [rand(2**32)].pack('N') }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
describe "source_from_proc" do
|
|
16
|
+
it "returns the whole string, once" do
|
|
17
|
+
fib = @obj.source_from_proc { @str }
|
|
18
|
+
assert_equal(@str, collector(fib))
|
|
19
|
+
assert_equal('', collector(fib))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
15
23
|
describe "source_from_string" do
|
|
16
24
|
it "doesn't modify the given string" do
|
|
17
25
|
str = @str.dup
|
|
@@ -40,6 +40,15 @@ describe HexaPDF::Importer do
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
describe "::copy" do
|
|
44
|
+
it "copies a complete object including references" do
|
|
45
|
+
obj1 = HexaPDF::Importer.copy(@dest, @obj)
|
|
46
|
+
obj2 = HexaPDF::Importer.copy(@dest, @obj)
|
|
47
|
+
refute_same(obj1, obj2)
|
|
48
|
+
refute_same(obj1[:ref], obj2[:ref])
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
43
52
|
describe "import" do
|
|
44
53
|
it "updates the associated document" do
|
|
45
54
|
obj = @importer.import(@obj)
|
data/test/hexapdf/test_object.rb
CHANGED
|
@@ -50,26 +50,37 @@ describe HexaPDF::Object do
|
|
|
50
50
|
@doc = HexaPDF::Document.new
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
it "
|
|
53
|
+
it "makes values of wrapped direct objects also direct" do
|
|
54
54
|
obj = HexaPDF::Object.new(5)
|
|
55
|
-
assert_same(obj, HexaPDF::Object.make_direct(obj))
|
|
55
|
+
assert_same(obj, HexaPDF::Object.make_direct(obj, @doc))
|
|
56
|
+
obj = HexaPDF::Dictionary.new({a: 5, b: HexaPDF::Object.new(:a, oid: 3, document: @doc)})
|
|
57
|
+
assert_same(obj, HexaPDF::Object.make_direct(obj, @doc))
|
|
58
|
+
assert_equal(:a, obj[:b])
|
|
56
59
|
end
|
|
57
60
|
|
|
58
61
|
it "works for simple values" do
|
|
59
62
|
obj = HexaPDF::Object.new(5, oid: 1, document: @doc)
|
|
60
|
-
assert_same(5, HexaPDF::Object.make_direct(obj))
|
|
63
|
+
assert_same(5, HexaPDF::Object.make_direct(obj, @doc))
|
|
61
64
|
end
|
|
62
65
|
|
|
63
66
|
it "works for hashes" do
|
|
64
67
|
obj = HexaPDF::Dictionary.new({a: 5, b: HexaPDF::Object.new(:a, oid: 3, document: @doc)},
|
|
65
68
|
oid: 1, document: @doc)
|
|
66
|
-
assert_equal({a: 5, b: :a}, HexaPDF::Object.make_direct(obj))
|
|
69
|
+
assert_equal({a: 5, b: :a}, HexaPDF::Object.make_direct(obj, @doc))
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
it "works for arrays" do
|
|
70
73
|
obj = HexaPDF::PDFArray.new([:b, HexaPDF::Object.new(:a, oid: 3, document: @doc)],
|
|
71
74
|
oid: 1, document: @doc)
|
|
72
|
-
assert_equal([:b, :a], HexaPDF::Object.make_direct(obj))
|
|
75
|
+
assert_equal([:b, :a], HexaPDF::Object.make_direct(obj, @doc))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "resolves references" do
|
|
79
|
+
@doc.add(:Test, oid: 1)
|
|
80
|
+
obj = HexaPDF::PDFArray.new([HexaPDF::Reference.new(1, 0)],
|
|
81
|
+
oid: 2, document: @doc)
|
|
82
|
+
assert_equal([:Test], HexaPDF::Object.make_direct(obj, @doc))
|
|
83
|
+
assert(@doc.object(1).null?)
|
|
73
84
|
end
|
|
74
85
|
end
|
|
75
86
|
|
data/test/hexapdf/test_stream.rb
CHANGED
|
@@ -31,6 +31,13 @@ describe HexaPDF::StreamData do
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
describe "fiber" do
|
|
34
|
+
it "returns a duplicate for a FiberDoubleForString source" do
|
|
35
|
+
source = HexaPDF::Filter.source_from_string("str")
|
|
36
|
+
fiber = HexaPDF::StreamData.new(source).fiber
|
|
37
|
+
assert_equal("str", fiber.resume)
|
|
38
|
+
refute_same(source, fiber)
|
|
39
|
+
end
|
|
40
|
+
|
|
34
41
|
it "returns a fiber for a Proc source" do
|
|
35
42
|
s = HexaPDF::StreamData.new(proc { :source })
|
|
36
43
|
assert_equal(:source, s.fiber.resume)
|
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.
|
|
43
|
+
<</Producer(HexaPDF version 0.34.0)>>
|
|
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.
|
|
75
|
+
<</Producer(HexaPDF version 0.34.0)>>
|
|
76
76
|
endobj
|
|
77
77
|
2 0 obj
|
|
78
78
|
<</Length 10>>stream
|
|
@@ -214,7 +214,7 @@ describe HexaPDF::Writer do
|
|
|
214
214
|
<</Type/Page/MediaBox[0 0 595 842]/Parent 2 0 R/Resources<<>>>>
|
|
215
215
|
endobj
|
|
216
216
|
5 0 obj
|
|
217
|
-
<</Producer(HexaPDF version 0.
|
|
217
|
+
<</Producer(HexaPDF version 0.34.0)>>
|
|
218
218
|
endobj
|
|
219
219
|
4 0 obj
|
|
220
220
|
<</Root 1 0 R/Info 5 0 R/Size 6/Type/XRef/W[1 1 2]/Index[0 6]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 33>>stream
|
|
@@ -467,12 +467,20 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
|
467
467
|
it "calculates the font size based on the rectangle height and border width" do
|
|
468
468
|
@generator.create_appearances
|
|
469
469
|
assert_operators(@widget[:AP][:N].stream,
|
|
470
|
-
[:set_font_and_size, [:F1,
|
|
470
|
+
[:set_font_and_size, [:F1, 13.235294]],
|
|
471
471
|
range: 5)
|
|
472
472
|
@widget.border_style(width: 2, color: :transparent)
|
|
473
473
|
@generator.create_appearances
|
|
474
474
|
assert_operators(@widget[:AP][:N].stream,
|
|
475
|
-
[:set_font_and_size, [:F1, 11.
|
|
475
|
+
[:set_font_and_size, [:F1, 11.764706]],
|
|
476
|
+
range: 5)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it "shrinks the font size if necessary to fit the rectangle width" do
|
|
480
|
+
@field.field_value = "This is some arbitrary, long text"
|
|
481
|
+
@generator.create_appearances
|
|
482
|
+
assert_operators(@widget[:AP][:N].stream,
|
|
483
|
+
[:set_font_and_size, [:F1, 6.909955]],
|
|
476
484
|
range: 5)
|
|
477
485
|
end
|
|
478
486
|
|
|
@@ -573,7 +581,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
|
573
581
|
assert_format("2, 3, #{style}, 0, \"E\", true",
|
|
574
582
|
[[:set_device_rgb_non_stroking_color, [style % 2, 0.0, 0.0]],
|
|
575
583
|
[:begin_text],
|
|
576
|
-
[:set_text_matrix, [1, 0, 0, 1, 2, 3.
|
|
584
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 3.183272]],
|
|
577
585
|
[:show_text, [result]]], 6..9)
|
|
578
586
|
end
|
|
579
587
|
end
|
|
@@ -598,10 +606,10 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
|
598
606
|
[:append_rectangle, [1, 1, 98, 9.25]],
|
|
599
607
|
[:clip_path_non_zero],
|
|
600
608
|
[:end_path],
|
|
601
|
-
[:set_font_and_size, [:F1, 6.
|
|
609
|
+
[:set_font_and_size, [:F1, 6.801471]],
|
|
602
610
|
[:set_device_rgb_non_stroking_color, [1.0, 0.0, 0.0]],
|
|
603
611
|
[:begin_text],
|
|
604
|
-
[:set_text_matrix, [1, 0, 0, 1, 2, 3.
|
|
612
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 3.183272]],
|
|
605
613
|
[:show_text, ["Text"]],
|
|
606
614
|
[:end_text],
|
|
607
615
|
[:restore_graphics_state],
|
|
@@ -42,11 +42,12 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it "finds the root fields" do
|
|
45
|
-
@doc.pages.add[:Annots] = [{
|
|
46
|
-
|
|
45
|
+
@doc.pages.add[:Annots] = [{Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx},
|
|
46
|
+
{Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx, Parent: {FT: :Tx}}]
|
|
47
|
+
@doc.pages.add[:Annots] = [{Subtype: :Widget, Rect: [0, 0, 0, 0]}]
|
|
47
48
|
@doc.pages.add
|
|
48
49
|
|
|
49
|
-
result = [{FT: :Tx}, {FT: :
|
|
50
|
+
result = [{Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx}, {FT: :Tx}]
|
|
50
51
|
root_fields = @acro_form.find_root_fields
|
|
51
52
|
assert_equal(result, root_fields.map(&:value))
|
|
52
53
|
assert_kind_of(HexaPDF::Type::AcroForm::TextField, root_fields[0])
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/actions/set_ocg_state'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::Actions::SetOCGState do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@action = HexaPDF::Type::Actions::SetOCGState.new({}, document: @doc)
|
|
11
|
+
@ocg = @doc.optional_content.add_ocg('Test')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "add_state_change" do
|
|
15
|
+
it "allows using Ruby-esque and PDF type names for the state change type" do
|
|
16
|
+
@action.add_state_change(:on, @ocg)
|
|
17
|
+
@action.add_state_change(:ON, @ocg)
|
|
18
|
+
@action.add_state_change(:off, @ocg)
|
|
19
|
+
@action.add_state_change(:OFF, @ocg)
|
|
20
|
+
@action.add_state_change(:toggle, @ocg)
|
|
21
|
+
@action.add_state_change(:Toggle, @ocg)
|
|
22
|
+
assert_equal([:ON, @ocg, :ON, @ocg, :OFF, @ocg, :OFF, @ocg, :Toggle, @ocg, :Toggle, @ocg],
|
|
23
|
+
@action[:State].value)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "allows specifying more than one OCG" do
|
|
27
|
+
@action.add_state_change(:on, [@ocg, @doc.optional_content.add_ocg('Test2')])
|
|
28
|
+
assert_equal([:ON, @ocg, @doc.optional_content.ocg('Test2')], @action[:State].value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "raises an error if the provide state change type is invalid" do
|
|
32
|
+
assert_raises(ArgumentError) { @action.add_state_change(:unknown, nil) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "raises an error if an OCG specified via a string does not exist" do
|
|
36
|
+
error = assert_raises(HexaPDF::Error) { @action.add_state_change(:on, "Unknown") }
|
|
37
|
+
assert_match(/Invalid OCG.*Unknown.*specified/, error.message)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -39,6 +39,17 @@ describe HexaPDF::Type::Catalog do
|
|
|
39
39
|
assert_same(outline, @catalog.outline)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
it "uses or creates the optional content properties dictionary on access" do
|
|
43
|
+
@catalog[:OCProperties] = hash = {}
|
|
44
|
+
assert_equal(:XXOCProperties, @catalog.optional_content.type)
|
|
45
|
+
assert_same(hash, @catalog.optional_content.value)
|
|
46
|
+
|
|
47
|
+
@catalog.delete(:OCProperties)
|
|
48
|
+
oc = @catalog.optional_content
|
|
49
|
+
assert_equal([], oc[:OCGs])
|
|
50
|
+
assert_equal(:XXOCConfiguration, oc[:D].type)
|
|
51
|
+
end
|
|
52
|
+
|
|
42
53
|
describe "acro_form" do
|
|
43
54
|
it "returns an existing form object" do
|
|
44
55
|
@catalog[:AcroForm] = :test
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
require 'test_helper'
|
|
4
|
+
require 'stringio'
|
|
5
|
+
require 'tempfile'
|
|
4
6
|
require 'hexapdf/document'
|
|
5
7
|
require 'hexapdf/type/form'
|
|
6
8
|
|
|
@@ -85,6 +87,18 @@ describe HexaPDF::Type::Form do
|
|
|
85
87
|
@form.process_contents(processor, original_resources: resources)
|
|
86
88
|
assert_same(resources, processor.resources)
|
|
87
89
|
end
|
|
90
|
+
|
|
91
|
+
it "uses the referenced content in case of a Reference XObject" do
|
|
92
|
+
@form[:Ref] = @doc.add({F: {}})
|
|
93
|
+
io = StringIO.new
|
|
94
|
+
HexaPDF::Document.new.tap {|d| d.pages.add.canvas.line_width(5) }.write(io)
|
|
95
|
+
@form[:Ref][:F].embed(io, name: 'test')
|
|
96
|
+
@form[:Ref][:Page] = 0
|
|
97
|
+
|
|
98
|
+
processor = HexaPDF::TestUtils::OperatorRecorder.new
|
|
99
|
+
@form.process_contents(processor)
|
|
100
|
+
assert_equal([[:set_line_width, [5]]], processor.recorded_ops)
|
|
101
|
+
end
|
|
88
102
|
end
|
|
89
103
|
|
|
90
104
|
describe "canvas" do
|
|
@@ -116,4 +130,109 @@ describe HexaPDF::Type::Form do
|
|
|
116
130
|
assert_raises(HexaPDF::Error) { @form.canvas }
|
|
117
131
|
end
|
|
118
132
|
end
|
|
133
|
+
|
|
134
|
+
describe "reference_xobject?" do
|
|
135
|
+
it "returns true if the form is a reference XObject" do
|
|
136
|
+
refute(@form.reference_xobject?)
|
|
137
|
+
@form[:Ref] = {}
|
|
138
|
+
assert(@form.reference_xobject?)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe "referenced_content" do
|
|
143
|
+
before do
|
|
144
|
+
@form[:BBox] = [10, 10, 110, 60]
|
|
145
|
+
@form[:Matrix] = [1, 0, 0, 1, 10, 20]
|
|
146
|
+
@form[:Ref] = @doc.add({F: {}})
|
|
147
|
+
@ref = @form[:Ref]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "returns a Form XObject with the imported page from an embedded file" do
|
|
151
|
+
io = StringIO.new
|
|
152
|
+
HexaPDF::Document.new.tap {|d| d.pages.add.canvas.line_width(5) }.write(io)
|
|
153
|
+
@ref[:F].embed(io, name: 'test.pdf')
|
|
154
|
+
@ref[:Page] = 0
|
|
155
|
+
|
|
156
|
+
ref_form = @form.referenced_content
|
|
157
|
+
refute_nil(ref_form)
|
|
158
|
+
assert_equal([10, 10, 110, 60], ref_form[:BBox].value)
|
|
159
|
+
assert_equal([1, 0, 0, 1, 10, 20], ref_form[:Matrix].value)
|
|
160
|
+
assert_equal("5 w\n", ref_form.contents)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "returns a Form XObject with the imported page from an external file" do
|
|
164
|
+
file = Tempfile.new('hexapdf')
|
|
165
|
+
HexaPDF::Document.new.tap {|d| d.pages.add.canvas.line_width(5) }.write(file.path)
|
|
166
|
+
@ref[:F].path = file.path
|
|
167
|
+
@ref[:Page] = 0
|
|
168
|
+
assert_equal("5 w\n", @form.referenced_content.contents)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "also works with a page label" do
|
|
172
|
+
file = Tempfile.new('hexapdf')
|
|
173
|
+
HexaPDF::Document.new.tap do |d|
|
|
174
|
+
d.pages.add
|
|
175
|
+
d.pages.add
|
|
176
|
+
d.pages.add.canvas.line_width(5)
|
|
177
|
+
d.pages.add
|
|
178
|
+
d.pages.add_labelling_range(1, numbering_style: :decimal, prefix: 'Test', start_number: 4)
|
|
179
|
+
end.write(file.path)
|
|
180
|
+
@ref[:F].path = file.path
|
|
181
|
+
@ref[:Page] = 'Test5'
|
|
182
|
+
assert_equal("5 w\n", @form.referenced_content.contents)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "flattens printable annotations into the page's content stream" do
|
|
186
|
+
io = StringIO.new
|
|
187
|
+
HexaPDF::Document.new.tap do |d|
|
|
188
|
+
d.pages.add.canvas.line_width(5)
|
|
189
|
+
tf = d.acro_form(create: true).create_text_field('text')
|
|
190
|
+
widget = tf.create_widget(d.pages[0], Rect: [10, 10, 30, 30])
|
|
191
|
+
widget.border_style(color: "black")
|
|
192
|
+
widget = tf.create_widget(d.pages[0], Rect: [40, 10, 70, 30])
|
|
193
|
+
widget.border_style(color: "red")
|
|
194
|
+
tf.field_value = 't'
|
|
195
|
+
widget.unflag(:print)
|
|
196
|
+
end.write(io)
|
|
197
|
+
@ref[:F].embed(io, name: 'Test')
|
|
198
|
+
@ref[:Page] = 0
|
|
199
|
+
assert_equal(" q Q q 5 w\n Q q q\n1.0 0 0 1.0 10.0 10.0 cm\n/XO1 Do\nQ\n Q ",
|
|
200
|
+
@form.referenced_content.contents)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "returns nil if the form is not a reference XObject" do
|
|
204
|
+
@form.delete(:Ref)
|
|
205
|
+
assert_nil(@form.referenced_content)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "returns nil if the file is not embedded and not found" do
|
|
209
|
+
@ref[:F].path = '/tmp/non_existing_path'
|
|
210
|
+
assert_nil(@form.referenced_content)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it "returns nil if the page referenced by page number is not found" do
|
|
214
|
+
io = StringIO.new
|
|
215
|
+
HexaPDF::Document.new.tap {|d| d.pages.add; d.pages.add }.write(io)
|
|
216
|
+
@ref[:F].embed(io, name: 'test.pdf')
|
|
217
|
+
@ref[:Page] = 5
|
|
218
|
+
assert_nil(@form.referenced_content)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "returns nil if the page referenced by page label is not found" do
|
|
222
|
+
io = StringIO.new
|
|
223
|
+
HexaPDF::Document.new.tap do |d|
|
|
224
|
+
d.pages.add
|
|
225
|
+
d.pages.add
|
|
226
|
+
d.pages.add_labelling_range(1, numbering_style: :decimal, prefix: 'Test')
|
|
227
|
+
end.write(io)
|
|
228
|
+
@ref[:F].embed(io, name: 'test.pdf')
|
|
229
|
+
@ref[:Page] = 'Test5'
|
|
230
|
+
assert_nil(@form.referenced_content)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "returns nil if an error happens during processing" do
|
|
234
|
+
@ref[:F].embed(StringIO.new('temp'), name: 'test.pdf')
|
|
235
|
+
assert_nil(@form.referenced_content)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
119
238
|
end
|