hexapdf 0.34.1 → 0.35.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -0
  3. data/examples/009-text_layouter_alignment.rb +7 -7
  4. data/examples/010-text_layouter_inline_boxes.rb +1 -1
  5. data/examples/011-text_layouter_line_wrapping.rb +2 -4
  6. data/examples/013-text_layouter_shapes.rb +9 -11
  7. data/examples/014-text_in_polygon.rb +2 -2
  8. data/examples/016-frame_automatic_box_placement.rb +6 -7
  9. data/examples/017-frame_text_flow.rb +2 -2
  10. data/examples/018-composer.rb +5 -6
  11. data/examples/020-column_box.rb +2 -2
  12. data/examples/021-list_box.rb +1 -1
  13. data/examples/027-composer_optional_content.rb +5 -5
  14. data/examples/028-frame_mask_mode.rb +23 -0
  15. data/examples/029-composer_fallback_fonts.rb +22 -0
  16. data/lib/hexapdf/cli/info.rb +1 -0
  17. data/lib/hexapdf/cli/inspect.rb +55 -2
  18. data/lib/hexapdf/composer.rb +2 -2
  19. data/lib/hexapdf/configuration.rb +61 -1
  20. data/lib/hexapdf/content/canvas.rb +63 -0
  21. data/lib/hexapdf/content/canvas_composer.rb +142 -0
  22. data/lib/hexapdf/content.rb +1 -0
  23. data/lib/hexapdf/dictionary.rb +14 -3
  24. data/lib/hexapdf/document/layout.rb +35 -13
  25. data/lib/hexapdf/encryption/standard_security_handler.rb +15 -0
  26. data/lib/hexapdf/error.rb +2 -1
  27. data/lib/hexapdf/font/invalid_glyph.rb +22 -6
  28. data/lib/hexapdf/font/true_type_wrapper.rb +48 -20
  29. data/lib/hexapdf/font/type1_wrapper.rb +48 -24
  30. data/lib/hexapdf/layout/box.rb +11 -8
  31. data/lib/hexapdf/layout/column_box.rb +5 -3
  32. data/lib/hexapdf/layout/frame.rb +77 -39
  33. data/lib/hexapdf/layout/image_box.rb +3 -3
  34. data/lib/hexapdf/layout/list_box.rb +20 -19
  35. data/lib/hexapdf/layout/style.rb +173 -68
  36. data/lib/hexapdf/layout/table_box.rb +3 -3
  37. data/lib/hexapdf/layout/text_box.rb +5 -5
  38. data/lib/hexapdf/layout/text_fragment.rb +50 -0
  39. data/lib/hexapdf/layout/text_layouter.rb +7 -6
  40. data/lib/hexapdf/object.rb +5 -2
  41. data/lib/hexapdf/pdf_array.rb +5 -0
  42. data/lib/hexapdf/type/acro_form/appearance_generator.rb +16 -11
  43. data/lib/hexapdf/utils/sorted_tree_node.rb +0 -10
  44. data/lib/hexapdf/version.rb +1 -1
  45. data/test/hexapdf/content/test_canvas.rb +37 -0
  46. data/test/hexapdf/content/test_canvas_composer.rb +112 -0
  47. data/test/hexapdf/document/test_layout.rb +40 -12
  48. data/test/hexapdf/encryption/test_standard_security_handler.rb +43 -0
  49. data/test/hexapdf/font/test_invalid_glyph.rb +13 -1
  50. data/test/hexapdf/font/test_true_type_wrapper.rb +15 -2
  51. data/test/hexapdf/font/test_type1_wrapper.rb +21 -2
  52. data/test/hexapdf/layout/test_column_box.rb +14 -0
  53. data/test/hexapdf/layout/test_frame.rb +181 -95
  54. data/test/hexapdf/layout/test_list_box.rb +7 -7
  55. data/test/hexapdf/layout/test_style.rb +14 -10
  56. data/test/hexapdf/layout/test_table_box.rb +3 -3
  57. data/test/hexapdf/layout/test_text_box.rb +2 -2
  58. data/test/hexapdf/layout/test_text_fragment.rb +37 -0
  59. data/test/hexapdf/layout/test_text_layouter.rb +10 -10
  60. data/test/hexapdf/test_configuration.rb +49 -0
  61. data/test/hexapdf/test_dictionary.rb +1 -1
  62. data/test/hexapdf/test_object.rb +13 -12
  63. data/test/hexapdf/test_pdf_array.rb +9 -0
  64. data/test/hexapdf/test_writer.rb +3 -3
  65. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +41 -13
  66. data/test/hexapdf/utils/test_sorted_tree_node.rb +1 -1
  67. metadata +7 -3
