hexapdf 0.12.3 → 0.14.3
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 +132 -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/dictionary.rb +12 -6
- data/lib/hexapdf/dictionary_fields.rb +2 -10
- 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/true_type/subsetter.rb +16 -3
- 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/true_type/table/post.rb +15 -10
- data/lib/hexapdf/font_loader/from_configuration.rb +2 -2
- data/lib/hexapdf/font_loader/from_file.rb +18 -8
- data/lib/hexapdf/image_loader/png.rb +3 -2
- data/lib/hexapdf/importer.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 +107 -7
- data/lib/hexapdf/pdf_array.rb +15 -5
- data/lib/hexapdf/revisions.rb +29 -21
- data/lib/hexapdf/serializer.rb +37 -10
- data/lib/hexapdf/task/optimize.rb +6 -4
- data/lib/hexapdf/tokenizer.rb +22 -0
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +130 -27
- data/lib/hexapdf/type/acro_form/button_field.rb +5 -2
- 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 +6 -2
- data/lib/hexapdf/type/image.rb +2 -2
- data/lib/hexapdf/type/page.rb +21 -12
- data/lib/hexapdf/type/page_tree_node.rb +29 -5
- data/lib/hexapdf/type/resources.rb +5 -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 +2 -2
- 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/true_type/table/test_post.rb +1 -1
- data/test/hexapdf/font/true_type/test_subsetter.rb +10 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +7 -3
- data/test/hexapdf/font_loader/test_from_file.rb +7 -0
- data/test/hexapdf/layout/test_text_layouter.rb +12 -5
- data/test/hexapdf/test_configuration.rb +2 -2
- data/test/hexapdf/test_dictionary.rb +8 -1
- data/test/hexapdf/test_dictionary_fields.rb +9 -2
- data/test/hexapdf/test_document.rb +18 -10
- data/test/hexapdf/test_object.rb +71 -26
- data/test/hexapdf/test_parser.rb +205 -51
- data/test/hexapdf/test_pdf_array.rb +8 -1
- data/test/hexapdf/test_revisions.rb +35 -0
- data/test/hexapdf/test_serializer.rb +7 -0
- data/test/hexapdf/test_tokenizer.rb +28 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +288 -35
- data/test/hexapdf/type/acro_form/test_button_field.rb +15 -0
- 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 +8 -1
- data/test/hexapdf/type/test_page.rb +8 -1
- data/test/hexapdf/type/test_page_tree_node.rb +42 -0
- data/test/hexapdf/type/test_resources.rb +6 -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 -12
|
@@ -99,6 +99,12 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
99
99
|
refute(@field.terminal_field?)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
+
it "can check whether a widget is embedded in the field" do
|
|
103
|
+
refute(@field.embedded_widget?)
|
|
104
|
+
@field[:Subtype] = :Wdiget
|
|
105
|
+
assert(@field.embedded_widget?)
|
|
106
|
+
end
|
|
107
|
+
|
|
102
108
|
describe "each_widget" do
|
|
103
109
|
it "yields a wrapped instance of self if a single widget is embedded" do
|
|
104
110
|
@field[:Subtype] = :Widget
|
|
@@ -175,6 +181,39 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
|
175
181
|
end
|
|
176
182
|
end
|
|
177
183
|
|
|
184
|
+
describe "delete_widget" do
|
|
185
|
+
before do
|
|
186
|
+
@page = @doc.pages.add
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "does nothing if the provided widget doesn't belong to the field" do
|
|
190
|
+
wrong_widget = @doc.add({Subtype: :Widget})
|
|
191
|
+
|
|
192
|
+
@field.create_widget(@page)
|
|
193
|
+
@field.delete_widget(wrong_widget)
|
|
194
|
+
assert_equal(:Widget, @field[:Subtype])
|
|
195
|
+
|
|
196
|
+
@field.create_widget(@page)
|
|
197
|
+
@field.delete_widget(wrong_widget)
|
|
198
|
+
assert_equal(2, @field[:Kids].size)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "deletes the widget if it is embedded" do
|
|
202
|
+
widget = @field.create_widget(@page)
|
|
203
|
+
@field.delete_widget(widget)
|
|
204
|
+
refute(@field.key?(:Subtype))
|
|
205
|
+
assert(@page[:Annots].empty?)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "deletes the widget if it is not embedded" do
|
|
209
|
+
@field.create_widget(@page)
|
|
210
|
+
widget2 = @field.create_widget(@page)
|
|
211
|
+
@field.delete_widget(widget2)
|
|
212
|
+
assert_equal(1, @field[:Kids].size)
|
|
213
|
+
assert_equal(@field[:Kids].value, @page[:Annots].value)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
178
217
|
describe "perform_validation" do
|
|
179
218
|
before do
|
|
180
219
|
@field[:FT] = :Tx
|
|
@@ -7,7 +7,7 @@ require 'hexapdf/type/acro_form/form'
|
|
|
7
7
|
describe HexaPDF::Type::AcroForm::Form do
|
|
8
8
|
before do
|
|
9
9
|
@doc = HexaPDF::Document.new
|
|
10
|
-
@acro_form = @doc.add({}, type: :XXAcroForm)
|
|
10
|
+
@acro_form = @doc.add({Fields: []}, type: :XXAcroForm)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
describe "signature flags" do
|
|
@@ -49,7 +49,7 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
49
49
|
root_fields = @acro_form.find_root_fields
|
|
50
50
|
assert_equal(result, root_fields.map(&:value))
|
|
51
51
|
assert_kind_of(HexaPDF::Type::AcroForm::TextField, root_fields[0])
|
|
52
|
-
|
|
52
|
+
assert_equal([], @acro_form[:Fields].value)
|
|
53
53
|
|
|
54
54
|
@acro_form.find_root_fields!
|
|
55
55
|
assert_equal(result, @acro_form[:Fields].value.map(&:value))
|
|
@@ -115,6 +115,10 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
describe "create fields" do
|
|
118
|
+
before do
|
|
119
|
+
@acro_form = @doc.acro_form(create: true)
|
|
120
|
+
end
|
|
121
|
+
|
|
118
122
|
describe "handles the general case" do
|
|
119
123
|
it "works for names with a dot" do
|
|
120
124
|
@acro_form[:Fields] = [{T: "root"}]
|
|
@@ -134,9 +138,57 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
134
138
|
end
|
|
135
139
|
end
|
|
136
140
|
|
|
141
|
+
def applies_variable_text_properties(method, **args)
|
|
142
|
+
field = @acro_form.send(method, "field", **args, font: 'Times')
|
|
143
|
+
font_name, font_size = field.parse_default_appearance_string
|
|
144
|
+
assert_equal(:'Times-Roman', @acro_form.default_resources.font(font_name)[:BaseFont])
|
|
145
|
+
assert_equal(0, font_size)
|
|
146
|
+
|
|
147
|
+
field = @acro_form.send(method, "field", **args, font_size: 10)
|
|
148
|
+
font_name, font_size = field.parse_default_appearance_string
|
|
149
|
+
assert_equal(:Helvetica, @acro_form.default_resources.font(font_name)[:BaseFont])
|
|
150
|
+
assert_equal(10, font_size)
|
|
151
|
+
|
|
152
|
+
field = @acro_form.send(method, "field", **args, font: 'Courier', font_size: 10, align: :center)
|
|
153
|
+
font_name, font_size = field.parse_default_appearance_string
|
|
154
|
+
assert_equal(:Courier, @acro_form.default_resources.font(font_name)[:BaseFont])
|
|
155
|
+
assert_equal(10, font_size)
|
|
156
|
+
assert_equal(:center, field.text_alignment)
|
|
157
|
+
end
|
|
158
|
+
|
|
137
159
|
it "creates a text field" do
|
|
138
160
|
field = @acro_form.create_text_field("field")
|
|
139
161
|
assert_equal(:Tx, field.field_type)
|
|
162
|
+
applies_variable_text_properties(:create_text_field)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "creates a multiline text field" do
|
|
166
|
+
field = @acro_form.create_multiline_text_field("field")
|
|
167
|
+
assert_equal(:Tx, field.field_type)
|
|
168
|
+
assert(field.multiline_text_field?)
|
|
169
|
+
applies_variable_text_properties(:create_multiline_text_field)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "creates a comb text field" do
|
|
173
|
+
field = @acro_form.create_comb_text_field("field", max_chars: 9)
|
|
174
|
+
assert_equal(:Tx, field.field_type)
|
|
175
|
+
assert_equal(9, field[:MaxLen])
|
|
176
|
+
assert(field.comb_text_field?)
|
|
177
|
+
applies_variable_text_properties(:create_comb_text_field, max_chars: 9)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "creates a password field" do
|
|
181
|
+
field = @acro_form.create_password_field("field")
|
|
182
|
+
assert_equal(:Tx, field.field_type)
|
|
183
|
+
assert(field.password_field?)
|
|
184
|
+
applies_variable_text_properties(:create_password_field)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "creates a file select field" do
|
|
188
|
+
field = @acro_form.create_file_select_field("field")
|
|
189
|
+
assert_equal(:Tx, field.field_type)
|
|
190
|
+
assert(field.file_select_field?)
|
|
191
|
+
applies_variable_text_properties(:create_file_select_field)
|
|
140
192
|
end
|
|
141
193
|
|
|
142
194
|
it "creates a check box" do
|
|
@@ -150,13 +202,19 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
150
202
|
end
|
|
151
203
|
|
|
152
204
|
it "creates a combo box" do
|
|
153
|
-
field = @acro_form.create_combo_box("field")
|
|
205
|
+
field = @acro_form.create_combo_box("field", option_items: ['a', 'b', 'c'], editable: true)
|
|
154
206
|
assert(field.combo_box?)
|
|
207
|
+
assert_equal(['a', 'b', 'c'], field.option_items)
|
|
208
|
+
assert(field.flagged?(:edit))
|
|
209
|
+
applies_variable_text_properties(:create_combo_box)
|
|
155
210
|
end
|
|
156
211
|
|
|
157
212
|
it "creates a list box" do
|
|
158
|
-
field = @acro_form.create_list_box("field")
|
|
213
|
+
field = @acro_form.create_list_box("field", option_items: ['a', 'b', 'c'], multi_select: true)
|
|
159
214
|
assert(field.list_box?)
|
|
215
|
+
assert_equal(['a', 'b', 'c'], field.option_items)
|
|
216
|
+
assert(field.flagged?(:multi_select))
|
|
217
|
+
applies_variable_text_properties(:create_list_box)
|
|
160
218
|
end
|
|
161
219
|
end
|
|
162
220
|
|
|
@@ -185,15 +243,29 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
185
243
|
assert(@acro_form[:NeedAppearances])
|
|
186
244
|
end
|
|
187
245
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
246
|
+
describe "create_appearances" do
|
|
247
|
+
before do
|
|
248
|
+
@tf = @acro_form.create_text_field('test')
|
|
249
|
+
@tf.set_default_appearance_string
|
|
250
|
+
@tf.create_widget(@doc.pages.add)
|
|
251
|
+
@cb = @acro_form.create_check_box('test2')
|
|
252
|
+
@cb.create_widget(@doc.pages.add)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "creates the appearances of all field widgets if necessary" do
|
|
256
|
+
@acro_form.create_appearances
|
|
257
|
+
assert(@tf.each_widget.all? {|w| w.appearance.normal_appearance.kind_of?(HexaPDF::Stream) })
|
|
258
|
+
assert(@cb.each_widget.all? {|w| w.appearance.normal_appearance[:Yes].kind_of?(HexaPDF::Stream) })
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "force the creation of appearances if force is true" do
|
|
262
|
+
@acro_form.create_appearances
|
|
263
|
+
text_stream = @tf[:AP][:N].raw_stream
|
|
264
|
+
@acro_form.create_appearances
|
|
265
|
+
assert_same(text_stream, @tf[:AP][:N].raw_stream)
|
|
266
|
+
@acro_form.create_appearances(force: true)
|
|
267
|
+
refute_same(text_stream, @tf[:AP][:N].raw_stream)
|
|
268
|
+
end
|
|
197
269
|
end
|
|
198
270
|
|
|
199
271
|
describe "perform_validation" do
|
|
@@ -204,9 +276,9 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
|
204
276
|
|
|
205
277
|
it "checks whether the font used in /DA is available in /DR" do
|
|
206
278
|
@acro_form[:DA] = '/F2 0 Tf /F1 0 Tf'
|
|
207
|
-
refute(@acro_form.validate {|msg
|
|
279
|
+
refute(@acro_form.validate {|msg| assert_match(/DR must also be present/, msg) })
|
|
208
280
|
@acro_form.default_resources[:Font] = {}
|
|
209
|
-
refute(@acro_form.validate {|msg
|
|
281
|
+
refute(@acro_form.validate {|msg| assert_match(/font.*is not.*resource/, msg) })
|
|
210
282
|
@acro_form.default_resources[:Font][:F1] = :yes
|
|
211
283
|
assert(@acro_form.validate)
|
|
212
284
|
end
|
|
@@ -21,6 +21,56 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
|
21
21
|
assert_equal(6, @field[:MaxLen])
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
it "can be initialized as a multiline text field" do
|
|
25
|
+
@field.flag(:comb)
|
|
26
|
+
@field.initialize_as_multiline_text_field
|
|
27
|
+
assert(@field.multiline_text_field?)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "can be initialized as comb text field" do
|
|
31
|
+
@field.flag(:multiline)
|
|
32
|
+
@field.initialize_as_comb_text_field
|
|
33
|
+
assert(@field.comb_text_field?)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "can be initialized as password field" do
|
|
37
|
+
@field.flag(:multiline)
|
|
38
|
+
@field[:V] = 'test'
|
|
39
|
+
@field.initialize_as_password_field
|
|
40
|
+
assert_nil(@field[:V])
|
|
41
|
+
assert(@field.password_field?)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "can be initialized as a file select field" do
|
|
45
|
+
@field.flag(:multiline)
|
|
46
|
+
@field.initialize_as_file_select_field
|
|
47
|
+
assert(@field.file_select_field?)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "can check whether the field is a multiline text field" do
|
|
51
|
+
refute(@field.multiline_text_field?)
|
|
52
|
+
@field.flag(:multiline)
|
|
53
|
+
assert(@field.multiline_text_field?)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "can check whether the field is a comb text field" do
|
|
57
|
+
refute(@field.comb_text_field?)
|
|
58
|
+
@field.flag(:comb)
|
|
59
|
+
assert(@field.comb_text_field?)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "can check whether the field is a password field" do
|
|
63
|
+
refute(@field.password_field?)
|
|
64
|
+
@field.flag(:password)
|
|
65
|
+
assert(@field.password_field?)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "can check whether the field is a file select field" do
|
|
69
|
+
refute(@field.file_select_field?)
|
|
70
|
+
@field.flag(:file_select)
|
|
71
|
+
assert(@field.file_select_field?)
|
|
72
|
+
end
|
|
73
|
+
|
|
24
74
|
describe "field_value" do
|
|
25
75
|
it "handles unset values" do
|
|
26
76
|
assert_nil(@field.field_value)
|
|
@@ -81,14 +131,38 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
|
81
131
|
end
|
|
82
132
|
|
|
83
133
|
describe "create_appearances" do
|
|
84
|
-
|
|
134
|
+
before do
|
|
85
135
|
@doc.acro_form(create: true)
|
|
86
136
|
@field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
87
137
|
@field.set_default_appearance_string
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "creates the needed streams" do
|
|
88
141
|
@field.create_appearances
|
|
89
142
|
assert(@field[:AP][:N])
|
|
90
143
|
end
|
|
91
144
|
|
|
145
|
+
it "doesn't create a new appearance stream if the field value hasn't changed, checked per widget" do
|
|
146
|
+
@field.create_appearances
|
|
147
|
+
stream = @field[:AP][:N].raw_stream
|
|
148
|
+
@field.create_appearances
|
|
149
|
+
assert_same(stream, @field[:AP][:N].raw_stream)
|
|
150
|
+
@field.field_value = 'test'
|
|
151
|
+
refute_same(stream, @field[:AP][:N].raw_stream)
|
|
152
|
+
|
|
153
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
|
154
|
+
assert_nil(widget[:AP])
|
|
155
|
+
@field.create_appearances
|
|
156
|
+
refute_nil(widget[:AP][:N])
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "always creates a new appearance stream if force is true" do
|
|
160
|
+
@field.create_appearances
|
|
161
|
+
stream = @field[:AP][:N].raw_stream
|
|
162
|
+
@field.create_appearances(force: true)
|
|
163
|
+
refute_same(stream, @field[:AP][:N].raw_stream)
|
|
164
|
+
end
|
|
165
|
+
|
|
92
166
|
it "uses the configuration option acro_form.appearance_generator" do
|
|
93
167
|
@doc.config['acro_form.appearance_generator'] = 'NonExistent'
|
|
94
168
|
assert_raises(Exception) { @field.create_appearances }
|
|
@@ -114,6 +188,8 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
|
114
188
|
assert(@field.validate)
|
|
115
189
|
@field[:MaxLen] = 2
|
|
116
190
|
refute(@field.validate)
|
|
191
|
+
@field[:V] = nil
|
|
192
|
+
assert(@field.validate)
|
|
117
193
|
end
|
|
118
194
|
end
|
|
119
195
|
end
|
|
@@ -161,8 +161,9 @@ describe HexaPDF::Type::FontSimple do
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
describe "validation" do
|
|
164
|
+
before { assert(@font.validate) }
|
|
165
|
+
|
|
164
166
|
it "validates the existence of required keys" do
|
|
165
|
-
assert(@font.validate)
|
|
166
167
|
@font.delete(:FirstChar)
|
|
167
168
|
refute(@font.validate)
|
|
168
169
|
end
|
|
@@ -16,6 +16,12 @@ describe HexaPDF::Type::FontTrueType do
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
describe "validation" do
|
|
19
|
+
it "ignores some missing fields if the font name is one of the standard PDF fonts" do
|
|
20
|
+
@font[:BaseFont] = :'Arial,Bold'
|
|
21
|
+
[:FirstChar, :LastChar, :Widths, :FontDescriptor].each {|field| @font.delete(field) }
|
|
22
|
+
assert(@font.validate)
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
it "requires that the FontDescriptor key is set" do
|
|
20
26
|
assert(@font.validate)
|
|
21
27
|
@font.delete(:FontDescriptor)
|
|
@@ -43,13 +43,20 @@ describe HexaPDF::Type::Form do
|
|
|
43
43
|
@form.contents = 'test'
|
|
44
44
|
assert_equal('test', @form.stream)
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
it "clears the cache to make sure that a new canvas can be created" do
|
|
48
|
+
@form[:BBox] = [0, 0, 100, 100]
|
|
49
|
+
canvas = @form.canvas
|
|
50
|
+
@form.contents = ''
|
|
51
|
+
refute_same(canvas, @form.canvas)
|
|
52
|
+
end
|
|
46
53
|
end
|
|
47
54
|
|
|
48
55
|
describe "resources" do
|
|
49
56
|
it "creates the resource dictionary if it is not found" do
|
|
50
57
|
resources = @form.resources
|
|
51
58
|
assert_equal(:XXResources, resources.type)
|
|
52
|
-
assert_equal({}, resources.value)
|
|
59
|
+
assert_equal({ProcSet: [:PDF, :Text, :ImageB, :ImageC, :ImageI]}, resources.value)
|
|
53
60
|
end
|
|
54
61
|
|
|
55
62
|
it "returns the already used resource dictionary" do
|
|
@@ -277,7 +277,7 @@ describe HexaPDF::Type::Page do
|
|
|
277
277
|
page = @doc.add({Type: :Page, Parent: @doc.pages.root})
|
|
278
278
|
resources = page.resources
|
|
279
279
|
assert_equal(:XXResources, resources.type)
|
|
280
|
-
assert_equal({}, resources.value)
|
|
280
|
+
assert_equal({ProcSet: [:PDF, :Text, :ImageB, :ImageC, :ImageI]}, resources.value)
|
|
281
281
|
end
|
|
282
282
|
|
|
283
283
|
it "returns the already used resource dictionary" do
|
|
@@ -319,6 +319,13 @@ describe HexaPDF::Type::Page do
|
|
|
319
319
|
end
|
|
320
320
|
end
|
|
321
321
|
|
|
322
|
+
it "returns all ancestor page tree nodes of a page" do
|
|
323
|
+
root = @doc.add({Type: :Pages})
|
|
324
|
+
kid = @doc.add({Type: :Pages, Parent: root})
|
|
325
|
+
page = @doc.add({Type: :Page, Parent: kid})
|
|
326
|
+
assert_equal([kid, root], page.ancestor_nodes)
|
|
327
|
+
end
|
|
328
|
+
|
|
322
329
|
describe "canvas" do
|
|
323
330
|
before do
|
|
324
331
|
@page = @doc.pages.add
|
|
@@ -206,6 +206,48 @@ describe HexaPDF::Type::PageTreeNode do
|
|
|
206
206
|
end
|
|
207
207
|
end
|
|
208
208
|
|
|
209
|
+
describe "move_page" do
|
|
210
|
+
before do
|
|
211
|
+
define_multilevel_page_tree
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "moves the page to the first place" do
|
|
215
|
+
@root.move_page(@pages[1], 0)
|
|
216
|
+
assert_equal([@pages[1], @pages[0], *@pages[2..-1]], @root.each_page.to_a)
|
|
217
|
+
assert(@root.validate)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "moves the page to the correct location with a positive index" do
|
|
221
|
+
@root.move_page(1, 3)
|
|
222
|
+
assert_equal([@pages[0], @pages[2], @pages[1], *@pages[3..-1]], @root.each_page.to_a)
|
|
223
|
+
assert(@root.validate)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "moves the page to the last place" do
|
|
227
|
+
@root.move_page(1, -1)
|
|
228
|
+
assert_equal([@pages[0], *@pages[2..-1], @pages[1]], @root.each_page.to_a)
|
|
229
|
+
assert(@root.validate)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "fails if the index to the moving page is invalid" do
|
|
233
|
+
assert_raises(HexaPDF::Error) { @root.move_page(10, 0) }
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "fails if the moving page was deleted/is null" do
|
|
237
|
+
@doc.delete(@pages[0])
|
|
238
|
+
assert_raises(HexaPDF::Error) { @root.move_page(@pages[0], 3) }
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "fails if the page was not yet added to a page tree" do
|
|
242
|
+
page = @doc.add({Type: :Page})
|
|
243
|
+
assert_raises(HexaPDF::Error) { @root.move_page(page, 3) }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "fails if the page is not part of the page tree" do
|
|
247
|
+
assert_raises(HexaPDF::Error) { @kid1.move_page(@pages[6], 3) }
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
209
251
|
describe "each_page" do
|
|
210
252
|
before do
|
|
211
253
|
define_multilevel_page_tree
|
|
@@ -194,6 +194,12 @@ describe HexaPDF::Type::Resources do
|
|
|
194
194
|
assert_equal([:PDF, :Text, :ImageB, :ImageC, :ImageI], @res[:ProcSet].value)
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
+
it "handles an invalid ProcSet containing a single value instead of an array" do
|
|
198
|
+
@res[:ProcSet] = :PDF
|
|
199
|
+
@res.validate
|
|
200
|
+
assert_equal([:PDF], @res[:ProcSet].value)
|
|
201
|
+
end
|
|
202
|
+
|
|
197
203
|
it "removes invalid procedure set names from ProcSet" do
|
|
198
204
|
@res[:ProcSet] = [:PDF, :Unknown]
|
|
199
205
|
@res.validate
|