hexapdf 0.33.0 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -1
  3. data/examples/026-optional_content.rb +55 -0
  4. data/examples/027-composer_optional_content.rb +83 -0
  5. data/lib/hexapdf/cli/command.rb +7 -1
  6. data/lib/hexapdf/cli/fonts.rb +1 -1
  7. data/lib/hexapdf/cli/inspect.rb +2 -4
  8. data/lib/hexapdf/composer.rb +2 -1
  9. data/lib/hexapdf/configuration.rb +21 -1
  10. data/lib/hexapdf/content/canvas.rb +52 -0
  11. data/lib/hexapdf/content/operator.rb +2 -0
  12. data/lib/hexapdf/dictionary.rb +1 -0
  13. data/lib/hexapdf/dictionary_fields.rb +1 -2
  14. data/lib/hexapdf/digital_signature/verification_result.rb +1 -2
  15. data/lib/hexapdf/document/layout.rb +3 -0
  16. data/lib/hexapdf/document/pages.rb +1 -1
  17. data/lib/hexapdf/document.rb +7 -0
  18. data/lib/hexapdf/encryption/ruby_aes.rb +10 -20
  19. data/lib/hexapdf/layout/box.rb +23 -3
  20. data/lib/hexapdf/layout/column_box.rb +2 -1
  21. data/lib/hexapdf/layout/frame.rb +23 -6
  22. data/lib/hexapdf/layout/inline_box.rb +20 -9
  23. data/lib/hexapdf/layout/list_box.rb +34 -20
  24. data/lib/hexapdf/layout/page_style.rb +2 -1
  25. data/lib/hexapdf/layout/style.rb +46 -6
  26. data/lib/hexapdf/layout/table_box.rb +9 -7
  27. data/lib/hexapdf/layout/text_box.rb +9 -2
  28. data/lib/hexapdf/layout/text_fragment.rb +28 -2
  29. data/lib/hexapdf/layout/text_layouter.rb +21 -5
  30. data/lib/hexapdf/stream.rb +1 -2
  31. data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
  32. data/lib/hexapdf/type/actions.rb +1 -0
  33. data/lib/hexapdf/type/annotations/text.rb +1 -2
  34. data/lib/hexapdf/type/catalog.rb +10 -1
  35. data/lib/hexapdf/type/cid_font.rb +15 -1
  36. data/lib/hexapdf/type/form.rb +75 -5
  37. data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
  38. data/lib/hexapdf/type/optional_content_group.rb +370 -0
  39. data/lib/hexapdf/type/optional_content_membership.rb +63 -0
  40. data/lib/hexapdf/type/optional_content_properties.rb +158 -0
  41. data/lib/hexapdf/type/page.rb +27 -11
  42. data/lib/hexapdf/type/page_label.rb +4 -8
  43. data/lib/hexapdf/type.rb +4 -0
  44. data/lib/hexapdf/utils/pdf_doc_encoding.rb +0 -1
  45. data/lib/hexapdf/version.rb +1 -1
  46. data/test/hexapdf/content/test_canvas.rb +49 -0
  47. data/test/hexapdf/document/test_layout.rb +7 -2
  48. data/test/hexapdf/document/test_pages.rb +6 -6
  49. data/test/hexapdf/layout/test_box.rb +13 -4
  50. data/test/hexapdf/layout/test_frame.rb +13 -1
  51. data/test/hexapdf/layout/test_inline_box.rb +17 -8
  52. data/test/hexapdf/layout/test_list_box.rb +48 -31
  53. data/test/hexapdf/layout/test_style.rb +10 -0
  54. data/test/hexapdf/layout/test_table_box.rb +32 -26
  55. data/test/hexapdf/layout/test_text_box.rb +8 -0
  56. data/test/hexapdf/layout/test_text_fragment.rb +33 -0
  57. data/test/hexapdf/layout/test_text_layouter.rb +32 -5
  58. data/test/hexapdf/test_composer.rb +10 -0
  59. data/test/hexapdf/test_dictionary.rb +10 -0
  60. data/test/hexapdf/test_document.rb +4 -0
  61. data/test/hexapdf/test_writer.rb +3 -3
  62. data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
  63. data/test/hexapdf/type/test_catalog.rb +11 -0
  64. data/test/hexapdf/type/test_form.rb +119 -0
  65. data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
  66. data/test/hexapdf/type/test_optional_content_group.rb +158 -0
  67. data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
  68. data/test/hexapdf/type/test_page.rb +2 -2
  69. metadata +14 -3