@@ -651,7 +651,7 @@ describe HexaPDF::Layout::TextLayouter do
651
651
  end
652
652
 
653
653
  it "aligns the contents to the left" do
654
- @style.align = :left
654
+ @style.text_align = :left
655
655
  result = @layouter.fit(@items, 100, 100)
656
656
  assert_equal(0, result.lines[0].x_offset)
657
657
  assert_equal(80, result.lines[0].width)
@@ -661,7 +661,7 @@ describe HexaPDF::Layout::TextLayouter do
661
661
  end
662
662
 
663
663
  it "aligns the contents to the center" do
664
- @style.align = :center
664
+ @style.text_align = :center
665
665
  result = @layouter.fit(@items, 100, 100)
666
666
  assert_equal(10, result.lines[0].x_offset)
667
667
  result = @layouter.fit(@items, proc { 100 }, 100)
@@ -669,7 +669,7 @@ describe HexaPDF::Layout::TextLayouter do
669
669
  end
670
670
 
671
671
  it "aligns the contents to the right" do
672
- @style.align = :right
672
+ @style.text_align = :right
673
673
  result = @layouter.fit(@items, 100, 100)
674
674
  assert_equal(20, result.lines[0].x_offset)
675
675
  result = @layouter.fit(@items, proc { 100 }, 100)
@@ -683,28 +683,28 @@ describe HexaPDF::Layout::TextLayouter do
683
683
  end
684
684
 
685
685
  it "aligns the contents to the top" do
686
- @style.valign = :top
686
+ @style.text_valign = :top
687
687
  result = @layouter.fit(@items, 40, 100)
688
688
  assert_equal(result.lines[0].y_max, result.lines[0].y_offset)
689
689
  assert_equal(40, result.height)
690
690
  end
691
691
 
692
692
  it "aligns the contents to the center" do
693
- @style.valign = :center
693
+ @style.text_valign = :center
694
694
  result = @layouter.fit(@items, 40, 100)
695
695
  assert_equal((100 - 40) / 2 + 20, result.lines[0].y_offset)
696
696
  assert_equal(70, result.height)
697
697
  end
698
698
 
699
699
  it "aligns the contents to the bottom" do
700
- @style.valign = :bottom
700
+ @style.text_valign = :bottom
701
701
  result = @layouter.fit(@items, 40, 100)
702
702
  assert_equal(100 - 20 * 2 + 20, result.lines[0].y_offset)
703
703
  assert_equal(100, result.height)
704
704
  end
705
705
 
706
706
  it "doesn't vertically align when layouting in variable-width mode" do
707
- @style.valign = :bottom
707
+ @style.text_valign = :bottom
708
708
  result = @layouter.fit(@items, proc { 40 }, 100)
709
709
  assert_equal(result.lines[0].y_max, result.lines[0].y_offset)
710
710
  assert_equal(40, result.height)
@@ -723,7 +723,7 @@ describe HexaPDF::Layout::TextLayouter do
723
723
  # Missing width: 100 - 90 = 10
724
724
  # -> Each space must be doubled!
725
725
 
726
- @style.align = :justify
726
+ @style.text_align = :justify
727
727
  result = @layouter.fit(items, 100, 100)
728
728
  assert(result.remaining_items.empty?)
729
729
  assert_equal(:success, result.status)
