hexapdf 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/hexapdf/cli/form.rb +9 -4
  4. data/lib/hexapdf/configuration.rb +10 -0
  5. data/lib/hexapdf/dictionary_fields.rb +1 -1
  6. data/lib/hexapdf/digital_signature/signing/default_handler.rb +1 -2
  7. data/lib/hexapdf/document/annotations.rb +47 -0
  8. data/lib/hexapdf/document/layout.rb +73 -33
  9. data/lib/hexapdf/document/metadata.rb +10 -3
  10. data/lib/hexapdf/document.rb +9 -0
  11. data/lib/hexapdf/encryption/standard_security_handler.rb +7 -2
  12. data/lib/hexapdf/layout/box.rb +5 -0
  13. data/lib/hexapdf/layout/container_box.rb +63 -28
  14. data/lib/hexapdf/layout/style.rb +28 -13
  15. data/lib/hexapdf/layout/table_box.rb +20 -2
  16. data/lib/hexapdf/type/annotations/appearance_generator.rb +94 -16
  17. data/lib/hexapdf/type/annotations/interior_color.rb +1 -1
  18. data/lib/hexapdf/type/annotations/line.rb +1 -157
  19. data/lib/hexapdf/type/annotations/line_ending_styling.rb +208 -0
  20. data/lib/hexapdf/type/annotations/markup_annotation.rb +0 -1
  21. data/lib/hexapdf/type/annotations/polygon.rb +64 -0
  22. data/lib/hexapdf/type/annotations/polygon_polyline.rb +109 -0
  23. data/lib/hexapdf/type/annotations/polyline.rb +64 -0
  24. data/lib/hexapdf/type/annotations.rb +4 -0
  25. data/lib/hexapdf/type/measure.rb +57 -0
  26. data/lib/hexapdf/type.rb +1 -0
  27. data/lib/hexapdf/version.rb +1 -1
  28. data/test/hexapdf/digital_signature/signing/test_default_handler.rb +0 -1
  29. data/test/hexapdf/document/test_annotations.rb +20 -0
  30. data/test/hexapdf/document/test_layout.rb +16 -10
  31. data/test/hexapdf/document/test_metadata.rb +13 -1
  32. data/test/hexapdf/encryption/test_standard_security_handler.rb +2 -1
  33. data/test/hexapdf/layout/test_box.rb +8 -0
  34. data/test/hexapdf/layout/test_container_box.rb +34 -6
  35. data/test/hexapdf/layout/test_page_style.rb +1 -1
  36. data/test/hexapdf/layout/test_style.rb +20 -1
  37. data/test/hexapdf/layout/test_table_box.rb +14 -1
  38. data/test/hexapdf/test_dictionary_fields.rb +1 -0
  39. data/test/hexapdf/type/annotations/test_appearance_generator.rb +126 -0
  40. data/test/hexapdf/type/annotations/test_line.rb +0 -25
  41. data/test/hexapdf/type/annotations/test_line_ending_styling.rb +42 -0
  42. data/test/hexapdf/type/annotations/test_polygon_polyline.rb +29 -0
  43. metadata +9 -2
