hexapdf 0.12.0 → 0.14.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 +126 -0
- data/examples/019-acro_form.rb +41 -4
- data/lib/hexapdf/cli/command.rb +4 -2
- data/lib/hexapdf/cli/image2pdf.rb +2 -1
- data/lib/hexapdf/cli/info.rb +51 -2
- data/lib/hexapdf/cli/inspect.rb +30 -8
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/split.rb +74 -14
- data/lib/hexapdf/configuration.rb +15 -0
- data/lib/hexapdf/content/graphic_object/arc.rb +3 -3
- data/lib/hexapdf/content/parser.rb +1 -1
- data/lib/hexapdf/dictionary.rb +4 -4
- data/lib/hexapdf/dictionary_fields.rb +1 -9
- data/lib/hexapdf/document.rb +41 -16
- data/lib/hexapdf/document/files.rb +0 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +1 -0
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -0
- data/lib/hexapdf/font/cmap.rb +1 -4
- data/lib/hexapdf/font/encoding/base.rb +8 -0
- data/lib/hexapdf/font/encoding/difference_encoding.rb +6 -0
- data/lib/hexapdf/font/true_type/table/head.rb +1 -0
- data/lib/hexapdf/font/true_type/table/os2.rb +2 -0
- data/lib/hexapdf/font/type1_wrapper.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +3 -2
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/style.rb +23 -23
- data/lib/hexapdf/layout/text_layouter.rb +2 -2
- data/lib/hexapdf/layout/text_shaper.rb +3 -2
- data/lib/hexapdf/object.rb +52 -25
- data/lib/hexapdf/parser.rb +87 -3
- data/lib/hexapdf/pdf_array.rb +11 -4
- data/lib/hexapdf/revisions.rb +29 -21
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +6 -4
- data/lib/hexapdf/tokenizer.rb +4 -3
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +132 -28
- data/lib/hexapdf/type/acro_form/button_field.rb +21 -13
- data/lib/hexapdf/type/acro_form/choice_field.rb +68 -14
- data/lib/hexapdf/type/acro_form/field.rb +35 -5
- data/lib/hexapdf/type/acro_form/form.rb +139 -14
- data/lib/hexapdf/type/acro_form/text_field.rb +70 -4
- data/lib/hexapdf/type/actions/uri.rb +3 -2
- data/lib/hexapdf/type/annotations/widget.rb +3 -4
- data/lib/hexapdf/type/catalog.rb +2 -2
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +4 -2
- data/lib/hexapdf/type/font_true_type.rb +6 -2
- data/lib/hexapdf/type/font_type0.rb +4 -4
- data/lib/hexapdf/type/form.rb +15 -2
- data/lib/hexapdf/type/image.rb +2 -2
- data/lib/hexapdf/type/page.rb +37 -13
- data/lib/hexapdf/type/page_tree_node.rb +29 -5
- data/lib/hexapdf/type/resources.rb +1 -0
- data/lib/hexapdf/type/trailer.rb +2 -3
- data/lib/hexapdf/utils/object_hash.rb +0 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +18 -15
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/common_tokenizer_tests.rb +6 -1
- data/test/hexapdf/content/graphic_object/test_arc.rb +4 -4
- data/test/hexapdf/content/test_canvas.rb +3 -3
- data/test/hexapdf/content/test_color_space.rb +1 -1
- data/test/hexapdf/encryption/test_aes.rb +4 -4
- data/test/hexapdf/encryption/test_standard_security_handler.rb +11 -11
- data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
- data/test/hexapdf/font/encoding/test_base.rb +10 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +4 -3
- data/test/hexapdf/layout/test_style.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +12 -5
- data/test/hexapdf/test_configuration.rb +2 -2
- data/test/hexapdf/test_dictionary.rb +3 -1
- data/test/hexapdf/test_dictionary_fields.rb +2 -2
- data/test/hexapdf/test_document.rb +18 -10
- data/test/hexapdf/test_object.rb +71 -26
- data/test/hexapdf/test_parser.rb +159 -53
- data/test/hexapdf/test_pdf_array.rb +8 -1
- data/test/hexapdf/test_revisions.rb +35 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +296 -38
- data/test/hexapdf/type/acro_form/test_button_field.rb +22 -2
- data/test/hexapdf/type/acro_form/test_choice_field.rb +92 -9
- data/test/hexapdf/type/acro_form/test_field.rb +39 -0
- data/test/hexapdf/type/acro_form/test_form.rb +87 -15
- data/test/hexapdf/type/acro_form/test_text_field.rb +77 -1
- data/test/hexapdf/type/test_font_simple.rb +2 -1
- data/test/hexapdf/type/test_font_true_type.rb +6 -0
- data/test/hexapdf/type/test_form.rb +26 -1
- data/test/hexapdf/type/test_page.rb +45 -7
- data/test/hexapdf/type/test_page_tree_node.rb +42 -0
- data/test/hexapdf/utils/test_bit_field.rb +2 -0
- data/test/hexapdf/utils/test_object_hash.rb +5 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -9
- data/test/test_helper.rb +2 -0
- metadata +6 -11
@@ -107,6 +107,13 @@ describe HexaPDF::PDFArray do
|
|
107
107
|
assert_equal([1, :data, @array[2]], @array[0, 5])
|
108
108
|
end
|
109
109
|
|
110
|
+
it "allows deleting an object" do
|
111
|
+
obj = @array.value[1]
|
112
|
+
assert_same(obj, @array.delete(obj))
|
113
|
+
ref = HexaPDF::Object.new(:test, oid: 1)
|
114
|
+
assert_equal(ref, @array.delete(ref))
|
115
|
+
end
|
116
|
+
|
110
117
|
describe "slice!" do
|
111
118
|
it "allows deleting a single element" do
|
112
119
|
@array.slice!(2)
|
@@ -157,6 +164,6 @@ describe HexaPDF::PDFArray do
|
|
157
164
|
end
|
158
165
|
|
159
166
|
it "can be converted to a simple array" do
|
160
|
-
assert_equal(@array
|
167
|
+
assert_equal([1, :data, "deref", @array[3]], @array.to_ary)
|
161
168
|
end
|
162
169
|
end
|
@@ -158,4 +158,39 @@ describe HexaPDF::Revisions do
|
|
158
158
|
doc = HexaPDF::Document.new(io: io)
|
159
159
|
assert_equal(2, doc.revisions.count)
|
160
160
|
end
|
161
|
+
|
162
|
+
it "uses the reconstructed revision if errors are found when loading from an IO" do
|
163
|
+
io = StringIO.new(<<~EOF)
|
164
|
+
%PDF-1.7
|
165
|
+
1 0 obj
|
166
|
+
10
|
167
|
+
endobj
|
168
|
+
|
169
|
+
xref
|
170
|
+
0 2
|
171
|
+
0000000000 65535 f
|
172
|
+
0000000009 00000 n
|
173
|
+
trailer
|
174
|
+
<< /Size 5 >>
|
175
|
+
startxref
|
176
|
+
28
|
177
|
+
%%EOF
|
178
|
+
|
179
|
+
2 0 obj
|
180
|
+
300
|
181
|
+
endobj
|
182
|
+
|
183
|
+
xref
|
184
|
+
2 1
|
185
|
+
0000000301 00000 n
|
186
|
+
trailer
|
187
|
+
<< /Size 3 /Prev 100>>
|
188
|
+
startxref
|
189
|
+
139
|
190
|
+
%%EOF
|
191
|
+
EOF
|
192
|
+
doc = HexaPDF::Document.new(io: io)
|
193
|
+
assert_equal(2, doc.revisions.count)
|
194
|
+
assert_same(doc.revisions[0].trailer.value, doc.revisions[1].trailer.value)
|
195
|
+
end
|
161
196
|
end
|
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.14.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.14.0)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
@@ -25,14 +25,6 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
25
25
|
assert_raises(HexaPDF::Error) { @generator.create_appearances }
|
26
26
|
end
|
27
27
|
|
28
|
-
it "fails for unsupported choice fields" do
|
29
|
-
@field = @doc.wrap(@field, type: :XXAcroFormField, subtype: :Ch)
|
30
|
-
@field[:FT] = :Ch
|
31
|
-
@field.initialize_as_list_box
|
32
|
-
@generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
|
33
|
-
assert_raises(HexaPDF::Error) { @generator.create_appearances }
|
34
|
-
end
|
35
|
-
|
36
28
|
it "fails for unsupported field types" do
|
37
29
|
@field[:FT] = :Unknown
|
38
30
|
assert_raises(HexaPDF::Error) { @generator.create_appearances }
|
@@ -121,6 +113,24 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
121
113
|
[:curve_to, [8.236068, 7.249543, 9.0, 8.572712, 9.0, 10.0]],
|
122
114
|
[:stroke_path], [:restore_graphics_state]])
|
123
115
|
end
|
116
|
+
|
117
|
+
it "handles the special case of a comb field" do
|
118
|
+
@field = @doc.add({FT: :Tx, MaxLen: 4}, type: :XXAcroFormField, subtype: :Tx)
|
119
|
+
@field.initialize_as_comb_text_field
|
120
|
+
@widget = @field.create_widget(@page, Rect: [0, 0, 10, 20])
|
121
|
+
@xform = @doc.add({Type: :XObject, Subtype: :Form, BBox: @widget[:Rect]})
|
122
|
+
@generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
|
123
|
+
@widget.border_style(width: 2)
|
124
|
+
execute
|
125
|
+
assert_operators(@xform.stream,
|
126
|
+
[[:save_graphics_state],
|
127
|
+
[:set_line_width, [2]],
|
128
|
+
[:append_rectangle, [1, 1, 8, 18]],
|
129
|
+
[:move_to, [2.5, 2]], [:line_to, [2.5, 20.0]],
|
130
|
+
[:move_to, [5.0, 2]], [:line_to, [5.0, 20.0]],
|
131
|
+
[:move_to, [7.5, 2]], [:line_to, [7.5, 20.0]],
|
132
|
+
[:stroke_path], [:restore_graphics_state]])
|
133
|
+
end
|
124
134
|
end
|
125
135
|
|
126
136
|
describe "draw_marker" do
|
@@ -342,7 +352,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
342
352
|
end
|
343
353
|
end
|
344
354
|
|
345
|
-
describe "text
|
355
|
+
describe "text fields" do
|
346
356
|
before do
|
347
357
|
@form.set_default_appearance_string
|
348
358
|
@field = @doc.add({FT: :Tx}, type: :XXAcroFormField, subtype: :Tx)
|
@@ -392,35 +402,58 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
392
402
|
assert_equal(@doc.acro_form.default_resources[:Font][:F1], form[:Resources][:Font][:F1])
|
393
403
|
end
|
394
404
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
@field.field_value = ''
|
401
|
-
end
|
405
|
+
it "re-uses the existing form XObject" do
|
406
|
+
@field[:V] = 'test'
|
407
|
+
@generator.create_appearances
|
408
|
+
form = @widget[:AP][:N]
|
409
|
+
form[:key] = :value
|
402
410
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
end
|
411
|
+
@field[:V] = 'test1'
|
412
|
+
@generator.create_appearances
|
413
|
+
assert_same(form, @widget[:AP][:N])
|
414
|
+
refute(form.key?(:key))
|
415
|
+
assert_match(/test1/, form.contents)
|
416
|
+
end
|
410
417
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
418
|
+
describe "font size calculation" do
|
419
|
+
before do
|
420
|
+
@widget[:Rect].height = 20
|
421
|
+
@widget[:Rect].width = 100
|
422
|
+
@field.field_value = ''
|
423
|
+
end
|
424
|
+
|
425
|
+
it "uses the non-zero font size" do
|
426
|
+
@field.set_default_appearance_string(font_size: 10)
|
427
|
+
@generator.create_appearances
|
428
|
+
assert_operators(@widget[:AP][:N].stream,
|
429
|
+
[:set_font_and_size, [:F1, 10]],
|
430
|
+
range: 5)
|
431
|
+
end
|
432
|
+
|
433
|
+
it "calculates the font size based on the rectangle height and border width" do
|
434
|
+
@generator.create_appearances
|
435
|
+
assert_operators(@widget[:AP][:N].stream,
|
436
|
+
[:set_font_and_size, [:F1, 12.923875]],
|
437
|
+
range: 5)
|
438
|
+
@widget.border_style(width: 2, color: :transparent)
|
439
|
+
@generator.create_appearances
|
440
|
+
assert_operators(@widget[:AP][:N].stream,
|
441
|
+
[:set_font_and_size, [:F1, 11.487889]],
|
442
|
+
range: 5)
|
443
|
+
end
|
444
|
+
|
445
|
+
it " in case of mulitline auto-sizing" do
|
446
|
+
@field.initialize_as_multiline_text_field
|
447
|
+
@field[:V] = 'a'
|
448
|
+
@field.set_default_appearance_string(font_size: 0)
|
449
|
+
@generator.create_appearances
|
450
|
+
assert_operators(@widget[:AP][:N].stream,
|
451
|
+
[:set_font_and_size, [:F1, 12]],
|
452
|
+
range: 6)
|
422
453
|
end
|
454
|
+
end
|
423
455
|
|
456
|
+
describe "single line text fields" do
|
424
457
|
describe "quadding e.g. text alignment" do
|
425
458
|
before do
|
426
459
|
@field.field_value = 'Test'
|
@@ -478,7 +511,166 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
478
511
|
[:restore_graphics_state],
|
479
512
|
[:end_marked_content]])
|
480
513
|
end
|
514
|
+
end
|
515
|
+
|
516
|
+
describe "multiline text fields" do
|
517
|
+
before do
|
518
|
+
@field.set_default_appearance_string(font_size: 10)
|
519
|
+
@field.initialize_as_multiline_text_field
|
520
|
+
@widget[:Rect].height = 30
|
521
|
+
@widget[:Rect].width = 100
|
522
|
+
end
|
523
|
+
|
524
|
+
describe "quadding e.g. text alignment" do
|
525
|
+
before do
|
526
|
+
@field[:V] = "Test\nValue"
|
527
|
+
end
|
481
528
|
|
529
|
+
it "works for left aligned text" do
|
530
|
+
@field.text_alignment(:left)
|
531
|
+
@generator.create_appearances
|
532
|
+
assert_operators(@widget[:AP][:N].stream,
|
533
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 16.195]],
|
534
|
+
range: 9)
|
535
|
+
end
|
536
|
+
|
537
|
+
it "works for right aligned text" do
|
538
|
+
@field.text_alignment(:right)
|
539
|
+
@generator.create_appearances
|
540
|
+
assert_operators(@widget[:AP][:N].stream,
|
541
|
+
[:set_text_matrix, [1, 0, 0, 1, 78.55, 16.195]],
|
542
|
+
range: 9)
|
543
|
+
end
|
544
|
+
|
545
|
+
it "works for center aligned text" do
|
546
|
+
@field.text_alignment(:center)
|
547
|
+
@generator.create_appearances
|
548
|
+
assert_operators(@widget[:AP][:N].stream,
|
549
|
+
[:set_text_matrix, [1, 0, 0, 1, 40.275, 16.195]],
|
550
|
+
range: 9)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
it "creates the /N appearance stream according to the set string" do
|
555
|
+
@field.field_value = "Test\nValue"
|
556
|
+
@generator.create_appearances
|
557
|
+
assert_operators(@widget[:AP][:N].stream,
|
558
|
+
[[:begin_marked_content, [:Tx]],
|
559
|
+
[:save_graphics_state],
|
560
|
+
[:append_rectangle, [1, 1, 98, 28]],
|
561
|
+
[:clip_path_non_zero],
|
562
|
+
[:end_path],
|
563
|
+
[:save_graphics_state],
|
564
|
+
[:set_leading, [11.5625]],
|
565
|
+
[:set_font_and_size, [:F1, 10]],
|
566
|
+
[:begin_text],
|
567
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 16.195]],
|
568
|
+
[:show_text, ['Test']],
|
569
|
+
[:move_text_next_line],
|
570
|
+
[:show_text, ['Value']],
|
571
|
+
[:end_text],
|
572
|
+
[:restore_graphics_state],
|
573
|
+
[:restore_graphics_state],
|
574
|
+
[:end_marked_content]])
|
575
|
+
|
576
|
+
@field.field_value = "Test\nTest\nTest"
|
577
|
+
@field.set_default_appearance_string(font_size: 0)
|
578
|
+
@generator.create_appearances
|
579
|
+
assert_operators(@widget[:AP][:N].stream,
|
580
|
+
[[:begin_marked_content, [:Tx]],
|
581
|
+
[:save_graphics_state],
|
582
|
+
[:append_rectangle, [1, 1, 98, 28]],
|
583
|
+
[:clip_path_non_zero],
|
584
|
+
[:end_path],
|
585
|
+
[:save_graphics_state],
|
586
|
+
[:set_leading, [9.25]],
|
587
|
+
[:set_font_and_size, [:F1, 8]],
|
588
|
+
[:begin_text],
|
589
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 18.556]],
|
590
|
+
[:show_text, ['Test']],
|
591
|
+
[:move_text_next_line],
|
592
|
+
[:show_text, ['Test']],
|
593
|
+
[:move_text_next_line],
|
594
|
+
[:show_text, ['Test']],
|
595
|
+
[:end_text],
|
596
|
+
[:restore_graphics_state],
|
597
|
+
[:restore_graphics_state],
|
598
|
+
[:end_marked_content]],
|
599
|
+
)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
describe "comb text fields" do
|
604
|
+
before do
|
605
|
+
@field.set_default_appearance_string(font_size: 10)
|
606
|
+
@field.initialize_as_comb_text_field
|
607
|
+
@field[:MaxLen] = 10
|
608
|
+
@widget[:Rect].height = 20
|
609
|
+
@widget[:Rect].width = 100
|
610
|
+
end
|
611
|
+
|
612
|
+
describe "quadding e.g. text alignment" do
|
613
|
+
before do
|
614
|
+
@field[:V] = 'Test'
|
615
|
+
end
|
616
|
+
|
617
|
+
it "works for left aligned text" do
|
618
|
+
@field.text_alignment(:left)
|
619
|
+
@generator.create_appearances
|
620
|
+
assert_operators(@widget[:AP][:N].stream,
|
621
|
+
[:set_text_matrix, [1, 0, 0, 1, 2.945, 6.41]],
|
622
|
+
range: 7)
|
623
|
+
end
|
624
|
+
|
625
|
+
it "works for right aligned text" do
|
626
|
+
@field.text_alignment(:right)
|
627
|
+
@generator.create_appearances
|
628
|
+
assert_operators(@widget[:AP][:N].stream,
|
629
|
+
[:set_text_matrix, [1, 0, 0, 1, 62.945, 6.41]],
|
630
|
+
range: 7)
|
631
|
+
end
|
632
|
+
|
633
|
+
it "works for center aligned text" do
|
634
|
+
@field.text_alignment(:center)
|
635
|
+
@generator.create_appearances
|
636
|
+
assert_operators(@widget[:AP][:N].stream,
|
637
|
+
[:set_text_matrix, [1, 0, 0, 1, 32.945, 6.41]],
|
638
|
+
range: 7)
|
639
|
+
end
|
640
|
+
|
641
|
+
it "handles centering like Adobe, e.g. shift left, when text cannot be completely centered" do
|
642
|
+
@field.field_value = 'Hello'
|
643
|
+
@field.text_alignment(:center)
|
644
|
+
@generator.create_appearances
|
645
|
+
assert_operators(@widget[:AP][:N].stream,
|
646
|
+
[:set_text_matrix, [1, 0, 0, 1, 22.39, 6.41]],
|
647
|
+
range: 7)
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
it "creates the /N appearance stream according to the set string" do
|
652
|
+
@field.field_value = 'Text'
|
653
|
+
@generator.create_appearances
|
654
|
+
assert_operators(@widget[:AP][:N].stream,
|
655
|
+
[[:begin_marked_content, [:Tx]],
|
656
|
+
[:save_graphics_state],
|
657
|
+
[:append_rectangle, [1, 1, 98, 18]],
|
658
|
+
[:clip_path_non_zero],
|
659
|
+
[:end_path],
|
660
|
+
[:set_font_and_size, [:F1, 10]],
|
661
|
+
[:begin_text],
|
662
|
+
[:set_text_matrix, [1, 0, 0, 1, 2.945, 6.41]],
|
663
|
+
[:show_text_with_positioning, [['T', -416.5, 'e', -472, 'x', -611, 't']]],
|
664
|
+
[:end_text],
|
665
|
+
[:restore_graphics_state],
|
666
|
+
[:end_marked_content]])
|
667
|
+
end
|
668
|
+
|
669
|
+
it "fails if the /MaxLen key is not set" do
|
670
|
+
@field.delete(:MaxLen)
|
671
|
+
@field[:V] = 't'
|
672
|
+
assert_raises(HexaPDF::Error) { @generator.create_appearances }
|
673
|
+
end
|
482
674
|
end
|
483
675
|
|
484
676
|
describe "choice fields" do
|
@@ -486,27 +678,93 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
|
|
486
678
|
@form.set_default_appearance_string
|
487
679
|
field = @doc.add({FT: :Ch}, type: :XXAcroFormField, subtype: :Ch)
|
488
680
|
field.initialize_as_combo_box
|
681
|
+
field.flag(:edit)
|
682
|
+
field.field_value = 'Test'
|
489
683
|
widget = field.create_widget(@page, Rect: [0, 0, 0, 0])
|
490
684
|
generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(widget)
|
491
685
|
generator.create_appearances
|
492
686
|
assert_kind_of(HexaPDF::Type::Form, widget[:AP][:N])
|
493
687
|
end
|
688
|
+
|
689
|
+
describe "list boxes" do
|
690
|
+
before do
|
691
|
+
@field = @doc.add({FT: :Ch}, type: :XXAcroFormField, subtype: :Ch)
|
692
|
+
@field.initialize_as_list_box
|
693
|
+
@field.flag(:multi_select)
|
694
|
+
@field.option_items = ['a', 'b', 'c']
|
695
|
+
@widget = @field.create_widget(@page, Rect: [0, 0, 90, 36])
|
696
|
+
@generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
|
697
|
+
end
|
698
|
+
|
699
|
+
it "uses a fixed font size for list box items if auto-sizing is used" do
|
700
|
+
@field.set_default_appearance_string(font_size: 0)
|
701
|
+
@generator.create_appearances
|
702
|
+
assert_operators(@widget[:AP][:N].stream,
|
703
|
+
[:set_font_and_size, [:F1, 12]],
|
704
|
+
range: 8)
|
705
|
+
end
|
706
|
+
|
707
|
+
it "uses the set values instead of the ones from /I if in conflict" do
|
708
|
+
@field[:I] = [0, 1]
|
709
|
+
@field[:V] = ['b']
|
710
|
+
@generator.create_appearances
|
711
|
+
assert_operators(@widget[:AP][:N].stream,
|
712
|
+
[[:set_device_rgb_non_stroking_color, [0.6, 0.756863, 0.854902]],
|
713
|
+
[:append_rectangle, [1, 7.25, 88, 13.875]],
|
714
|
+
[:fill_path_non_zero]],
|
715
|
+
range: 5..7)
|
716
|
+
end
|
717
|
+
|
718
|
+
it "creates the /N appearance stream" do
|
719
|
+
@field[:I] = [1, 2]
|
720
|
+
@field[:V] = ['b', 'c']
|
721
|
+
@generator.create_appearances
|
722
|
+
assert_operators(@widget[:AP][:N].stream,
|
723
|
+
[[:begin_marked_content, [:Tx]],
|
724
|
+
[:save_graphics_state],
|
725
|
+
[:append_rectangle, [1, 1, 88, 34]],
|
726
|
+
[:clip_path_non_zero], [:end_path],
|
727
|
+
[:set_device_rgb_non_stroking_color, [0.6, 0.756863, 0.854902]],
|
728
|
+
[:append_rectangle, [1, 7.25, 88, 13.875]],
|
729
|
+
[:append_rectangle, [1, -6.625, 88, 13.875]],
|
730
|
+
[:fill_path_non_zero],
|
731
|
+
[:save_graphics_state],
|
732
|
+
[:set_leading, [13.875]],
|
733
|
+
[:set_font_and_size, [:F1, 12]],
|
734
|
+
[:set_device_gray_non_stroking_color, [0.0]],
|
735
|
+
[:begin_text],
|
736
|
+
[:set_text_matrix, [1, 0, 0, 1, 2, 23.609]],
|
737
|
+
[:show_text, ["a"]],
|
738
|
+
[:move_text_next_line],
|
739
|
+
[:show_text, ["b"]],
|
740
|
+
[:end_text],
|
741
|
+
[:restore_graphics_state], [:restore_graphics_state],
|
742
|
+
[:end_marked_content]])
|
743
|
+
end
|
744
|
+
end
|
494
745
|
end
|
495
746
|
|
496
747
|
describe "font resolution in case the referenced font is not usable" do
|
497
748
|
before do
|
498
|
-
|
499
|
-
@field
|
749
|
+
@doc.config['acro_form.fallback_font'] = ['Times', {variant: :none}]
|
750
|
+
@field[:V] = 'Test'
|
500
751
|
end
|
501
752
|
|
502
|
-
it "uses the fallback font if
|
503
|
-
@
|
753
|
+
it "uses the fallback font if the font is not usable" do
|
754
|
+
def (@form.default_resources.font(:F1)).font_wrapper; nil; end
|
504
755
|
@generator.create_appearances
|
505
756
|
assert_equal(:'Times-Roman', @widget[:AP][:N][:Resources][:Font][:F2][:BaseFont])
|
506
757
|
end
|
507
758
|
|
759
|
+
it "uses the fallback font if the font is not found" do
|
760
|
+
@form.default_resources[:Font].delete(:F1)
|
761
|
+
@generator.create_appearances
|
762
|
+
assert_equal(:'Times-Roman', @widget[:AP][:N][:Resources][:Font][:F1][:BaseFont])
|
763
|
+
end
|
764
|
+
|
508
765
|
it "fails if fallback fonts are disabled" do
|
509
766
|
@doc.config['acro_form.fallback_font'] = nil
|
767
|
+
@form.default_resources[:Font].delete(:F1)
|
510
768
|
msg = assert_raises(HexaPDF::Error) { @generator.create_appearances }
|
511
769
|
assert_match(/Font.*not usable/, msg.message)
|
512
770
|
end
|