hexapdf 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -47
- data/examples/019-acro_form.rb +5 -0
- data/lib/hexapdf/cli/inspect.rb +5 -0
- data/lib/hexapdf/composer.rb +1 -1
- data/lib/hexapdf/configuration.rb +8 -0
- data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
- data/lib/hexapdf/document/layout.rb +48 -27
- data/lib/hexapdf/document.rb +24 -2
- data/lib/hexapdf/importer.rb +15 -5
- data/lib/hexapdf/layout/box.rb +25 -28
- data/lib/hexapdf/layout/frame.rb +1 -1
- data/lib/hexapdf/layout/inline_box.rb +17 -23
- data/lib/hexapdf/layout/list_box.rb +24 -29
- data/lib/hexapdf/layout/page_style.rb +23 -16
- data/lib/hexapdf/layout/style.rb +2 -2
- data/lib/hexapdf/layout/text_box.rb +2 -6
- data/lib/hexapdf/parser.rb +5 -1
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/stream.rb +3 -3
- data/lib/hexapdf/tokenizer.rb +3 -2
- data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/field.rb +8 -0
- data/lib/hexapdf/type/acro_form/form.rb +2 -1
- data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/digital_signature/common.rb +66 -84
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
- data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
- data/test/hexapdf/digital_signature/test_handler.rb +2 -1
- data/test/hexapdf/document/test_layout.rb +28 -5
- data/test/hexapdf/layout/test_box.rb +12 -5
- data/test/hexapdf/layout/test_frame.rb +12 -2
- data/test/hexapdf/layout/test_inline_box.rb +17 -28
- data/test/hexapdf/layout/test_list_box.rb +5 -5
- data/test/hexapdf/layout/test_page_style.rb +7 -2
- data/test/hexapdf/layout/test_text_box.rb +3 -9
- data/test/hexapdf/layout/test_text_layouter.rb +0 -3
- data/test/hexapdf/test_document.rb +27 -0
- data/test/hexapdf/test_importer.rb +17 -0
- data/test/hexapdf/test_revisions.rb +54 -41
- data/test/hexapdf/type/acro_form/test_form.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9c1a35d4ad93b48faa1f728bcddc91778da584c8d673e2f15557bd22050a438
|
4
|
+
data.tar.gz: 2ef8ca70891723643080a402f0808882f66f01a816c422477cc03fad34774859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87c109bd8a6711b4df27a40c689a025d816075d6c68c21a1cc22924b5ae827cd44d98e45bff8f43c85403dd82d6a6e54b66c99bfe135298cba33292e9511a1fc
|
7
|
+
data.tar.gz: e0529e3e244be8366e722ea29ab06a8b922f18698526c79a28d5d11f02da5ee103cba71ecbc6882fefe3de27f02d38f8ce8b505fefbb45839069c74aefaed9ae
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,43 @@
|
|
1
|
+
## 0.46.0 - 2024-08-11
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::DigitalSignature::CMSHandler#embedded_tsa_signature] to return the
|
6
|
+
embedded timestamp authority signature if any
|
7
|
+
* [HexaPDF::DigitalSignature::Signing::DefaultHandler#signing_time] for setting
|
8
|
+
a custom signing time
|
9
|
+
* [HexaPDF::Document#duplicate] for making an in-memory copy of a PDF document
|
10
|
+
* Configuration option 'font.default' for setting the default font for the
|
11
|
+
document layout engine
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
|
15
|
+
* [HexaPDF::Document::Layout::CellArgumentCollector#[]=] to allow stepped ranges
|
16
|
+
* [HexaPDF::Document::Layout::ChildrenCollector] to also return the box when
|
17
|
+
creating and adding one to the list
|
18
|
+
* [HexaPDF::Layout::InlineBox] to allow usage without predefined width
|
19
|
+
* [HexaPDF::DigitalSignature::CMSHandler#verify] to recognize non-repudiation
|
20
|
+
signatures
|
21
|
+
* [HexaPDF::DigitalSignature::CMSHandler#signing_time] to use time from an
|
22
|
+
embedded timestamp authority signature if possible
|
23
|
+
* [HexaPDF::Layout::Box#fit] to return success for boxes with content
|
24
|
+
width/height of zero
|
25
|
+
* [HexaPDF::Importer::copy] to optionally allow copying the catalog and page
|
26
|
+
tree nodes
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
|
30
|
+
* Setting of correct x-position in fit result for boxes with flow positioning
|
31
|
+
* [HexaPDF::Layout::ListBox#fit] to respect the set height
|
32
|
+
* CLI command `hexapdf inspect` to work in case of missing Unicde mappings
|
33
|
+
* [HexaPDF::Type::AcroForm::Form#delete_field] to correctly work for fields with
|
34
|
+
an embedded widget
|
35
|
+
* Parsing of "linearized" PDF files where the first cross-reference section
|
36
|
+
isn't actually used
|
37
|
+
* [HexaPDF::Layout::PageStyle#create_page] to return new frame objects on each
|
38
|
+
invocation
|
39
|
+
|
40
|
+
|
1
41
|
## 0.45.0 - 2024-06-18
|
2
42
|
|
3
43
|
### Added
|
@@ -375,8 +415,8 @@
|
|
375
415
|
|
376
416
|
### Fixed
|
377
417
|
|
378
|
-
* [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for
|
379
|
-
|
418
|
+
* [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for the
|
419
|
+
default range starting at page 1
|
380
420
|
* [HexaPDF::Type::Page#flatten_annotations] to correctly handle scaled
|
381
421
|
appearances
|
382
422
|
* Using an unknown style name in [HexaPDF:Document::Layout] method by providing
|
@@ -387,6 +427,8 @@
|
|
387
427
|
than the item content height
|
388
428
|
* [HexaPDF::Dictionary] setting default values on wrong classes in certain
|
389
429
|
situations
|
430
|
+
* [HexaPDF::Importer#import] to correctly import stream objects backed by a
|
431
|
+
[HexaPDF::FiberDoubleForString]
|
390
432
|
|
391
433
|
|
392
434
|
## 0.33.0 - 2023-08-02
|
@@ -439,8 +481,8 @@
|
|
439
481
|
* [HexaPDF::Content::Canvas#text] to set the leading only when multiple lines
|
440
482
|
are drawn
|
441
483
|
* [HexaPDF::Layout::TextBox#split] to use float comparison
|
442
|
-
* Validation of standard encryption dictionary to auto-correct invalid /U and
|
443
|
-
|
484
|
+
* Validation of standard encryption dictionary to auto-correct invalid /U and /O
|
485
|
+
fields in case they are padded with zeros
|
444
486
|
* [HexaPDF::Document#wrap] handling of sub-type mapping in case of missing type
|
445
487
|
* [HexaPDF::Type::AcroForm::AppearanceGenerator] to also take a text field
|
446
488
|
widget's width into account when auto-sizing
|
@@ -761,8 +803,8 @@
|
|
761
803
|
* Support for the document outline
|
762
804
|
* [HexaPDF::Layout::Style#line_height] for setting a custom line height
|
763
805
|
independent of the font size
|
764
|
-
* [HexaPDF::Document::Destinations#use_or_create] as unified interface for
|
765
|
-
|
806
|
+
* [HexaPDF::Document::Destinations#use_or_create] as unified interface for using
|
807
|
+
or creating destinations
|
766
808
|
* [HexaPDF::Document::Destinations::Destination#valid?] and class method for
|
767
809
|
checking whether a destination array is valid
|
768
810
|
|
@@ -771,8 +813,8 @@
|
|
771
813
|
* Calculation of text related [HexaPDF::Layout::Style] values for Type3 fonts
|
772
814
|
* [HexaPDF::Encryption::SecurityHandler#encrypt_string] to either return a
|
773
815
|
dupped or encrypted string
|
774
|
-
* [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering
|
775
|
-
|
816
|
+
* [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering a
|
817
|
+
non-zero width breakpoint penalty
|
776
818
|
* [HexaPDF::Type::ObjectStream] to parse the initial stream data right after
|
777
819
|
initialization to avoid access errors
|
778
820
|
* [HexaPDF::Revisions::from_io] to merge a completely empty revision with just a
|
@@ -854,8 +896,7 @@
|
|
854
896
|
fragment if there would not be enough height left anyway
|
855
897
|
* [HexaPDF::Layout::WidthFromPolygon] to work correctly in case of very small
|
856
898
|
floating point errors
|
857
|
-
* HexaPDF::Layout::TextFragment#inspect to work in case of interspersed
|
858
|
-
numbers
|
899
|
+
* HexaPDF::Layout::TextFragment#inspect to work in case of interspersed numbers
|
859
900
|
* [HexaPDF::Layout::TextBox#split] to work for position :flow when box is wider
|
860
901
|
than the initial available width
|
861
902
|
* [HexaPDF::Layout::Frame#fit] to create minimally sized mask rectangles
|
@@ -1137,8 +1178,8 @@
|
|
1137
1178
|
dictionary are indirect objects
|
1138
1179
|
* [HexaPDF::Content::GraphicObject::EndpointArc] to correctly determine the
|
1139
1180
|
start and end points
|
1140
|
-
* HexaPDF::Dictionary#perform_validation to correctly handle objects that
|
1141
|
-
|
1181
|
+
* HexaPDF::Dictionary#perform_validation to correctly handle objects that should
|
1182
|
+
not be indirect objects
|
1142
1183
|
|
1143
1184
|
|
1144
1185
|
## 0.17.3 - 2021-10-31
|
@@ -1260,8 +1301,8 @@
|
|
1260
1301
|
|
1261
1302
|
### Fixed
|
1262
1303
|
|
1263
|
-
* [HexaPDF::Type::Annotation#appearance] to handle cases where there is
|
1264
|
-
|
1304
|
+
* [HexaPDF::Type::Annotation#appearance] to handle cases where there is no valid
|
1305
|
+
appearance stream
|
1265
1306
|
|
1266
1307
|
|
1267
1308
|
## 0.15.3 - 2021-05-01
|
@@ -1316,8 +1357,8 @@
|
|
1316
1357
|
empty background color arrays
|
1317
1358
|
* [HexaPDF::Type::AcroForm::Field#delete_widget] to update the wrapper object
|
1318
1359
|
stored in the document in case the widget is embedded
|
1319
|
-
* Processing of invalid PDF files containing a space,CR,LF combination after
|
1320
|
-
|
1360
|
+
* Processing of invalid PDF files containing a space,CR,LF combination after the
|
1361
|
+
'stream' keyword
|
1321
1362
|
* Cross-reference stream reconstruction with respect to detection of linearized
|
1322
1363
|
files
|
1323
1364
|
* Detection of existing appearances for AcroForm push button fields when
|
@@ -1412,8 +1453,8 @@
|
|
1412
1453
|
|
1413
1454
|
* [HexaPDF::Utils::ObjectHash#oids] to be public instead of private
|
1414
1455
|
* Cross-reference table parsing to handle invalidly numbered main sections
|
1415
|
-
* [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating
|
1416
|
-
|
1456
|
+
* [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating values
|
1457
|
+
for existing keys
|
1417
1458
|
* Appearance creation methods of AcroForm objects to allow forcing the creation
|
1418
1459
|
of new appearances
|
1419
1460
|
* [HexaPDF::Type::AcroForm::AppearanceGenerator#create_text_appearances] to
|
@@ -1451,8 +1492,8 @@
|
|
1451
1492
|
new 'parser.try_xref_reconstruction' option
|
1452
1493
|
* Two new `hexapdf inspect` commands for showing page objects and page content
|
1453
1494
|
streams by page number
|
1454
|
-
* Flag `--check` to the CLI command `hexapdf info` for checking a file for
|
1455
|
-
|
1495
|
+
* Flag `--check` to the CLI command `hexapdf info` for checking a file for parse
|
1496
|
+
and validation errors
|
1456
1497
|
* [HexaPDF::Type::AcroForm::Field#embedded_widget?] for checking if a widget is
|
1457
1498
|
embedded in the field object
|
1458
1499
|
* [HexaPDF::Type::AcroForm::Field#delete_widget] for deleting a widget
|
@@ -1509,8 +1550,8 @@
|
|
1509
1550
|
|
1510
1551
|
### Added
|
1511
1552
|
|
1512
|
-
* [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given
|
1513
|
-
|
1553
|
+
* [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given glyph
|
1554
|
+
name
|
1514
1555
|
|
1515
1556
|
### Fixed
|
1516
1557
|
|
@@ -1526,11 +1567,11 @@
|
|
1526
1567
|
[HexaPDF::Type::AcroForm::Field]
|
1527
1568
|
* [HexaPDF::Type::AcroForm::TextField] and
|
1528
1569
|
[HexaPDF::Type::AcroForm::VariableTextField] for basic text field support
|
1529
|
-
* [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and
|
1530
|
-
|
1570
|
+
* [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and check
|
1571
|
+
box support
|
1531
1572
|
* [HexaPDF::Type::AcroForm::ChoiceField] for combo box and list box support
|
1532
|
-
* [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for
|
1533
|
-
|
1573
|
+
* [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for generating
|
1574
|
+
appearance streams for form fields
|
1534
1575
|
* Various convenience methods for [HexaPDF::Type::AcroForm::Form]
|
1535
1576
|
* Various convenience methods for [HexaPDF::Type::AcroForm::Field]
|
1536
1577
|
* Various convenience methods for [HexaPDF::Type::Annotations::Widget]
|
@@ -1549,8 +1590,8 @@
|
|
1549
1590
|
* [HexaPDF::Type::Annotation::Border] class
|
1550
1591
|
* [HexaPDF::Content::ColorSpace::device_color_from_specification] for easily
|
1551
1592
|
getting a device color object
|
1552
|
-
* [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
|
1553
|
-
color object without normalizing values
|
1593
|
+
* [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
|
1594
|
+
device color object without normalizing values
|
1554
1595
|
* [HexaPDF::Type::Annotation#appearance] for returning the associated appearance
|
1555
1596
|
dictionary
|
1556
1597
|
* [HexaPDF::Type::Annotation#appearance?] for checking whether an appearance for
|
@@ -1669,8 +1710,8 @@
|
|
1669
1710
|
|
1670
1711
|
### Fixed
|
1671
1712
|
|
1672
|
-
* Conversion of [HexaPDF::Rectangle] type when the original is not a plain
|
1673
|
-
|
1713
|
+
* Conversion of [HexaPDF::Rectangle] type when the original is not a plain Array
|
1714
|
+
but a [HexaPDF::PDFArray]
|
1674
1715
|
|
1675
1716
|
|
1676
1717
|
## 0.11.1 - 2019-11-19
|
@@ -1831,12 +1872,12 @@
|
|
1831
1872
|
|
1832
1873
|
### Added
|
1833
1874
|
|
1834
|
-
* [HexaPDF::Layout::Frame] for box positioning and easier text layouting
|
1835
|
-
|
1875
|
+
* [HexaPDF::Layout::Frame] for box positioning and easier text layouting inside
|
1876
|
+
an arbitrary polygon
|
1836
1877
|
* [HexaPDF::Layout::TextBox] for displaying text in a rectangular and for
|
1837
1878
|
flowing text inside a frame
|
1838
|
-
* [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from
|
1839
|
-
|
1879
|
+
* [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from a
|
1880
|
+
polygon for use with the text layouting engine
|
1840
1881
|
* [HexaPDF::Type::Image#width] and [HexaPDF::Type::Image#height] convenience
|
1841
1882
|
methods
|
1842
1883
|
* [HexaPDF::Type::FontType3] for Type 3 font support
|
@@ -1888,12 +1929,12 @@
|
|
1888
1929
|
character in a text fragment is \r
|
1889
1930
|
* [HexaPDF::Layout::TextLayouter] to work if an optional break point (think
|
1890
1931
|
soft-hyphen) is followed by whitespace
|
1891
|
-
* [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the
|
1892
|
-
|
1932
|
+
* [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the table
|
1933
|
+
directory
|
1893
1934
|
* [HexaPDF::Font::TrueType::Builder] to pad the table data to achieve the
|
1894
1935
|
correct alignment
|
1895
|
-
* [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were
|
1896
|
-
|
1936
|
+
* [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were not
|
1937
|
+
thread safe
|
1897
1938
|
* All color space classes to accept the color space definition as argument to
|
1898
1939
|
`::new`
|
1899
1940
|
|
@@ -1925,9 +1966,8 @@
|
|
1925
1966
|
* Cross-reference subsection parsing can handle missing whitespace
|
1926
1967
|
* Renamed HexaPDF::Layout::LineFragment to [HexaPDF::Layout::Line]
|
1927
1968
|
* Renamed HexaPDF::Layout::TextBox to [HexaPDF::Layout::TextLayouter]
|
1928
|
-
* [HexaPDF::Layout::TextFragment::new] and
|
1929
|
-
|
1930
|
-
style options
|
1969
|
+
* [HexaPDF::Layout::TextFragment::new] and [HexaPDF::Layout::TextLayouter::new]
|
1970
|
+
to either take a Style object or style options
|
1931
1971
|
* [HexaPDF::Layout::TextLayouter#fit] method signature
|
1932
1972
|
* [HexaPDF::Layout::InlineBox] to wrap a generic box
|
1933
1973
|
* HexaPDF::Document::Fonts#load to [HexaPDF::Document::Fonts#add] for
|
@@ -1989,8 +2029,8 @@
|
|
1989
2029
|
|
1990
2030
|
* Handling of invalid glyphs is done using the special
|
1991
2031
|
[HexaPDF::Font::InvalidGlyph] class
|
1992
|
-
* Configuration option 'font.on_missing_glyph'; returns an invalid glyph
|
1993
|
-
|
2032
|
+
* Configuration option 'font.on_missing_glyph'; returns an invalid glyph instead
|
2033
|
+
of raising an error
|
1994
2034
|
* Bounding box of TrueType glyphs without contours is set to `[0, 0, 0, 0]`
|
1995
2035
|
* Ligature pairs for AFM fonts are stored like kerning pairs
|
1996
2036
|
* Use TrueType configuration option 'font.true_type.unknown_format' in all
|
@@ -2007,8 +2047,8 @@
|
|
2007
2047
|
|
2008
2048
|
* [HexaPDF::Task::Dereference] to work correctly when encountering invalid
|
2009
2049
|
references
|
2010
|
-
* [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary
|
2011
|
-
|
2050
|
+
* [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary plus
|
2051
|
+
sign
|
2012
2052
|
* Usage of Strings instead of Symbols for AFM font kerning and ligature pairs
|
2013
2053
|
* Processing the contents of form XObjects in case they don't have a resources
|
2014
2054
|
dictionary
|
@@ -2031,8 +2071,8 @@
|
|
2031
2071
|
* CLI option `--verbose` for more verbose output; also changed the default
|
2032
2072
|
verbosity level to only display warnings and not informational messages
|
2033
2073
|
* CLI option `--quiet` for suppressing additional and diagnostic output
|
2034
|
-
* CLI option `--strict` for enabling strict parsing and validation; also
|
2035
|
-
|
2074
|
+
* CLI option `--strict` for enabling strict parsing and validation; also changed
|
2075
|
+
the default from strict to non-strict parsing/validation
|
2036
2076
|
* CLI optimization option `--optimize-fonts` for optimizing embedded fonts
|
2037
2077
|
* Method `#word_spacing_applicable?` to font types
|
2038
2078
|
* Support for marked-content points and sequences in [HexaPDF::Content::Canvas]
|
data/examples/019-acro_form.rb
CHANGED
@@ -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
|
#
|
data/lib/hexapdf/cli/inspect.rb
CHANGED
@@ -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
|
data/lib/hexapdf/composer.rb
CHANGED
@@ -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
|
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
|
@@ -277,6 +277,13 @@ module HexaPDF
|
|
277
277
|
#
|
278
278
|
# See PDF2.0 s7.4.1, ADB sH.3 3.3
|
279
279
|
#
|
280
|
+
# font.default::
|
281
|
+
# This font is used by the layout engine when no font is specified but one is needed.
|
282
|
+
#
|
283
|
+
# This is used, for example, for the font set on styles that don't have a font set.
|
284
|
+
#
|
285
|
+
# The default value is 'Times'.
|
286
|
+
#
|
280
287
|
# font.fallback::
|
281
288
|
# An array of fallback font names to be used when replacing invalid glyphs.
|
282
289
|
#
|
@@ -518,6 +525,7 @@ module HexaPDF
|
|
518
525
|
Crypt: 'HexaPDF::Filter::Crypt',
|
519
526
|
Encryption: 'HexaPDF::Filter::Encryption',
|
520
527
|
},
|
528
|
+
'font.default' => 'Times',
|
521
529
|
'font.fallback' => ['ZapfDingbats', 'Symbol'],
|
522
530
|
'font.map' => {},
|
523
531
|
'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
|
-
|
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
|
-
|
106
|
-
|
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(
|
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))
|
@@ -77,9 +77,9 @@ module HexaPDF
|
|
77
77
|
#
|
78
78
|
# One style property, Layout::Style#font, is handled specially:
|
79
79
|
#
|
80
|
-
# * If no font is set on a style, the font
|
81
|
-
#
|
82
|
-
# valid default value).
|
80
|
+
# * If no font is set on a style, the default font specified via the configuration option
|
81
|
+
# 'font.default' is automatically set because otherwise there would be problems with text
|
82
|
+
# drawing operations (font is the only style property that has no valid default value).
|
83
83
|
#
|
84
84
|
# * Standard style objects only allow font wrapper objects to be set via the Layout::Style#font
|
85
85
|
# method. This class makes usage easier by allowing strings or an array [name, options_hash]
|
@@ -151,7 +151,9 @@ module HexaPDF
|
|
151
151
|
# :nodoc:
|
152
152
|
def method_missing(name, *args, **kwargs, &block)
|
153
153
|
if @layout.box_creation_method?(name)
|
154
|
-
|
154
|
+
box = @layout.send(name, *args, **kwargs, &block)
|
155
|
+
@children << box
|
156
|
+
box
|
155
157
|
else
|
156
158
|
super
|
157
159
|
end
|
@@ -354,6 +356,7 @@ module HexaPDF
|
|
354
356
|
width: width, height: height, properties: properties,
|
355
357
|
style: box_style)
|
356
358
|
end
|
359
|
+
alias text text_box
|
357
360
|
|
358
361
|
# Creates a HexaPDF::Layout::TextBox like #text_box but allows parts of the text to be
|
359
362
|
# formatted differently.
|
@@ -456,6 +459,7 @@ module HexaPDF
|
|
456
459
|
box_class_for_name(:text).new(items: data, width: width, height: height,
|
457
460
|
properties: properties, style: box_style)
|
458
461
|
end
|
462
|
+
alias formatted_text formatted_text_box
|
459
463
|
|
460
464
|
# Creates a HexaPDF::Layout::ImageBox for the given image.
|
461
465
|
#
|
@@ -477,6 +481,7 @@ module HexaPDF
|
|
477
481
|
box_class_for_name(:image).new(image: image, width: width, height: height,
|
478
482
|
properties: properties, style: style)
|
479
483
|
end
|
484
|
+
alias image image_box
|
480
485
|
|
481
486
|
# This helper class is used by Layout#table_box to allow specifying the keyword arguments used
|
482
487
|
# when converting cell data to box instances.
|
@@ -495,8 +500,25 @@ module HexaPDF
|
|
495
500
|
@number_of_columns = number_of_columns
|
496
501
|
end
|
497
502
|
|
498
|
-
# Stores the
|
499
|
-
#
|
503
|
+
# Stores the hash +args+ containing styling properties for the cells specified via the given
|
504
|
+
# 0-based rows and columns.
|
505
|
+
#
|
506
|
+
# Rows and columns can either be single numbers, ranges of numbers or stepped ranges (i.e.
|
507
|
+
# Enumerator::ArithmeticSequence instances).
|
508
|
+
#
|
509
|
+
# Examples:
|
510
|
+
#
|
511
|
+
# # Gray background for all cells
|
512
|
+
# args[] = {cell: {background_color: "gray"}}
|
513
|
+
#
|
514
|
+
# # Cell at (2, 3) gets a bigger font size
|
515
|
+
# args[2, 3] = {font_size: 50}
|
516
|
+
#
|
517
|
+
# # First column of every row has bold font
|
518
|
+
# args[0..-1, 0] = {font: 'Helvetica bold'}
|
519
|
+
#
|
520
|
+
# # Every second row has a blue background
|
521
|
+
# args[(0..-1).step(2)] = {cell: {background_color: "blue"}}
|
500
522
|
def []=(rows = 0..-1, cols = 0..-1, args)
|
501
523
|
rows = adjust_range(rows.kind_of?(Integer) ? rows..rows : rows, @number_of_rows)
|
502
524
|
cols = adjust_range(cols.kind_of?(Integer) ? cols..cols : cols, @number_of_columns)
|
@@ -509,7 +531,7 @@ module HexaPDF
|
|
509
531
|
# is merged.
|
510
532
|
def retrieve_arguments_for(row, col)
|
511
533
|
@argument_infos.each_with_object({}) do |arg_info, result|
|
512
|
-
next unless arg_info.rows.
|
534
|
+
next unless arg_info.rows.include?(row) && arg_info.cols.include?(col)
|
513
535
|
if arg_info.args[:cell]
|
514
536
|
arg_info.args[:cell] = (result[:cell] || {}).merge(arg_info.args[:cell])
|
515
537
|
end
|
@@ -522,7 +544,8 @@ module HexaPDF
|
|
522
544
|
# Adjusts the +range+ so that both the begin and the end of the range are zero or positive
|
523
545
|
# integers smaller than +max+.
|
524
546
|
def adjust_range(range, max)
|
525
|
-
(range.begin % max)..(range.end % max)
|
547
|
+
r = (range.begin % max)..(range.end % max)
|
548
|
+
range.kind_of?(Range) ? r : r.step(range.step)
|
526
549
|
end
|
527
550
|
|
528
551
|
end
|
@@ -540,7 +563,8 @@ module HexaPDF
|
|
540
563
|
# Additional arguments for the #text_box invocations can be specified using the optional block
|
541
564
|
# that yields a CellArgumentCollector instance. This allows customization of the text boxes.
|
542
565
|
# By specifying the special key +:cell+ it is also possible to assign style properties to the
|
543
|
-
# cells themselves.
|
566
|
+
# cells themselves, irrespective of the type of content of the cells. See
|
567
|
+
# CellArgumentCollector#[]= for details.
|
544
568
|
#
|
545
569
|
# See HexaPDF::Layout::TableBox::new for details on +column_widths+, +header+, +footer+, and
|
546
570
|
# +cell_style+.
|
@@ -586,6 +610,7 @@ module HexaPDF
|
|
586
610
|
footer: footer, cell_style: cell_style, width: width,
|
587
611
|
height: height, properties: properties, style: style)
|
588
612
|
end
|
613
|
+
alias table table_box
|
589
614
|
|
590
615
|
LOREM_IPSUM = [ # :nodoc:
|
591
616
|
"Lorem ipsum dolor sit amet, con\u{00AD}sectetur adipis\u{00AD}cing elit, sed " \
|
@@ -605,22 +630,13 @@ module HexaPDF
|
|
605
630
|
def lorem_ipsum_box(sentences: 4, count: 1, **text_box_properties)
|
606
631
|
text_box(([LOREM_IPSUM[0, sentences].join(" ")] * count).join("\n\n"), **text_box_properties)
|
607
632
|
end
|
633
|
+
alias lorem_ipsum lorem_ipsum_box
|
608
634
|
|
609
|
-
|
610
|
-
|
611
|
-
# Allows creating boxes using more convenient method names:
|
612
|
-
#
|
613
|
-
# * #text for #text_box
|
614
|
-
# * #formatted_text for #formatted_text_box
|
615
|
-
# * #image for #image_box
|
616
|
-
# * #lorem_ipsum for #lorem_ipsum_box
|
617
|
-
# * The name of a pre-defined box class like #column will invoke #box appropriately. Same if
|
618
|
-
# used with a '_box' suffix.
|
635
|
+
# Allows creating boxes using more convenient method names: The name of a pre-defined box
|
636
|
+
# class like #column will invoke #box appropriately. Same if used with a '_box' suffix.
|
619
637
|
def method_missing(name, *args, **kwargs, &block)
|
620
638
|
name_without_box = name.to_s.sub(/_box$/, '').intern
|
621
|
-
if
|
622
|
-
send("#{name}_box", *args, **kwargs, &block)
|
623
|
-
elsif @document.config['layout.boxes.map'].key?(name_without_box)
|
639
|
+
if @document.config['layout.boxes.map'].key?(name_without_box)
|
624
640
|
box(name_without_box, *args, **kwargs, &block)
|
625
641
|
else
|
626
642
|
super
|
@@ -632,6 +648,8 @@ module HexaPDF
|
|
632
648
|
box_creation_method?(name) || super
|
633
649
|
end
|
634
650
|
|
651
|
+
BOX_METHOD_NAMES = [:text, :formatted_text, :image, :table, :lorem_ipsum] #:nodoc:
|
652
|
+
|
635
653
|
# :nodoc:
|
636
654
|
def box_creation_method?(name)
|
637
655
|
name = name.to_s.sub(/_box$/, '').intern
|
@@ -648,8 +666,8 @@ module HexaPDF
|
|
648
666
|
end
|
649
667
|
end
|
650
668
|
|
651
|
-
# Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and
|
652
|
-
# arguments.
|
669
|
+
# Retrieves the appropriate HexaPDF::Layout::Style object based on the +style+ and
|
670
|
+
# +properties+ arguments.
|
653
671
|
#
|
654
672
|
# The +style+ argument specifies the style to retrieve. It can either be a registered style
|
655
673
|
# name (see #style), a hash with style properties or +nil+. In the latter case the registered
|
@@ -658,15 +676,18 @@ module HexaPDF
|
|
658
676
|
# If the +properties+ hash is not empty, the retrieved style is duplicated and the properties
|
659
677
|
# hash is applied to it.
|
660
678
|
#
|
661
|
-
# Finally, a default font (the one from the :base style or otherwise
|
662
|
-
# necessary to ensure that the style object
|
679
|
+
# Finally, a default font (the one from the :base style or otherwise the one set using the
|
680
|
+
# configuration option 'font.default') is set if necessary to ensure that the style object
|
681
|
+
# works in all cases.
|
663
682
|
def retrieve_style(style, properties = nil)
|
664
683
|
if style.kind_of?(Symbol) && !@styles.key?(style)
|
665
684
|
raise HexaPDF::Error, "Style #{style} not defined"
|
666
685
|
end
|
667
686
|
style = HexaPDF::Layout::Style.create(@styles[style] || style || @styles[:base])
|
668
687
|
style = style.dup.update(**properties) unless properties.nil? || properties.empty?
|
669
|
-
|
688
|
+
unless style.font?
|
689
|
+
style.font(@styles[:base].font? && @styles[:base].font || @document.config['font.default'])
|
690
|
+
end
|
670
691
|
unless style.font.respond_to?(:pdf_object)
|
671
692
|
name, options = *style.font
|
672
693
|
style.font(@document.fonts.add(name, **(options || {})))
|