hexapdf 0.32.2 → 0.33.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 +63 -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/lib/hexapdf/cli/command.rb +5 -2
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +3 -3
- data/lib/hexapdf/composer.rb +104 -52
- data/lib/hexapdf/configuration.rb +44 -39
- data/lib/hexapdf/content/canvas.rb +393 -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 +52 -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 +6 -5
- data/lib/hexapdf/dictionary_fields.rb +42 -14
- 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 +2 -2
- 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 +167 -39
- data/lib/hexapdf/document/pages.rb +3 -2
- data/lib/hexapdf/document.rb +89 -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 +1 -1
- 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 +9 -2
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +18 -4
- data/lib/hexapdf/layout/frame.rb +30 -12
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +1 -0
- data/lib/hexapdf/layout/list_box.rb +17 -1
- data/lib/hexapdf/layout/page_style.rb +4 -4
- data/lib/hexapdf/layout/style.rb +18 -3
- data/lib/hexapdf/layout/table_box.rb +682 -0
- data/lib/hexapdf/layout/text_box.rb +5 -3
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +12 -4
- 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 +4 -2
- 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/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +1 -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 +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +1 -1
- data/lib/hexapdf/type/cid_font.rb +3 -3
- 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 +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 +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/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +19 -10
- data/lib/hexapdf/type/page_label.rb +1 -1
- 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/utils/pdf_doc_encoding.rb +1 -1
- 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 +0 -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 +98 -0
- 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 +1 -1
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +14 -14
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +5 -0
- data/test/hexapdf/layout/test_list_box.rb +40 -6
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +50 -0
- data/test/hexapdf/layout/test_table_box.rb +722 -0
- data/test/hexapdf/layout/test_text_box.rb +18 -0
- data/test/hexapdf/layout/test_text_layouter.rb +4 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +1 -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/test_page.rb +18 -4
- metadata +17 -8
|
@@ -50,7 +50,12 @@ module HexaPDF
|
|
|
50
50
|
# field object is automatically assigned a stateless converter object that knows if data read
|
|
51
51
|
# from a PDF file potentially needs to be converted into a standard format before use.
|
|
52
52
|
#
|
|
53
|
-
# The
|
|
53
|
+
# The available converter objects can be retrieved or modified via the Field.converters method.
|
|
54
|
+
#
|
|
55
|
+
#
|
|
56
|
+
# == Converter Objects
|
|
57
|
+
#
|
|
58
|
+
# The methods that need to be implemented by a stateless converter objects are the following:
|
|
54
59
|
#
|
|
55
60
|
# usable_for?(type)::
|
|
56
61
|
# Should return +true+ if the converter is usable for the given type.
|
|
@@ -63,19 +68,28 @@ module HexaPDF
|
|
|
63
68
|
# Should return the +converted+ data if conversion is possible and +nil+ otherwise. The +type+
|
|
64
69
|
# argument is the result of the Field#type method call and +document+ is the HexaPDF::Document
|
|
65
70
|
# for which the data should be converted.
|
|
71
|
+
#
|
|
72
|
+
# Since a converter usually doesn't need to store any data, it can be implemented as a module
|
|
73
|
+
# using class methods. This is how it is done for the built-in converter objects.
|
|
66
74
|
module DictionaryFields
|
|
67
75
|
|
|
68
76
|
# This constant should *always* be used for boolean fields.
|
|
77
|
+
#
|
|
78
|
+
# See: PDF2.0 s7.3.2
|
|
69
79
|
Boolean = [TrueClass, FalseClass].freeze
|
|
70
80
|
|
|
71
81
|
# PDFByteString is used for defining fields with strings in binary encoding.
|
|
82
|
+
#
|
|
83
|
+
# See: PDF2.0 s7.9.2.4
|
|
72
84
|
PDFByteString = Class.new { private_class_method :new }
|
|
73
85
|
|
|
74
86
|
# PDFDate is used for defining fields which store a date object as a string.
|
|
87
|
+
#
|
|
88
|
+
# See: PDF2.0 s7.9.4
|
|
75
89
|
PDFDate = Class.new { private_class_method :new }
|
|
76
90
|
|
|
77
|
-
# A
|
|
78
|
-
#
|
|
91
|
+
# A field contains information about one field of a structured PDF object and this information
|
|
92
|
+
# comes directly from the PDF specification.
|
|
79
93
|
#
|
|
80
94
|
# By incorporating this field information into HexaPDF it is possible to do many things
|
|
81
95
|
# automatically, like checking for the correct minimum PDF version to use or converting a date
|
|
@@ -91,9 +105,9 @@ module HexaPDF
|
|
|
91
105
|
|
|
92
106
|
# Returns the converter for the given +type+ specification.
|
|
93
107
|
#
|
|
94
|
-
# The converter list is checked for a suitable converter from the front to
|
|
95
|
-
# two converters could potentially be used for the same type, the one that
|
|
96
|
-
# is used.
|
|
108
|
+
# The converter list from #converters is checked for a suitable converter from the front to
|
|
109
|
+
# the back. So if two converters could potentially be used for the same type, the one that
|
|
110
|
+
# appears earlier is used.
|
|
97
111
|
def self.converter_for(type)
|
|
98
112
|
@converters.find {|converter| converter.usable_for?(type) }
|
|
99
113
|
end
|
|
@@ -148,8 +162,7 @@ module HexaPDF
|
|
|
148
162
|
!@default.nil?
|
|
149
163
|
end
|
|
150
164
|
|
|
151
|
-
# Returns a duplicated default value
|
|
152
|
-
# account.
|
|
165
|
+
# Returns a duplicated default value.
|
|
153
166
|
def default
|
|
154
167
|
@default.dup
|
|
155
168
|
end
|
|
@@ -171,8 +184,10 @@ module HexaPDF
|
|
|
171
184
|
|
|
172
185
|
end
|
|
173
186
|
|
|
174
|
-
# Converter module for fields of type Dictionary and its subclasses.
|
|
175
|
-
#
|
|
187
|
+
# Converter module for fields of type Dictionary and its subclasses.
|
|
188
|
+
#
|
|
189
|
+
# The first class in the type array of the field is used for the conversion. Symbol names for
|
|
190
|
+
# classes may also be used since they are automatically resolved.
|
|
176
191
|
module DictionaryConverter
|
|
177
192
|
|
|
178
193
|
# This converter is used when either a Symbol is provided as +type+ (for lazy loading) or
|
|
@@ -199,6 +214,8 @@ module HexaPDF
|
|
|
199
214
|
end
|
|
200
215
|
|
|
201
216
|
# Converter module for fields of type PDFArray.
|
|
217
|
+
#
|
|
218
|
+
# This converter ensures that arrays are wrapped by the PDFArray class for more convenient use.
|
|
202
219
|
module ArrayConverter
|
|
203
220
|
|
|
204
221
|
# This converter is usable if the +type+ is PDFArray.
|
|
@@ -220,6 +237,8 @@ module HexaPDF
|
|
|
220
237
|
end
|
|
221
238
|
|
|
222
239
|
# Converter module for string fields to automatically convert a string into UTF-8 encoding.
|
|
240
|
+
#
|
|
241
|
+
# See: PDF2.0 s7.9.2
|
|
223
242
|
module StringConverter
|
|
224
243
|
|
|
225
244
|
# This converter is usable if the +type+ is the String class.
|
|
@@ -231,8 +250,8 @@ module HexaPDF
|
|
|
231
250
|
def self.additional_types
|
|
232
251
|
end
|
|
233
252
|
|
|
234
|
-
# Converts the string into UTF-8 encoding, assuming it is a binary string.
|
|
235
|
-
#
|
|
253
|
+
# Converts the string into UTF-8 encoding, assuming it is a binary string (i.e. one not yet
|
|
254
|
+
# converted). Otherwise returns +nil+.
|
|
236
255
|
def self.convert(str, _type, document)
|
|
237
256
|
return unless str.kind_of?(String) && str.encoding == Encoding::BINARY
|
|
238
257
|
|
|
@@ -252,6 +271,8 @@ module HexaPDF
|
|
|
252
271
|
|
|
253
272
|
# Converter module for binary string fields to automatically convert a string into binary
|
|
254
273
|
# encoding.
|
|
274
|
+
#
|
|
275
|
+
# See: PDF2.0 s7.9.2.4
|
|
255
276
|
module PDFByteStringConverter
|
|
256
277
|
|
|
257
278
|
# This converter is usable if the +type+ is PDFByteString.
|
|
@@ -279,7 +300,7 @@ module HexaPDF
|
|
|
279
300
|
# date format. When converting from a date string to a Time object, this is taken into
|
|
280
301
|
# account.
|
|
281
302
|
#
|
|
282
|
-
# See:
|
|
303
|
+
# See: PDF2.0 s7.9.4, ADB1.7 3.8.3
|
|
283
304
|
module DateConverter
|
|
284
305
|
|
|
285
306
|
# This converter is usable if the +type+ is PDFDate.
|
|
@@ -297,6 +318,8 @@ module HexaPDF
|
|
|
297
318
|
|
|
298
319
|
# Checks if the given object is a string and converts into a Time object if possible.
|
|
299
320
|
# Otherwise returns +nil+.
|
|
321
|
+
#
|
|
322
|
+
# This method takes some forms of mangled date strings into account that were found in the wild.
|
|
300
323
|
def self.convert(str, _type, _document)
|
|
301
324
|
return unless str.kind_of?(String) && (m = str.match(DATE_RE))
|
|
302
325
|
|
|
@@ -318,6 +341,8 @@ module HexaPDF
|
|
|
318
341
|
|
|
319
342
|
# Converter module for file specification fields. A file specification in string format is
|
|
320
343
|
# converted to the corresponding file specification dictionary.
|
|
344
|
+
#
|
|
345
|
+
# See: PDF2.0 s7.11, HexaPDF::Type::FileSpecification
|
|
321
346
|
module FileSpecificationConverter
|
|
322
347
|
|
|
323
348
|
# This converter is only used for the :Filespec type.
|
|
@@ -343,6 +368,8 @@ module HexaPDF
|
|
|
343
368
|
end
|
|
344
369
|
|
|
345
370
|
# Converter module for fields of type Rectangle.
|
|
371
|
+
#
|
|
372
|
+
# See: PDF2.0 s7.9.5
|
|
346
373
|
module RectangleConverter
|
|
347
374
|
|
|
348
375
|
# This converter is usable if the +type+ is Rectangle.
|
|
@@ -355,7 +382,8 @@ module HexaPDF
|
|
|
355
382
|
Array
|
|
356
383
|
end
|
|
357
384
|
|
|
358
|
-
# Wraps a given array
|
|
385
|
+
# Wraps a given array using the Rectangle class or as a Null value if the array is invalid.
|
|
386
|
+
# Otherwise returns +nil+.
|
|
359
387
|
def self.convert(data, _type, document)
|
|
360
388
|
return unless data.kind_of?(Array) || data.kind_of?(HexaPDF::PDFArray)
|
|
361
389
|
data.empty? ? document.wrap(nil) : document.wrap(data, type: Rectangle)
|
|
@@ -41,9 +41,9 @@ module HexaPDF
|
|
|
41
41
|
module DigitalSignature
|
|
42
42
|
|
|
43
43
|
# The signature handler for PKCS#7 a.k.a. CMS signatures. Those include, for example, the
|
|
44
|
-
# adbe.pkcs7.detached sub-
|
|
44
|
+
# adbe.pkcs7.detached and ETSI.CAdES.detached sub-filters.
|
|
45
45
|
#
|
|
46
|
-
# See:
|
|
46
|
+
# See: PDF2.0 s12.8.3.3
|
|
47
47
|
class CMSHandler < Handler
|
|
48
48
|
|
|
49
49
|
# Creates a new signature handler for the given signature dictionary.
|
|
@@ -41,7 +41,7 @@ module HexaPDF
|
|
|
41
41
|
|
|
42
42
|
# The base signature handler providing common functionality.
|
|
43
43
|
#
|
|
44
|
-
# Specific signature
|
|
44
|
+
# Specific signature handlers need to override methods if necessary and implement the needed
|
|
45
45
|
# ones that don't have a default implementation.
|
|
46
46
|
class Handler
|
|
47
47
|
|
|
@@ -43,10 +43,9 @@ module HexaPDF
|
|
|
43
43
|
# The signature handler for PKCS#1 based sub-filters, the only being the adbe.x509.rsa_sha1
|
|
44
44
|
# sub-filter.
|
|
45
45
|
#
|
|
46
|
-
#
|
|
47
|
-
# implementation for reading and verifying signatures.
|
|
46
|
+
# Note that PKCS#1 signatures are deprecated with PDF 2.0.
|
|
48
47
|
#
|
|
49
|
-
# See:
|
|
48
|
+
# See: PDF2.0 s12.8.3.2
|
|
50
49
|
class PKCS1Handler < Handler
|
|
51
50
|
|
|
52
51
|
# Returns the certificate chain.
|
|
@@ -50,10 +50,10 @@ module HexaPDF
|
|
|
50
50
|
# differ from use-case to use-case. Therefore HexaPDF provides as much diagnostic information as
|
|
51
51
|
# possible so that the user can decide whether a signature is valid.
|
|
52
52
|
#
|
|
53
|
-
# By defining a custom signature handler one is able to also
|
|
54
|
-
# verification.
|
|
53
|
+
# By defining a custom signature handler based on BaseHandler or CMSHandler one is able to also
|
|
54
|
+
# customize the signature verification.
|
|
55
55
|
#
|
|
56
|
-
# See:
|
|
56
|
+
# See: PDF2.0 s12.8.1, HexaPDF::Type::AcroForm::SignatureField
|
|
57
57
|
class Signature < Dictionary
|
|
58
58
|
|
|
59
59
|
# Represents a transform parameters dictionary.
|
|
@@ -61,7 +61,7 @@ module HexaPDF
|
|
|
61
61
|
# The allowed fields depend on the transform method, so not all fields are available all the
|
|
62
62
|
# time.
|
|
63
63
|
#
|
|
64
|
-
# See:
|
|
64
|
+
# See: PDF2.0 s12.8.2.2, s12.8.2.3, s12.8.2.4
|
|
65
65
|
class TransformParams < Dictionary
|
|
66
66
|
|
|
67
67
|
define_type :TransformParams
|
|
@@ -117,7 +117,7 @@ module HexaPDF
|
|
|
117
117
|
|
|
118
118
|
# Represents a signature reference dictionary.
|
|
119
119
|
#
|
|
120
|
-
# See:
|
|
120
|
+
# See: PDF2.0 s12.8.1, HexaPDF::DigitalSignature::Signature
|
|
121
121
|
class SignatureReference < Dictionary
|
|
122
122
|
|
|
123
123
|
define_type :SigRef
|
|
@@ -202,7 +202,7 @@ module HexaPDF
|
|
|
202
202
|
self[:Contents]
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
# Returns the signed data as indicated by the /ByteRange entry as
|
|
205
|
+
# Returns the signed data as indicated by the /ByteRange entry as binary string.
|
|
206
206
|
def signed_data
|
|
207
207
|
unless document.revisions.parser
|
|
208
208
|
raise HexaPDF::Error, "Can't load signed data without existing PDF file"
|
|
@@ -42,7 +42,7 @@ require 'hexapdf/error'
|
|
|
42
42
|
module HexaPDF
|
|
43
43
|
module DigitalSignature
|
|
44
44
|
|
|
45
|
-
# This class provides methods for interacting with digital signatures of a PDF file.
|
|
45
|
+
# This class provides methods for interacting with digital signatures of a PDF file. It is used
|
|
46
46
|
# through HexaPDF::Document#signatures.
|
|
47
47
|
class Signatures
|
|
48
48
|
|
|
@@ -56,7 +56,7 @@ module HexaPDF
|
|
|
56
56
|
# Creates a signing handler with the given attributes and returns it.
|
|
57
57
|
#
|
|
58
58
|
# A signing handler name is mapped to a class via the 'signature.signing_handler'
|
|
59
|
-
# configuration option. The default signing handler is DefaultHandler.
|
|
59
|
+
# configuration option. The default signing handler is Signing::DefaultHandler.
|
|
60
60
|
def signing_handler(name: :default, **attributes)
|
|
61
61
|
handler = @document.config.constantize('signature.signing_handler', name) do
|
|
62
62
|
raise HexaPDF::Error, "No signing handler named '#{name}' is available"
|
|
@@ -90,19 +90,12 @@ module HexaPDF
|
|
|
90
90
|
#
|
|
91
91
|
# +handler+::
|
|
92
92
|
# The signing handler that provides the necessary methods for signing and adjusting the
|
|
93
|
-
# signature and signature field objects to one's liking, see #
|
|
93
|
+
# signature and signature field objects to one's liking, see #signing_handler and
|
|
94
|
+
# Signing::DefaultHandler.
|
|
94
95
|
#
|
|
95
96
|
# +write_options+::
|
|
96
97
|
# The key-value pairs of this hash will be passed on to the HexaPDF::Document#write
|
|
97
98
|
# method. Note that +incremental+ will be automatically set to ensure proper behaviour.
|
|
98
|
-
#
|
|
99
|
-
# The used signature object will have the following default values set:
|
|
100
|
-
#
|
|
101
|
-
# /Filter:: /Adobe.PPKLite
|
|
102
|
-
# /SubFilter:: /adbe.pkcs7.detached
|
|
103
|
-
# /M:: The current time.
|
|
104
|
-
#
|
|
105
|
-
# These values can be overridden in the #finalize_objects method of the signature handler.
|
|
106
99
|
def add(file_or_io, handler, signature: nil, write_options: {})
|
|
107
100
|
if signature && signature.type != :Sig
|
|
108
101
|
signature_field = signature
|
|
@@ -123,6 +116,14 @@ module HexaPDF
|
|
|
123
116
|
signature_field.create_widget(@document.pages[0], Rect: [0, 0, 0, 0])
|
|
124
117
|
end
|
|
125
118
|
|
|
119
|
+
# Work-around for Adobe Acrobat to recognize images (https://stackoverflow.com/a/73011571/8203541)
|
|
120
|
+
signature_field.each_widget do |widget|
|
|
121
|
+
next unless (resources = widget.appearance&.resources)
|
|
122
|
+
resources[:XObject]&.each do |_name, entry|
|
|
123
|
+
entry[:Resources] ||= {}
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
126
127
|
# Prepare signature object
|
|
127
128
|
handler.finalize_objects(signature_field, signature)
|
|
128
129
|
signature[:ByteRange] = [0, 1_000_000_000_000, 1_000_000_000_000, 1_000_000_000_000]
|
|
@@ -178,7 +179,7 @@ module HexaPDF
|
|
|
178
179
|
# signatures.each {|signature| block } -> signatures
|
|
179
180
|
# signatures.each -> Enumerator
|
|
180
181
|
#
|
|
181
|
-
# Iterates over all signatures in the order they are found.
|
|
182
|
+
# Iterates over all signatures in the order they are found in the PDF.
|
|
182
183
|
def each
|
|
183
184
|
return to_enum(__method__) unless block_given?
|
|
184
185
|
|
|
@@ -158,12 +158,18 @@ module HexaPDF
|
|
|
158
158
|
#
|
|
159
159
|
# If the certificate is provided, HexaPDF creates the signature object. Otherwise the
|
|
160
160
|
# #external_signing callable object has to create it.
|
|
161
|
+
#
|
|
162
|
+
# See the class documentation section "Signing Modes" on how #certificate, #key and
|
|
163
|
+
# #external_signing play together.
|
|
161
164
|
attr_accessor :certificate
|
|
162
165
|
|
|
163
166
|
# The private key for the #certificate.
|
|
164
167
|
#
|
|
165
168
|
# If the key is provided, HexaPDF does the signing. Otherwise the #external_signing callable
|
|
166
169
|
# object has to sign the data.
|
|
170
|
+
#
|
|
171
|
+
# See the class documentation section "Signing Modes" on how #certificate, #key and
|
|
172
|
+
# #external_signing play together.
|
|
167
173
|
attr_accessor :key
|
|
168
174
|
|
|
169
175
|
# The certificate chain that should be embedded in the PDF; usually contains all
|
|
@@ -191,21 +197,24 @@ module HexaPDF
|
|
|
191
197
|
# * If #certificate is set and #key is not, it is just used for signing. Here it needs to
|
|
192
198
|
# accept the used digest algorithm and the already digested data as arguments and return
|
|
193
199
|
# the signature.
|
|
200
|
+
#
|
|
201
|
+
# Also dee the class documentation section "Signing Modes" on how #certificate, #key and
|
|
202
|
+
# #external_signing play together.
|
|
194
203
|
attr_accessor :external_signing
|
|
195
204
|
|
|
196
|
-
# The reason for signing. If used, will be set on the signature
|
|
205
|
+
# The reason for signing. If used, will be set on the signature dictionary.
|
|
197
206
|
attr_accessor :reason
|
|
198
207
|
|
|
199
|
-
# The signing location. If used, will be set on the signature
|
|
208
|
+
# The signing location. If used, will be set on the signature dictionary.
|
|
200
209
|
attr_accessor :location
|
|
201
210
|
|
|
202
|
-
# The contact information. If used, will be set on the signature
|
|
211
|
+
# The contact information. If used, will be set on the signature dictionary.
|
|
203
212
|
attr_accessor :contact_info
|
|
204
213
|
|
|
205
214
|
# The size of the serialized signature that should be reserved.
|
|
206
215
|
#
|
|
207
|
-
# If this attribute
|
|
208
|
-
#
|
|
216
|
+
# If this attribute is not set, an empty string will be signed using #sign to determine the
|
|
217
|
+
# signature size.
|
|
209
218
|
#
|
|
210
219
|
# The size needs to be at least as big as the final signature, otherwise signing results in
|
|
211
220
|
# an error.
|
|
@@ -55,7 +55,7 @@ module HexaPDF
|
|
|
55
55
|
#
|
|
56
56
|
# Additionally, only RSA signatures are currently supported!
|
|
57
57
|
#
|
|
58
|
-
# See:
|
|
58
|
+
# See: PDF2.0 s12.8.3.3, PDF2.0 s12.8.3.4, RFC5652, ETSI TS 102 778 Parts 1-4
|
|
59
59
|
class SignedDataCreator
|
|
60
60
|
|
|
61
61
|
# Creates a SignedDataCreator, sets the given attributes if they are not nil and then calls
|
|
@@ -88,8 +88,6 @@ module HexaPDF
|
|
|
88
88
|
attr_accessor :timestamp_handler
|
|
89
89
|
|
|
90
90
|
# Creates a new SignedData object.
|
|
91
|
-
#
|
|
92
|
-
# Use the attribute accessor methods to set the required attributes.
|
|
93
91
|
def initialize
|
|
94
92
|
@certificate = nil
|
|
95
93
|
@key = nil
|
|
@@ -170,7 +168,7 @@ module HexaPDF
|
|
|
170
168
|
|
|
171
169
|
# Digests the data and then signs it using the assigned key, or if the key is not available,
|
|
172
170
|
# by yielding to the caller.
|
|
173
|
-
def digest_and_sign_data(data)
|
|
171
|
+
def digest_and_sign_data(data) #:yields: digest_algorithm, hashed_data
|
|
174
172
|
hash = OpenSSL::Digest.digest(@digest_algorithm, data)
|
|
175
173
|
if @key
|
|
176
174
|
@key.sign_raw(@digest_algorithm, hash)
|
|
@@ -75,19 +75,19 @@ module HexaPDF
|
|
|
75
75
|
# The size of the serialized signature that should be reserved.
|
|
76
76
|
#
|
|
77
77
|
# If this attribute has not been set, an empty string will be signed using #sign to
|
|
78
|
-
# determine the signature size
|
|
78
|
+
# determine the signature size. Note thtat this will contact the TSA server!
|
|
79
79
|
#
|
|
80
80
|
# The size needs to be at least as big as the final signature, otherwise signing results in
|
|
81
81
|
# an error.
|
|
82
82
|
attr_writer :signature_size
|
|
83
83
|
|
|
84
|
-
# The reason for timestamping. If used, will be set on the signature
|
|
84
|
+
# The reason for timestamping. If used, will be set on the signature dictionary.
|
|
85
85
|
attr_accessor :reason
|
|
86
86
|
|
|
87
|
-
# The timestamping location. If used, will be set on the signature
|
|
87
|
+
# The timestamping location. If used, will be set on the signature dictionary.
|
|
88
88
|
attr_accessor :location
|
|
89
89
|
|
|
90
|
-
# The contact information. If used, will be set on the signature
|
|
90
|
+
# The contact information. If used, will be set on the signature dictionary.
|
|
91
91
|
attr_accessor :contact_info
|
|
92
92
|
|
|
93
93
|
# Creates a new TimestampHandler with the given attributes.
|
|
@@ -41,6 +41,10 @@ module HexaPDF
|
|
|
41
41
|
|
|
42
42
|
# This module contains everything related to the signing of a PDF document, i.e. signing
|
|
43
43
|
# handlers and the actual code for signing.
|
|
44
|
+
#
|
|
45
|
+
# * The DefaultHandler is the standard signing handler and should be sufficient for most cases.
|
|
46
|
+
# * The TimestampHandler is used for timestamping purposes.
|
|
47
|
+
# * The SignedDataCreator provides the functionality to create custom CMS signed data objects.
|
|
44
48
|
module Signing
|
|
45
49
|
|
|
46
50
|
autoload(:DefaultHandler, 'hexapdf/digital_signature/signing/default_handler')
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
module HexaPDF
|
|
38
38
|
module DigitalSignature
|
|
39
39
|
|
|
40
|
-
# Holds the result
|
|
40
|
+
# Holds the result of verifying a signature.
|
|
41
41
|
class VerificationResult
|
|
42
42
|
|
|
43
43
|
# :nodoc:
|
|
@@ -47,7 +47,7 @@ module HexaPDF
|
|
|
47
47
|
error: {info: -1, warning: -1, error: 0},
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
# This structure represents a single status message, containing the type (:info, :warning,
|
|
50
|
+
# This structure represents a single status message, containing the type (:info, :warning, or
|
|
51
51
|
# :error) and the content of the message.
|
|
52
52
|
Message = Struct.new(:type, :content) do
|
|
53
53
|
def <=>(other)
|
|
@@ -39,9 +39,14 @@ module HexaPDF
|
|
|
39
39
|
# PDF documents can be signed using digital signatures. Such a signature can be used to
|
|
40
40
|
# authenticate the identity of the signer and the contents of the documents.
|
|
41
41
|
#
|
|
42
|
-
# This module contains all code related to digital signatures in PDF
|
|
42
|
+
# This module contains all code related to digital signatures in PDF:
|
|
43
43
|
#
|
|
44
|
-
#
|
|
44
|
+
# * Signatures provides the convenience interface accessible via Document#signatures.
|
|
45
|
+
# * Signature implements the PDF signature dictionary.
|
|
46
|
+
# * BaseHandler, CMSHandler and PKCS1Handler are used for verifying existing signatures.
|
|
47
|
+
# * The Signing module implements the functionality for creating digital signatures.
|
|
48
|
+
#
|
|
49
|
+
# See: PDF2.0 s12.8
|
|
45
50
|
module DigitalSignature
|
|
46
51
|
|
|
47
52
|
autoload(:Signatures, 'hexapdf/digital_signature/signatures')
|
|
@@ -49,7 +49,7 @@ module HexaPDF
|
|
|
49
49
|
# may be named and later referenced through the name. This class allows to create destinations
|
|
50
50
|
# with or without a name.
|
|
51
51
|
#
|
|
52
|
-
# See:
|
|
52
|
+
# See: PDF2.0 s12.3.2
|
|
53
53
|
class Destinations
|
|
54
54
|
|
|
55
55
|
# Wraps an explicit destination array to allow easy access to query its properties.
|
|
@@ -127,8 +127,9 @@ module HexaPDF
|
|
|
127
127
|
destination[2..-1].all? {|item| item.nil? || item.kind_of?(Numeric) }
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
# Creates a new Destination for the given +destination+ which may be an
|
|
131
|
-
# array or a dictionary with a /D entry (as allowed for a named
|
|
130
|
+
# Creates a new Destination for the given +destination+ specification which may be an
|
|
131
|
+
# explicit destination array or a dictionary with a /D entry (as allowed for a named
|
|
132
|
+
# destination).
|
|
132
133
|
def initialize(destination)
|
|
133
134
|
@destination = if destination.kind_of?(HexaPDF::Dictionary) || destination.kind_of?(Hash)
|
|
134
135
|
destination[:D]
|
|
@@ -235,15 +236,15 @@ module HexaPDF
|
|
|
235
236
|
# destinations.use_or_create(type:, page, **options) -> destination
|
|
236
237
|
#
|
|
237
238
|
# Uses the given destination name/array or creates a destination array based on the given
|
|
238
|
-
#
|
|
239
|
+
# arguments.
|
|
239
240
|
#
|
|
240
241
|
# This is the main utility method for other parts of HexaPDF for getting a valid destination
|
|
241
|
-
# array based on various different types of the given
|
|
242
|
+
# array based on various different types of the given arguments:
|
|
242
243
|
#
|
|
243
244
|
# String::
|
|
244
245
|
#
|
|
245
246
|
# If a string is provided, it is assumed to be a named destination. If the named
|
|
246
|
-
# destination exists, the
|
|
247
|
+
# destination exists, the destination itself is returned. Otherwise an error is raised.
|
|
247
248
|
#
|
|
248
249
|
# Array::
|
|
249
250
|
#
|
|
@@ -438,7 +439,7 @@ module HexaPDF
|
|
|
438
439
|
# :call-seq:
|
|
439
440
|
# destinations.add(name, destination)
|
|
440
441
|
#
|
|
441
|
-
# Adds the given +destination+ under +name+ to the destinations name tree.
|
|
442
|
+
# Adds the given +destination+ under +name+ (a String) to the destinations name tree.
|
|
442
443
|
#
|
|
443
444
|
# If the name does already exist, an error is raised.
|
|
444
445
|
def add(name, destination)
|
|
@@ -448,8 +449,8 @@ module HexaPDF
|
|
|
448
449
|
# :call-seq:
|
|
449
450
|
# destinations.delete(name) -> destination
|
|
450
451
|
#
|
|
451
|
-
# Deletes the
|
|
452
|
-
# destination was registered under that name.
|
|
452
|
+
# Deletes the destination specified via +name+ (a String) from the destinations name tree and
|
|
453
|
+
# returns it or +nil+ if no destination was registered under that name.
|
|
453
454
|
def delete(name)
|
|
454
455
|
destinations.delete_entry(name)
|
|
455
456
|
end
|
|
@@ -487,8 +488,8 @@ module HexaPDF
|
|
|
487
488
|
# :call-seq:
|
|
488
489
|
# destinations[name] -> destination
|
|
489
490
|
#
|
|
490
|
-
# Returns the destination registered under the given +name+ or +nil+ if no
|
|
491
|
-
# registered under that name.
|
|
491
|
+
# Returns the destination registered under the given +name+ (a String) or +nil+ if no
|
|
492
|
+
# destination was registered under that name.
|
|
492
493
|
def [](name)
|
|
493
494
|
destinations.find_entry(name)
|
|
494
495
|
end
|
|
@@ -96,7 +96,7 @@ module HexaPDF
|
|
|
96
96
|
#
|
|
97
97
|
# Iterates over indirect file specification dictionaries of the PDF.
|
|
98
98
|
#
|
|
99
|
-
# By default, only the file specifications in their standard locations,
|
|
99
|
+
# By default, only the file specifications in their standard locations, i.e. in the
|
|
100
100
|
# EmbeddedFiles name tree and in the page annotations, are returned. If the +search+ option is
|
|
101
101
|
# +true+, then all indirect objects are searched for file specification dictionaries which can
|
|
102
102
|
# be much slower.
|
|
@@ -53,7 +53,7 @@ module HexaPDF
|
|
|
53
53
|
# :call-seq:
|
|
54
54
|
# fonts.add(name, **options) -> font
|
|
55
55
|
#
|
|
56
|
-
# Adds the font to the document and returns it (using the loaders specified with the
|
|
56
|
+
# Adds the font to the document and returns it (using the font loaders specified with the
|
|
57
57
|
# configuration option 'font_loaders').
|
|
58
58
|
#
|
|
59
59
|
# If a font with the same parameters has been loaded before, the cached font object is used.
|