hexapdf 0.11.9 → 0.12.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 +82 -0
- data/LICENSE +1 -1
- data/examples/001-hello_world.rb +1 -1
- data/examples/002-graphics.rb +1 -1
- data/examples/003-arcs.rb +1 -1
- data/examples/004-optimizing.rb +1 -1
- data/examples/005-merging.rb +1 -1
- data/examples/006-standard_pdf_fonts.rb +1 -1
- data/examples/007-truetype.rb +1 -1
- data/examples/008-show_char_bboxes.rb +1 -1
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +1 -1
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +1 -1
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +1 -1
- data/examples/016-frame_automatic_box_placement.rb +1 -1
- data/examples/017-frame_text_flow.rb +1 -1
- data/examples/018-composer.rb +1 -1
- data/examples/019-acro_form.rb +51 -0
- data/lib/hexapdf.rb +1 -1
- data/lib/hexapdf/cli.rb +3 -1
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +18 -9
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/form.rb +240 -0
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +1 -1
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +1 -1
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/modify.rb +1 -1
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/split.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +1 -1
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +66 -11
- data/lib/hexapdf/content.rb +3 -1
- data/lib/hexapdf/content/canvas.rb +5 -18
- data/lib/hexapdf/content/color_space.rb +111 -32
- data/lib/hexapdf/content/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/content/operator.rb +9 -9
- data/lib/hexapdf/content/parser.rb +18 -5
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/data_dir.rb +1 -1
- data/lib/hexapdf/dictionary.rb +1 -1
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/document.rb +14 -5
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/document/pages.rb +3 -14
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +1 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +1 -1
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
- data/lib/hexapdf/error.rb +1 -1
- data/lib/hexapdf/filter.rb +3 -3
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/encryption.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/{jpx_decode.rb → pass_through.rb} +5 -5
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +1 -1
- data/lib/hexapdf/font/encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/base.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
- 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 +1 -1
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +1 -1
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type/builder.rb +1 -1
- data/lib/hexapdf/font/true_type/font.rb +1 -1
- data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
- data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
- data/lib/hexapdf/font/true_type/table.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
- data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
- data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
- data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
- data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
- data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
- data/lib/hexapdf/font/true_type/table/name.rb +1 -1
- data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
- data/lib/hexapdf/font/true_type/table/post.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +54 -51
- data/lib/hexapdf/font/type1.rb +1 -1
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +67 -51
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
- data/lib/hexapdf/font_loader/from_file.rb +1 -1
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +1 -1
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/importer.rb +2 -4
- data/lib/hexapdf/layout.rb +1 -1
- data/lib/hexapdf/layout/box.rb +1 -1
- data/lib/hexapdf/layout/frame.rb +1 -1
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/inline_box.rb +1 -1
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
- data/lib/hexapdf/layout/style.rb +1 -1
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +1 -1
- data/lib/hexapdf/layout/text_shaper.rb +1 -1
- data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +2 -2
- data/lib/hexapdf/parser.rb +4 -3
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +31 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +2 -1
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/tokenizer.rb +1 -1
- data/lib/hexapdf/type.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +7 -1
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +401 -0
- data/lib/hexapdf/type/acro_form/button_field.rb +300 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
- data/lib/hexapdf/type/acro_form/field.rb +220 -17
- data/lib/hexapdf/type/acro_form/form.rb +157 -7
- data/lib/hexapdf/type/acro_form/text_field.rb +186 -0
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +122 -0
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions.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/uri.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +73 -3
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/annotations/link.rb +2 -2
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +239 -2
- data/lib/hexapdf/type/catalog.rb +21 -1
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +18 -1
- data/lib/hexapdf/type/font_descriptor.rb +2 -2
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_true_type.rb +1 -1
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type1.rb +16 -1
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +1 -1
- 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 +3 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/page.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +8 -11
- data/lib/hexapdf/type/resources.rb +16 -3
- data/lib/hexapdf/type/trailer.rb +2 -3
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +1 -1
- data/lib/hexapdf/utils/bit_field.rb +38 -24
- data/lib/hexapdf/utils/bit_stream.rb +1 -1
- data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
- data/lib/hexapdf/utils/lru_cache.rb +1 -1
- data/lib/hexapdf/utils/math_helpers.rb +1 -1
- data/lib/hexapdf/utils/object_hash.rb +1 -1
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +1 -1
- data/lib/hexapdf/xref_section.rb +1 -1
- data/test/hexapdf/content/common.rb +2 -2
- data/test/hexapdf/content/test_color_space.rb +71 -8
- data/test/hexapdf/content/test_operator.rb +22 -22
- data/test/hexapdf/content/test_parser.rb +14 -0
- data/test/hexapdf/document/test_fonts.rb +1 -1
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
- data/test/hexapdf/font/test_type1_wrapper.rb +32 -8
- data/test/hexapdf/test_document.rb +12 -0
- data/test/hexapdf/test_parser.rb +10 -0
- data/test/hexapdf/test_rectangle.rb +14 -0
- data/test/hexapdf/test_revision.rb +3 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +515 -0
- data/test/hexapdf/type/acro_form/test_button_field.rb +276 -0
- data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
- data/test/hexapdf/type/acro_form/test_field.rb +124 -6
- data/test/hexapdf/type/acro_form/test_form.rb +189 -22
- data/test/hexapdf/type/acro_form/test_text_field.rb +119 -0
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
- data/test/hexapdf/type/annotations/test_text.rb +1 -1
- data/test/hexapdf/type/annotations/test_widget.rb +199 -0
- data/test/hexapdf/type/test_annotation.rb +45 -0
- data/test/hexapdf/type/test_catalog.rb +18 -0
- data/test/hexapdf/type/test_font.rb +5 -0
- data/test/hexapdf/type/test_font_type1.rb +8 -0
- data/test/hexapdf/type/test_image.rb +7 -0
- data/test/hexapdf/type/test_page_tree_node.rb +20 -12
- data/test/hexapdf/type/test_resources.rb +20 -0
- data/test/hexapdf/type/test_trailer.rb +4 -0
- data/test/hexapdf/utils/test_bit_field.rb +13 -1
- data/test/test_helper.rb +1 -1
- metadata +37 -18
- data/lib/hexapdf/filter/dct_decode.rb +0 -60
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require_relative '../../content/common'
|
|
5
|
+
require 'hexapdf/document'
|
|
6
|
+
require 'hexapdf/type/acro_form/button_field'
|
|
7
|
+
|
|
8
|
+
describe HexaPDF::Type::AcroForm::ButtonField do
|
|
9
|
+
before do
|
|
10
|
+
@doc = HexaPDF::Document.new
|
|
11
|
+
@field = @doc.add({FT: :Btn, T: 'button'}, type: :XXAcroFormField, subtype: :Btn)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "can be initialized as push button" do
|
|
15
|
+
@field.initialize_as_push_button
|
|
16
|
+
assert_nil(@field[:V])
|
|
17
|
+
assert(@field.push_button?)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "can be initialized as check box" do
|
|
21
|
+
@field.initialize_as_check_box
|
|
22
|
+
assert_equal(:Off, @field[:V])
|
|
23
|
+
assert(@field.check_box?)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "can be initialized as radio button" do
|
|
27
|
+
@field.initialize_as_radio_button
|
|
28
|
+
assert_equal(:Off, @field[:V])
|
|
29
|
+
assert_equal(1 << 15, @field[:Ff])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "push button" do
|
|
33
|
+
before do
|
|
34
|
+
@field.flag(:push_button)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "can be asked whether it is a push button field" do
|
|
38
|
+
@field.flag(:push_button)
|
|
39
|
+
assert(@field.push_button?)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "always returns nil when getting the field value" do
|
|
43
|
+
@field[:V] = :test
|
|
44
|
+
assert_nil(@field.field_value)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "doesn't set a field value" do
|
|
48
|
+
@field.field_value = :test
|
|
49
|
+
assert_nil(@field[:V])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "returns the correct concrete field type" do
|
|
53
|
+
assert_equal(:push_button, @field.concrete_field_type)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "applies sensible default values when creating a widget" do
|
|
57
|
+
widget = @field.create_widget(@doc.pages.add)
|
|
58
|
+
border_style = widget.border_style
|
|
59
|
+
assert_equal([0], border_style.color.components)
|
|
60
|
+
assert_equal(1, border_style.width)
|
|
61
|
+
assert_equal(:beveled, border_style.style)
|
|
62
|
+
assert_equal([0.5], widget.background_color.components)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "check box" do
|
|
67
|
+
before do
|
|
68
|
+
@field.unflag(:push_button)
|
|
69
|
+
@field.unflag(:radio)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "can be asked whether it is a check box field" do
|
|
73
|
+
assert(@field.check_box?)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "returns a correct field value" do
|
|
77
|
+
refute(@field.field_value)
|
|
78
|
+
@field[:V] = :Off
|
|
79
|
+
refute(@field.field_value)
|
|
80
|
+
@field[:V] = :Yes
|
|
81
|
+
assert(@field.field_value)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "sets a correct field value" do
|
|
85
|
+
@field.field_value = true
|
|
86
|
+
assert_equal(:Yes, @field[:V])
|
|
87
|
+
@field.field_value = false
|
|
88
|
+
assert_equal(:Off, @field[:V])
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "returns the correct concrete field type" do
|
|
92
|
+
assert_equal(:check_box, @field.concrete_field_type)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "updates the widgets after setting the field value" do
|
|
96
|
+
widget = @field.create_widget(@doc.pages.add)
|
|
97
|
+
@field.field_value = true
|
|
98
|
+
assert_equal(:Yes, widget[:AS])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "can determine the name of the on state" do
|
|
102
|
+
assert_equal(:Yes, @field.check_box_on_name)
|
|
103
|
+
widget = @field.create_widget(@doc.pages.add)
|
|
104
|
+
assert_equal(:Yes, @field.check_box_on_name)
|
|
105
|
+
widget[:AP][:N].delete(:Yes)
|
|
106
|
+
widget[:AP][:N][:On] = nil
|
|
107
|
+
assert_equal(:On, @field.check_box_on_name)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "applies sensible default values when creating a widget" do
|
|
111
|
+
widget = @field.create_widget(@doc.pages.add)
|
|
112
|
+
assert_equal({Yes: nil, Off: nil}, widget[:AP][:N].value)
|
|
113
|
+
border_style = widget.border_style
|
|
114
|
+
assert_equal([0], border_style.color.components)
|
|
115
|
+
assert_equal(1, border_style.width)
|
|
116
|
+
assert_equal(:solid, border_style.style)
|
|
117
|
+
assert_equal([1], widget.background_color.components)
|
|
118
|
+
assert_equal(:check, widget.marker_style.style)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "radio button" do
|
|
123
|
+
before do
|
|
124
|
+
@field.unflag(:push_button)
|
|
125
|
+
@field.flag(:radio)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "can be asked whether it is a radio button field" do
|
|
129
|
+
assert(@field.radio_button?)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "returns a correct field value" do
|
|
133
|
+
assert_nil(@field.field_value)
|
|
134
|
+
@field[:V] = :Off
|
|
135
|
+
assert_nil(@field.field_value)
|
|
136
|
+
@field[:V] = :name
|
|
137
|
+
assert_equal(:name, @field.field_value)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "sets a correct field value" do
|
|
141
|
+
@field.create_widget(@doc.pages.add, value: :button1)
|
|
142
|
+
|
|
143
|
+
@field.field_value = :button1
|
|
144
|
+
assert_equal(:button1, @field[:V])
|
|
145
|
+
@field.field_value = nil
|
|
146
|
+
assert_equal(:Off, @field[:V])
|
|
147
|
+
assert_raises(HexaPDF::Error) { @field.field_value = :unknown }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "returns the correct concrete field type" do
|
|
151
|
+
assert_equal(:radio_button, @field.concrete_field_type)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "updates the widgets after setting the field value" do
|
|
155
|
+
widget = @field.create_widget(@doc.pages.add, value: :Test)
|
|
156
|
+
@field.field_value = :Test
|
|
157
|
+
assert_equal(:Test, widget[:AS])
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "returns an array of possible values" do
|
|
161
|
+
@field.create_widget(@doc.pages.add, value: :Test)
|
|
162
|
+
@field.create_widget(@doc.pages.add, value: :x)
|
|
163
|
+
@field.create_widget(@doc.pages.add, value: :y)
|
|
164
|
+
assert_equal([:Test, :x, :y], @field.radio_button_values)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "applies sensible default values when creating a widget" do
|
|
168
|
+
widget = @field.create_widget(@doc.pages.add, value: 'test')
|
|
169
|
+
border_style = widget.border_style
|
|
170
|
+
assert_equal([0], border_style.color.components)
|
|
171
|
+
assert_equal(1, border_style.width)
|
|
172
|
+
assert_equal(:solid, border_style.style)
|
|
173
|
+
assert_equal([1], widget.background_color.components)
|
|
174
|
+
assert_equal(:circle, widget.marker_style.style)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "always creates standalone widgets" do
|
|
178
|
+
refute_same(@field.data, @field.create_widget(@doc.pages.add, value: 'test'))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "fails if the value argument is not provided for create_widget" do
|
|
182
|
+
assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add) }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "returns a default field value" do
|
|
187
|
+
assert_method_invoked(@field, :normalized_field_value, [:DV]) do
|
|
188
|
+
@field.default_field_value
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "sets a default field value" do
|
|
193
|
+
assert_method_invoked(@field, :normalized_field_value_set, [:DV, :value]) do
|
|
194
|
+
@field.default_field_value = :value
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "resolves /Opt as inheritable field" do
|
|
199
|
+
@field[:Parent] = {Opt: 5}
|
|
200
|
+
assert_equal(5, @field[:Opt])
|
|
201
|
+
|
|
202
|
+
@field[:Opt] = 6
|
|
203
|
+
assert_equal(6, @field[:Opt])
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
describe "create_appearances" do
|
|
207
|
+
it "works for check boxes" do
|
|
208
|
+
@field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
209
|
+
@field.create_appearances
|
|
210
|
+
assert(@field[:AP][:N][:Yes])
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it "works for radio buttons" do
|
|
214
|
+
@field.initialize_as_radio_button
|
|
215
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0], value: :test)
|
|
216
|
+
@field.create_appearances
|
|
217
|
+
assert(widget[:AP][:N][:test])
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "won't generate appearances if they already exist" do
|
|
221
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
222
|
+
@field.create_appearances
|
|
223
|
+
yes = widget.appearance.normal_appearance[:Yes]
|
|
224
|
+
off = widget.appearance.normal_appearance[:Off]
|
|
225
|
+
widget.appearance.normal_appearance.delete(:Off)
|
|
226
|
+
@field.create_appearances
|
|
227
|
+
assert_same(yes, widget.appearance.normal_appearance[:Yes])
|
|
228
|
+
refute_same(off, widget.appearance.normal_appearance[:Off])
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "fails for unsupported button types" do
|
|
232
|
+
@field.flag(:push_button)
|
|
233
|
+
@field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
234
|
+
assert_raises(HexaPDF::Error) { @field.create_appearances }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "uses the configuration option acro_form.appearance_generator" do
|
|
238
|
+
@doc.config['acro_form.appearance_generator'] = 'NonExistent'
|
|
239
|
+
assert_raises(Exception) { @field.create_appearances }
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe "update_widgets" do
|
|
244
|
+
it "does nothing for push buttons" do
|
|
245
|
+
@field.flag(:push_button)
|
|
246
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
247
|
+
@field.update_widgets
|
|
248
|
+
assert_nil(widget[:AS])
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "sets the /AS entry correctly" do
|
|
252
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
253
|
+
assert_nil(widget[:AS])
|
|
254
|
+
@field.update_widgets
|
|
255
|
+
assert_equal(:Off, widget[:AS])
|
|
256
|
+
|
|
257
|
+
@field[:V] = :Yes
|
|
258
|
+
@field.update_widgets
|
|
259
|
+
assert_equal(:Yes, widget[:AS])
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
describe "validation" do
|
|
264
|
+
it "checks the value of the /FT field" do
|
|
265
|
+
@field.delete(:FT)
|
|
266
|
+
refute(@field.validate(auto_correct: false))
|
|
267
|
+
assert(@field.validate)
|
|
268
|
+
assert_equal(:Btn, @field.field_type)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "sets the field value to :Off it it is not set" do
|
|
272
|
+
assert(@field.validate)
|
|
273
|
+
assert_equal(:Off, @field[:V])
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/acro_form/choice_field'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::AcroForm::ChoiceField do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@field = @doc.add({FT: :Ch, T: 'choice'}, type: :XXAcroFormField, subtype: :Ch)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "can be initialized as list box" do
|
|
14
|
+
@field.initialize_as_list_box
|
|
15
|
+
assert_nil(@field[:V])
|
|
16
|
+
assert(@field.list_box?)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "can be initialized as combo box" do
|
|
20
|
+
@field.initialize_as_combo_box
|
|
21
|
+
assert_nil(@field[:V])
|
|
22
|
+
assert(@field.combo_box?)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "field_value" do
|
|
26
|
+
it "returns the correct Unicode string value" do
|
|
27
|
+
@field[:V] = "H\xe4llo".b
|
|
28
|
+
assert_equal("Hällo", @field.field_value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "returns an array of Unicode string values" do
|
|
32
|
+
@field[:V] = ["H\xe4llo".b, "\xFE\xFF".b << "Óthér".encode('UTF-16BE').b]
|
|
33
|
+
assert_equal(["Hällo", "Óthér"], @field.field_value)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "field_value=" do
|
|
38
|
+
before do
|
|
39
|
+
@field.option_items = ["test", "other"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "combo_box" do
|
|
43
|
+
before do
|
|
44
|
+
@field.initialize_as_combo_box
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "can set the value for an uneditable combo box" do
|
|
48
|
+
@field.field_value = 'test'
|
|
49
|
+
assert_equal("test", @field[:V])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "can set the value for an editable combo box" do
|
|
53
|
+
@field.flag(:edit)
|
|
54
|
+
@field.field_value = 'another'
|
|
55
|
+
assert_equal("another", @field[:V])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "fails if mulitple values are provided for a combo box" do
|
|
59
|
+
assert_raises(HexaPDF::Error) { @field.field_value = ['a', 'b'] }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "fails if an unlisted value is specified for an uneditable combo box" do
|
|
63
|
+
assert_raises(HexaPDF::Error) { @field.field_value = 'a' }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "list_box" do
|
|
68
|
+
before do
|
|
69
|
+
@field.initialize_as_list_box
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "can set a single value" do
|
|
73
|
+
@field.field_value = 'test'
|
|
74
|
+
assert_equal("test", @field[:V])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "can set a multiple values if the list box is a multi-select" do
|
|
78
|
+
@field.flag(:multi_select)
|
|
79
|
+
@field.field_value = ['test', 'other']
|
|
80
|
+
assert_equal(['test', 'other'], @field[:V].value)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "fails if mulitple values are provided but the list box is not a multi-select" do
|
|
84
|
+
assert_raises(HexaPDF::Error) { @field.field_value = ['a', 'b'] }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "fails if an unlisted value is specified" do
|
|
88
|
+
assert_raises(HexaPDF::Error) { @field.field_value = 'a' }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "sets and returns the default field value" do
|
|
94
|
+
@field.option_items = ["hällo"]
|
|
95
|
+
@field.default_field_value = 'hällo'
|
|
96
|
+
assert_equal('hällo', @field.default_field_value)
|
|
97
|
+
assert_raises(HexaPDF::Error) { @field.default_field_value = 'unknown' }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "sets and returns the array with the option items" do
|
|
101
|
+
assert_equal([], @field.option_items)
|
|
102
|
+
@field.option_items = ["H\xe4llo".b, "\xFE\xFF".b << "Töne".encode('UTF-16BE').b]
|
|
103
|
+
assert_equal(["Hällo", "Töne"], @field.option_items)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "returns the correct concrete field type" do
|
|
107
|
+
assert_equal(:list_box, @field.concrete_field_type)
|
|
108
|
+
@field.initialize_as_combo_box
|
|
109
|
+
assert_equal(:combo_box, @field.concrete_field_type)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "create_appearances" do
|
|
113
|
+
before do
|
|
114
|
+
@widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "works for combo box fields" do
|
|
118
|
+
@field.initialize_as_combo_box
|
|
119
|
+
@field.set_default_appearance_string
|
|
120
|
+
@field.create_appearances
|
|
121
|
+
assert(@field[:AP][:N])
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "fails for list boxes" do
|
|
125
|
+
assert_raises(HexaPDF::Error) { @field.create_appearances }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe "validation" do
|
|
130
|
+
it "checks the value of the /FT field" do
|
|
131
|
+
@field.delete(:FT)
|
|
132
|
+
refute(@field.validate(auto_correct: false))
|
|
133
|
+
assert(@field.validate)
|
|
134
|
+
assert_equal(:Ch, @field.field_type)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -4,6 +4,15 @@ require 'test_helper'
|
|
|
4
4
|
require 'hexapdf/document'
|
|
5
5
|
require 'hexapdf/type/acro_form/field'
|
|
6
6
|
|
|
7
|
+
describe HexaPDF::Type::AcroForm::Field::HashRefinement do
|
|
8
|
+
using HexaPDF::Type::AcroForm::Field::HashRefinement
|
|
9
|
+
|
|
10
|
+
it "returns self when calling value" do
|
|
11
|
+
x = {}
|
|
12
|
+
assert_same(x, x.value)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
7
16
|
describe HexaPDF::Type::AcroForm::Field do
|
|
8
17
|
before do
|
|
9
18
|
@doc = HexaPDF::Document.new
|
|
@@ -24,6 +33,14 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
24
33
|
assert_equal(:Ch, @field[:FT])
|
|
25
34
|
end
|
|
26
35
|
|
|
36
|
+
it "has convenience methods for accessing the field flags" do
|
|
37
|
+
assert_equal([], @field.flags)
|
|
38
|
+
refute(@field.flagged?(:required))
|
|
39
|
+
@field.flag(:required, 2)
|
|
40
|
+
assert(@field.flagged?(2))
|
|
41
|
+
assert_equal(6, @field[:Ff])
|
|
42
|
+
end
|
|
43
|
+
|
|
27
44
|
it "returns the field type" do
|
|
28
45
|
assert_nil(@field.field_type)
|
|
29
46
|
|
|
@@ -31,17 +48,42 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
31
48
|
assert_equal(:Tx, @field.field_type)
|
|
32
49
|
end
|
|
33
50
|
|
|
51
|
+
it "returns the concrete field type" do
|
|
52
|
+
assert_nil(@field.concrete_field_type)
|
|
53
|
+
|
|
54
|
+
@field[:FT] = :Tx
|
|
55
|
+
assert_equal(:text_field, @field.concrete_field_type)
|
|
56
|
+
@field[:FT] = :Btn
|
|
57
|
+
assert_equal(:button_field, @field.concrete_field_type)
|
|
58
|
+
@field[:FT] = :Ch
|
|
59
|
+
assert_equal(:choice_field, @field.concrete_field_type)
|
|
60
|
+
@field[:FT] = :Sig
|
|
61
|
+
assert_equal(:signature_field, @field.concrete_field_type)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "returns the field name" do
|
|
65
|
+
assert_nil(@field.field_name)
|
|
66
|
+
@field[:T] = 'test'
|
|
67
|
+
assert_equal('test', @field.field_name)
|
|
68
|
+
end
|
|
69
|
+
|
|
34
70
|
it "returns the full name of the field" do
|
|
35
|
-
assert_nil(@field.
|
|
71
|
+
assert_nil(@field.full_field_name)
|
|
36
72
|
|
|
37
73
|
@field[:T] = "Test"
|
|
38
|
-
assert_equal("Test", @field.
|
|
74
|
+
assert_equal("Test", @field.full_field_name)
|
|
39
75
|
|
|
40
76
|
@field[:Parent] = {}
|
|
41
|
-
assert_equal("Test", @field.
|
|
77
|
+
assert_equal("Test", @field.full_field_name)
|
|
42
78
|
|
|
43
79
|
@field[:Parent] = {T: 'Parent'}
|
|
44
|
-
assert_equal("Parent.Test", @field.
|
|
80
|
+
assert_equal("Parent.Test", @field.full_field_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "allows setting and retrieving the alternate field name" do
|
|
84
|
+
@field.alternate_field_name = 'Alternate'
|
|
85
|
+
assert_equal('Alternate', @field.alternate_field_name)
|
|
86
|
+
assert_equal('Alternate', @field[:TU])
|
|
45
87
|
end
|
|
46
88
|
|
|
47
89
|
it "returns whether the field is a terminal field" do
|
|
@@ -53,10 +95,86 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
53
95
|
@field[:Kids] = [{Subtype: :Widget}]
|
|
54
96
|
assert(@field.terminal_field?)
|
|
55
97
|
|
|
56
|
-
@field[:Kids] = [{FT: :Tx}]
|
|
98
|
+
@field[:Kids] = [{FT: :Tx, T: 'name'}]
|
|
57
99
|
refute(@field.terminal_field?)
|
|
58
100
|
end
|
|
59
101
|
|
|
102
|
+
describe "each_widget" do
|
|
103
|
+
it "yields a wrapped instance of self if a single widget is embedded" do
|
|
104
|
+
@field[:Subtype] = :Widget
|
|
105
|
+
@field[:Rect] = [0, 0, 0, 0]
|
|
106
|
+
widgets = @field.each_widget.to_a
|
|
107
|
+
assert_kind_of(HexaPDF::Type::Annotations::Widget, *widgets)
|
|
108
|
+
assert_same(@field.data, widgets.first.data)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "yields all widgets in the /Kids array" do
|
|
112
|
+
@field[:Kids] = [{Subtype: :Widget, Rect: [0, 0, 0, 0], X: 1}]
|
|
113
|
+
widgets = @field.each_widget.to_a
|
|
114
|
+
assert_kind_of(HexaPDF::Type::Annotations::Widget, *widgets)
|
|
115
|
+
assert_equal(1, widgets.first[:X])
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "yields nothing if no widgets are defined" do
|
|
119
|
+
assert_equal([], @field.each_widget.to_a)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe "create_widget" do
|
|
124
|
+
before do
|
|
125
|
+
@page = @doc.pages.add
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "sets all required widget keys" do
|
|
129
|
+
widget = @field.create_widget(@page)
|
|
130
|
+
assert_equal(:Annot, widget.type)
|
|
131
|
+
assert_equal(:Widget, widget[:Subtype])
|
|
132
|
+
assert_equal([0, 0, 0, 0], widget[:Rect])
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "sets the additionally specified keys on the widget" do
|
|
136
|
+
widget = @field.create_widget(@page, X: 5)
|
|
137
|
+
assert_equal(5, widget[:X])
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "adds the new widget to the given page's annotations" do
|
|
141
|
+
widget = @field.create_widget(@page)
|
|
142
|
+
assert_equal([widget], @page[:Annots].value)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "populates the field with the widget data if there is no widget" do
|
|
146
|
+
widget = @field.create_widget(@page)
|
|
147
|
+
assert_same(widget.data, @field.data)
|
|
148
|
+
assert_nil(@field[:Kids])
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "creates a standalone widget if embedding is not allowed" do
|
|
152
|
+
refute_same(@field.data, @field.create_widget(@page, allow_embedded: false).data)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "extracts an embedded widget into a standalone object if necessary" do
|
|
156
|
+
widget1 = @field.create_widget(@page, Rect: [1, 2, 3, 4])
|
|
157
|
+
widget2 = @field.create_widget(@doc.pages.add, Rect: [2, 1, 4, 3])
|
|
158
|
+
kids = @field[:Kids]
|
|
159
|
+
|
|
160
|
+
assert_equal(2, kids.length)
|
|
161
|
+
refute_same(widget1, kids[0])
|
|
162
|
+
assert_same(widget2, kids[1])
|
|
163
|
+
assert_nil(@field[:Rect])
|
|
164
|
+
assert_equal({Rect: [1, 2, 3, 4], Type: :Annot, Subtype: :Widget, Parent: @field},
|
|
165
|
+
kids[0].value)
|
|
166
|
+
assert_equal([2, 1, 4, 3], kids[1][:Rect].value)
|
|
167
|
+
|
|
168
|
+
refute_equal([widget1], @page[:Annots].value)
|
|
169
|
+
assert_equal([kids[0]], @page[:Annots].value)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "fails if called on a non-terminal field" do
|
|
173
|
+
@field[:Kids] = [{T: 'name'}]
|
|
174
|
+
assert_raises(HexaPDF::Error) { @field.create_widget(@page) }
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
60
178
|
describe "perform_validation" do
|
|
61
179
|
before do
|
|
62
180
|
@field[:FT] = :Tx
|
|
@@ -68,7 +186,7 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
68
186
|
@field.delete(:FT)
|
|
69
187
|
refute(@field.validate)
|
|
70
188
|
|
|
71
|
-
@field[:Kids] = [{}]
|
|
189
|
+
@field[:Kids] = [{T: 'name'}]
|
|
72
190
|
assert(@field.validate)
|
|
73
191
|
end
|
|
74
192
|
|