hexapdf 1.2.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +90 -0
  3. data/README.md +1 -1
  4. data/lib/hexapdf/cli/form.rb +9 -4
  5. data/lib/hexapdf/cli/inspect.rb +13 -4
  6. data/lib/hexapdf/composer.rb +14 -0
  7. data/lib/hexapdf/configuration.rb +15 -0
  8. data/lib/hexapdf/dictionary_fields.rb +1 -1
  9. data/lib/hexapdf/digital_signature/signing/default_handler.rb +1 -2
  10. data/lib/hexapdf/document/annotations.rb +107 -2
  11. data/lib/hexapdf/document/layout.rb +94 -15
  12. data/lib/hexapdf/document/metadata.rb +10 -3
  13. data/lib/hexapdf/document.rb +9 -0
  14. data/lib/hexapdf/encryption/standard_security_handler.rb +7 -2
  15. data/lib/hexapdf/error.rb +11 -3
  16. data/lib/hexapdf/font/true_type/subsetter.rb +15 -2
  17. data/lib/hexapdf/layout/box.rb +5 -0
  18. data/lib/hexapdf/layout/container_box.rb +63 -28
  19. data/lib/hexapdf/layout/style.rb +129 -20
  20. data/lib/hexapdf/layout/table_box.rb +20 -2
  21. data/lib/hexapdf/object.rb +2 -2
  22. data/lib/hexapdf/pdf_array.rb +25 -3
  23. data/lib/hexapdf/tokenizer.rb +4 -1
  24. data/lib/hexapdf/type/acro_form/appearance_generator.rb +57 -8
  25. data/lib/hexapdf/type/acro_form/field.rb +1 -0
  26. data/lib/hexapdf/type/acro_form/form.rb +7 -6
  27. data/lib/hexapdf/type/annotation.rb +12 -0
  28. data/lib/hexapdf/type/annotations/appearance_generator.rb +169 -16
  29. data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
  30. data/lib/hexapdf/type/annotations/circle.rb +65 -0
  31. data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
  32. data/lib/hexapdf/type/annotations/line.rb +5 -192
  33. data/lib/hexapdf/type/annotations/line_ending_styling.rb +208 -0
  34. data/lib/hexapdf/type/annotations/markup_annotation.rb +0 -1
  35. data/lib/hexapdf/type/annotations/polygon.rb +64 -0
  36. data/lib/hexapdf/type/annotations/polygon_polyline.rb +109 -0
  37. data/lib/hexapdf/type/annotations/polyline.rb +64 -0
  38. data/lib/hexapdf/type/annotations/square.rb +65 -0
  39. data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
  40. data/lib/hexapdf/type/annotations/widget.rb +50 -20
  41. data/lib/hexapdf/type/annotations.rb +9 -0
  42. data/lib/hexapdf/type/measure.rb +57 -0
  43. data/lib/hexapdf/type.rb +1 -0
  44. data/lib/hexapdf/version.rb +1 -1
  45. data/test/hexapdf/digital_signature/signing/test_default_handler.rb +0 -1
  46. data/test/hexapdf/document/test_annotations.rb +42 -0
  47. data/test/hexapdf/document/test_layout.rb +38 -10
  48. data/test/hexapdf/document/test_metadata.rb +13 -1
  49. data/test/hexapdf/encryption/test_standard_security_handler.rb +2 -1
  50. data/test/hexapdf/font/true_type/test_subsetter.rb +10 -0
  51. data/test/hexapdf/layout/test_box.rb +8 -0
  52. data/test/hexapdf/layout/test_container_box.rb +34 -6
  53. data/test/hexapdf/layout/test_page_style.rb +1 -1
  54. data/test/hexapdf/layout/test_style.rb +46 -2
  55. data/test/hexapdf/layout/test_table_box.rb +14 -1
  56. data/test/hexapdf/test_composer.rb +7 -0
  57. data/test/hexapdf/test_dictionary_fields.rb +1 -0
  58. data/test/hexapdf/test_object.rb +1 -1
  59. data/test/hexapdf/test_pdf_array.rb +36 -3
  60. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +78 -3
  61. data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
  62. data/test/hexapdf/type/acro_form/test_field.rb +5 -0
  63. data/test/hexapdf/type/acro_form/test_form.rb +17 -1
  64. data/test/hexapdf/type/annotations/test_appearance_generator.rb +210 -0
  65. data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
  66. data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
  67. data/test/hexapdf/type/annotations/test_line.rb +0 -45
  68. data/test/hexapdf/type/annotations/test_line_ending_styling.rb +42 -0
  69. data/test/hexapdf/type/annotations/test_polygon_polyline.rb +29 -0
  70. data/test/hexapdf/type/annotations/test_widget.rb +35 -0
  71. metadata +16 -2
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/border_effect'
6
+
7
+ describe HexaPDF::Type::Annotations::BorderEffect do
8
+ class TestAnnot < HexaPDF::Type::Annotation
9
+ define_field :BE, type: :XXBorderEffect
10
+ include HexaPDF::Type::Annotations::BorderEffect
11
+ end
12
+
13
+ before do
14
+ @doc = HexaPDF::Document.new
15
+ @annot = @doc.wrap({Type: :Annot}, type: TestAnnot)
16
+ end
17
+
18
+ describe "border_effect" do
19
+ it "returns :none if no border effect is set" do
20
+ assert_equal(:none, @annot.border_effect)
21
+ @annot[:BE] = {}
22
+ assert_equal(:none, @annot.border_effect)
23
+ @annot[:BE] = {S: :S}
24
+ assert_equal(:none, @annot.border_effect)
25
+ @annot[:BE] = {S: :K}
26
+ assert_equal(:none, @annot.border_effect)
27
+ end
28
+
29
+ it "returns cloud(y|ier|iest) if /S is /C and depending on /I" do
30
+ @annot[:BE] = {S: :C}
31
+ assert_equal(:cloudy, @annot.border_effect)
32
+ @annot[:BE][:I] = 0
33
+ assert_equal(:cloudy, @annot.border_effect)
34
+ @annot[:BE][:I] = 1
35
+ assert_equal(:cloudier, @annot.border_effect)
36
+ @annot[:BE][:I] = 2
37
+ assert_equal(:cloudiest, @annot.border_effect)
38
+ @annot[:BE][:I] = 3
39
+ assert_equal(:cloudy, @annot.border_effect)
40
+ end
41
+
42
+ it "sets the /BE entry appropriately" do
43
+ @annot.border_effect(:none)
44
+ refute(@annot.key?(:BE))
45
+ @annot.border_effect(nil)
46
+ refute(@annot.key?(:BE))
47
+ @annot.border_effect(:cloudy)
48
+ assert_equal({S: :C, I: 0}, @annot[:BE])
49
+ @annot.border_effect(:cloudier)
50
+ assert_equal({S: :C, I: 1}, @annot[:BE])
51
+ @annot.border_effect(:cloudiest)
52
+ assert_equal({S: :C, I: 2}, @annot[:BE])
53
+ end
54
+
55
+ it "raises an error if the given type is unknown" do
56
+ assert_raises(ArgumentError) { @annot.border_effect(:unknown) }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/interior_color'
6
+
7
+ describe HexaPDF::Type::Annotations::InteriorColor do
8
+ class TestAnnot < HexaPDF::Type::Annotation
9
+ define_field :IC, type: HexaPDF::PDFArray
10
+ include HexaPDF::Type::Annotations::InteriorColor
11
+ end
12
+
13
+ before do
14
+ @doc = HexaPDF::Document.new
15
+ @annot = @doc.wrap({Type: :Annot}, type: TestAnnot)
16
+ end
17
+
18
+ describe "interior_color" do
19
+ it "returns the interior color" do
20
+ assert_nil(@annot.interior_color)
21
+ @annot[:IC] = []
22
+ assert_nil(@annot.interior_color)
23
+ @annot[:IC] = [0.5]
24
+ assert_equal(HexaPDF::Content::ColorSpace.device_color_from_specification(0.5),
25
+ @annot.interior_color)
26
+ end
27
+
28
+ it "sets the interior color" do
29
+ @annot.interior_color(255)
30
+ assert_equal([1.0], @annot[:IC])
31
+ @annot.interior_color(255, 255, 0)
32
+ assert_equal([1.0, 1.0, 0], @annot[:IC])
33
+ @annot.interior_color(:transparent)
34
+ assert_equal([], @annot[:IC])
35
+ end
36
+ end
37
+ end
@@ -26,51 +26,6 @@ describe HexaPDF::Type::Annotations::Line do
26
26
  end