@@ -770,8 +770,8 @@ describe HexaPDF::Layout::TextLayouter do
770
770
 
771
771
  it "respects the x- and y-offsets" do
772
772
  top = 100
773
- @layouter.style.valign = :center
774
- @layouter.style.align = :center
773
+ @layouter.style.text_valign = :center
774
+ @layouter.style.text_align = :center
775
775
 
776
776
  result = @layouter.fit([@frag], @width, top)
777
777
  result.draw(@canvas, 5, top)
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'test_helper'
4
4
  require 'hexapdf/configuration'
5
+ require 'hexapdf/document'
5
6
 
6
7
  describe HexaPDF::Configuration do
7
8
  before do
@@ -91,3 +92,51 @@ describe HexaPDF::Configuration do
91
92
  end
92
93
  end
93
94
  end
95
+
96
+ describe "HexaPDF.font_on_invalid_glyph" do
97
+ before do
98
+ @doc = HexaPDF::Document.new
99
+ @font = @doc.fonts.add('Helvetica')
100
+ end
101
+
102
+ def assert_glyph(font, codepoint, font_name, glyph_name)
103
+ invalid_glyph = HexaPDF::Font::InvalidGlyph.new(font, codepoint.chr("UTF-8"))
104
+ glyph = HexaPDF.font_on_invalid_glyph(codepoint, invalid_glyph)
105
+
106
+ assert_equal(1, glyph.size)
107
+ glyph = glyph.first
108
+ assert(glyph.valid?)
109
+ assert_equal(font_name, glyph.font_wrapper.wrapped_font.font_name)
110
+ assert_equal(glyph_name, glyph.name)
111
+ glyph
112
+ end
113
+
114
+ it "tries each fallback font and uses the first valid glyph" do
115
+ assert_glyph(@font, 10102, "ZapfDingbats", :a130)
116
+ assert_glyph(@font, 8855, "Symbol", :circlemultiply)
117
+ end
118
+
119
+ it "takes the font variant into account" do
120
+ @doc.config['font.fallback'] = ['Times']
121
+
122
+ glyph = assert_glyph(@doc.fonts.add("Helvetica", variant: :bold), 65, "Times-Bold", :A)
123
+ assert(glyph.font_wrapper.bold?)
124
+
125
+ glyph = assert_glyph(@doc.fonts.add("Helvetica", variant: :italic), 65, "Times-Italic", :A)
126
+ assert(glyph.font_wrapper.italic?)
127
+
128
+ glyph = assert_glyph(@doc.fonts.add("Helvetica", variant: :bold_italic), 65, "Times-BoldItalic", :A)
129
+ assert(glyph.font_wrapper.bold?)
130
+ assert(glyph.font_wrapper.italic?)
131
+ end
132
+
133
+ it "falls back to the :none variant of a fallback font if a more specific one doesn't exist" do
134
+ assert_glyph(@doc.fonts.add("Helvetica", variant: :bold), 9985, "ZapfDingbats", :a1)
135
+ end
136
+
137
+ it "returns the given invalid glyph if no fallback glyph could be found" do
138
+ @doc.config['font.fallback'] = []
139
+ invalid_glyph = HexaPDF::Font::InvalidGlyph.new(@font, "A")
140
+ assert_equal([invalid_glyph], HexaPDF.font_on_invalid_glyph(65, invalid_glyph))
141
+ end
142
+ end
@@ -204,7 +204,7 @@ describe HexaPDF::Dictionary do
204
204
  end
205
205
  end
206
206
 
207
- describe "validate_fields" do
207
+ describe "perform_validation" do
208
208
  before do
209
209
  @test_class.define_field(:Inherited, type: [Array, Symbol], required: true, indirect: false)
210
210
  @test_class.define_field(:AllowedValues, type: Integer, allowed_values: [1, 5])
@@ -186,6 +186,19 @@ describe HexaPDF::Object do
186
186
  refute(@obj.validate(auto_correct: false))
187
187
  assert_equal([:before], invoked)
188
188
  end
