hexapdf 0.33.0 → 0.34.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -1
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +7 -1
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +2 -4
- data/lib/hexapdf/composer.rb +2 -1
- data/lib/hexapdf/configuration.rb +21 -1
- data/lib/hexapdf/content/canvas.rb +52 -0
- data/lib/hexapdf/content/operator.rb +2 -0
- data/lib/hexapdf/dictionary.rb +1 -0
- data/lib/hexapdf/dictionary_fields.rb +1 -2
- data/lib/hexapdf/digital_signature/verification_result.rb +1 -2
- data/lib/hexapdf/document/layout.rb +3 -0
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/document.rb +7 -0
- data/lib/hexapdf/encryption/ruby_aes.rb +10 -20
- data/lib/hexapdf/layout/box.rb +23 -3
- data/lib/hexapdf/layout/column_box.rb +2 -1
- data/lib/hexapdf/layout/frame.rb +23 -6
- data/lib/hexapdf/layout/inline_box.rb +20 -9
- data/lib/hexapdf/layout/list_box.rb +34 -20
- data/lib/hexapdf/layout/page_style.rb +2 -1
- data/lib/hexapdf/layout/style.rb +46 -6
- data/lib/hexapdf/layout/table_box.rb +9 -7
- data/lib/hexapdf/layout/text_box.rb +9 -2
- data/lib/hexapdf/layout/text_fragment.rb +28 -2
- data/lib/hexapdf/layout/text_layouter.rb +21 -5
- data/lib/hexapdf/stream.rb +1 -2
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions.rb +1 -0
- data/lib/hexapdf/type/annotations/text.rb +1 -2
- data/lib/hexapdf/type/catalog.rb +10 -1
- data/lib/hexapdf/type/cid_font.rb +15 -1
- data/lib/hexapdf/type/form.rb +75 -5
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/page.rb +27 -11
- data/lib/hexapdf/type/page_label.rb +4 -8
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +0 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas.rb +49 -0
- data/test/hexapdf/document/test_layout.rb +7 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/layout/test_box.rb +13 -4
- data/test/hexapdf/layout/test_frame.rb +13 -1
- data/test/hexapdf/layout/test_inline_box.rb +17 -8
- data/test/hexapdf/layout/test_list_box.rb +48 -31
- data/test/hexapdf/layout/test_style.rb +10 -0
- data/test/hexapdf/layout/test_table_box.rb +32 -26
- data/test/hexapdf/layout/test_text_box.rb +8 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +32 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_document.rb +4 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +2 -2
- 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.
|
|
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,
|
|
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.
|
|
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-
|
|
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.
|
|
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
|