27
27
  end
28
28
 
29
- describe "line_ending_style" do
30
- it "returns the current style" do
31
- assert_kind_of(HexaPDF::Type::Annotations::Line::LineEndingStyle, @line.line_ending_style)
32
- assert_equal([:none, :none], @line.line_ending_style.to_a)
33
- @line[:LE] = [:Diamond, :OpenArrow]
34
- assert_equal([:diamond, :open_arrow], @line.line_ending_style.to_a)
35
- @line[:LE] = [:Diamond, :Unknown]
36
- assert_equal([:diamond, :none], @line.line_ending_style.to_a)
37
- end
38
-
39
- it "sets the style" do
40
- assert_same(@line, @line.line_ending_style(start_style: :OpenArrow))
41
- assert_equal([:OpenArrow, :None], @line[:LE])
42
- assert_same(@line, @line.line_ending_style(end_style: :open_arrow))
43
- assert_equal([:OpenArrow, :OpenArrow], @line[:LE])
44
- assert_same(@line, @line.line_ending_style(start_style: :circle, end_style: :ClosedArrow))
45
- assert_equal([:Circle, :ClosedArrow], @line[:LE])
46
- end
47
-
48
- it "raises an error for unknown styles" do
49
- assert_raises(ArgumentError) { @line.line_ending_style(start_style: :unknown) }
50
- assert_raises(ArgumentError) { @line.line_ending_style(end_style: :unknown) }
51
- end
52
- end
53
-
54
- describe "interior_color" do
55
- it "returns the interior color" do
56
- assert_nil(@line.interior_color)
57
- @line[:IC] = []
58
- assert_nil(@line.interior_color)
59
- @line[:IC] = [0.5]
60
- assert_equal(HexaPDF::Content::ColorSpace.device_color_from_specification(0.5),
61
- @line.interior_color)
62
- end
63
-
64
- it "sets the interior color" do
65
- @line.interior_color(255)
66
- assert_equal([1.0], @line[:IC])
67
- @line.interior_color(255, 255, 0)
68
- assert_equal([1.0, 1.0, 0], @line[:IC])
69
- @line.interior_color(:transparent)
70
- assert_equal([], @line[:IC])
71
- end
72
- end
73
-
74
29
  describe "leader_line_length" do