189
+
190
+ it "re-raises caught HexaPDF::Error exceptions" do
191
+ @obj.define_singleton_method(:perform_validation) { raise HexaPDF::Error, "Unknown" }
192
+ invoked = []
193
+ assert_raises(HexaPDF::Error) { @obj.validate {|*a| invoked << a } }
194
+ end
195
+
196
+ it "catches errors raised in perform_validation and produces an appropriate message" do
197
+ @obj.define_singleton_method(:perform_validation) { raise "Unknown" }
198
+ invoked = []
199
+ refute(@obj.validate {|*a| invoked << a })
200
+ assert_equal([["Error: Unexpected value encountered", false, @obj]], invoked)
201
+ end
189
202
  end
190
203
 
191
204
  it "can represent itself during inspection" do
@@ -286,17 +299,5 @@ describe HexaPDF::Object do
286
299
  obj.validate
287
300
  assert_equal(1, obj.oid)
288
301
  end
289
-
290
- it "validates collection values" do
291
- x = HexaPDF::Object.new(:x, document: @doc)
292
- x.must_be_indirect = true
293
- y = HexaPDF::Object.new(:y, document: @doc)
294
- y.must_be_indirect = true
295
-
296
- obj = HexaPDF::Object.new([1, 2, 3, [4, x], {X: [y, 5]}])
297
- obj.validate
298
- assert_equal(1, x.oid)
299
- assert_equal(1, y.oid)
300
- end
301
302
  end
302
303
  end
@@ -166,4 +166,13 @@ describe HexaPDF::PDFArray do
166
166
  it "can be converted to a simple array" do
167
167
  assert_equal([1, :data, "deref", @array[3]], @array.to_ary)
168
168
  end
169
+
170
+ describe "perform_validation" do
171
+ it "validates nested objects" do
172
+ @array.value << HexaPDF::PDFArray.new([HexaPDF::Reference.new(1, 0)], document: self)
173
+ assert(@array.validate)
174
+ assert_kind_of(HexaPDF::Object, @array.value[2])
175
+ assert_kind_of(HexaPDF::Object, @array.value.last.value[0])
176
+ end
177
+ end
169
178
  end
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.34.1)>>
43
+ <</Producer(HexaPDF version 0.35.0)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.34.1)>>
75
+ <</Producer(HexaPDF version 0.35.0)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
@@ -214,7 +214,7 @@ describe HexaPDF::Writer do
214
214
  <</Type/Page/MediaBox[0 0 595 842]/Parent 2 0 R/Resources<<>>>>
215
215
  endobj
216
216
  5 0 obj
217
- <</Producer(HexaPDF version 0.34.1)>>
217
+ <</Producer(HexaPDF version 0.35.0)>>
218
218
  endobj
219
219
  4 0 obj
220
220
  <</Root 1 0 R/Info 5 0 R/Size 6/Type/XRef/W[1 1 2]/Index[0 6]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 33>>stream
@@ -453,7 +453,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
453
453
  before do
454
454
  @widget[:Rect].height = 20
455
455
  @widget[:Rect].width = 100
456
- @field.field_value = ''
456
+ @field[:V] = ''
457
457
  end
458
458
 
459
459
  it "uses the non-zero font size" do
@@ -477,7 +477,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
477
477
  end
478
478
 
479
479
  it "shrinks the font size if necessary to fit the rectangle width" do
480
- @field.field_value = "This is some arbitrary, long text"
480
+ @field[:V] = "This is some arbitrary, long text"
481
481
  @generator.create_appearances
