hexapdf 0.32.2 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/examples/026-optional_content.rb +55 -0
  19. data/examples/027-composer_optional_content.rb +83 -0
  20. data/lib/hexapdf/cli/command.rb +12 -3
  21. data/lib/hexapdf/cli/fonts.rb +1 -1
  22. data/lib/hexapdf/cli/form.rb +5 -5
  23. data/lib/hexapdf/cli/inspect.rb +5 -7
  24. data/lib/hexapdf/composer.rb +106 -53
  25. data/lib/hexapdf/configuration.rb +65 -40
  26. data/lib/hexapdf/content/canvas.rb +445 -267
  27. data/lib/hexapdf/content/color_space.rb +72 -25
  28. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  31. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  32. data/lib/hexapdf/content/graphic_object.rb +6 -7
  33. data/lib/hexapdf/content/graphics_state.rb +54 -45
  34. data/lib/hexapdf/content/operator.rb +54 -54
  35. data/lib/hexapdf/content/parser.rb +2 -2
  36. data/lib/hexapdf/content/processor.rb +15 -15
  37. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  38. data/lib/hexapdf/content.rb +5 -0
  39. data/lib/hexapdf/dictionary.rb +7 -5
  40. data/lib/hexapdf/dictionary_fields.rb +43 -16
  41. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  42. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  43. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  44. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  45. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  46. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  47. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  48. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  49. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  50. data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
  51. data/lib/hexapdf/digital_signature.rb +7 -2
  52. data/lib/hexapdf/document/destinations.rb +12 -11
  53. data/lib/hexapdf/document/files.rb +1 -1
  54. data/lib/hexapdf/document/fonts.rb +1 -1
  55. data/lib/hexapdf/document/layout.rb +170 -39
  56. data/lib/hexapdf/document/pages.rb +4 -3
  57. data/lib/hexapdf/document.rb +96 -55
  58. data/lib/hexapdf/encryption/aes.rb +5 -5
  59. data/lib/hexapdf/encryption/arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  61. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/identity.rb +1 -1
  63. data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
  64. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  65. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  66. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  67. data/lib/hexapdf/encryption.rb +7 -2
  68. data/lib/hexapdf/error.rb +18 -0
  69. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  70. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  71. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  72. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  73. data/lib/hexapdf/filter/pass_through.rb +1 -1
  74. data/lib/hexapdf/filter/predictor.rb +1 -1
  75. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  76. data/lib/hexapdf/filter.rb +55 -6
  77. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  78. data/lib/hexapdf/font/cmap.rb +1 -1
  79. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  82. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  83. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  84. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  85. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  86. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  87. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  88. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  89. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  90. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  91. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  92. data/lib/hexapdf/font_loader.rb +3 -0
  93. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  94. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  95. data/lib/hexapdf/image_loader/png.rb +2 -2
  96. data/lib/hexapdf/image_loader.rb +1 -1
  97. data/lib/hexapdf/importer.rb +13 -0
  98. data/lib/hexapdf/layout/box.rb +32 -5
  99. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  100. data/lib/hexapdf/layout/column_box.rb +20 -5
  101. data/lib/hexapdf/layout/frame.rb +53 -18
  102. data/lib/hexapdf/layout/image_box.rb +5 -0
  103. data/lib/hexapdf/layout/inline_box.rb +21 -9
  104. data/lib/hexapdf/layout/list_box.rb +50 -20
  105. data/lib/hexapdf/layout/page_style.rb +6 -5
  106. data/lib/hexapdf/layout/style.rb +64 -9
  107. data/lib/hexapdf/layout/table_box.rb +684 -0
  108. data/lib/hexapdf/layout/text_box.rb +12 -3
  109. data/lib/hexapdf/layout/text_fragment.rb +29 -3
  110. data/lib/hexapdf/layout/text_layouter.rb +32 -8
  111. data/lib/hexapdf/layout.rb +1 -0
  112. data/lib/hexapdf/name_tree_node.rb +1 -1
  113. data/lib/hexapdf/number_tree_node.rb +1 -1
  114. data/lib/hexapdf/object.rb +18 -7
  115. data/lib/hexapdf/parser.rb +7 -7
  116. data/lib/hexapdf/pdf_array.rb +1 -1
  117. data/lib/hexapdf/rectangle.rb +1 -1
  118. data/lib/hexapdf/reference.rb +1 -1
  119. data/lib/hexapdf/revision.rb +1 -1
  120. data/lib/hexapdf/revisions.rb +3 -3
  121. data/lib/hexapdf/serializer.rb +15 -15
  122. data/lib/hexapdf/stream.rb +5 -4
  123. data/lib/hexapdf/tokenizer.rb +14 -14
  124. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  125. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  128. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  130. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  131. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  132. data/lib/hexapdf/type/acro_form.rb +1 -1
  133. data/lib/hexapdf/type/action.rb +1 -1
  134. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  135. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  136. data/lib/hexapdf/type/actions/launch.rb +1 -1
  137. data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
  138. data/lib/hexapdf/type/actions/uri.rb +1 -1
  139. data/lib/hexapdf/type/actions.rb +2 -1
  140. data/lib/hexapdf/type/annotation.rb +3 -3
  141. data/lib/hexapdf/type/annotations/link.rb +1 -1
  142. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  143. data/lib/hexapdf/type/annotations/text.rb +2 -3
  144. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  145. data/lib/hexapdf/type/annotations.rb +1 -1
  146. data/lib/hexapdf/type/catalog.rb +11 -2
  147. data/lib/hexapdf/type/cid_font.rb +18 -4
  148. data/lib/hexapdf/type/embedded_file.rb +1 -1
  149. data/lib/hexapdf/type/file_specification.rb +2 -2
  150. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  151. data/lib/hexapdf/type/font_simple.rb +2 -2
  152. data/lib/hexapdf/type/font_type0.rb +3 -3
  153. data/lib/hexapdf/type/font_type3.rb +1 -1
  154. data/lib/hexapdf/type/form.rb +76 -6
  155. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  156. data/lib/hexapdf/type/icon_fit.rb +1 -1
  157. data/lib/hexapdf/type/image.rb +1 -1
  158. data/lib/hexapdf/type/info.rb +1 -1
  159. data/lib/hexapdf/type/mark_information.rb +1 -1
  160. data/lib/hexapdf/type/names.rb +2 -2
  161. data/lib/hexapdf/type/object_stream.rb +2 -1
  162. data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
  163. data/lib/hexapdf/type/optional_content_group.rb +370 -0
  164. data/lib/hexapdf/type/optional_content_membership.rb +63 -0
  165. data/lib/hexapdf/type/optional_content_properties.rb +158 -0
  166. data/lib/hexapdf/type/outline.rb +1 -1
  167. data/lib/hexapdf/type/outline_item.rb +1 -1
  168. data/lib/hexapdf/type/page.rb +46 -21
  169. data/lib/hexapdf/type/page_label.rb +5 -9
  170. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  171. data/lib/hexapdf/type/resources.rb +1 -1
  172. data/lib/hexapdf/type/trailer.rb +2 -2
  173. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  174. data/lib/hexapdf/type/xref_stream.rb +2 -2
  175. data/lib/hexapdf/type.rb +4 -0
  176. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
  177. data/lib/hexapdf/version.rb +1 -1
  178. data/lib/hexapdf/writer.rb +4 -4
  179. data/lib/hexapdf/xref_section.rb +2 -2
  180. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  181. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  182. data/test/hexapdf/content/test_canvas.rb +49 -1
  183. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  184. data/test/hexapdf/document/test_files.rb +2 -2
  185. data/test/hexapdf/document/test_layout.rb +105 -2
  186. data/test/hexapdf/document/test_pages.rb +6 -6
  187. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  188. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  189. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  190. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  191. data/test/hexapdf/layout/test_box.rb +14 -5
  192. data/test/hexapdf/layout/test_column_box.rb +65 -21
  193. data/test/hexapdf/layout/test_frame.rb +27 -15
  194. data/test/hexapdf/layout/test_image_box.rb +4 -0
  195. data/test/hexapdf/layout/test_inline_box.rb +17 -3
  196. data/test/hexapdf/layout/test_list_box.rb +84 -33
  197. data/test/hexapdf/layout/test_page_style.rb +3 -2
  198. data/test/hexapdf/layout/test_style.rb +60 -0
  199. data/test/hexapdf/layout/test_table_box.rb +728 -0
  200. data/test/hexapdf/layout/test_text_box.rb +26 -0
  201. data/test/hexapdf/layout/test_text_fragment.rb +33 -0
  202. data/test/hexapdf/layout/test_text_layouter.rb +36 -5
  203. data/test/hexapdf/test_composer.rb +10 -0
  204. data/test/hexapdf/test_dictionary.rb +10 -0
  205. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  206. data/test/hexapdf/test_document.rb +5 -0
  207. data/test/hexapdf/test_filter.rb +8 -0
  208. data/test/hexapdf/test_importer.rb +9 -0
  209. data/test/hexapdf/test_object.rb +16 -5
  210. data/test/hexapdf/test_stream.rb +7 -0
  211. data/test/hexapdf/test_writer.rb +3 -3
  212. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  213. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  214. data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
  215. data/test/hexapdf/type/test_catalog.rb +11 -0
  216. data/test/hexapdf/type/test_form.rb +119 -0
  217. data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
  218. data/test/hexapdf/type/test_optional_content_group.rb +158 -0
  219. data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
  220. data/test/hexapdf/type/test_page.rb +20 -6
  221. metadata +28 -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 methods that need to be implemented by such stateless converter objects are:
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 dictionary field contains information about one field of a structured PDF object and this
78
- # information comes directly from the PDF specification.
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 the back. So if
95
- # two converters could potentially be used for the same type, the one that appears earlier
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, automatically taking unduplicatable classes into
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. The first class in the
175
- # type array of the field is used for the conversion.
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. Otherwise +nil+ is
235
- # returned.
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: PDF1.7 s7.9.4, ADB1.7 3.8.3
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.
@@ -292,11 +313,12 @@ module HexaPDF
292
313
  [String, Time, Date, DateTime]