75
30
  it "returns the leader line length" do
76
31
  assert_equal(0, @line.leader_line_length)
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/line_ending_styling'
6
+
7
+ describe HexaPDF::Type::Annotations::LineEndingStyling do
8
+ class TestAnnotLineEndingStyling < HexaPDF::Type::Annotation
9
+ define_field :LE, type: HexaPDF::PDFArray, default: [:None, :None]
10
+ include HexaPDF::Type::Annotations::LineEndingStyling
11
+ end
12
+
13
+ before do
14
+ @doc = HexaPDF::Document.new
15
+ @annot = @doc.wrap({Type: :Annot}, type: TestAnnotLineEndingStyling)
16
+ end
17
+
18
+ describe "line_ending_style" do
19
+ it "returns the current style" do
20
+ assert_kind_of(HexaPDF::Type::Annotations::Line::LineEndingStyle, @annot.line_ending_style)
21
+ assert_equal([:none, :none], @annot.line_ending_style.to_a)
22
+ @annot[:LE] = [:Diamond, :OpenArrow]
23
+ assert_equal([:diamond, :open_arrow], @annot.line_ending_style.to_a)
24
+ @annot[:LE] = [:Diamond, :Unknown]
25
+ assert_equal([:diamond, :none], @annot.line_ending_style.to_a)
26
+ end
27
+
28
+ it "sets the style" do
29
+ assert_same(@annot, @annot.line_ending_style(start_style: :OpenArrow))
30
+ assert_equal([:OpenArrow, :None], @annot[:LE])
31
+ assert_same(@annot, @annot.line_ending_style(end_style: :open_arrow))
32
+ assert_equal([:OpenArrow, :OpenArrow], @annot[:LE])
33
+ assert_same(@annot, @annot.line_ending_style(start_style: :circle, end_style: :ClosedArrow))
34
+ assert_equal([:Circle, :ClosedArrow], @annot[:LE])
35
+ end
36
+
37
+ it "raises an error for unknown styles" do
38
+ assert_raises(ArgumentError) { @annot.line_ending_style(start_style: :unknown) }
39
+ assert_raises(ArgumentError) { @annot.line_ending_style(end_style: :unknown) }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/polygon_polyline'
6
+
7
+ describe HexaPDF::Type::Annotations::PolygonPolyline do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @annot = @doc.add({Type: :Annot, Subtype: :Polyline, Rect: [0, 0, 0, 0]},
11
+ type: HexaPDF::Type::Annotations::PolygonPolyline)
12
+ end
13
+
14
+ describe "vertices" do
15
+ it "returns the coordinates of the vertices" do
16
+ @annot[:Vertices] = [10, 20, 30, 40, 50, 60]
17
+ assert_equal([10, 20, 30, 40, 50, 60], @annot.vertices)
18
+ end
19
+
20
+ it "sets the vertices" do
21
+ assert_same(@annot, @annot.vertices(1, 2, 3, 4, 5, 6))
22
+ assert_equal([1, 2, 3, 4, 5, 6], @annot[:Vertices])
23
+ end
24
+
25
+ it "raises an ArgumentError if an uneven number of arguments is provided" do
26
+ assert_raises(ArgumentError) { @annot.vertices(1, 2, 3) }
27
+ end
28
+ end
29
+ end
@@ -98,6 +98,20 @@ describe HexaPDF::Type::Annotations::Widget do
98
98
  end
99
99
  end
100
100
 
101
+ it "uses the correct default style" do
102
+ @widget.form_field.initialize_as_check_box
103
+ @widget.marker_style(size: 10)
104
+ assert_equal('4', @widget[:MK][:CA])
105
+
106
+ @widget.form_field.initialize_as_radio_button
107
+ @widget.marker_style(size: 10)
108
+ assert_equal('l', @widget[:MK][:CA])
109
+
110
+ @widget.form_field.initialize_as_push_button
111
+ @widget.marker_style(size: 10)
112
+ assert_equal('', @widget[:MK][:CA])
113
+ end
114
+
101
115
  it "fails if an invalid argument is provided" do
102
116
  assert_raises(ArgumentError) { @widget.marker_style(style: 5) }
103
117
  end
@@ -144,5 +158,26 @@ describe HexaPDF::Type::Annotations::Widget do
144
158
  assert_equal([1, 0.2, 1, 1], @widget.marker_style.color.components)
145
159
  end
146
160
  end
161
+
162
+ describe "font_name" do
163
+ it "returns the font_name" do
164
+ @widget.form_field[:DA] = "/F1 15 Tf"
165
+ assert_equal(:F1, @widget.marker_style.font_name)
166
+ @widget[:DA] = "/F2 10 Tf"
167
+ assert_equal(:F2, @widget.marker_style.font_name)
168
+ end
169
+
170
+ it "returns nil if none is set" do
171
+ assert_nil(@widget.marker_style.font_name)
172
+ @widget.form_field[:DA] = "0.0 g"
173
+ assert_nil(@widget.marker_style.font_name)
174
+ end
175
+
176
+ it "sets the given font_name" do
177
+ @widget.form_field.initialize_as_push_button
178
+ @widget.marker_style(font_name: 'Helvetica', size: 10)
179
+ assert_equal('/F1 10 Tf 0.0 g', @widget[:DA])
180
+ end
181
+ end
147
182
  end
148
183
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-10 00:00:00.000000000 Z
10
+ date: 2025-08-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: cmdparse
@@ -509,10 +509,19 @@ files:
509
509
  - lib/hexapdf/type/annotation.rb
510
510
  - lib/hexapdf/type/annotations.rb
511
511
  - lib/hexapdf/type/annotations/appearance_generator.rb
512
+ - lib/hexapdf/type/annotations/border_effect.rb
512
513
  - lib/hexapdf/type/annotations/border_styling.rb
514
+ - lib/hexapdf/type/annotations/circle.rb
515
+ - lib/hexapdf/type/annotations/interior_color.rb
513
516
  - lib/hexapdf/type/annotations/line.rb
517
+ - lib/hexapdf/type/annotations/line_ending_styling.rb
514
518
  - lib/hexapdf/type/annotations/link.rb
515
519
  - lib/hexapdf/type/annotations/markup_annotation.rb
520
+ - lib/hexapdf/type/annotations/polygon.rb
521
+ - lib/hexapdf/type/annotations/polygon_polyline.rb
522
+ - lib/hexapdf/type/annotations/polyline.rb
523
+ - lib/hexapdf/type/annotations/square.rb
524
+ - lib/hexapdf/type/annotations/square_circle.rb
516
525
  - lib/hexapdf/type/annotations/text.rb
517
526
  - lib/hexapdf/type/annotations/widget.rb
518
527
  - lib/hexapdf/type/catalog.rb
@@ -534,6 +543,7 @@ files:
534
543
  - lib/hexapdf/type/info.rb
535
544
  - lib/hexapdf/type/mark_information.rb
536
545
  - lib/hexapdf/type/marked_content_reference.rb
546
+ - lib/hexapdf/type/measure.rb
537
547
  - lib/hexapdf/type/metadata.rb
538
548
  - lib/hexapdf/type/names.rb
539
549
  - lib/hexapdf/type/namespace.rb
@@ -791,9 +801,13 @@ files:
791
801
  - test/hexapdf/type/actions/test_set_ocg_state.rb
792
802
  - test/hexapdf/type/actions/test_uri.rb
793
803
  - test/hexapdf/type/annotations/test_appearance_generator.rb
804
+ - test/hexapdf/type/annotations/test_border_effect.rb
794
805
  - test/hexapdf/type/annotations/test_border_styling.rb
806
+ - test/hexapdf/type/annotations/test_interior_color.rb
795
807
  - test/hexapdf/type/annotations/test_line.rb
808
+ - test/hexapdf/type/annotations/test_line_ending_styling.rb
796
809
  - test/hexapdf/type/annotations/test_markup_annotation.rb
810
+ - test/hexapdf/type/annotations/test_polygon_polyline.rb
797
811
  - test/hexapdf/type/annotations/test_text.rb
798
812
  - test/hexapdf/type/annotations/test_widget.rb
799
813
  - test/hexapdf/type/test_annotation.rb