@@ -0,0 +1,112 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/type/optional_content_configuration'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::Type::OptionalContentConfiguration do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @oc_config = @doc.optional_content.default_configuration
11
+ @ocg = @doc.optional_content.ocg('Test')
12
+ end
13
+
14
+ describe "ocg_state" do
15
+ it "defaults to the base state if nothing specific is set" do
16
+ assert_equal(:on, @oc_config.ocg_state(@ocg))
17
+ @oc_config[:BaseState] = :OFF
18
+ assert_equal(:off, @oc_config.ocg_state(@ocg))
19
+ @oc_config[:BaseState] = :Unchanged
20
+ assert_nil(@oc_config.ocg_state(@ocg))
21
+ end
22
+
23
+ it "returns :on if the OCG is in the /ON key" do
24
+ @oc_config[:ON] = [@ocg]
25
+ [:ON, :OFF, :Unchanged].each do |base_state|
26
+ @oc_config[:BaseState] = base_state
27
+ assert_equal(:on, @oc_config.ocg_state(@ocg))
28
+ end
29
+ end
30
+
31
+ it "returns :off if the OCG is in the /OFF key" do
32
+ @oc_config[:OFF] = [@ocg]
33
+ [:ON, :OFF, :Unchanged].each do |base_state|
34
+ @oc_config[:BaseState] = base_state
35
+ assert_equal(:off, @oc_config.ocg_state(@ocg))
36
+ end
37
+ end
38
+
39
+ it "adds the OCG to the respective dictionary key if a state is given" do
40
+ [[:ON, :OFF], [:OFF, :ON]].each do |state, other_state|
41
+ @oc_config[other_state] = [@ocg]
42
+ @oc_config.ocg_state(@ocg, state.downcase)
43
+ assert_equal([], @oc_config[other_state].value)
44
+ assert_equal([@ocg], @oc_config[state].value)
45
+ @oc_config.ocg_state(@ocg, state)
46
+ assert_equal([@ocg], @oc_config[state].value)
47
+ end
48
+ end
49
+
50
+ it "fails if an invalid state is given" do
51
+ assert_raises(ArgumentError) { @oc_config.ocg_state(@ocg, :unknwo) }
52
+ end
53
+ end
54
+
55
+ it "returns whether a given ocg is on" do
56
+ assert(@oc_config.ocg_on?(@ocg))
57
+ @oc_config[:OFF] = [@ocg]
58
+ refute(@oc_config.ocg_on?(@ocg))
59
+ end
60
+
61
+ describe "add_ocg_to_ui" do
62
+ it "adds the ocg to the top level" do
63
+ @oc_config.add_ocg_to_ui(@ocg)
64
+ @oc_config.add_ocg_to_ui(@ocg)
65
+ assert_equal([@ocg, @ocg], @oc_config[:Order].value)
66
+ end
67
+
68
+ it "adds the ocg under an existing label" do
69
+ @oc_config[:Order] = [:ocg1, ['Test'], :ocg2]
70
+ @oc_config.add_ocg_to_ui(@ocg, path: 'Test')
71
+ @oc_config.add_ocg_to_ui(@ocg, path: 'Test')
72
+ assert_equal([:ocg1, ['Test', @ocg, @ocg], :ocg2], @oc_config[:Order].value)
73
+ end
74
+
75
+ it "adds the ocg under a new label" do
76
+ @oc_config[:Order] = []
77
+ @oc_config.add_ocg_to_ui(@ocg, path: 'Test')
78
+ @oc_config.add_ocg_to_ui(@ocg, path: 'Test')
79
+ @oc_config.add_ocg_to_ui(@ocg, path: 'Test2')
80
+ assert_equal([['Test', @ocg, @ocg], ['Test2', @ocg]], @oc_config[:Order].value)
81
+ end
82
+
83
+ it "adds the ocg under an existing ocg" do
84
+ @oc_config[:Order] = [:ocg1, :ocg2]
85
+ @oc_config.add_ocg_to_ui(@ocg, path: :ocg2)
86
+ @oc_config.add_ocg_to_ui(@ocg, path: :ocg2)
87
+ assert_equal([:ocg1, :ocg2, [@ocg, @ocg]], @oc_config[:Order].value)
88
+ end
89
+
90
+ it "adds the ocg under a new ocg" do
91
+ @oc_config[:Order] = []
92
+ @oc_config.add_ocg_to_ui(@ocg, path: :ocg1)
93
+ @oc_config.add_ocg_to_ui(@ocg, path: :ocg1)
94
+ @oc_config.add_ocg_to_ui(@ocg, path: :ocg2)
95
+ assert_equal([:ocg1, [@ocg, @ocg], :ocg2, [@ocg]], @oc_config[:Order].value)
96
+ end
97
+
98
+ it "adds the ocg under an existing multi-level path" do
99
+ @oc_config[:Order] = [:ocg1, ['Test', :ocg2, [:ocg4, ['Test2', :ocg5]]], :ocg3]
100
+ @oc_config.add_ocg_to_ui(@ocg, path: ['Test', :ocg2, 'Test2'])
101
+ assert_equal([:ocg1, ['Test', :ocg2, [:ocg4, ['Test2', :ocg5, @ocg]]], :ocg3],
102
+ @oc_config[:Order].value)
103
+ end
104
+
105
+ it "adds the ocg under a new multi-level path" do
106
+ @oc_config[:Order] = [:ocg1, ['Test', :ocg2]]
107
+ @oc_config.add_ocg_to_ui(@ocg, path: ['Test2', :ocg3, 'Test3'])
108
+ assert_equal([:ocg1, ['Test', :ocg2], ['Test2', :ocg3, [['Test3', @ocg]]]],
109
+ @oc_config[:Order].value)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,158 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/type/optional_content_group'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::Type::OptionalContentGroup do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @ocg = @doc.add({Type: :OCG, Name: 'OCG'})
11
+ end
12
+
13
+ it "resolves all referenced type classes" do
14
+ hash = {
15
+ Usage: {
16
+ CreatorInfo: {},
17
+ Language: {},
18
+ Export: {},
19
+ Zoom: {},
20
+ Print: {},
21
+ View: {},
22
+ User: {},
23
+ PageElement: {}
24
+ }
25
+ }
26
+ ocg = @doc.add(hash, type: :OCG)
27
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup, ocg)
28
+ ocu = ocg[:Usage]
29
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage, ocu)
30
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::CreatorInfo,
31
+ ocu[:CreatorInfo])
32
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Language,
33
+ ocu[:Language])
34
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Export,
35
+ ocu[:Export])
36
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Zoom,
37
+ ocu[:Zoom])
38
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::Print,
39
+ ocu[:Print])
40
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::View,
41
+ ocu[:View])
42
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::User,
43
+ ocu[:User])
44
+ assert_kind_of(HexaPDF::Type::OptionalContentGroup::OptionalContentUsage::PageElement,
45
+ ocu[:PageElement])
46
+ end
47
+
48
+ it "must always be an indirect object" do
49
+ assert(@ocg.must_be_indirect?)
50
+ end
51
+
52
+ it "returns the name" do
53
+ assert_equal('OCG', @ocg.name)
54
+ @ocg.name('Other')
55
+ assert_equal('Other', @ocg.name)
56
+ end
57
+
58
+ describe "intent" do
59
+ it "can be ask whether the intent is :View" do
60
+ assert(@ocg.intent_view?)
61
+ @ocg[:Intent] = :Design
62
+ refute(@ocg.intent_view?)
63
+ end
64
+
65
+ it "can be ask whether the intent is :Design" do
66
+ refute(@ocg.intent_design?)
67
+ @ocg[:Intent] = :Design
68
+ assert(@ocg.intent_design?)
69
+ end
70
+
71
+ it "can apply one or more intents" do
72
+ @ocg.apply_intent(:View)
73
+ @ocg.apply_intent(:Design)
74
+ assert(@ocg.intent_view?)
75
+ assert(@ocg.intent_design?)
76
+ end
77
+ end
78
+
79
+ describe "managing the OCG's default configuration" do
80
+ it "can be asked whether it is on by default" do
81
+ assert(@ocg.on?)
82
+ @doc.optional_content.default_configuration[:OFF] = [@ocg]
83
+ refute(@ocg.on?)
84
+ end
85
+
86
+ it "can set its default state to on" do
87
+ @doc.optional_content.default_configuration[:OFF] = [@ocg]
88
+ @ocg.on!
89
+ assert(@ocg.on?)
90
+ end
91
+
92
+ it "can set its default state to off" do
93
+ @ocg.off!
94
+ refute(@ocg.on?)
95
+ end
96
+
97
+ it "can add itself to the UI" do
98
+ @ocg.add_to_ui(path: 'Test')
99
+ assert_equal([['Test', @ocg]], @doc.optional_content.default_configuration[:Order].value)
100
+ end
101
+ end
102
+
103
+ it "can set and return the creator info usage entry" do
104
+ refute(@ocg.creator_info)
105
+ dict = @ocg.creator_info("HexaPDF", :Technical)
106
+ assert_equal({Creator: "HexaPDF", Subtype: :Technical}, dict.value)
107
+ assert_raises(ArgumentError) { @ocg.creator_info("HexaPDF") }
108
+ end
109
+
110
+ it "can set and return the language usage entry" do
111
+ refute(@ocg.language)
112
+ dict = @ocg.language('de')
113
+ assert_equal({Lang: "de", Preferred: :OFF}, dict.value)
114
+ @ocg.language('de', preferred: true)
115
+ assert_equal({Lang: "de", Preferred: :ON}, @ocg.language.value)
116
+ end
117
+
118
+ it "can set and return the export state usage entry" do
119
+ refute(@ocg.export_state)
120
+ assert(@ocg.export_state(true))
121
+ assert(@ocg.export_state)
122
+ end
123
+
124
+ it "can set and return the view state usage entry" do
125
+ refute(@ocg.view_state)
126
+ assert(@ocg.view_state(true))
127
+ assert(@ocg.view_state)
128
+ end
129
+
130
+ it "can set and return the print state usage entry" do
131
+ refute(@ocg.print_state)
132
+ dict = @ocg.print_state(true)
133
+ assert_equal({PrintState: :ON, Subtype: nil}, dict.value)
134
+ @ocg.print_state(true, subtype: :Watermark)
135
+ assert_equal({PrintState: :ON, Subtype: :Watermark}, @ocg.print_state.value)
136
+ end
137
+
138
+ it "can set and return the zoom usage entry" do
139
+ refute(@ocg.zoom)
140
+ dict = @ocg.zoom(min: 2.0)
141
+ assert_equal({min: 2.0, max: nil}, dict.value)
142
+ assert_equal({min: nil, max: 3.0}, @ocg.zoom(max: 3.0).value)
143
+ assert_equal({min: 1.0, max: 3.0}, @ocg.zoom(min: 1.0, max: 3.0).value)
144
+ end
145
+
146
+ it "can set and return the intended user usage entry" do
147
+ refute(@ocg.intended_user)
148
+ dict = @ocg.intended_user(:Ind, 'Me')
149
+ assert_equal({Type: :Ind, Name: "Me"}, dict.value)
150
+ end
151
+
152
+ it "can set and return the page element usage entry" do
153
+ refute(@ocg.page_element)
154
+ assert_equal(:HF, @ocg.page_element(:HF))
155
+ @ocg.page_element(:L)
156
+ assert_equal(:L, @ocg.page_element)
157
+ end
158
+ end
@@ -0,0 +1,109 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/type/optional_content_properties'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::Type::OptionalContentProperties do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @oc = @doc.optional_content
11
+ end
12
+
13
+ describe "add_ocg" do
14
+ it "adds a given OCG object" do
15
+ ocg = @doc.add({Type: :OCG, Name: 'test'})
16
+ assert_same(ocg, @oc.add_ocg(ocg))
17
+ assert_equal([ocg], @oc[:OCGs])
18
+ end
19
+
20
+ it "doesn't add an OCG if it has been added before" do
21
+ ocg = @doc.add({Type: :OCG, Name: 'test'})
22
+ @oc.add_ocg(ocg)
23
+ @oc.add_ocg(ocg)
24
+ assert_equal([ocg], @oc[:OCGs])
25
+ end
26
+
27
+ it "creates a new OCG object with the given name and adds it" do
28
+ ocg = @oc.add_ocg('Test')
29
+ assert_equal([ocg], @oc[:OCGs])
30
+ end
31
+ end
32
+
33
+ describe "ocg" do
34
+ it "returns the first OCG with the given name, regardless of the create argument" do
35
+ ocg1 = @oc.add_ocg('Test')
36
+ _ocg2 = @oc.add_ocg('Test')
37
+ assert_same(ocg1, @oc.ocg('Test', create: false))
38
+ assert_same(ocg1, @oc.ocg('Test', create: true))
39
+ end
40
+
41
+ it "returns nil if no OCG with the given name exists and create is false" do
42
+ assert_nil(@oc.ocg('Other', create: false))
43
+ @oc.add_ocg('Test')
44
+ assert_nil(@oc.ocg('Other', create: false))
45
+ end
46
+
47
+ it "creates an OCG with the given name if none is found and create is true" do
48
+ ocg = @oc.ocg('Test')
49
+ assert_same(ocg, @oc.ocg('Test'))
50
+ assert_equal([ocg], @oc[:OCGs])
51
+ end
52
+ end
53
+
54
+ describe "ocgs" do
55
+ it "returns the list of the known optional content groups, with duplicates removed" do
56
+ ocg1 = @oc.add_ocg(@oc.add_ocg('Test'))
57
+ @oc[:OCGs] << nil
58
+ ocg2 = @oc.add_ocg('Test')
59
+ ocg3 = @oc.add_ocg('Other')
60
+ assert_equal([ocg1, ocg2, ocg3], @oc.ocgs)
61
+ end
62
+ end
63
+
64
+ describe "create_ocmd" do
65
+ it "creates the optional content membership dictionary for the given OCGs" do
66
+ ocmd = @oc.create_ocmd(@oc.ocg('Test'))
67
+ assert_equal({Type: :OCMD, OCGs: [@oc.ocg('Test')], P: :AnyOn}, ocmd.value)
68
+
69
+ ocmd = @oc.create_ocmd([@oc.ocg('Test'), @oc.ocg('Test2')], policy: :any_off)
70
+ assert_equal({Type: :OCMD, OCGs: [@oc.ocg('Test'), @oc.ocg('Test2')], P: :AnyOff}, ocmd.value)
71
+ end
72
+
73
+ it "fails if the policy is invalid" do
74
+ error = assert_raises(ArgumentError) { @oc.create_ocmd(:ocg, policy: :unknown) }
75
+ assert_match(/Invalid OCMD.*unknown/, error.message)
76
+ end
77
+ end
78
+
79
+ describe "default_configuration" do
80
+ it "returns an existing dictionary" do
81
+ dict = @oc.default_configuration
82
+ assert_same(@oc[:D], dict)
83
+ assert_kind_of(HexaPDF::Type::OptionalContentConfiguration, dict)
84
+ end
85
+
86
+ it "sets and returns a default configuration dictionary if none is set" do
87
+ @oc.delete(:D)
88
+ assert_equal({Creator: 'HexaPDF'}, @oc.default_configuration.value)
89
+ end
90
+
91
+ it "sets the default configuration dictionary to the given value" do
92
+ d_before = @oc[:D]
93
+ d_new = @oc.default_configuration(Creator: 'Test')
94
+ refute_same(d_before, d_new)
95
+ assert_same(@oc[:D], d_new)
96
+ assert_equal({Creator: 'Test'}, d_new.value)
97
+ end
98
+ end
99
+
100
+ describe "perform_validation" do
101
+ it "creates the /D entry if it is not set" do
102
+ @oc.delete(:D)
103
+ refute(@oc.validate(auto_correct: false))
104
+ refute(@oc.key?(:D))
105
+ assert(@oc.validate(auto_correct: true))
106
+ assert_equal({Creator: 'HexaPDF'}, @oc[:D].value)
107
+ end
108
+ end
109
+ end
@@ -706,14 +706,14 @@ describe HexaPDF::Type::Page do
706
706
  @appearance[:Matrix] = [0.707106, 0.707106, -0.707106, 0.707106, 10, 30]
