hexapdf 0.32.1 → 0.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -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/cli.rb +4 -0
- 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 +8 -8
- 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 +7 -3
- 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_parser.rb +1 -1
- 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_object_stream.rb +9 -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.
|