hexapdf 0.44.0 → 0.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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))
|