707
707
  @page.flatten_annotations
708
708
  assert_operators(@canvas.contents,
709
- [:concatenate_matrix, [0.998269, 0.0, 0.0, 0.415946, 111.21318, 80.60659]],
709
+ [:concatenate_matrix, [0.998269, 0.0, 0.0, 0.415946, 111.193776, 91.933396]],
710
710
  range: 1)
711
711
  end
712
712
 
713
713
  it "scales the appearance to fit into the annotations's rectangle" do
714
714
  @annot1[:Rect] = [100, 100, 130, 150]
715
715
  @page.flatten_annotations
716
- assert_operators(@canvas.contents, [:concatenate_matrix, [0.5, 0, 0, 2, 110, 105]], range: 1)
716
+ assert_operators(@canvas.contents, [:concatenate_matrix, [0.5, 0, 0, 2, 105, 110]], range: 1)
717
717
  end
718
718
  end
719
719
 
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.33.0
4
+ version: 0.34.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-08-02 00:00:00.000000000 Z
11
+ date: 2023-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -299,6 +299,8 @@ files:
299
299
  - examples/023-images.rb
300
300
  - examples/024-digital-signatures.rb
301
301
  - examples/025-table_box.rb
302
+ - examples/026-optional_content.rb
303
+ - examples/027-composer_optional_content.rb
302
304
  - examples/emoji-smile.png