482
482
  assert_operators(@widget[:AP][:N].stream,
483
483
  [:set_font_and_size, [:F1, 6.909955]],
@@ -498,7 +498,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
498
498
  describe "single line text fields" do
499
499
  describe "quadding e.g. text alignment" do
500
500
  before do
501
- @field.field_value = 'Test'
501
+ @field[:V] = 'Test'
502
502
  @field.set_default_appearance_string(font_size: 10)
503
503
  @widget[:Rect].height = 20
504
504
  end
@@ -551,7 +551,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
551
551
 
552
552
  describe "Javascript action AFNumber_Format" do
553
553
  before do
554
- @field.field_value = '1234567.898765'
554
+ @field[:V] = '1234567.898765'
555
555
  @action = {S: :JavaScript, JS: ''}
556
556
  @field[:AA] = {F: @action}
557
557
  end
@@ -576,7 +576,8 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
576
576
  end
577
577
 
578
578
  it "respects the negative value styling" do
579
- @field.field_value = '-1234567.898'
579
+ @field[:V] = '-1234567.898'
580
+ @widget[:Rect].height = 11.25
580
581
  ["-E1234567,90", "E1234567,90", "(E1234567,90)", "(E1234567,90)"].each_with_index do |result, style|
581
582
  assert_format("2, 3, #{style}, 0, \"E\", true",
582
583
  [[:set_device_rgb_non_stroking_color, [style % 2, 0.0, 0.0]],
@@ -597,8 +598,11 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
597
598
  end
598
599
 
599
600
  it "creates the /N appearance stream according to the set string" do
600
- @field.field_value = 'Text'
601
+ @doc.config['font.on_invalid_glyph'] = lambda do |codepoint, _|
602
+ [@doc.fonts.add('ZapfDingbats').decode_codepoint(codepoint)]
603
+ end
601
604
  @field.set_default_appearance_string(font_color: "red")
605
+ @field[:V] = 'Te ✂ xt'
602
606
  @generator.create_appearances
603
607
  assert_operators(@widget[:AP][:N].stream,
604
608
  [[:begin_marked_content, [:Tx]],
@@ -606,11 +610,17 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
606
610
  [:append_rectangle, [1, 1, 98, 9.25]],
607
611
  [:clip_path_non_zero],
608
612
  [:end_path],
609
- [:set_font_and_size, [:F1, 6.801471]],
613
+ [:set_font_and_size, [:F1, 10]],
610
614
  [:set_device_rgb_non_stroking_color, [1.0, 0.0, 0.0]],
611
615
  [:begin_text],
612
- [:set_text_matrix, [1, 0, 0, 1, 2, 3.183272]],
613
- [:show_text, ["Text"]],
616
+ [:set_text_matrix, [1, 0, 0, 1, 2, 2.035]],
617
+ [:show_text, ["Te "]],
618
+ [:set_font_and_size, [:F2, 10]],
619
+ [:move_text, [14.45, 0]],
620
+ [:show_text, ["\""]],
621
+ [:set_font_and_size, [:F1, 10]],
622
+ [:move_text, [9.61, 0]],
623
+ [:show_text, [" xt"]],
614
624
  [:end_text],
615
625
  [:restore_graphics_state],
616
626
  [:end_marked_content]])
@@ -656,7 +666,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
656
666
  end
657
667
 
658
668
  it "creates the /N appearance stream according to the set string" do
659
- @field.field_value = "Test\nValue"
669
+ @field[:V] = "Test\nValue"
660
670
  @field.set_default_appearance_string(font_size: 10, font_color: "red")
661
671
  @generator.create_appearances
662
672
  assert_operators(@widget[:AP][:N].stream,
@@ -679,7 +689,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
679
689
  [:restore_graphics_state],
680
690
  [:end_marked_content]])
681
691
 
682
- @field.field_value = "Test\nTest\nTest"
692
+ @field[:V] = "Test\nTest\nTest"
683
693
  @field.set_default_appearance_string(font_size: 0)
684
694
  @generator.create_appearances
685
695
  assert_operators(@widget[:AP][:N].stream,
@@ -744,7 +754,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
744
754
  end
745
755
 
746
756
  it "handles centering like Adobe, e.g. shift left, when text cannot be completely centered" do
747
- @field.field_value = 'Hello'
757
+ @field[:V] = 'Hello'
748
758
  @field.text_alignment(:center)
749
759
  @generator.create_appearances
750
760
  assert_operators(@widget[:AP][:N].stream,
@@ -754,7 +764,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
754
764
  end
755
765
 
756
766
  it "creates the /N appearance stream according to the set string" do
757
- @field.field_value = 'Text'
767
+ @field[:V] = 'Text'
758
768
  @field.set_default_appearance_string(font_size: 10, font_color: "red")
759
769
  @generator.create_appearances
760
770
  assert_operators(@widget[:AP][:N].stream,
@@ -773,11 +783,29 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
773
783
  [:end_marked_content]])
774
784
  end
775
785
 
786
+ it "works for empty strings" do
787
+ @field[:V] = ''
788
+ @generator.create_appearances
789
+ assert_operators(@widget[:AP][:N].stream,
790
+ [[:begin_text],
791
+ [:set_text_matrix, [1, 0, 0, 1, 2, 6.41]],
792
+ [:end_text]], range: 6..8)
793
+ end
794
+
776
795
  it "fails if the /MaxLen key is not set" do
777
796
  @field.delete(:MaxLen)
778
797
  @field[:V] = 't'
779
798
  assert_raises(HexaPDF::Error) { @generator.create_appearances }
780
799
  end
800
+
801
+ it "fails if fallback glyphs are needed for rendering" do
802
+ @doc.config['font.on_invalid_glyph'] = lambda do |codepoint, _|
803
+ [@doc.fonts.add('ZapfDingbats').decode_codepoint(codepoint)]
804
+ end
805
+ @field[:V] = 'Test ✂'
806
+ ex = assert_raises(HexaPDF::Error) { @generator.create_appearances }
807
+ assert_match(/Fallback glyphs/, ex.message)
808
+ end
781
809
  end
782
810
 
783
811
  describe "choice fields" do
@@ -209,7 +209,7 @@ describe HexaPDF::Utils::SortedTreeNode do
209
209
  @root[:Kids][0] = ref
210
210
  @kid1.oid = 0
211
211
  assert(@root.validate do |message, c|
212
- assert_match(/must be indirect objects/, message)
212
+ assert_match(/must be an indirect object/, message)
213
213
  assert(c)
214
214
  end)
215
215
  assert(@kid1.indirect?)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.1
4
+ version: 0.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-01 00:00:00.000000000 Z
11
+ date: 2024-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -301,6 +301,8 @@ files:
301
301
  - examples/025-table_box.rb
302
302
  - examples/026-optional_content.rb
303
303
  - examples/027-composer_optional_content.rb
304
+ - examples/028-frame_mask_mode.rb
305
+ - examples/029-composer_fallback_fonts.rb
304
306
  - examples/emoji-smile.png
305
307
  - examples/emoji-wink.png
306
308
  - examples/machupicchu.jpg
@@ -324,6 +326,7 @@ files:
324
326
  - lib/hexapdf/configuration.rb
325
327
  - lib/hexapdf/content.rb
326
328
  - lib/hexapdf/content/canvas.rb
329
+ - lib/hexapdf/content/canvas_composer.rb
327
330
  - lib/hexapdf/content/color_space.rb
328
331
  - lib/hexapdf/content/graphic_object.rb
329
332
  - lib/hexapdf/content/graphic_object/arc.rb
@@ -603,6 +606,7 @@ files:
603
606
  - test/hexapdf/content/graphic_object/test_geom2d.rb
604
607
  - test/hexapdf/content/graphic_object/test_solid_arc.rb
605
608
  - test/hexapdf/content/test_canvas.rb
609
+ - test/hexapdf/content/test_canvas_composer.rb
606
610
  - test/hexapdf/content/test_color_space.rb
607
611
  - test/hexapdf/content/test_graphics_state.rb
608
612
  - test/hexapdf/content/test_operator.rb
@@ -795,7 +799,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
795
799
  - !ruby/object:Gem::Version
796
800
  version: '0'
797
801
  requirements: []
798
- rubygems_version: 3.4.10
802
+ rubygems_version: 3.5.3
799
803
  signing_key:
800
804
  specification_version: 4
801
805
  summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby