hexapdf 0.45.0 → 0.47.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +120 -47
  3. data/examples/019-acro_form.rb +5 -0
  4. data/lib/hexapdf/cli/inspect.rb +5 -0
  5. data/lib/hexapdf/composer.rb +1 -1
  6. data/lib/hexapdf/configuration.rb +19 -0
  7. data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
  8. data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
  9. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
  10. data/lib/hexapdf/document/layout.rb +48 -27
  11. data/lib/hexapdf/document.rb +24 -2
  12. data/lib/hexapdf/encryption/standard_security_handler.rb +32 -26
  13. data/lib/hexapdf/importer.rb +15 -5
  14. data/lib/hexapdf/layout/box.rb +25 -28
  15. data/lib/hexapdf/layout/frame.rb +1 -1
  16. data/lib/hexapdf/layout/inline_box.rb +17 -23
  17. data/lib/hexapdf/layout/list_box.rb +24 -29
  18. data/lib/hexapdf/layout/page_style.rb +23 -16
  19. data/lib/hexapdf/layout/style.rb +2 -2
  20. data/lib/hexapdf/layout/table_box.rb +57 -10
  21. data/lib/hexapdf/layout/text_box.rb +2 -6
  22. data/lib/hexapdf/parser.rb +5 -1
  23. data/lib/hexapdf/revisions.rb +1 -1
  24. data/lib/hexapdf/stream.rb +3 -3
  25. data/lib/hexapdf/task/optimize.rb +4 -4
  26. data/lib/hexapdf/tokenizer.rb +3 -2
  27. data/lib/hexapdf/type/acro_form/appearance_generator.rb +8 -4
  28. data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
  29. data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
  30. data/lib/hexapdf/type/acro_form/field.rb +8 -0
  31. data/lib/hexapdf/type/acro_form/form.rb +10 -6
  32. data/lib/hexapdf/type/acro_form/signature_field.rb +2 -1
  33. data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
  34. data/lib/hexapdf/type/acro_form/variable_text_field.rb +11 -3
  35. data/lib/hexapdf/type/annotations/widget.rb +4 -2
  36. data/lib/hexapdf/version.rb +1 -1
  37. data/lib/hexapdf/writer.rb +1 -0
  38. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5-R5.pdf +43 -0
  39. data/test/data/standard-security-handler/nopwd-aes-256bit-V5-R5.pdf +44 -0
  40. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5-R5.pdf +43 -0
  41. data/test/data/standard-security-handler/userpwd-aes-256bit-V5-R5.pdf +0 -0
  42. data/test/hexapdf/digital_signature/common.rb +66 -84
  43. data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
  44. data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
  45. data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
  46. data/test/hexapdf/digital_signature/test_handler.rb +2 -1
  47. data/test/hexapdf/digital_signature/test_signatures.rb +4 -4
  48. data/test/hexapdf/document/test_layout.rb +28 -5
  49. data/test/hexapdf/encryption/test_standard_security_handler.rb +5 -2
  50. data/test/hexapdf/layout/test_box.rb +12 -5
  51. data/test/hexapdf/layout/test_frame.rb +12 -2
  52. data/test/hexapdf/layout/test_inline_box.rb +17 -28
  53. data/test/hexapdf/layout/test_list_box.rb +5 -5
  54. data/test/hexapdf/layout/test_page_style.rb +7 -2
  55. data/test/hexapdf/layout/test_table_box.rb +52 -0
  56. data/test/hexapdf/layout/test_text_box.rb +3 -9
  57. data/test/hexapdf/layout/test_text_layouter.rb +0 -3
  58. data/test/hexapdf/task/test_optimize.rb +2 -0
  59. data/test/hexapdf/test_document.rb +30 -3
  60. data/test/hexapdf/test_importer.rb +24 -0
  61. data/test/hexapdf/test_revisions.rb +54 -41
  62. data/test/hexapdf/test_writer.rb +11 -2
  63. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +22 -5
  64. data/test/hexapdf/type/acro_form/test_form.rb +9 -5
  65. data/test/hexapdf/type/acro_form/test_signature_field.rb +3 -1
  66. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +14 -1
  67. data/test/hexapdf/type/annotations/test_widget.rb +4 -0
  68. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd31e769d2a906198da2a4194085cb2a884fa3879442b75add168d7f81d67d8b
4
- data.tar.gz: 43c2b4ba4df2f997d470835995f2581aa306c639c63ddc892e648d94605f3b22
3
+ metadata.gz: 15f4c7590b5f2ce321519ac0b4871971c12073a9d4b0df36ab2f2e3c156f09ab
4
+ data.tar.gz: 76dac6196e06e80fd88dade3f831b7744c2b763f004d3c389d3efebcace3be82
5
5
  SHA512:
6
- metadata.gz: f17a303dba8104974564a213c72c0f0862c520964a3255b575544489ccb5a17a468d093d3970817903c4eb798e888592410db18447d3264d535f3a01a4a94c82
7
- data.tar.gz: d5727e2f2bfb5ed827ac92eecc8cd9e0ba73044150ba07d03623dccde43dc29db1cddc2fbce24bfd63268522e7965519e188271c2bc9c00162b1a660fc468b74
6
+ metadata.gz: 8ea19ed17370cad1a1fa48a7e0cb85c16e3ff62b344d2a9a90c42d2ac98d5ce5f75c356facf6bb8276822db460e2d9f912f523783c82b3539200e33f9de9f383
7
+ data.tar.gz: bdf2d93feade9f0654366bbf89711b670cbd03ee88b81f197f756c2032305f9ee7b9265973f31c5a4e18e7afd3e4f9dfd08b46a0483502b896774494294c111a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,76 @@
1
+ ## 0.47.0 - 2024-09-07
2
+
3
+ ### Added
4
+
5
+ * Configuration option 'acro_form.fallback_default_appearance' to allow setting
6
+ a standard default appearance string for a variable text field if none is
7
+ found
8
+ * Support for decrypting files with the proprietary algorithm /R 5
9
+
10
+ ### Changed
11
+
12
+ * [HexaPDF::Task::Optimize] to not remove optional /Type entries containing
13
+ default values
14
+ * Validation of [HexaPDF::Type::AcroForm::Form] to not add a /DA entry
15
+
16
+ ### Fixed
17
+
18
+ * [HexaPDF::Layout::TableBox] to correctly calculcate and distribute row
19
+ heights when row spans are involved
20
+ * [HexaPDF::Type::AcroForm::AppearanceGenerator] to work for files where check
21
+ boxes don't define the name of the on state
22
+ * [HexaPDF::Importer#import] to handle null values in all cases
23
+ * [HexaPDF::Type::AcroForm::VariableTextField] to handle parsing of invalid PDFs
24
+ with symbolic appearance strings
25
+ * [HexaPDF::Type::Annotations::Widget#marker_style] to handle invalid /DA values
26
+ with missing font size or color information
27
+ * [HexaPDF::Type::AcroForm::SignatureField#field_value] to always return a
28
+ correctly wrapped object
29
+ * [HexaPDF::Writer] to remove /Type entry from trailer
30
+ * [HexaPDF::Type::AcroForm::AppearanceGenerator#create_text_appearances] to
31
+ handle invalid appearance streams that are not correct Form XObjects
32
+
33
+
34
+ ## 0.46.0 - 2024-08-11
35
+
36
+ ### Added
37
+
38
+ * [HexaPDF::DigitalSignature::CMSHandler#embedded_tsa_signature] to return the
39
+ embedded timestamp authority signature if any
40
+ * [HexaPDF::DigitalSignature::Signing::DefaultHandler#signing_time] for setting
41
+ a custom signing time
42
+ * [HexaPDF::Document#duplicate] for making an in-memory copy of a PDF document
43
+ * Configuration option 'font.default' for setting the default font for the
44
+ document layout engine
45
+
46
+ ### Changed
47
+
48
+ * [HexaPDF::Document::Layout::CellArgumentCollector#[]=] to allow stepped ranges
49
+ * [HexaPDF::Document::Layout::ChildrenCollector] to also return the box when
50
+ creating and adding one to the list
51
+ * [HexaPDF::Layout::InlineBox] to allow usage without predefined width
52
+ * [HexaPDF::DigitalSignature::CMSHandler#verify] to recognize non-repudiation
53
+ signatures
54
+ * [HexaPDF::DigitalSignature::CMSHandler#signing_time] to use time from an
55
+ embedded timestamp authority signature if possible
56
+ * [HexaPDF::Layout::Box#fit] to return success for boxes with content
57
+ width/height of zero
58
+ * [HexaPDF::Importer::copy] to optionally allow copying the catalog and page
59
+ tree nodes
60
+
61
+ ### Fixed
62
+
63
+ * Setting of correct x-position in fit result for boxes with flow positioning
64
+ * [HexaPDF::Layout::ListBox#fit] to respect the set height
65
+ * CLI command `hexapdf inspect` to work in case of missing Unicde mappings
66
+ * [HexaPDF::Type::AcroForm::Form#delete_field] to correctly work for fields with
67
+ an embedded widget
68
+ * Parsing of "linearized" PDF files where the first cross-reference section
69
+ isn't actually used
70
+ * [HexaPDF::Layout::PageStyle#create_page] to return new frame objects on each
71
+ invocation
72
+
73
+
1
74
  ## 0.45.0 - 2024-06-18
2
75
 
3
76
  ### Added
@@ -375,8 +448,8 @@
375
448
 
376
449
  ### Fixed
377
450
 
378
- * [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for
379
- the default range starting at page 1
451
+ * [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for the
452
+ default range starting at page 1
380
453
  * [HexaPDF::Type::Page#flatten_annotations] to correctly handle scaled
381
454
  appearances
382
455
  * Using an unknown style name in [HexaPDF:Document::Layout] method by providing
@@ -387,6 +460,8 @@
387
460
  than the item content height
388
461
  * [HexaPDF::Dictionary] setting default values on wrong classes in certain
389
462
  situations
463
+ * [HexaPDF::Importer#import] to correctly import stream objects backed by a
464
+ [HexaPDF::FiberDoubleForString]
390
465
 
391
466
 
392
467
  ## 0.33.0 - 2023-08-02
@@ -439,8 +514,8 @@
439
514
  * [HexaPDF::Content::Canvas#text] to set the leading only when multiple lines
440
515
  are drawn
441
516
  * [HexaPDF::Layout::TextBox#split] to use float comparison
442
- * Validation of standard encryption dictionary to auto-correct invalid /U and
443
- /O fields in case they are padded with zeros
517
+ * Validation of standard encryption dictionary to auto-correct invalid /U and /O
518
+ fields in case they are padded with zeros
444
519
  * [HexaPDF::Document#wrap] handling of sub-type mapping in case of missing type
445
520
  * [HexaPDF::Type::AcroForm::AppearanceGenerator] to also take a text field
446
521
  widget's width into account when auto-sizing
@@ -761,8 +836,8 @@
761
836
  * Support for the document outline
762
837
  * [HexaPDF::Layout::Style#line_height] for setting a custom line height
763
838
  independent of the font size
764
- * [HexaPDF::Document::Destinations#use_or_create] as unified interface for
765
- using or creating destinations
839
+ * [HexaPDF::Document::Destinations#use_or_create] as unified interface for using
840
+ or creating destinations
766
841
  * [HexaPDF::Document::Destinations::Destination#valid?] and class method for
767
842
  checking whether a destination array is valid
768
843
 
@@ -771,8 +846,8 @@
771
846
  * Calculation of text related [HexaPDF::Layout::Style] values for Type3 fonts
772
847
  * [HexaPDF::Encryption::SecurityHandler#encrypt_string] to either return a
773
848
  dupped or encrypted string
774
- * [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering
775
- a non-zero width breakpoint penalty
849
+ * [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering a
850
+ non-zero width breakpoint penalty
776
851
  * [HexaPDF::Type::ObjectStream] to parse the initial stream data right after
777
852
  initialization to avoid access errors
778
853
  * [HexaPDF::Revisions::from_io] to merge a completely empty revision with just a
@@ -854,8 +929,7 @@
854
929
  fragment if there would not be enough height left anyway
855
930
  * [HexaPDF::Layout::WidthFromPolygon] to work correctly in case of very small
856
931
  floating point errors
857
- * HexaPDF::Layout::TextFragment#inspect to work in case of interspersed
858
- numbers
932
+ * HexaPDF::Layout::TextFragment#inspect to work in case of interspersed numbers
859
933
  * [HexaPDF::Layout::TextBox#split] to work for position :flow when box is wider
860
934
  than the initial available width
861
935
  * [HexaPDF::Layout::Frame#fit] to create minimally sized mask rectangles
@@ -1137,8 +1211,8 @@
1137
1211
  dictionary are indirect objects
1138
1212
  * [HexaPDF::Content::GraphicObject::EndpointArc] to correctly determine the
1139
1213
  start and end points
1140
- * HexaPDF::Dictionary#perform_validation to correctly handle objects that
1141
- should not be indirect objects
1214
+ * HexaPDF::Dictionary#perform_validation to correctly handle objects that should
1215
+ not be indirect objects
1142
1216
 
1143
1217
 
1144
1218
  ## 0.17.3 - 2021-10-31
@@ -1260,8 +1334,8 @@
1260
1334
 
1261
1335
  ### Fixed
1262
1336
 
1263
- * [HexaPDF::Type::Annotation#appearance] to handle cases where there is
1264
- no valid appearance stream
1337
+ * [HexaPDF::Type::Annotation#appearance] to handle cases where there is no valid
1338
+ appearance stream
1265
1339
 
1266
1340
 
1267
1341
  ## 0.15.3 - 2021-05-01
@@ -1316,8 +1390,8 @@
1316
1390
  empty background color arrays
1317
1391
  * [HexaPDF::Type::AcroForm::Field#delete_widget] to update the wrapper object
1318
1392
  stored in the document in case the widget is embedded
1319
- * Processing of invalid PDF files containing a space,CR,LF combination after
1320
- the 'stream' keyword
1393
+ * Processing of invalid PDF files containing a space,CR,LF combination after the
1394
+ 'stream' keyword
1321
1395
  * Cross-reference stream reconstruction with respect to detection of linearized
1322
1396
  files
1323
1397
  * Detection of existing appearances for AcroForm push button fields when
@@ -1412,8 +1486,8 @@
1412
1486
 
1413
1487
  * [HexaPDF::Utils::ObjectHash#oids] to be public instead of private
1414
1488
  * Cross-reference table parsing to handle invalidly numbered main sections
1415
- * [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating
1416
- values for existing keys
1489
+ * [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating values
1490
+ for existing keys
1417
1491
  * Appearance creation methods of AcroForm objects to allow forcing the creation
1418
1492
  of new appearances
1419
1493
  * [HexaPDF::Type::AcroForm::AppearanceGenerator#create_text_appearances] to
@@ -1451,8 +1525,8 @@
1451
1525
  new 'parser.try_xref_reconstruction' option
1452
1526
  * Two new `hexapdf inspect` commands for showing page objects and page content
1453
1527
  streams by page number
1454
- * Flag `--check` to the CLI command `hexapdf info` for checking a file for
1455
- parse and validation errors
1528
+ * Flag `--check` to the CLI command `hexapdf info` for checking a file for parse
1529
+ and validation errors
1456
1530
  * [HexaPDF::Type::AcroForm::Field#embedded_widget?] for checking if a widget is
1457
1531
  embedded in the field object
1458
1532
  * [HexaPDF::Type::AcroForm::Field#delete_widget] for deleting a widget
@@ -1509,8 +1583,8 @@
1509
1583
 
1510
1584
  ### Added
1511
1585
 
1512
- * [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given
1513
- glyph name
1586
+ * [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given glyph
1587
+ name
1514
1588
 
1515
1589
  ### Fixed
1516
1590
 
@@ -1526,11 +1600,11 @@
1526
1600
  [HexaPDF::Type::AcroForm::Field]
1527
1601
  * [HexaPDF::Type::AcroForm::TextField] and
1528
1602
  [HexaPDF::Type::AcroForm::VariableTextField] for basic text field support
1529
- * [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and
1530
- check box support
1603
+ * [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and check
1604
+ box support
1531
1605
  * [HexaPDF::Type::AcroForm::ChoiceField] for combo box and list box support
1532
- * [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for
1533
- generating appearance streams for form fields
1606
+ * [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for generating
1607
+ appearance streams for form fields
1534
1608
  * Various convenience methods for [HexaPDF::Type::AcroForm::Form]
1535
1609
  * Various convenience methods for [HexaPDF::Type::AcroForm::Field]
1536
1610
  * Various convenience methods for [HexaPDF::Type::Annotations::Widget]
@@ -1549,8 +1623,8 @@
1549
1623
  * [HexaPDF::Type::Annotation::Border] class
1550
1624
  * [HexaPDF::Content::ColorSpace::device_color_from_specification] for easily
1551
1625
  getting a device color object
1552
- * [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a device
1553
- color object without normalizing values
1626
+ * [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
1627
+ device color object without normalizing values
1554
1628
  * [HexaPDF::Type::Annotation#appearance] for returning the associated appearance
1555
1629
  dictionary
1556
1630
  * [HexaPDF::Type::Annotation#appearance?] for checking whether an appearance for
@@ -1669,8 +1743,8 @@
1669
1743
 
1670
1744
  ### Fixed
1671
1745
 
1672
- * Conversion of [HexaPDF::Rectangle] type when the original is not a plain
1673
- Array but a [HexaPDF::PDFArray]
1746
+ * Conversion of [HexaPDF::Rectangle] type when the original is not a plain Array
1747
+ but a [HexaPDF::PDFArray]
1674
1748
 
1675
1749
 
1676
1750
  ## 0.11.1 - 2019-11-19
@@ -1831,12 +1905,12 @@
1831
1905
 
1832
1906
  ### Added
1833
1907
 
1834
- * [HexaPDF::Layout::Frame] for box positioning and easier text layouting
1835
- inside an arbitrary polygon
1908
+ * [HexaPDF::Layout::Frame] for box positioning and easier text layouting inside
1909
+ an arbitrary polygon
1836
1910
  * [HexaPDF::Layout::TextBox] for displaying text in a rectangular and for
1837
1911
  flowing text inside a frame
1838
- * [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from
1839
- a polygon for use with the text layouting engine
1912
+ * [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from a
1913
+ polygon for use with the text layouting engine
1840
1914
  * [HexaPDF::Type::Image#width] and [HexaPDF::Type::Image#height] convenience
1841
1915
  methods
1842
1916
  * [HexaPDF::Type::FontType3] for Type 3 font support
@@ -1888,12 +1962,12 @@
1888
1962
  character in a text fragment is \r
1889
1963
  * [HexaPDF::Layout::TextLayouter] to work if an optional break point (think
1890
1964
  soft-hyphen) is followed by whitespace
1891
- * [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the
1892
- table directory
1965
+ * [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the table
1966
+ directory
1893
1967
  * [HexaPDF::Font::TrueType::Builder] to pad the table data to achieve the
1894
1968
  correct alignment
1895
- * [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were
1896
- not thread safe
1969
+ * [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were not
1970
+ thread safe
1897
1971
  * All color space classes to accept the color space definition as argument to
1898
1972
  `::new`
1899
1973
 
@@ -1925,9 +1999,8 @@
1925
1999
  * Cross-reference subsection parsing can handle missing whitespace
1926
2000
  * Renamed HexaPDF::Layout::LineFragment to [HexaPDF::Layout::Line]
1927
2001
  * Renamed HexaPDF::Layout::TextBox to [HexaPDF::Layout::TextLayouter]
1928
- * [HexaPDF::Layout::TextFragment::new] and
1929
- [HexaPDF::Layout::TextLayouter::new] to either take a Style object or
1930
- style options
2002
+ * [HexaPDF::Layout::TextFragment::new] and [HexaPDF::Layout::TextLayouter::new]
2003
+ to either take a Style object or style options
1931
2004
  * [HexaPDF::Layout::TextLayouter#fit] method signature
1932
2005
  * [HexaPDF::Layout::InlineBox] to wrap a generic box
1933
2006
  * HexaPDF::Document::Fonts#load to [HexaPDF::Document::Fonts#add] for
@@ -1989,8 +2062,8 @@
1989
2062
 
1990
2063
  * Handling of invalid glyphs is done using the special
1991
2064
  [HexaPDF::Font::InvalidGlyph] class
1992
- * Configuration option 'font.on_missing_glyph'; returns an invalid glyph
1993
- instead of raising an error
2065
+ * Configuration option 'font.on_missing_glyph'; returns an invalid glyph instead
2066
+ of raising an error
1994
2067
  * Bounding box of TrueType glyphs without contours is set to `[0, 0, 0, 0]`
1995
2068
  * Ligature pairs for AFM fonts are stored like kerning pairs
1996
2069
  * Use TrueType configuration option 'font.true_type.unknown_format' in all
@@ -2007,8 +2080,8 @@
2007
2080
 
2008
2081
  * [HexaPDF::Task::Dereference] to work correctly when encountering invalid
2009
2082
  references
2010
- * [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary
2011
- plus sign
2083
+ * [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary plus
2084
+ sign
2012
2085
  * Usage of Strings instead of Symbols for AFM font kerning and ligature pairs
2013
2086
  * Processing the contents of form XObjects in case they don't have a resources
2014
2087
  dictionary
@@ -2031,8 +2104,8 @@
2031
2104
  * CLI option `--verbose` for more verbose output; also changed the default
2032
2105
  verbosity level to only display warnings and not informational messages
2033
2106
  * CLI option `--quiet` for suppressing additional and diagnostic output
2034
- * CLI option `--strict` for enabling strict parsing and validation; also
2035
- changed the default from strict to non-strict parsing/validation
2107
+ * CLI option `--strict` for enabling strict parsing and validation; also changed
2108
+ the default from strict to non-strict parsing/validation
2036
2109
  * CLI optimization option `--optimize-fonts` for optimizing embedded fonts
2037
2110
  * Method `#word_spacing_applicable?` to font types
2038
2111
  * Support for marked-content points and sequences in [HexaPDF::Content::Canvas]
@@ -6,6 +6,11 @@
6
6
  # This example show-cases how to create the various form field types and their
7
7
  # possible standard appearances.
8
8
  #
9
+ # The [HexaPDF::Type::AcroForm::Form] and [HexaPDF::Type::AcroForm::Field]
10
+ # classes provide a plethora of convenience methods for working with forms, like
11
+ # for creating fields and their widgets, getting field properties like the full
12
+ # hierarchical field name or for setting the field value.
13
+ #
9
14
  # Usage:
10
15
  # : `ruby acro_form.rb`
11
16
  #
@@ -117,6 +117,11 @@ module HexaPDF
117
117
 
118
118
  def execute(file, *commands) #:nodoc:
119
119
  with_document(file, password: @password) do |doc|
120
+ doc.config['font.on_missing_unicode_mapping'] = lambda do |code, font|
121
+ $stderr.puts("No Unicode mapping for code point #{code} in font #{font[:BaseFont]}, " \
122
+ "using the Unicode replacement character")
123
+ "\u{FFFD}"
124
+ end
120
125
  @doc = doc
121
126
  if commands.empty?
122
127
  begin
@@ -450,7 +450,7 @@ module HexaPDF
450
450
  (box = draw_box; break) unless box
451
451
  elsif !@frame.find_next_region
452
452
  unless drawn_on_page
453
- raise HexaPDF::Error, "Box doesn't fit on empty page"
453
+ raise HexaPDF::Error, "Box didn't fit multiple times, even on empty page"
454
454
  end
455
455
  new_page
456
456
  drawn_on_page = false
@@ -182,6 +182,16 @@ module HexaPDF
182
182
  # acro_form.default_font_size::
183
183
  # A number specifying the default font size of AcroForm text fields which should be auto-sized.
184
184
  #
185
+ # acro_form.fallback_default_appearance::
186
+ # A hash containging arguments for
187
+ # HexaPDF::Type::AcroForm::VariableTextField#set_defaut_appearance_string which is used as
188
+ # fallback for fields without a default appearance.
189
+ #
190
+ # If this value is set to +nil+, an error is raised in case a variable text field cannot
191
+ # resolve a default appearance string.
192
+ #
193
+ # The default is the empty hash meaning the defaults from the method are used.
194
+ #
185
195
  # acro_form.fallback_font::
186
196
  # The font that should be used when a variable text field references a font that cannot be used.
187
197
  #
@@ -277,6 +287,13 @@ module HexaPDF
277
287
  #
278
288
  # See PDF2.0 s7.4.1, ADB sH.3 3.3
279
289
  #
290
+ # font.default::
291
+ # This font is used by the layout engine when no font is specified but one is needed.
292
+ #
293
+ # This is used, for example, for the font set on styles that don't have a font set.
294
+ #
295
+ # The default value is 'Times'.
296
+ #
280
297
  # font.fallback::
281
298
  # An array of fallback font names to be used when replacing invalid glyphs.
282
299
  #
@@ -478,6 +495,7 @@ module HexaPDF
478
495
  Configuration.new('acro_form.appearance_generator' => 'HexaPDF::Type::AcroForm::AppearanceGenerator',
479
496
  'acro_form.create_appearances' => true,
480
497
  'acro_form.default_font_size' => 10,
498
+ 'acro_form.fallback_default_appearance' => {},
481
499
  'acro_form.fallback_font' => 'Helvetica',
482
500
  'acro_form.on_invalid_value' => proc do |field, value|
483
501
  raise HexaPDF::Error, "Invalid value #{value.inspect} for " \
@@ -518,6 +536,7 @@ module HexaPDF
518
536
  Crypt: 'HexaPDF::Filter::Crypt',
519
537
  Encryption: 'HexaPDF::Filter::Encryption',
520
538
  },
539
+ 'font.default' => 'Times',
521
540
  'font.fallback' => ['ZapfDingbats', 'Symbol'],
522
541
  'font.map' => {},
523
542
  'font.on_invalid_glyph' => method(:font_on_invalid_glyph),
@@ -59,7 +59,11 @@ module HexaPDF
59
59
 
60
60
  # Returns the time of signing.
61
61
  def signing_time
62
- signer_info.signed_time rescue super
62
+ if embedded_tsa_signature
63
+ embedded_tsa_signature.signers.first.signed_time
64
+ else
65
+ signer_info.signed_time rescue super
66
+ end
63
67
  end
64
68
 
65
69
  # Returns the certificate chain.
@@ -78,6 +82,23 @@ module HexaPDF
78
82
  @pkcs7.signers.first
79
83
  end
80
84
 
85
+ # Returns the OpenSSL::PKCS7 object for the embedded TSA signature if there is one or +nil+
86
+ # otherwise.
87
+ def embedded_tsa_signature
88
+ return @embedded_tsa_signature if defined?(@embedded_tsa_signature)
89
+
90
+ @embedded_tsa_signature = nil
91
+ p7 = OpenSSL::ASN1.decode(signature_dict.contents.sub(/\x00*\z/, ''))
92
+ signed_data = p7.value[1].value[0]
93
+ signer_info = signed_data.value[-1].value[0] # first (and only) signer info
94
+ return unless signer_info.value[-1].tag == 1 # check for unsigned attributes
95
+ timestamp_token = signer_info.value[-1].value.find do |unsigned_attr|
96
+ unsigned_attr.value[0].value == "id-smime-aa-timeStampToken"
97
+ end
98
+ return unless timestamp_token
99
+ @embedded_tsa_signature = OpenSSL::PKCS7.new(timestamp_token.value[1].value[0])
100
+ end
101
+
81
102
  # Verifies the signature using the provided OpenSSL::X509::Store object.
82
103
  def verify(store, allow_self_signed: false)
83
104
  result = super
@@ -101,9 +122,16 @@ module HexaPDF
101
122
  return result
102
123
  end
103
124
 
125
+ if embedded_tsa_signature
126
+ result.log(:info, 'Signing time comes from timestamp authority')
127
+ end
128
+
104
129
  key_usage = signer_certificate.extensions.find {|ext| ext.oid == 'keyUsage' }
105
- unless key_usage && key_usage.value.split(', ').include?("Digital Signature")
106
- result.log(:error, "Certificate key usage is missing 'Digital Signature'")
130
+ key_usage = key_usage&.value&.split(', ')
131
+ if key_usage&.include?("Non Repudiation") && !key_usage.include?("Digital Signature")
132
+ result.log(:info, 'Certificate used for non-repudiation')
133
+ elsif !key_usage || !key_usage.include?("Digital Signature")
134
+ result.log(:error, "Certificate key usage is missing 'Digital Signature' or 'Non Repudiation'")
107
135
  end
108
136
 
109
137
  if signature_dict.signature_type == 'ETSI.RFC3161'
@@ -211,6 +211,13 @@ module HexaPDF
211
211
  # The contact information. If used, will be set on the signature dictionary.
212
212
  attr_accessor :contact_info
213
213
 
214
+ # The custom signing time.
215
+ #
216
+ # The signing time is usually the time when signing actually happens. This is also what
217
+ # HexaPDF uses. If it is known that signing happened at a different point in time, that time
218
+ # can be provided using this accessor.
219
+ attr_accessor :signing_time
220
+
214
221
  # The size of the serialized signature that should be reserved.
215
222
  #
216
223
  # If this attribute is not set, an empty string will be signed using #sign to determine the
@@ -277,7 +284,7 @@ module HexaPDF
277
284
  def finalize_objects(_signature_field, signature)
278
285
  signature[:Filter] = :'Adobe.PPKLite'
279
286
  signature[:SubFilter] = (signature_type == :pades ? :'ETSI.CAdES.detached' : :'adbe.pkcs7.detached')
280
- signature[:M] = Time.now
287
+ signature[:M] = self.signing_time ||= Time.now
281
288
  signature[:Reason] = reason if reason
282
289
  signature[:Location] = location if location
283
290
  signature[:ContactInfo] = contact_info if contact_info
@@ -312,6 +319,7 @@ module HexaPDF
312
319
  type: signature_type,
313
320
  certificate: certificate, key: key,
314
321
  digest_algorithm: digest_algorithm,
322
+ signing_time: signing_time,
315
323
  timestamp_handler: timestamp_handler,
316
324
  certificates: certificate_chain, &external_signing).to_der
317
325
  else
@@ -84,6 +84,9 @@ module HexaPDF
84
84
  # Allowed values: sha256, sha384, sha512.
85
85
  attr_accessor :digest_algorithm
86
86
 
87
+ # The signing time to use instead of Time.now.
88
+ attr_accessor :signing_time
89
+
87
90
  # The timestamp handler instance that should be used for timestamping.
88
91
  attr_accessor :timestamp_handler
89
92
 
@@ -119,9 +122,10 @@ module HexaPDF
119
122
 
120
123
  # Creates the set of signed attributes for the signer information structure.
121
124
  def create_signed_attrs(data, signing_time: true)
125
+ signing_time = (self.signing_time || Time.now).utc if signing_time
122
126
  set(
123
127
  attribute('content-type', oid('id-data')),
124
- (attribute('id-signingTime', utc_time(Time.now.utc)) if signing_time),
128
+ (attribute('id-signingTime', utc_time(signing_time)) if signing_time),
125
129
  attribute(
126
130
  'message-digest',
127
131
  binary(OpenSSL::Digest.digest(@digest_algorithm, data))