303
305
  - examples/emoji-wink.png
304
306
  - examples/machupicchu.jpg
@@ -474,6 +476,7 @@ files:
474
476
  - lib/hexapdf/type/actions/go_to.rb
475
477
  - lib/hexapdf/type/actions/go_to_r.rb
476
478
  - lib/hexapdf/type/actions/launch.rb
479
+ - lib/hexapdf/type/actions/set_ocg_state.rb
477
480
  - lib/hexapdf/type/actions/uri.rb
478
481
  - lib/hexapdf/type/annotation.rb
479
482
  - lib/hexapdf/type/annotations.rb
@@ -500,6 +503,10 @@ files:
500
503
  - lib/hexapdf/type/mark_information.rb
501
504
  - lib/hexapdf/type/names.rb
502
505
  - lib/hexapdf/type/object_stream.rb
506
+ - lib/hexapdf/type/optional_content_configuration.rb
507
+ - lib/hexapdf/type/optional_content_group.rb
508
+ - lib/hexapdf/type/optional_content_membership.rb
509
+ - lib/hexapdf/type/optional_content_properties.rb
503
510
  - lib/hexapdf/type/outline.rb
504
511
  - lib/hexapdf/type/outline_item.rb
505
512
  - lib/hexapdf/type/page.rb
@@ -728,6 +735,7 @@ files:
728
735
  - test/hexapdf/type/acro_form/test_text_field.rb