@@ -0,0 +1,208 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/type/annotations'
38
+
39
+ module HexaPDF
40
+ module Type
41
+ module Annotations
42
+
43
+ # This module provides a convenience method for getting and setting the line ending style for
44
+ # line and polyline annotations.
45
+ #
46
+ # See: PDF2.0 s12.5.6.7
47
+ module LineEndingStyling
48
+
49
+ # Maps HexaPDF names to PDF names.
50
+ LINE_ENDING_STYLE_MAP = { # :nodoc:
51
+ Square: :Square, square: :Square,
52
+ Circle: :Circle, circle: :Circle,
53
+ Diamond: :Diamond, diamond: :Diamond,
54
+ OpenArrow: :OpenArrow, open_arrow: :OpenArrow,
55
+ ClosedArrow: :ClosedArrow, closed_arrow: :ClosedArrow,
56
+ None: :None, none: :None,
57
+ Butt: :Butt, butt: :Butt,
58
+ ROpenArrow: :ROpenArrow, ropen_arrow: :ROpenArrow,
59
+ RClosedArrow: :RClosedArrow, rclosed_arrow: :RClosedArrow,
60
+ Slash: :Slash, slash: :Slash,
61
+ }.freeze
62
+ LINE_ENDING_STYLE_REVERSE_MAP = LINE_ENDING_STYLE_MAP.invert # :nodoc:
63
+
64
+ # Describes the line ending style, i.e. the +start_style+ and the +end_style+.
65
+ #
66
+ # See LineEndingStyling#line_ending_style for more information.
67
+ LineEndingStyle = Struct.new(:start_style, :end_style)
68
+
69
+ # :call-seq:
70
+ # annot.line_ending_style => style
71
+ # annot.line_ending_style(start_style: :none, end_style: :none) => line
72
+ #
73
+ # Returns a LineEndingStyle instance holding the current line ending styles when no argument
74
+ # is given. Otherwise sets the line ending style of the annotation and returns self.
75
+ #
76
+ # When returning the styles, unknown line ending styles are mapped to :none.
77
+ #
78
+ # When setting the line ending style, arguments that are not provided will use the currently
79
+ # defined value or fall back to the default of +:none+.
80
+ #
81
+ # Possible line ending styles (the first one is the HexaPDF name, the second the PDF name):
82
+ #
83
+ # :square or :Square::
84
+ # A square filled with the annotation's interior colour, if any.
85
+ #
86
+ # #>pdf-small-hide
87
+ # doc.annotations.
88
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
89
+ # interior_color("hp-orange").
90
+ # line_ending_style(end_style: :square).
91
+ # regenerate_appearance
92
+ #
93
+ # :circle or :Circle::
94
+ # A circle filled with the annotation’s interior colour, if any.
95
+ #
96
+ # #>pdf-small-hide
97
+ # doc.annotations.
98
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
99
+ # interior_color("hp-orange").
100
+ # line_ending_style(end_style: :circle).
101
+ # regenerate_appearance
102
+ #
103
+ # :diamond or :Diamond::
104
+ # A diamond shape filled with the annotation’s interior colour, if any.
105
+ #
106
+ # #>pdf-small-hide
107
+ # doc.annotations.
108
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
109
+ # interior_color("hp-orange").
110
+ # line_ending_style(end_style: :diamond).
111
+ # regenerate_appearance
112
+ #
113
+ # :open_arrow or :OpenArrow::
114
+ # Two short lines meeting in an acute angle to form an open arrowhead.
115
+ #
116
+ # #>pdf-small-hide
117
+ # doc.annotations.
118
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
119
+ # interior_color("hp-orange").
120
+ # line_ending_style(end_style: :open_arrow).
121
+ # regenerate_appearance
122
+ #
123
+ # :closed_arrow or :ClosedArrow::
124
+ # Two short lines meeting in an acute angle as in the +:open_arrow+ style and connected
125
+ # by a third line to form a triangular closed arrowhead filled with the annotation’s
126
+ # interior colour, if any.
127
+ #
128
+ # #>pdf-small-hide
129
+ # doc.annotations.
130
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
131
+ # interior_color("hp-orange").
132
+ # line_ending_style(end_style: :closed_arrow).
133
+ # regenerate_appearance
134
+ #
135
+ # :none or :None::
136
+ # No line ending.
137
+ #
138
+ # #>pdf-small-hide
139
+ # doc.annotations.
140
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
141
+ # interior_color("hp-orange").
142
+ # line_ending_style(end_style: :none).
143
+ # regenerate_appearance
144
+ #
145
+ # :butt or :Butt::
146
+ # A short line at the endpoint perpendicular to the line itself.
147
+ #
148
+ # #>pdf-small-hide
149
+ # doc.annotations.
150
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
151
+ # interior_color("hp-orange").
152
+ # line_ending_style(end_style: :butt).
153
+ # regenerate_appearance
154
+ #
155
+ # :ropen_arrow or :ROpenArrow::
156
+ # Two short lines in the reverse direction from +:open_arrow+.
157
+ #
158
+ # #>pdf-small-hide
159
+ # doc.annotations.
160
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
161
+ # interior_color("hp-orange").
162
+ # line_ending_style(end_style: :ropen_arrow).
163
+ # regenerate_appearance
164
+ #
165
+ # :rclosed_arrow or :RClosedArrow::
166
+ # A triangular closed arrowhead in the reverse direction from +:closed_arrow+.
167
+ #
168
+ # #>pdf-small-hide
169
+ # doc.annotations.
170
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
171
+ # interior_color("hp-orange").
172
+ # line_ending_style(end_style: :rclosed_arrow).
173
+ # regenerate_appearance
174
+ #
175
+ # :slash or :Slash::
176
+ # A short line at the endpoint approximately 30 degrees clockwise from perpendicular to
177
+ # the line itself.
178
+ #
179
+ # #>pdf-small-hide
180
+ # doc.annotations.
181
+ # create_line(doc.pages[0], start_point: [20, 20], end_point: [80, 60]).
182
+ # interior_color("hp-orange").
183
+ # line_ending_style(end_style: :slash).
184
+ # regenerate_appearance
185
+ def line_ending_style(start_style: :UNSET, end_style: :UNSET)
186
+ if start_style == :UNSET && end_style == :UNSET
187
+ le = self[:LE]
188
+ LineEndingStyle.new(LINE_ENDING_STYLE_REVERSE_MAP.fetch(le[0], :none),
189
+ LINE_ENDING_STYLE_REVERSE_MAP.fetch(le[1], :none))
190
+ else
191
+ start_style = self[:LE][0] if start_style == :UNSET
192
+ end_style = self[:LE][1] if end_style == :UNSET
193
+ start_style = LINE_ENDING_STYLE_MAP.fetch(start_style) do
194
+ raise ArgumentError, "Invalid line ending style: #{start_style.inspect}"
195
+ end
196
+ end_style = LINE_ENDING_STYLE_MAP.fetch(end_style) do
197
+ raise ArgumentError, "Invalid line ending style: #{end_style.inspect}"
198
+ end
199
+ self[:LE] = [start_style, end_style]
200
+ self
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+ end
208
+ end
@@ -61,7 +61,6 @@ module HexaPDF
61
61
 
