hexapdf 1.1.1 → 1.3.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +79 -0
  3. data/README.md +1 -1
  4. data/lib/hexapdf/cli/command.rb +63 -63
  5. data/lib/hexapdf/cli/inspect.rb +14 -5
  6. data/lib/hexapdf/cli/modify.rb +0 -1
  7. data/lib/hexapdf/cli/optimize.rb +5 -5
  8. data/lib/hexapdf/composer.rb +14 -0
  9. data/lib/hexapdf/configuration.rb +26 -0
  10. data/lib/hexapdf/content/graphics_state.rb +1 -1
  11. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +1 -1
  12. data/lib/hexapdf/document/annotations.rb +173 -0
  13. data/lib/hexapdf/document/layout.rb +45 -6
  14. data/lib/hexapdf/document.rb +28 -7
  15. data/lib/hexapdf/error.rb +11 -3
  16. data/lib/hexapdf/font/true_type/subsetter.rb +15 -2
  17. data/lib/hexapdf/font/true_type_wrapper.rb +1 -0
  18. data/lib/hexapdf/font/type1_wrapper.rb +1 -0
  19. data/lib/hexapdf/layout/style.rb +101 -7
  20. data/lib/hexapdf/object.rb +2 -2
  21. data/lib/hexapdf/pdf_array.rb +25 -3
  22. data/lib/hexapdf/tokenizer.rb +4 -1
  23. data/lib/hexapdf/type/acro_form/appearance_generator.rb +57 -8
  24. data/lib/hexapdf/type/acro_form/field.rb +1 -0
  25. data/lib/hexapdf/type/acro_form/form.rb +7 -6
  26. data/lib/hexapdf/type/acro_form/java_script_actions.rb +9 -2
  27. data/lib/hexapdf/type/acro_form/text_field.rb +9 -2
  28. data/lib/hexapdf/type/annotation.rb +71 -1
  29. data/lib/hexapdf/type/annotations/appearance_generator.rb +348 -0
  30. data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
  31. data/lib/hexapdf/type/annotations/border_styling.rb +160 -0
  32. data/lib/hexapdf/type/annotations/circle.rb +65 -0
  33. data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
  34. data/lib/hexapdf/type/annotations/line.rb +490 -0
  35. data/lib/hexapdf/type/annotations/square.rb +65 -0
  36. data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
  37. data/lib/hexapdf/type/annotations/widget.rb +52 -116
  38. data/lib/hexapdf/type/annotations.rb +8 -0
  39. data/lib/hexapdf/type/form.rb +2 -2
  40. data/lib/hexapdf/version.rb +1 -1
  41. data/lib/hexapdf/writer.rb +0 -1
  42. data/lib/hexapdf/xref_section.rb +7 -4
  43. data/test/hexapdf/content/test_graphics_state.rb +2 -3
  44. data/test/hexapdf/content/test_operator.rb +4 -5
  45. data/test/hexapdf/digital_signature/test_cms_handler.rb +7 -8
  46. data/test/hexapdf/digital_signature/test_handler.rb +2 -3
  47. data/test/hexapdf/digital_signature/test_pkcs1_handler.rb +1 -2
  48. data/test/hexapdf/document/test_annotations.rb +55 -0
  49. data/test/hexapdf/document/test_layout.rb +24 -2
  50. data/test/hexapdf/font/test_true_type_wrapper.rb +7 -0
  51. data/test/hexapdf/font/test_type1_wrapper.rb +7 -0
  52. data/test/hexapdf/font/true_type/test_subsetter.rb +10 -0
  53. data/test/hexapdf/layout/test_style.rb +27 -2
  54. data/test/hexapdf/task/test_optimize.rb +1 -1
  55. data/test/hexapdf/test_composer.rb +7 -0
  56. data/test/hexapdf/test_document.rb +11 -3
  57. data/test/hexapdf/test_object.rb +1 -1
  58. data/test/hexapdf/test_pdf_array.rb +36 -3
  59. data/test/hexapdf/test_stream.rb +1 -2
  60. data/test/hexapdf/test_xref_section.rb +1 -1
  61. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +78 -3
  62. data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
  63. data/test/hexapdf/type/acro_form/test_field.rb +5 -0
  64. data/test/hexapdf/type/acro_form/test_form.rb +17 -1
  65. data/test/hexapdf/type/acro_form/test_java_script_actions.rb +21 -0
  66. data/test/hexapdf/type/acro_form/test_text_field.rb +7 -1
  67. data/test/hexapdf/type/annotations/test_appearance_generator.rb +482 -0
  68. data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
  69. data/test/hexapdf/type/annotations/test_border_styling.rb +114 -0
  70. data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
  71. data/test/hexapdf/type/annotations/test_line.rb +169 -0
  72. data/test/hexapdf/type/annotations/test_widget.rb +35 -81
  73. data/test/hexapdf/type/test_annotation.rb +55 -0
  74. data/test/hexapdf/type/test_form.rb +6 -0
  75. metadata +17 -2
@@ -0,0 +1,99 @@
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 border effect for
44
+ # square, circle and polygon annotations.
45
+ #
46
+ # See: PDF2.0 s12.5.4
47
+ module BorderEffect
48
+
49
+ # :call-seq:
50
+ # annot.border_effect => border_effect
51
+ # annot.border_effect(type) => annot
52
+ #
53
+ # Returns the border effect of the annotation when no argument is given. Otherwise sets the
54
+ # border effect of the annotation and returns self.
55
+ #
56
+ # The argument type can have the following values:
57
+ #
58
+ # +:none+:: No border effect is used.
59
+ #
60
+ # +:cloudy+:: The border appears "cloudy" (as a series of convex curved line segments).
61
+ #
62
+ # +:cloudier+:: Like +:cloudy+ but more intense.
63
+ #
64
+ # +:cloudiest+:: Like +:cloudier+ but still more intense.
65
+ def border_effect(type = :UNSET)
66
+ if type == :UNSET
67
+ be = self[:BE]
68
+ if !be || be[:S] != :C
69
+ :none
70
+ else
71
+ case be[:I]
72
+ when 0 then :cloudy
73
+ when 1 then :cloudier
74
+ when 2 then :cloudiest
75
+ else :cloudy
76
+ end
77
+ end
78
+ else
79
+ case type
80
+ when nil, :none
81
+ delete(:BE)
82
+ when :cloudy
83
+ self[:BE] = {S: :C, I: 0}
84
+ when :cloudier
85
+ self[:BE] = {S: :C, I: 1}
86
+ when :cloudiest
87
+ self[:BE] = {S: :C, I: 2}
88
+ else
89
+ raise ArgumentError, "Unknown value #{type} for type argument"
90
+ end
91
+ self
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,160 @@
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/annotation'
38
+ require 'hexapdf/content'
39
+ require 'hexapdf/serializer'
40
+
41
+ module HexaPDF
42
+ module Type
43
+ module Annotations
44
+
45
+ # This module provides a convenience method for getting and setting the border style and is
46
+ # included in the annotations that need it.
47
+ #
48
+ # See: PDF2.0 s12.5.4
49
+ module BorderStyling
50
+
51
+ # Describes the border of an annotation.
52
+ #
53
+ # The +color+ property is either +nil+ if the border is transparent or else a device color
54
+ # object - see HexaPDF::Content::ColorSpace.
55
+ #
56
+ # The +style+ property can be one of the following:
57
+ #
58
+ # :solid:: Solid line.
59
+ # :beveled:: Embossed rectangle seemingly raised above the surface of the page.
60
+ # :inset:: Engraved rectangle receeding into the page.
61
+ # :underlined:: Underlined, i.e. only the bottom border is draw.
62
+ # Array: Dash array describing how to dash the line.
63
+ BorderStyle = Struct.new(:width, :color, :style, :horizontal_corner_radius,
64
+ :vertical_corner_radius)
65
+
66
+ # :call-seq:
67
+ # annot.border_style => border_style
68
+ # annot.border_style(color: 0, width: 1, style: :solid) => annot
69
+ #
70
+ # Returns a BorderStyle instance representing the border style of the annotation when no
71
+ # argument is given. Otherwise sets the border style of the annotation and returns self.
72
+ #
73
+ # When setting a border style, arguments that are not provided will use the default: a
74
+ # border with a solid, black, 1pt wide line. This also means that multiple invocations will
75
+ # reset *all* prior values.
76
+ #
77
+ # +color+:: The color of the border. See
78
+ # HexaPDF::Content::ColorSpace.device_color_from_specification for information on
79
+ # the allowed arguments.
80
+ #
81
+ # If the special value +:transparent+ is used when setting the color, a
82
+ # transparent is used. A transparent border will return a +nil+ value when getting
83
+ # the border color.
84
+ #
85
+ # +width+:: The width of the border. If set to 0, no border is shown.
86
+ #
87
+ # +style+:: Defines how the border is drawn. can be one of the following:
88
+ #
89
+ # +:solid+:: Draws a solid border.
90
+ # +:beveled+:: Draws a beveled border.
91
+ # +:inset+:: Draws an inset border.
92
+ # +:underlined+:: Draws only the bottom border.
93
+ # Array:: An array specifying a line dash pattern (see
94
+ # HexaPDF::Content::LineDashPattern)
95
+ def border_style(color: nil, width: nil, style: nil)
96
+ if color || width || style
97
+ color = if color == :transparent
98
+ []
99
+ else
100
+ Content::ColorSpace.device_color_from_specification(color || 0).components
101
+ end
102
+ width ||= 1
103
+ style ||= :solid
104
+
105
+ if self[:Subtype] == :Widget
106
+ (self[:MK] ||= {})[:BC] = color
107
+ else
108
+ self[:C] = color
109
+ end
110
+ bs = self[:BS] = {W: width}
111
+ case style
112
+ when :solid then bs[:S] = :S
113
+ when :beveled then bs[:S] = :B
114
+ when :inset then bs[:S] = :I
115
+ when :underlined then bs[:S] = :U
116
+ when Array
117
+ bs[:S] = :D
118
+ bs[:D] = style
119
+ else
120
+ raise ArgumentError, "Unknown value #{style} for style argument"
121
+ end
122
+ self
123
+ else
124
+ result = BorderStyle.new(1, nil, :solid, 0, 0)
125
+ bc = if self[:Subtype] == :Widget
126
+ (ac = self[:MK]) && (bc = ac[:BC])
127
+ else
128
+ self[:C]
129
+ end
130
+ if bc && !bc.empty?
131
+ result.color = Content::ColorSpace.prenormalized_device_color(bc.value)
132
+ end
133
+
134
+ if (bs = self[:BS])
135
+ result.width = bs[:W] if bs.key?(:W)
136
+ result.style = case bs[:S]
137
+ when :S then :solid
138
+ when :B then :beveled
139
+ when :I then :inset
140
+ when :U then :underlined
141
+ when :D then bs[:D].value
142
+ else :solid
143
+ end
144
+ elsif key?(:Border)
145
+ border = self[:Border]
146
+ result.horizontal_corner_radius = border[0]
147
+ result.vertical_corner_radius = border[1]
148
+ result.width = border[2]
149
+ result.style = border[3] if border[3]
150
+ end
151
+
152
+ result
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,65 @@
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 circle annotation displays an ellipse inside the annotation rectangle (the "circle" name
44
+ # defined by the PDF specification is a bit misleading).
45
+ #
46
+ # Also see SquareCircle for more information.
47
+ #
48
+ # Example:
49
+ #
50
+ # #>pdf-small
51
+ # doc.annotations.create_ellipse(doc.pages[0], 50, 50, a: 30, b: 20).
52
+ # border_style(color: "hp-blue", width: 2, style: [3, 1]).
53
+ # interior_color("hp-orange").
54
+ # regenerate_appearance
55
+ #
56
+ # See: PDF2.0 s12.5.6.8, HexaPDF::Type::Annotations::SquareCircle,
57
+ class Circle < SquareCircle
58
+
59
+ define_field :Subtype, type: Symbol, required: true, default: :Circle
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,84 @@
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 interior color for
44
+ # various annotations.
45
+ #
46
+ # See: PDF2.0 s12.5
47
+ module InteriorColor
48
+
49
+ # :call-seq:
50
+ # line.interior_color => color or nil
51
+ # line.interior_color(*color) => line
52
+ #
53
+ # Returns the interior color or +nil+ (in case the interior color should be transparent)
54
+ # when no argument is given. Otherwise sets the interior color and returns self.
55
+ #
56
+ # How the interior color is used depends on the concrete annotation type. For line
57
+ # annotations, for example, it is the color to fill the line endings
58
+ #
59
+ # +color+:: The interior color. See
60
+ # HexaPDF::Content::ColorSpace.device_color_from_specification for information on
61
+ # the allowed arguments.
62
+ #
63
+ # If the special value +:transparent+ is used when setting the color, no color is
64
+ # used for filling the line endings.
65
+ def interior_color(*color)
66
+ if color.empty?
67
+ color = self[:IC]
68
+ color && !color.empty? ? Content::ColorSpace.prenormalized_device_color(color.value) : nil
69
+ else
70
+ color = if color.length == 1 && color.first == :transparent
71
+ []
72
+ else
73
+ Content::ColorSpace.device_color_from_specification(color).components
74
+ end
75
+ self[:IC] = color
76
+ self
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
84
+ end