293
314
  end
294
315
 
295
- # :nodoc:
296
- DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d+)(?:'|'(\d+)'?|\z)?)?\z/n
316
+ DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d+)(?:'|'(\d+)'?|\z)?)?\z/n # :nodoc:
297
317
 
298
318
  # Checks if the given object is a string and converts into a Time object if possible.
299
319
  # Otherwise returns +nil+.
320
+ #
321
+ # This method takes some forms of mangled date strings into account that were found in the wild.
300
322
  def self.convert(str, _type, _document)
301
323
  return unless str.kind_of?(String) && (m = str.match(DATE_RE))
302
324
 
@@ -318,6 +340,8 @@ module HexaPDF
318
340
 
319
341
  # Converter module for file specification fields. A file specification in string format is
320
342
  # converted to the corresponding file specification dictionary.
343
+ #
344
+ # See: PDF2.0 s7.11, HexaPDF::Type::FileSpecification
321
345
  module FileSpecificationConverter
322
346
 
323
347
  # This converter is only used for the :Filespec type.
@@ -343,6 +367,8 @@ module HexaPDF
343
367
  end
344
368
 
345
369
  # Converter module for fields of type Rectangle.
370
+ #
371
+ # See: PDF2.0 s7.9.5
346
372
  module RectangleConverter
347
373
 
348
374
  # This converter is usable if the +type+ is Rectangle.
@@ -355,7 +381,8 @@ module HexaPDF
355
381
  Array
356
382
  end
357
383
 
358
- # Wraps a given array in the Rectangle class. Otherwise returns +nil+.
384
+ # Wraps a given array using the Rectangle class or as a Null value if the array is invalid.
385
+ # Otherwise returns +nil+.
359
386
  def self.convert(data, _type, document)
360
387
  return unless data.kind_of?(Array) || data.kind_of?(HexaPDF::PDFArray)
361
388
  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-filter.
44
+ # adbe.pkcs7.detached and ETSI.CAdES.detached sub-filters.
45
45
  #
46
- # See: PDF1.7/2.0 s12.8.3.3
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 handler need to override methods if necessary and implement the needed
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
- # Since PKCS#1 signatures are deprecated with PDF 2.0, the handler only provides the
47
- # implementation for reading and verifying signatures.
46
+ # Note that PKCS#1 signatures are deprecated with PDF 2.0.
48
47
  #
49
- # See: PDF1.7/2.0 s12.8.3.2
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 customize the signature
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: PDF1.7/2.0 s12.8.1, HexaPDF::Type::AcroForm::SignatureField
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: PDF1.7 s12.8.2.2, s12.8.2.3, s12.8.2.4
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: PDF1.7/2.0 s12.8.1, HexaPDF::DigitalSignature::Signature
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 byte string.
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. Use it
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 #handler and DefaultHandler.
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 object.
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 object.
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 object.
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 has not been set, an empty string will be signed using #sign to
208
- # determine the signature size.
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: PDF1.7/2.0 s12.8.3.3, PDF2.0 s12.8.3.4, RFC5652, ETSI TS 102 778 Parts 1-4
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 which will contact the TSA server
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 object.
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 object.
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 object.
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,17 +37,16 @@
37
37
  module HexaPDF
38
38
  module DigitalSignature
39
39
 
40
- # Holds the result information when verifying a signature.
40
+ # Holds the result of verifying a signature.
41
41
  class VerificationResult
42
42
 
43
- # :nodoc:
44
- MESSAGE_SORT_MAP = {
43
+ MESSAGE_SORT_MAP = { # :nodoc:
45
44
  info: {warning: 1, error: 1, info: 0},
46
45
  warning: {info: -1, error: 1, warning: 0},
47
46
  error: {info: -1, warning: -1, error: 0},
48
47
  }
49
48
 
50
- # This structure represents a single status message, containing the type (:info, :warning,
49
+ # This structure represents a single status message, containing the type (:info, :warning, or
51
50
  # :error) and the content of the message.
52
51
  Message = Struct.new(:type, :content) do
53
52
  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
- # See: PDF1.7/2.0 s12.8
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: PDF1.7 s12.3.2
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 explicit destination
131
- # array or a dictionary with a /D entry (as allowed for a named destination).
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
- # +value+.
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 +value+:
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 value itself is returned. Otherwise an error is raised.
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 given destination from the destinations name tree and returns it or +nil+ if no
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 destination was
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, namely in the
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.