62
62
  define_field :T, type: String, version: '1.1'
63
63
  define_field :Popup, type: :Annot, version: '1.3'
64
- define_field :CA, type: Numeric, default: 1.0, version: '1.4'
65
64
  define_field :RC, type: [Stream, String], version: '1.5'
66
65
  define_field :CreationDate, type: PDFDate, version: '1.5'
67
66
  define_field :IRT, type: Dictionary, version: '1.5'
@@ -0,0 +1,64 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/type/annotations'
38
+
39
+ module HexaPDF
40
+ module Type
41
+ module Annotations
42
+
43
+ # A polygon annotation displays a closed polygon inside the annotation rectangle.
44
+ #
45
+ # Also see PolygonPolyline for more information.
46
+ #
47
+ # Example:
48
+ #
49
+ # #>pdf-small
50
+ # doc.annotations.create_polygon(doc.pages[0], 20, 20, 30, 70, 80, 60, 40, 30).
51
+ # border_style(color: "hp-blue", width: 2, style: [3, 1]).
52
+ # interior_color("hp-orange").
53
+ # regenerate_appearance
54
+ #
55
+ # See: PDF2.0 s12.5.6.9, HexaPDF::Type::Annotations::PolygonPolyline
56
+ class Polygon < PolygonPolyline
57
+
58
+ define_field :Subtype, type: Symbol, required: true, default: :Polygon
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,109 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/type/annotations'
38
+
39
+ module HexaPDF
40
+ module Type
41
+ module Annotations
42
+
43
+ # This is the base class for the polygon and polyline markup annotations which display either
44
+ # a closed polygon or a polyline inside the annotation rectangle.
45
+ #
46
+ # The styling is done through methods included by various modules:
47
+ #
48
+ # * Changing the line width, line dash pattern and color is done using the method
49
+ # BorderStyling#border_style. While that method allows special styling of the line (like
50
+ # :beveled), only a simple line dash pattern is supported.
51
+ #
52
+ # * The border effect can be changed through BorderEffect#border_effect. Note that cloudy
53
+ # borders are not supported.
54
+ #
55
+ # * The interior color can be changed through InteriorColor#interior_color.
56
+ #
57
+ # * The line ending style can be changed through LineEndingStyling#line_ending_style.
58
+ #
59
+ # See: PDF2.0 s12.5.6.9, HexaPDF::Type::Annotations::Polyline,
60
+ # HexaPDF::Type::Annotations::Polygon, HexaPDF::Type::MarkupAnnotation
61
+ class PolygonPolyline < MarkupAnnotation
62
+
63
+ include BorderStyling
64
+ include BorderEffect
65
+ include InteriorColor
66
+ include LineEndingStyling
67
+
68
+ # Field Subtype is defined in the two subclasses
69
+ define_field :Vertices, type: PDFArray, required: true
70
+ define_field :LE, type: PDFArray, default: [:None, :None]
71
+ define_field :BS, type: :Border
72
+ define_field :IC, type: PDFArray
73
+ define_field :BE, type: :XXBorderEffect, version: '1.5'
74
+ define_field :IT, type: Symbol, version: '1.6',
75
+ allowed_values: [:PolygonCloud, :PolyLineDimension, :PolygonDimension]
76
+ define_field :Measure, type: :Measure, version: '1.7'
77
+ define_field :Path, type: PDFArray, version: '2.0'
78
+
79
+ # :call-seq:
80
+ # annot.vertices => [x0, y0, x1, y1, ...]
81
+ # annot.vertices(*points) => annot
82
+ #
83
+ # Returns the array with the vertices, alternating between horizontal and vertical
84
+ # coordinates, when no argument is given. Otherwise sets the vertices and returns self.
85
+ #
86
+ # This is the only required setting. Note, however, that without setting the appearance
87
+ # style through convenience methods like #border_style nothing will be shown.
88
+ #
89
+ # Example:
90
+ #
91
+ # #>pdf-small
92
+ # doc.annotations.
93
+ # create_polyline(doc.pages[0], 20, 20, 30, 70, 80, 60, 40, 30).
94
+ # regenerate_appearance
95
+ def vertices(*points)
96
+ if points.empty?
97
+ self[:Vertices].to_ary
98
+ elsif points.length % 2 != 0
99
+ raise ArgumentError, "An even number of arguments must be provided"
100
+ else
101
+ self[:Vertices] = points
102
+ self
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,64 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/type/annotations'
38
+
39
+ module HexaPDF
40
+ module Type
41
+ module Annotations
42
+
43
+ # A polyline annotation displays a polyline inside the annotation rectangle.
44
+ #
45
+ # Also see PolygonPolyline for more information.
46
+ #
47
+ # Example:
48
+ #
49
+ # #>pdf-small
50
+ # doc.annotations.create_polyline(doc.pages[0], 20, 20, 30, 70, 80, 60, 40, 30).
51
+ # border_style(color: "hp-blue", width: 2, style: [3, 1]).
52
+ # interior_color("hp-orange").
53
+ # regenerate_appearance
54
+ #
55
+ # See: PDF2.0 s12.5.6.9, HexaPDF::Type::Annotations::PolygonPolyline
56
+ class Polyline < PolygonPolyline
57
+
58
+ define_field :Subtype, type: Symbol, required: true, default: :PolyLine
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -56,6 +56,10 @@ module HexaPDF
56
56
  autoload(:SquareCircle, 'hexapdf/type/annotations/square_circle')
57
57
  autoload(:Square, 'hexapdf/type/annotations/square')
58
58
  autoload(:Circle, 'hexapdf/type/annotations/circle')
59
+ autoload(:LineEndingStyling, 'hexapdf/type/annotations/line_ending_styling')
60
+ autoload(:PolygonPolyline, 'hexapdf/type/annotations/polygon_polyline')
61
+ autoload(:Polygon, 'hexapdf/type/annotations/polygon')
62
+ autoload(:Polyline, 'hexapdf/type/annotations/polyline')
59
63
 
60
64
  end
61
65
 
@@ -0,0 +1,57 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/dictionary'
38
+
39
+ module HexaPDF
40
+ module Type
41
+
42
+ # A Measure dictionary specifies how measurement information should be formatted in textual
43
+ # form.
44
+ #
45
+ # See: PDF2.0 s12.9.1
46
+ class Measure < Dictionary
47
+
48
+ define_type :Measure
49
+
50
+ define_field :Type, type: Symbol, default: type
51
+ define_field :Subtype, type: Symbol, default: :RL,
52
+ allowed_values: [:RL, :GEO]
53
+
54
+ end
55
+
56
+ end
57
+ end
data/lib/hexapdf/type.rb CHANGED
@@ -88,6 +88,7 @@ module HexaPDF
88
88
  autoload(:Namespace, 'hexapdf/type/namespace')
89
89
  autoload(:MarkedContentReference, 'hexapdf/type/marked_content_reference')
90
90
  autoload(:ObjectReference, 'hexapdf/type/object_reference')
91
+ autoload(:Measure, 'hexapdf/type/measure')
91
92
 
92
93
  end
93
94
 
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '1.3.0'
40
+ VERSION = '1.4.0'
41
41
 
42
42
  end
@@ -151,7 +151,6 @@ describe HexaPDF::DigitalSignature::Signing::DefaultHandler do
151
151
  @handler.finalize_objects(@field, @obj)
152
152
  ref = @obj[:Reference][0]
153
153
  assert_equal(:DocMDP, ref[:TransformMethod])
154
- assert_equal(:SHA256, ref[:DigestMethod])
155
154
  assert_equal(1, ref[:TransformParams][:P])
156
155
  assert_equal(:'1.2', ref[:TransformParams][:V])
157
156
  assert_same(@obj, @doc.catalog[:Perms][:DocMDP])
@@ -52,4 +52,24 @@ describe HexaPDF::Document::Annotations do
52
52
  assert_equal(annot, @page[:Annots].first)
53
53
  end
54
54
  end
55
+
56
+ describe "create_polyline" do
57
+ it "creates an appropriate polyline annotation object" do
58
+ annot = @annots.create(:polyline, @page, 10, 10, 20, 15)
59
+ assert_equal(:Annot, annot[:Type])
60
+ assert_equal(:PolyLine, annot[:Subtype])
61
+ assert_equal([10, 10, 20, 15], annot.vertices)
62
+ assert_equal(annot, @page[:Annots].first)
63
+ end
64
+ end
65
+
66
+ describe "create_polygon" do
67
+ it "creates an appropriate polygon annotation object" do
68
+ annot = @annots.create(:polygon, @page, 10, 10, 20, 15)
69
+ assert_equal(:Annot, annot[:Type])
70
+ assert_equal(:Polygon, annot[:Subtype])
71
+ assert_equal([10, 10, 20, 15], annot.vertices)
72
+ assert_equal(annot, @page[:Annots].first)
73
+ end
74
+ end
55
75
  end
@@ -110,11 +110,12 @@ describe HexaPDF::Document::Layout::CellArgumentCollector do
110
110
  assert_equal({key: :value, a: :c, e: :f}, @args.retrieve_arguments_for(5, 6))
111
111
  end
112
112
 
113
- it "deep merges the :cell keys" do
114
- @args[] = {cell: {a: :b, c: :d}}
113
+ it "deep merges the :cell keys in order of definition" do
115
114
  @args[3..7] = {cell: {a: :y, e: :f}}
115
+ @args[] = {cell: {a: :b, c: :d}}
116
116
  @args[5, 6] = {cell: {a: :z}}
117
117
  assert_equal({cell: {a: :z, c: :d, e: :f}}, @args.retrieve_arguments_for(5, 6))
118
+ assert_equal({cell: {a: :b, c: :d}}, @args.retrieve_arguments_for(1, 2))
118
119
  end
119
120
  end
120
121
  end
@@ -172,31 +173,36 @@ describe HexaPDF::Document::Layout do
172
173
  end
173
174
  end
174
175
 
175
- describe "private retrieve_style" do
176
+ describe "resolve_font" do
176
177
  it "resolves a font name to a font wrapper" do
177
- style = @layout.send(:retrieve_style, {font: 'Helvetica'})
178
+ style = @layout.style(:other, font: 'Helvetica')
179
+ @layout.resolve_font(style)
178
180
  assert_kind_of(HexaPDF::Font::Type1Wrapper, style.font)
179
181
  end
180
182
 
181
183
  it "uses the font_bold property when resolving a font name to a font wrapper" do
182
- style = @layout.send(:retrieve_style, {font: 'Helvetica', font_bold: true})
184
+ style = @layout.style(:other, font: 'Helvetica', font_bold: true)
185
+ @layout.resolve_font(style)
183
186
  assert_equal('Helvetica-Bold', style.font.wrapped_font.font_name)
184
187
  end
185
188
 
186
189
  it "uses the font_italic property when resolving a font name to a font wrapper" do
187
- style = @layout.send(:retrieve_style, {font: 'Helvetica', font_italic: true})
190
+ style = @layout.style(:other, font: 'Helvetica', font_italic: true)
191
+ @layout.resolve_font(style)
188
192
  assert_equal('Helvetica-Oblique', style.font.wrapped_font.font_name)
189
193
  end
190
194
 
191
195
  it "sets the :base style's font if no font is set" do
192
196
  @layout.style(:base, font: 'Helvetica')
193
- style = @layout.send(:retrieve_style, {})
194
- assert_equal('Helvetica', style.font.wrapped_font.font_name)
197
+ style = @layout.style(:other, base: nil, font_italic: true)
198
+ @layout.resolve_font(style)
199
+ assert_equal('Helvetica-Oblique', style.font.wrapped_font.font_name)
195
200
  end
196
201
 
197
202
  it "sets the font specified in the config option font.default as fallback" do
198
- style = @layout.send(:retrieve_style, {})
199
- assert_equal('Times-Roman', style.font.wrapped_font.font_name)
203
+ style = @layout.style(:other, base: nil, font_italic: true)
204
+ @layout.resolve_font(style)
205
+ assert_equal('Times-Italic', style.font.wrapped_font.font_name)
200
206
  end
201
207
  end
202
208
 
@@ -13,6 +13,17 @@ describe HexaPDF::Document::Metadata do
13
13
 
14
14
  it "parses the info dictionary on creation" do
15
15
  assert_equal('Title', @metadata.title)
16
+
17
+ time = Time.now
18
+ @doc.trailer.info[:ModDate] = ''
19
+ assert_nil(HexaPDF::Document::Metadata.new(@doc).modification_date)
20
+ @doc.trailer.info[:ModDate] = time
21
+ assert_equal(time, HexaPDF::Document::Metadata.new(@doc).modification_date)
22
+ @doc.trailer.info[:CreationDate] = ''
23
+ assert_nil(HexaPDF::Document::Metadata.new(@doc).creation_date)
24
+ @doc.trailer.info[:CreationDate] = time
25
+ assert_equal(time, HexaPDF::Document::Metadata.new(@doc).creation_date)
26
+
16
27
  @doc.trailer.info[:Trapped] = :Unknown
17
28
  assert_nil(HexaPDF::Document::Metadata.new(@doc).trapped)
18
29
  @doc.trailer.info[:Trapped] = :True
@@ -213,6 +224,7 @@ describe HexaPDF::Document::Metadata do
213
224
  title.language = 'de'
214
225
  @metadata.title(['Title', title])
215
226
  @metadata.author(['Author 1', 'Author 2'])
227
+ @metadata.creation_date('')
216
228
  @metadata.register_property_type('dc', 'other', 'URI')
217
229
  @metadata.property('dc', 'other', 'https://test.org/example')
218
230
  @metadata.property('pdfaid', 'part', 3)
@@ -243,7 +255,7 @@ describe HexaPDF::Document::Metadata do
243
255
  </rdf:Description>
244
256
  <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
245
257
  <xmp:CreatorTool>Creator</xmp:CreatorTool>
246
- <xmp:CreateDate>#{@metadata.send(:xmp_date, @time)}</xmp:CreateDate>
258
+ <xmp:CreateDate></xmp:CreateDate>
247
259
  <xmp:ModifyDate>#{@metadata.send(:xmp_date, @time)}</xmp:ModifyDate>
248
260
  </rdf:Description>
249
261
  <rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">