hexapdf 0.44.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 +106 -47
- data/examples/019-acro_form.rb +5 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +12 -11
- data/lib/hexapdf/cli/inspect.rb +5 -0
- data/lib/hexapdf/composer.rb +23 -1
- data/lib/hexapdf/configuration.rb +8 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -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 +63 -30
- data/lib/hexapdf/document.rb +24 -2
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/importer.rb +15 -5
- data/lib/hexapdf/layout/box.rb +48 -36
- data/lib/hexapdf/layout/column_box.rb +3 -11
- data/lib/hexapdf/layout/container_box.rb +4 -4
- data/lib/hexapdf/layout/frame.rb +7 -6
- data/lib/hexapdf/layout/inline_box.rb +17 -23
- data/lib/hexapdf/layout/list_box.rb +27 -42
- data/lib/hexapdf/layout/page_style.rb +23 -16
- data/lib/hexapdf/layout/style.rb +5 -5
- data/lib/hexapdf/layout/table_box.rb +14 -10
- data/lib/hexapdf/layout/text_box.rb +60 -36
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -1
- data/lib/hexapdf/rectangle.rb +4 -4
- 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/type/form.rb +2 -2
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- 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 +44 -5
- data/test/hexapdf/layout/test_box.rb +23 -5
- data/test/hexapdf/layout/test_frame.rb +21 -2
- data/test/hexapdf/layout/test_inline_box.rb +17 -28
- data/test/hexapdf/layout/test_list_box.rb +8 -8
- data/test/hexapdf/layout/test_page_style.rb +7 -2
- data/test/hexapdf/layout/test_table_box.rb +8 -1
- data/test/hexapdf/layout/test_text_box.rb +51 -29
- data/test/hexapdf/layout/test_text_layouter.rb +0 -3
- data/test/hexapdf/test_composer.rb +14 -5
- 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/test_serializer.rb +1 -0
- 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,62 @@
|
|
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
|
+
|
41
|
+
## 0.45.0 - 2024-06-18
|
42
|
+
|
43
|
+
### Added
|
44
|
+
|
45
|
+
* [HexaPDF::Document::Layout#styles] and [HexaPDF::Composer#styles] for defining
|
46
|
+
multiple styles at once
|
47
|
+
|
48
|
+
### Changed
|
49
|
+
|
50
|
+
* [HexaPDF::Layout::Box#fit] to set width/height correctly for boxes with
|
51
|
+
position `:flow`
|
52
|
+
|
53
|
+
### Fixed
|
54
|
+
|
55
|
+
* Regression in [HexaPDF::Layout::ListBox] that leads to missing markers
|
56
|
+
* [HexaPDF::Content::CanvasComposer#draw_box] to handle truncated boxes
|
57
|
+
* [HexaPDF::Layout::TableBox::Cell] to handle too-big content in all cases
|
58
|
+
|
59
|
+
|
1
60
|
## 0.44.0 - 2024-06-05
|
2
61
|
|
3
62
|
### Added
|
@@ -356,8 +415,8 @@
|
|
356
415
|
|
357
416
|
### Fixed
|
358
417
|
|
359
|
-
* [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for
|
360
|
-
|
418
|
+
* [HexaPDF::Document::Pages#add_labelling_range] to add a correct entry for the
|
419
|
+
default range starting at page 1
|
361
420
|
* [HexaPDF::Type::Page#flatten_annotations] to correctly handle scaled
|
362
421
|
appearances
|
363
422
|
* Using an unknown style name in [HexaPDF:Document::Layout] method by providing
|
@@ -368,6 +427,8 @@
|
|
368
427
|
than the item content height
|
369
428
|
* [HexaPDF::Dictionary] setting default values on wrong classes in certain
|
370
429
|
situations
|
430
|
+
* [HexaPDF::Importer#import] to correctly import stream objects backed by a
|
431
|
+
[HexaPDF::FiberDoubleForString]
|
371
432
|
|
372
433
|
|
373
434
|
## 0.33.0 - 2023-08-02
|
@@ -420,8 +481,8 @@
|
|
420
481
|
* [HexaPDF::Content::Canvas#text] to set the leading only when multiple lines
|
421
482
|
are drawn
|
422
483
|
* [HexaPDF::Layout::TextBox#split] to use float comparison
|
423
|
-
* Validation of standard encryption dictionary to auto-correct invalid /U and
|
424
|
-
|
484
|
+
* Validation of standard encryption dictionary to auto-correct invalid /U and /O
|
485
|
+
fields in case they are padded with zeros
|
425
486
|
* [HexaPDF::Document#wrap] handling of sub-type mapping in case of missing type
|
426
487
|
* [HexaPDF::Type::AcroForm::AppearanceGenerator] to also take a text field
|
427
488
|
widget's width into account when auto-sizing
|
@@ -742,8 +803,8 @@
|
|
742
803
|
* Support for the document outline
|
743
804
|
* [HexaPDF::Layout::Style#line_height] for setting a custom line height
|
744
805
|
independent of the font size
|
745
|
-
* [HexaPDF::Document::Destinations#use_or_create] as unified interface for
|
746
|
-
|
806
|
+
* [HexaPDF::Document::Destinations#use_or_create] as unified interface for using
|
807
|
+
or creating destinations
|
747
808
|
* [HexaPDF::Document::Destinations::Destination#valid?] and class method for
|
748
809
|
checking whether a destination array is valid
|
749
810
|
|
@@ -752,8 +813,8 @@
|
|
752
813
|
* Calculation of text related [HexaPDF::Layout::Style] values for Type3 fonts
|
753
814
|
* [HexaPDF::Encryption::SecurityHandler#encrypt_string] to either return a
|
754
815
|
dupped or encrypted string
|
755
|
-
* [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering
|
756
|
-
|
816
|
+
* [HexaPDF::Layout::TextLayouter#fit] to avoid infinite loop when encountering a
|
817
|
+
non-zero width breakpoint penalty
|
757
818
|
* [HexaPDF::Type::ObjectStream] to parse the initial stream data right after
|
758
819
|
initialization to avoid access errors
|
759
820
|
* [HexaPDF::Revisions::from_io] to merge a completely empty revision with just a
|
@@ -835,8 +896,7 @@
|
|
835
896
|
fragment if there would not be enough height left anyway
|
836
897
|
* [HexaPDF::Layout::WidthFromPolygon] to work correctly in case of very small
|
837
898
|
floating point errors
|
838
|
-
* HexaPDF::Layout::TextFragment#inspect to work in case of interspersed
|
839
|
-
numbers
|
899
|
+
* HexaPDF::Layout::TextFragment#inspect to work in case of interspersed numbers
|
840
900
|
* [HexaPDF::Layout::TextBox#split] to work for position :flow when box is wider
|
841
901
|
than the initial available width
|
842
902
|
* [HexaPDF::Layout::Frame#fit] to create minimally sized mask rectangles
|
@@ -1118,8 +1178,8 @@
|
|
1118
1178
|
dictionary are indirect objects
|
1119
1179
|
* [HexaPDF::Content::GraphicObject::EndpointArc] to correctly determine the
|
1120
1180
|
start and end points
|
1121
|
-
* HexaPDF::Dictionary#perform_validation to correctly handle objects that
|
1122
|
-
|
1181
|
+
* HexaPDF::Dictionary#perform_validation to correctly handle objects that should
|
1182
|
+
not be indirect objects
|
1123
1183
|
|
1124
1184
|
|
1125
1185
|
## 0.17.3 - 2021-10-31
|
@@ -1241,8 +1301,8 @@
|
|
1241
1301
|
|
1242
1302
|
### Fixed
|
1243
1303
|
|
1244
|
-
* [HexaPDF::Type::Annotation#appearance] to handle cases where there is
|
1245
|
-
|
1304
|
+
* [HexaPDF::Type::Annotation#appearance] to handle cases where there is no valid
|
1305
|
+
appearance stream
|
1246
1306
|
|
1247
1307
|
|
1248
1308
|
## 0.15.3 - 2021-05-01
|
@@ -1297,8 +1357,8 @@
|
|
1297
1357
|
empty background color arrays
|
1298
1358
|
* [HexaPDF::Type::AcroForm::Field#delete_widget] to update the wrapper object
|
1299
1359
|
stored in the document in case the widget is embedded
|
1300
|
-
* Processing of invalid PDF files containing a space,CR,LF combination after
|
1301
|
-
|
1360
|
+
* Processing of invalid PDF files containing a space,CR,LF combination after the
|
1361
|
+
'stream' keyword
|
1302
1362
|
* Cross-reference stream reconstruction with respect to detection of linearized
|
1303
1363
|
files
|
1304
1364
|
* Detection of existing appearances for AcroForm push button fields when
|
@@ -1393,8 +1453,8 @@
|
|
1393
1453
|
|
1394
1454
|
* [HexaPDF::Utils::ObjectHash#oids] to be public instead of private
|
1395
1455
|
* Cross-reference table parsing to handle invalidly numbered main sections
|
1396
|
-
* [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating
|
1397
|
-
|
1456
|
+
* [HexaPDF::Document#cache] and [HexaPDF::Object#cache] to allow updating values
|
1457
|
+
for existing keys
|
1398
1458
|
* Appearance creation methods of AcroForm objects to allow forcing the creation
|
1399
1459
|
of new appearances
|
1400
1460
|
* [HexaPDF::Type::AcroForm::AppearanceGenerator#create_text_appearances] to
|
@@ -1432,8 +1492,8 @@
|
|
1432
1492
|
new 'parser.try_xref_reconstruction' option
|
1433
1493
|
* Two new `hexapdf inspect` commands for showing page objects and page content
|
1434
1494
|
streams by page number
|
1435
|
-
* Flag `--check` to the CLI command `hexapdf info` for checking a file for
|
1436
|
-
|
1495
|
+
* Flag `--check` to the CLI command `hexapdf info` for checking a file for parse
|
1496
|
+
and validation errors
|
1437
1497
|
* [HexaPDF::Type::AcroForm::Field#embedded_widget?] for checking if a widget is
|
1438
1498
|
embedded in the field object
|
1439
1499
|
* [HexaPDF::Type::AcroForm::Field#delete_widget] for deleting a widget
|
@@ -1490,8 +1550,8 @@
|
|
1490
1550
|
|
1491
1551
|
### Added
|
1492
1552
|
|
1493
|
-
* [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given
|
1494
|
-
|
1553
|
+
* [HexaPDF::Font::Encoding::Base#code] for retrieving the code for a given glyph
|
1554
|
+
name
|
1495
1555
|
|
1496
1556
|
### Fixed
|
1497
1557
|
|
@@ -1507,11 +1567,11 @@
|
|
1507
1567
|
[HexaPDF::Type::AcroForm::Field]
|
1508
1568
|
* [HexaPDF::Type::AcroForm::TextField] and
|
1509
1569
|
[HexaPDF::Type::AcroForm::VariableTextField] for basic text field support
|
1510
|
-
* [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and
|
1511
|
-
|
1570
|
+
* [HexaPDF::Type::AcroForm::ButtonField] for push button, radio button and check
|
1571
|
+
box support
|
1512
1572
|
* [HexaPDF::Type::AcroForm::ChoiceField] for combo box and list box support
|
1513
|
-
* [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for
|
1514
|
-
|
1573
|
+
* [HexaPDF::Type::AcroForm::AppearanceGenerator] as central class for generating
|
1574
|
+
appearance streams for form fields
|
1515
1575
|
* Various convenience methods for [HexaPDF::Type::AcroForm::Form]
|
1516
1576
|
* Various convenience methods for [HexaPDF::Type::AcroForm::Field]
|
1517
1577
|
* Various convenience methods for [HexaPDF::Type::Annotations::Widget]
|
@@ -1530,8 +1590,8 @@
|
|
1530
1590
|
* [HexaPDF::Type::Annotation::Border] class
|
1531
1591
|
* [HexaPDF::Content::ColorSpace::device_color_from_specification] for easily
|
1532
1592
|
getting a device color object
|
1533
|
-
* [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
|
1534
|
-
color object without normalizing values
|
1593
|
+
* [HexaPDF::Content::ColorSpace::prenormalized_device_color] for getting a
|
1594
|
+
device color object without normalizing values
|
1535
1595
|
* [HexaPDF::Type::Annotation#appearance] for returning the associated appearance
|
1536
1596
|
dictionary
|
1537
1597
|
* [HexaPDF::Type::Annotation#appearance?] for checking whether an appearance for
|
@@ -1650,8 +1710,8 @@
|
|
1650
1710
|
|
1651
1711
|
### Fixed
|
1652
1712
|
|
1653
|
-
* Conversion of [HexaPDF::Rectangle] type when the original is not a plain
|
1654
|
-
|
1713
|
+
* Conversion of [HexaPDF::Rectangle] type when the original is not a plain Array
|
1714
|
+
but a [HexaPDF::PDFArray]
|
1655
1715
|
|
1656
1716
|
|
1657
1717
|
## 0.11.1 - 2019-11-19
|
@@ -1812,12 +1872,12 @@
|
|
1812
1872
|
|
1813
1873
|
### Added
|
1814
1874
|
|
1815
|
-
* [HexaPDF::Layout::Frame] for box positioning and easier text layouting
|
1816
|
-
|
1875
|
+
* [HexaPDF::Layout::Frame] for box positioning and easier text layouting inside
|
1876
|
+
an arbitrary polygon
|
1817
1877
|
* [HexaPDF::Layout::TextBox] for displaying text in a rectangular and for
|
1818
1878
|
flowing text inside a frame
|
1819
|
-
* [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from
|
1820
|
-
|
1879
|
+
* [HexaPDF::Layout::WidthFromPolygon] for getting a width specification from a
|
1880
|
+
polygon for use with the text layouting engine
|
1821
1881
|
* [HexaPDF::Type::Image#width] and [HexaPDF::Type::Image#height] convenience
|
1822
1882
|
methods
|
1823
1883
|
* [HexaPDF::Type::FontType3] for Type 3 font support
|
@@ -1869,12 +1929,12 @@
|
|
1869
1929
|
character in a text fragment is \r
|
1870
1930
|
* [HexaPDF::Layout::TextLayouter] to work if an optional break point (think
|
1871
1931
|
soft-hyphen) is followed by whitespace
|
1872
|
-
* [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the
|
1873
|
-
|
1932
|
+
* [HexaPDF::Font::TrueType::Builder] to correctly order the entries in the table
|
1933
|
+
directory
|
1874
1934
|
* [HexaPDF::Font::TrueType::Builder] to pad the table data to achieve the
|
1875
1935
|
correct alignment
|
1876
|
-
* [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were
|
1877
|
-
|
1936
|
+
* [HexaPDF::Filter::FlateDecode] by removing the Zlib pools since they were not
|
1937
|
+
thread safe
|
1878
1938
|
* All color space classes to accept the color space definition as argument to
|
1879
1939
|
`::new`
|
1880
1940
|
|
@@ -1906,9 +1966,8 @@
|
|
1906
1966
|
* Cross-reference subsection parsing can handle missing whitespace
|
1907
1967
|
* Renamed HexaPDF::Layout::LineFragment to [HexaPDF::Layout::Line]
|
1908
1968
|
* Renamed HexaPDF::Layout::TextBox to [HexaPDF::Layout::TextLayouter]
|
1909
|
-
* [HexaPDF::Layout::TextFragment::new] and
|
1910
|
-
|
1911
|
-
style options
|
1969
|
+
* [HexaPDF::Layout::TextFragment::new] and [HexaPDF::Layout::TextLayouter::new]
|
1970
|
+
to either take a Style object or style options
|
1912
1971
|
* [HexaPDF::Layout::TextLayouter#fit] method signature
|
1913
1972
|
* [HexaPDF::Layout::InlineBox] to wrap a generic box
|
1914
1973
|
* HexaPDF::Document::Fonts#load to [HexaPDF::Document::Fonts#add] for
|
@@ -1970,8 +2029,8 @@
|
|
1970
2029
|
|
1971
2030
|
* Handling of invalid glyphs is done using the special
|
1972
2031
|
[HexaPDF::Font::InvalidGlyph] class
|
1973
|
-
* Configuration option 'font.on_missing_glyph'; returns an invalid glyph
|
1974
|
-
|
2032
|
+
* Configuration option 'font.on_missing_glyph'; returns an invalid glyph instead
|
2033
|
+
of raising an error
|
1975
2034
|
* Bounding box of TrueType glyphs without contours is set to `[0, 0, 0, 0]`
|
1976
2035
|
* Ligature pairs for AFM fonts are stored like kerning pairs
|
1977
2036
|
* Use TrueType configuration option 'font.true_type.unknown_format' in all
|
@@ -1988,8 +2047,8 @@
|
|
1988
2047
|
|
1989
2048
|
* [HexaPDF::Task::Dereference] to work correctly when encountering invalid
|
1990
2049
|
references
|
1991
|
-
* [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary
|
1992
|
-
|
2050
|
+
* [HexaPDF::Tokenizer] and HexaPDF::Content::Tokenizer to parse a solitary plus
|
2051
|
+
sign
|
1993
2052
|
* Usage of Strings instead of Symbols for AFM font kerning and ligature pairs
|
1994
2053
|
* Processing the contents of form XObjects in case they don't have a resources
|
1995
2054
|
dictionary
|
@@ -2012,8 +2071,8 @@
|
|
2012
2071
|
* CLI option `--verbose` for more verbose output; also changed the default
|
2013
2072
|
verbosity level to only display warnings and not informational messages
|
2014
2073
|
* CLI option `--quiet` for suppressing additional and diagnostic output
|
2015
|
-
* CLI option `--strict` for enabling strict parsing and validation; also
|
2016
|
-
|
2074
|
+
* CLI option `--strict` for enabling strict parsing and validation; also changed
|
2075
|
+
the default from strict to non-strict parsing/validation
|
2017
2076
|
* CLI optimization option `--optimize-fonts` for optimizing embedded fonts
|
2018
2077
|
* Method `#word_spacing_applicable?` to font types
|
2019
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
|
#
|
@@ -16,8 +16,10 @@
|
|
16
16
|
require 'hexapdf'
|
17
17
|
|
18
18
|
HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
19
|
-
composer.
|
20
|
-
|
19
|
+
composer.styles(
|
20
|
+
question: {font_size: 16, margin: [0, 0, 16], fill_color: 'hp-blue'},
|
21
|
+
answer: {font: 'ZapfDingbats', fill_color: "green"},
|
22
|
+
)
|
21
23
|
|
22
24
|
all = composer.document.optional_content.ocg('All answers')
|
23
25
|
a1 = composer.document.optional_content.ocg('Answer 1')
|
@@ -38,7 +40,7 @@ HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
|
38
40
|
answers.text('Guido van Rossum')
|
39
41
|
answers.multiple do |answer|
|
40
42
|
answer.text('Yukihiro “Matz” Matsumoto', position: :float)
|
41
|
-
answer.text("\u{a0}\u{a0}
|
43
|
+
answer.text("\u{a0}\u{a0}✔", style: :answer,
|
42
44
|
properties: {'optional_content' => a1})
|
43
45
|
end
|
44
46
|
answers.text('Rob Pike')
|
@@ -54,7 +56,7 @@ HexaPDF::Composer.create('composer_optional_content.pdf') do |composer|
|
|
54
56
|
answers.text('1992')
|
55
57
|
answers.multiple do |answer|
|
56
58
|
answer.text('1993', position: :float)
|
57
|
-
answer.text("\u{a0}\u{a0}
|
59
|
+
answer.text("\u{a0}\u{a0}✔", style: :answer,
|
58
60
|
properties: {'optional_content' => a2})
|
59
61
|
end
|
60
62
|
end
|
data/examples/030-pdfa.rb
CHANGED
@@ -28,17 +28,18 @@ HexaPDF::Composer.create('pdfa.pdf') do |composer|
|
|
28
28
|
}
|
29
29
|
|
30
30
|
# Define all styles
|
31
|
-
composer.
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
31
|
+
composer.styles(
|
32
|
+
base: {font: 'Lato', font_size: 10, line_spacing: 1.3},
|
33
|
+
top: {font_size: 8},
|
34
|
+
top_box: {padding: [100, 0, 0], margin: [0, 0, 10], border: {width: [0, 0, 1]}},
|
35
|
+
header: {font: 'Lato bold', font_size: 20, margin: [50, 0, 20]},
|
36
|
+
line_items: {border: {width: 1, color: "eee"}, margin: [20, 0]},
|
37
|
+
line_item_cell: {font_size: 8},
|
38
|
+
footer: {border: {width: [1, 0, 0], color: "darkgrey"}, padding: [5, 0, 0],
|
39
|
+
valign: :bottom},
|
40
|
+
footer_heading: {font: 'Lato bold', font_size: 8, padding: [0, 0, 8]},
|
41
|
+
footer_text: {font_size: 8, fill_color: "darkgrey"},
|
42
|
+
)
|
42
43
|
|
43
44
|
# Top part
|
44
45
|
composer.box(:container, style: :top_box) do |container|
|
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
@@ -254,6 +254,28 @@ module HexaPDF
|
|
254
254
|
@document.layout.style(name, base: base, **properties)
|
255
255
|
end
|
256
256
|
|
257
|
+
# :call-seq:
|
258
|
+
# composer.styles -> styles
|
259
|
+
# composer.styles(**mapping) -> styles
|
260
|
+
#
|
261
|
+
# Creates multiple named styles at once if +mapping+ is provided, and returns the style mapping.
|
262
|
+
#
|
263
|
+
# See HexaPDF::Document::Layout#styles for details; this method is just a thin wrapper around
|
264
|
+
# that method.
|
265
|
+
#
|
266
|
+
# Example:
|
267
|
+
#
|
268
|
+
# composer.styles(
|
269
|
+
# base: {font_size: 12, leading: 1.2},
|
270
|
+
# header: {font: 'Helvetica', fill_color: "008"},
|
271
|
+
# header1: {base: :header, font_size: 30}
|
272
|
+
# )
|
273
|
+
#
|
274
|
+
# See: HexaPDF::Layout::Style
|
275
|
+
def styles(**mapping)
|
276
|
+
@document.layout.styles(**mapping)
|
277
|
+
end
|
278
|
+
|
257
279
|
# :call-seq:
|
258
280
|
# composer.page_style(name) -> page_style
|
259
281
|
# composer.page_style(name, **attributes, &template_block) -> page_style
|
@@ -428,7 +450,7 @@ module HexaPDF
|
|
428
450
|
(box = draw_box; break) unless box
|
429
451
|
elsif !@frame.find_next_region
|
430
452
|
unless drawn_on_page
|
431
|
-
raise HexaPDF::Error, "Box
|
453
|
+
raise HexaPDF::Error, "Box didn't fit multiple times, even on empty page"
|
432
454
|
end
|
433
455
|
new_page
|
434
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),
|
@@ -1127,7 +1127,7 @@ module HexaPDF
|
|
1127
1127
|
# canvas.rectangle(x, y, width, height, radius: 0) => canvas
|
1128
1128
|
#
|
1129
1129
|
# Appends a rectangle to the current path as a complete subpath (drawn in counterclockwise
|
1130
|
-
# direction), with the bottom
|
1130
|
+
# direction), with the bottom-left corner specified by +x+ and +y+ and the given +width+ and
|
1131
1131
|
# +height+. Returns +self+.
|
1132
1132
|
#
|
1133
1133
|
# If +radius+ is greater than 0, the corners are rounded with the given radius.
|
@@ -1137,7 +1137,7 @@ module HexaPDF
|
|
1137
1137
|
#
|
1138
1138
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1139
1139
|
#
|
1140
|
-
# The current point is set to the bottom
|
1140
|
+
# The current point is set to the bottom-left corner if +radius+ is zero, otherwise it is set
|
1141
1141
|
# to (x, y + radius).
|
1142
1142
|
#
|
1143
1143
|
# Examples:
|
@@ -1720,7 +1720,7 @@ module HexaPDF
|
|
1720
1720
|
# If the filename or the IO specifies a PDF file, the first page of this file is used to
|
1721
1721
|
# create a form XObject which is then drawn.
|
1722
1722
|
#
|
1723
|
-
# The +at+ argument has to be an array containing two numbers specifying the bottom
|
1723
|
+
# The +at+ argument has to be an array containing two numbers specifying the bottom-left
|
1724
1724
|
# corner at which to draw the XObject.
|
1725
1725
|
#
|
1726
1726
|
# If +width+ and +height+ are specified, the drawn XObject will have exactly these
|
@@ -96,6 +96,7 @@ module HexaPDF
|
|
96
96
|
draw_box, box = @frame.split(result)
|
97
97
|
if draw_box
|
98
98
|
@frame.draw(@canvas, result)
|
99
|
+
(box = draw_box; break) unless box
|
99
100
|
elsif !@frame.find_next_region
|
100
101
|
raise HexaPDF::Error, "Frame for canvas composer is full and box doesn't fit anymore"
|
101
102
|
end
|
@@ -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))
|