729
736
  - test/hexapdf/type/acro_form/test_variable_text_field.rb
730
737
  - test/hexapdf/type/actions/test_launch.rb
738
+ - test/hexapdf/type/actions/test_set_ocg_state.rb
731
739
  - test/hexapdf/type/actions/test_uri.rb
732
740
  - test/hexapdf/type/annotations/test_markup_annotation.rb
733
741
  - test/hexapdf/type/annotations/test_text.rb
@@ -748,6 +756,9 @@ files:
748
756
  - test/hexapdf/type/test_info.rb
749
757
  - test/hexapdf/type/test_names.rb
750
758
  - test/hexapdf/type/test_object_stream.rb
759
+ - test/hexapdf/type/test_optional_content_configuration.rb
760
+ - test/hexapdf/type/test_optional_content_group.rb
761
+ - test/hexapdf/type/test_optional_content_properties.rb
751
762
  - test/hexapdf/type/test_outline.rb
752
763
  - test/hexapdf/type/test_outline_item.rb
753
764
  - test/hexapdf/type/test_page.rb
@@ -784,7 +795,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
784
795
  - !ruby/object:Gem::Version
785
796
  version: '0'
786
797
  requirements: []
787
- rubygems_version: 3.5.0.dev
798
+ rubygems_version: 3.4.10
788
799
  signing_key:
789
800
  specification_version: 4
790
801
  summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby