subconv 0.1.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 +7 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +74 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +59 -0
- data/Rakefile +10 -0
- data/bin/subconv +58 -0
- data/dist/eia608.css +106 -0
- data/lib/subconv.rb +5 -0
- data/lib/subconv/caption.rb +106 -0
- data/lib/subconv/caption_filter.rb +129 -0
- data/lib/subconv/scc/reader.rb +470 -0
- data/lib/subconv/scc/transformer.rb +259 -0
- data/lib/subconv/utility.rb +42 -0
- data/lib/subconv/version.rb +3 -0
- data/lib/subconv/webvtt/writer.rb +131 -0
- data/spec/caption_filter_spec.rb +154 -0
- data/spec/scc/reader_spec.rb +311 -0
- data/spec/scc/transformer_spec.rb +167 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/test_helpers.rb +73 -0
- data/spec/webvtt/writer_spec.rb +106 -0
- data/subconv.gemspec +34 -0
- metadata +188 -0
@@ -0,0 +1,311 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Subconv
|
4
|
+
# Often used codes:
|
5
|
+
# 9420: Resume caption loading
|
6
|
+
# 91d0: Preamble address code for row 0 column 0
|
7
|
+
# 942f: End of caption
|
8
|
+
describe Scc::Reader do
|
9
|
+
include TestHelpers
|
10
|
+
|
11
|
+
let(:backspace) { '94a1 94a1' }
|
12
|
+
let(:test) { '54e5 73f4' }
|
13
|
+
let(:a) { 'c180' }
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@reader = Scc::Reader.new
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should reject garbage' do
|
20
|
+
expect {
|
21
|
+
@reader.read(StringIO.new('safjewofjpoajfljg'), default_fps)
|
22
|
+
}.to raise_error(Scc::Reader::InvalidFormatError)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Helper function to create a string that represents an SCC file with
|
26
|
+
# a single caption at zero time
|
27
|
+
# data must be given as fully formatted SCC string
|
28
|
+
def caption_at_zero(data)
|
29
|
+
"Scenarist_SCC V1.0\n\n00:00:00:00\t#{data}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Parse the input string with Scc::Reader and return the resulting captions
|
33
|
+
def get_captions(input, fps = default_fps, check_parity = true)
|
34
|
+
@reader.read(StringIO.new(input), fps, check_parity)
|
35
|
+
@reader.captions
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should reject data with wrong parity' do
|
39
|
+
expect {
|
40
|
+
get_captions(caption_at_zero("9420 11d0 #{test} 942f"))
|
41
|
+
}.to raise_error(Scc::Reader::ParityError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should decode simple text' do
|
45
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'Test')
|
46
|
+
|
47
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not reject data with wrong parity when checking is not requested' do
|
51
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'Test')
|
52
|
+
|
53
|
+
expect(get_captions(caption_at_zero("9420 11d0 #{test} 942f"), default_fps, false)).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
54
|
+
end
|
55
|
+
|
56
|
+
expected_rows = {
|
57
|
+
'9140' => 0,
|
58
|
+
'91E0' => 1,
|
59
|
+
'9240' => 2,
|
60
|
+
'92E0' => 3,
|
61
|
+
'1540' => 4,
|
62
|
+
'15E0' => 5,
|
63
|
+
'1640' => 6,
|
64
|
+
'16E0' => 7,
|
65
|
+
'9740' => 8,
|
66
|
+
'97E0' => 9,
|
67
|
+
'1040' => 10,
|
68
|
+
'1340' => 11,
|
69
|
+
'13E0' => 12,
|
70
|
+
'9440' => 13,
|
71
|
+
'94E0' => 14
|
72
|
+
}
|
73
|
+
|
74
|
+
expected_rows.each_pair do |pac, row|
|
75
|
+
it "should decode the preamble address code #{pac} to row #{row}" do
|
76
|
+
expected_grid = Scc::Grid.new.insert_text(row, 0, 'Test')
|
77
|
+
expect(get_captions(caption_at_zero("9420 #{pac} #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
expected_column = {
|
82
|
+
'91d0' => 0,
|
83
|
+
'9152' => 4,
|
84
|
+
'9154' => 8,
|
85
|
+
'91D6' => 12,
|
86
|
+
'9158' => 16,
|
87
|
+
'91da' => 20,
|
88
|
+
'91dc' => 24,
|
89
|
+
'915e' => 28
|
90
|
+
}
|
91
|
+
|
92
|
+
expected_column.each_pair do |pac, column|
|
93
|
+
it "should decode the preamble address code #{pac} to column #{column}" do
|
94
|
+
expected_grid = Scc::Grid.new.insert_text(0, column, 'Test')
|
95
|
+
expect(get_captions(caption_at_zero("9420 #{pac} #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should handle backspace' do
|
100
|
+
expected_grid = Scc::Grid.new.insert_text(1, 0, 'Test')
|
101
|
+
# Write AA, then backspace three times, go to next row, write Tesu, backspace one time, then write t
|
102
|
+
# -> Should result in the first line being empty and the second line reading "Test"
|
103
|
+
expect(get_captions(caption_at_zero('9420 91d0 c1c1 ' + (backspace + ' ') * 3 + "91e0 54e5 7375 #{backspace} f480 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(15, default_fps), grid: expected_grid)])
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should handle overflowing lines' do
|
107
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A' * 31 + 'B')
|
108
|
+
# Write 40 As and then tw Bs
|
109
|
+
# -> Should result in 31 As and one B since after overflow the last column is overwritten the whole time
|
110
|
+
expect(get_captions(caption_at_zero('9420 91d0 ' + ('c1c1 ' * 20) + 'c2c2 942f'))).to eq([Scc::Caption.new(timecode: Timecode.new(23, default_fps), grid: expected_grid)])
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should handle italics' do
|
114
|
+
style = Scc::CharacterStyle.default
|
115
|
+
style.italics = true
|
116
|
+
# Italics is a mid-row spacing code, so expect a space before the text
|
117
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ').insert_text(0, 1, 'Test', style)
|
118
|
+
expect(get_captions(caption_at_zero("9420 91d0 91ae #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(5, default_fps), grid: expected_grid)])
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should turn off flash on italics mid-row codes' do
|
122
|
+
style = Scc::CharacterStyle.default
|
123
|
+
flash_style = Scc::CharacterStyle.default
|
124
|
+
style.italics = true
|
125
|
+
flash_style.flash = true
|
126
|
+
# Two spaces before the text
|
127
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ').insert_text(0, 1, ' ', flash_style).insert_text(0, 2, 'Test', style)
|
128
|
+
# "<flash on><italics>Test"
|
129
|
+
expect(get_captions(caption_at_zero("9420 91d0 94a8 91ae #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should handle italics preamble address code' do
|
133
|
+
style = Scc::CharacterStyle.default
|
134
|
+
style.italics = true
|
135
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'Test', style)
|
136
|
+
expect(get_captions(caption_at_zero("9420 91ce #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should handle italics and underline preamble address code' do
|
140
|
+
style = Scc::CharacterStyle.default
|
141
|
+
style.italics = true
|
142
|
+
style.underline = true
|
143
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'Test', style)
|
144
|
+
expect(get_captions(caption_at_zero("9420 914f #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should handle underline' do
|
148
|
+
style = Scc::CharacterStyle.default
|
149
|
+
style.underline = true
|
150
|
+
# Underline is a mid-row spacing code, so expect a space before the text
|
151
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ').insert_text(0, 1, 'Test', style)
|
152
|
+
expect(get_captions(caption_at_zero("9420 91d0 91a1 #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(5, default_fps), grid: expected_grid)])
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should handle italics and underline' do
|
156
|
+
style = Scc::CharacterStyle.default
|
157
|
+
style.italics = true
|
158
|
+
style.underline = true
|
159
|
+
# Italics/underline is a mid-row spacing code, so expect a space before the text
|
160
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ').insert_text(0, 1, 'Test', style)
|
161
|
+
expect(get_captions(caption_at_zero("9420 91d0 912f #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(5, default_fps), grid: expected_grid)])
|
162
|
+
end
|
163
|
+
|
164
|
+
color_code_map = {
|
165
|
+
Scc::Color::WHITE => '9120',
|
166
|
+
Scc::Color::GREEN => '91a2',
|
167
|
+
Scc::Color::BLUE => '91a4',
|
168
|
+
Scc::Color::CYAN => '9126',
|
169
|
+
Scc::Color::RED => '91a8',
|
170
|
+
Scc::Color::YELLOW => '912a',
|
171
|
+
Scc::Color::MAGENTA => '912c'
|
172
|
+
}
|
173
|
+
|
174
|
+
color_code_map.each_pair do |color, color_code|
|
175
|
+
it "should handle the color #{color}" do
|
176
|
+
style = Scc::CharacterStyle.default
|
177
|
+
style.color = color
|
178
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A', style)
|
179
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{color_code} #{backspace} #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should turn off italics on color' do
|
184
|
+
style = Scc::CharacterStyle.default
|
185
|
+
italics_style = Scc::CharacterStyle.default
|
186
|
+
style.color = Scc::Color::RED
|
187
|
+
italics_style.italics = true
|
188
|
+
# Two spaces before the text
|
189
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ').insert_text(0, 1, ' ', italics_style).insert_text(0, 2, 'Test', style)
|
190
|
+
# "<italics><red>Test"
|
191
|
+
expect(get_captions(caption_at_zero("9420 91d0 91ae 91a8 #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'should handle all available attributes combined' do
|
195
|
+
style = Scc::CharacterStyle.default
|
196
|
+
style.color = Scc::Color::RED
|
197
|
+
# Space generated by italics/underline
|
198
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, ' ', style.dup)
|
199
|
+
style.italics = true
|
200
|
+
style.underline = true
|
201
|
+
# Space generated by flash
|
202
|
+
expected_grid.insert_text(0, 1, ' ', style.dup)
|
203
|
+
style.flash = true
|
204
|
+
expected_grid.insert_text(0, 2, 'Test', style.dup)
|
205
|
+
# Set color via preamble address code to test that too, then set italics/underline via mid-row code, then assign flash via "flash on" miscellaneous control code
|
206
|
+
expect(get_captions(caption_at_zero("9420 91c8 912f 94a8 #{test} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should handle transparent space' do
|
210
|
+
# Column 1 should be empty
|
211
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A').insert_text(0, 2, 'A')
|
212
|
+
# "A<transparent space>A"
|
213
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{a} 91b9 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(5, default_fps), grid: expected_grid)])
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should delete characters behind transparent space' do
|
217
|
+
# Column 1 should be empty
|
218
|
+
expected_grid = Scc::Grid.new.insert_text(0, 1, 'est')
|
219
|
+
# "Test<PAC><transparent space>"
|
220
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{test} 91d0 91b9 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should handle standard space' do
|
224
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A A')
|
225
|
+
# "A A"
|
226
|
+
expect(get_captions(caption_at_zero('9420 91d0 c120 c180 942f'))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid)])
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should handle tab offset' do
|
230
|
+
# Space between the As should be empty
|
231
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A').insert_text(0, 2, 'A').insert_text(0, 5, 'A').insert_text(0, 9, 'A')
|
232
|
+
# "A<tab offset 1>A<tab offset 2>A<tab offset 3>A"
|
233
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{a} 97a1 #{a} 97a2 #{a} 9723 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(9, default_fps), grid: expected_grid)])
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should not delete characters on tab offset' do
|
237
|
+
# Space between the As should be empty
|
238
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'TAst')
|
239
|
+
# "Test<PAC><tab offset 1>A"
|
240
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{test} 91d0 97a1 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(7, default_fps), grid: expected_grid)])
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should ignore repeated commands' do
|
244
|
+
# There should be only one, not two spaces between the As
|
245
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A').insert_text(0, 2, 'A')
|
246
|
+
# "A<transparent space><transparent space>A"
|
247
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{a} 91b9 91b9 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(6, default_fps), grid: expected_grid)])
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'should not ignore multiply repeated commands' do
|
251
|
+
# Now there should be not, not four or one, spaces between the As
|
252
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A').insert_text(0, 3, 'A')
|
253
|
+
# "A<transparent space><transparent space<transparent space><transparent space>>A"
|
254
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{a} 91b9 91b9 91b9 91b9 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(8, default_fps), grid: expected_grid)])
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should handle delete to end of row' do
|
258
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'AAAA')
|
259
|
+
# "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<PAC indent 4><delete to end of row>"
|
260
|
+
expect(get_captions(caption_at_zero('9420 91d0 ' + (a + ' ') * 32 + '9152 94a4 942f'))).to eq([Scc::Caption.new(timecode: Timecode.new(36, default_fps), grid: expected_grid)])
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should handle erase displayed memory' do
|
264
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'Test')
|
265
|
+
# Display "Test", wait 2 frames, erase displayed memory
|
266
|
+
# -> should result in an empty caption 3 frames later
|
267
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{test} 942f 8080 8080 942c"))).to eq([Scc::Caption.new(timecode: Timecode.new(4, default_fps), grid: expected_grid), Scc::Caption.new(timecode: Timecode.new(7, default_fps))])
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should handle erase non-displayed memory' do
|
271
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, 'A')
|
272
|
+
# Insert "Test", delete the non-displayed memory, insert "A" and then flip captions
|
273
|
+
expect(get_captions(caption_at_zero("9420 91d0 #{test} 94ae 91d0 #{a} 942f"))).to eq([Scc::Caption.new(timecode: Timecode.new(7, default_fps), grid: expected_grid)])
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should handle special characters' do
|
277
|
+
expected_grid = Scc::Grid.new.insert_text(0, 0, '♪')
|
278
|
+
expect(get_captions(caption_at_zero('9420 91d0 9137 942f'))).to eq([Scc::Caption.new(timecode: Timecode.new(3, default_fps), grid: expected_grid)])
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should handle multiple timecodes and captions' do
|
282
|
+
expected_grid_test = Scc::Grid.new.insert_text(0, 0, 'Test')
|
283
|
+
expected_grid_a = Scc::Grid.new.insert_text(0, 0, 'A')
|
284
|
+
expected_grid_b = Scc::Grid.new.insert_text(0, 0, 'B')
|
285
|
+
caption_text = <<"END"
|
286
|
+
Scenarist_SCC V1.0
|
287
|
+
|
288
|
+
00:00:01:00\t9420 91d0 #{test} 942f 94ae
|
289
|
+
|
290
|
+
00:00:02:00\t9420 91d0 #{test} 942f 94ae
|
291
|
+
|
292
|
+
00:00:03:00\t942c
|
293
|
+
|
294
|
+
00:00:04:00\t9420 91d0 c180 942f
|
295
|
+
|
296
|
+
00:00:05:00\t9420 91d0 c280 942f
|
297
|
+
END
|
298
|
+
expect(get_captions(caption_text)).to eq([
|
299
|
+
# First caption: Test
|
300
|
+
Scc::Caption.new(timecode: Timecode.parse('00:00:01:04', default_fps), grid: expected_grid_test),
|
301
|
+
# Caption at 00:00:02:00 should be identical to the first one and thus not get put out
|
302
|
+
# At 00:00:03:00: erase displayed caption
|
303
|
+
Scc::Caption.new(timecode: Timecode.parse('00:00:03:00', default_fps)),
|
304
|
+
# At 00:00:04:00: Display "A"
|
305
|
+
Scc::Caption.new(timecode: Timecode.parse('00:00:04:03', default_fps), grid: expected_grid_a),
|
306
|
+
# At 00:00:05:00: Display "B" without erasing A beforehand
|
307
|
+
Scc::Caption.new(timecode: Timecode.parse('00:00:05:03', default_fps), grid: expected_grid_b)
|
308
|
+
])
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Subconv
|
4
|
+
describe Scc::Transformer do
|
5
|
+
include TestHelpers
|
6
|
+
include Subconv
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@transformer = Scc::Transformer.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should handle empty captions' do
|
13
|
+
expect(@transformer.transform([])).to eq([])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should convert a simple caption' do
|
17
|
+
transformed = @transformer.transform(single_scc_caption_with_grid(test_grid))
|
18
|
+
expect(transformed).to eq([Caption.new(timespan: t1_2, position: left_top, content: test_content)])
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should auto-close dangling captions' do
|
22
|
+
transformed = @transformer.transform([Scc::Caption.new(timecode: t1, grid: test_grid)])
|
23
|
+
# Caption should be closed after 5 seconds
|
24
|
+
t_end = t1 + Timecode.from_seconds(5.0, default_fps)
|
25
|
+
expect(transformed).to eq([Caption.new(timespan: Utility::Timespan.new(t1, t_end), position: left_top, content: test_content)])
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should auto-close a previous caption on caption change' do
|
29
|
+
grid = Scc::Grid.new.insert_text(0, 0, 'AAAA')
|
30
|
+
transformed = @transformer.transform([Scc::Caption.new(timecode: t1, grid: test_grid), Scc::Caption.new(timecode: t2, grid: grid), Scc::Caption.new(timecode: t3)])
|
31
|
+
expect(transformed).to eq([Caption.new(timespan: t1_2, position: left_top, content: test_content), Caption.new(timespan: t2_3, position: left_top, content: root_with_text('AAAA'))])
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should position nodes at the edges at the correct positions' do
|
35
|
+
grid = Scc::Grid.new.insert_text(0, 0, 'a').insert_text(0, Scc::GRID_COLUMNS - 1, 'b').insert_text(Scc::GRID_ROWS - 1, 0, 'c').insert_text(Scc::GRID_ROWS - 1, Scc::GRID_COLUMNS - 1, 'd')
|
36
|
+
transformed = @transformer.transform(single_scc_caption_with_grid(grid))
|
37
|
+
# The exact positions are subject to change when comparison with real SCC data and rendering is done
|
38
|
+
expected = [['a', [0.2, 0.1]], ['b', [0.78125, 0.1]], ['c', [0.2, 0.8467]], ['d', [0.78125, 0.8467]]].map { |group|
|
39
|
+
Caption.new(timespan: t1_2, position: Position.new(group[1][0], group[1][1]), content: root_with_text(group[0]))
|
40
|
+
}
|
41
|
+
expect(transformed).to eq(expected)
|
42
|
+
end
|
43
|
+
|
44
|
+
def transform_test_style(style)
|
45
|
+
@transformer.transform(single_scc_caption_with_grid(Scc::Grid.new.insert_text(0, 0, 'Test', style)))
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should handle italics' do
|
49
|
+
style = Scc::CharacterStyle.default
|
50
|
+
style.italics = true
|
51
|
+
expect(transform_test_style(style)).to eq(single_caption_with_content(ItalicsNode.new([TextNode.new('Test')])))
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should handle underline' do
|
55
|
+
style = Scc::CharacterStyle.default
|
56
|
+
style.underline = true
|
57
|
+
expect(transform_test_style(style)).to eq(single_caption_with_content(UnderlineNode.new([TextNode.new('Test')])))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should handle flash' do
|
61
|
+
style = Scc::CharacterStyle.default
|
62
|
+
style.flash = true
|
63
|
+
expect(transform_test_style(style)).to eq(single_caption_with_content(FlashNode.new([TextNode.new('Test')])))
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should handle color' do
|
67
|
+
style = Scc::CharacterStyle.default
|
68
|
+
style.color = Scc::Color::RED
|
69
|
+
expect(transform_test_style(style)).to eq(single_caption_with_content(ColorNode.new(:red, [TextNode.new('Test')])))
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should handle all styles combined' do
|
73
|
+
style = Scc::CharacterStyle.default
|
74
|
+
style.underline = true
|
75
|
+
style.italics = true
|
76
|
+
style.flash = true
|
77
|
+
style.color = Scc::Color::MAGENTA
|
78
|
+
# This operates under the assumption that the nodes are sorted with these exact priorities
|
79
|
+
# (which may change in the future)
|
80
|
+
# Perhaps it would be better to compare independent of the exact order of the nodes
|
81
|
+
expect(transform_test_style(style)).to eq(single_caption_with_content(
|
82
|
+
ColorNode.new(:magenta, [
|
83
|
+
UnderlineNode.new([
|
84
|
+
ItalicsNode.new([
|
85
|
+
FlashNode.new([
|
86
|
+
TextNode.new('Test')
|
87
|
+
])
|
88
|
+
])
|
89
|
+
])
|
90
|
+
])
|
91
|
+
))
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should handle this complicated combination of styles and text' do
|
95
|
+
style = Scc::CharacterStyle.default
|
96
|
+
grid = Scc::Grid.new
|
97
|
+
grid.insert_text(0, 0, 'a')
|
98
|
+
style.color = Scc::Color::BLUE
|
99
|
+
style.italics = true
|
100
|
+
style.flash = true
|
101
|
+
grid.insert_text(0, 1, 'b', style.dup)
|
102
|
+
style.underline = true
|
103
|
+
grid.insert_text(0, 2, 'cde', style.dup)
|
104
|
+
style.color = Scc::Color::CYAN
|
105
|
+
style.flash = false
|
106
|
+
grid.insert_text(0, 5, 'f', style.dup)
|
107
|
+
transformed = @transformer.transform(single_scc_caption_with_grid(grid))
|
108
|
+
expect(transformed).to eq(single_caption_with_content(
|
109
|
+
[
|
110
|
+
TextNode.new('a'),
|
111
|
+
ItalicsNode.new([
|
112
|
+
ColorNode.new(:blue, [
|
113
|
+
FlashNode.new([
|
114
|
+
TextNode.new('b'),
|
115
|
+
UnderlineNode.new([
|
116
|
+
TextNode.new('cde')
|
117
|
+
])
|
118
|
+
])
|
119
|
+
]),
|
120
|
+
ColorNode.new(:cyan, [
|
121
|
+
UnderlineNode.new([
|
122
|
+
TextNode.new('f')
|
123
|
+
])
|
124
|
+
])
|
125
|
+
])
|
126
|
+
]
|
127
|
+
)
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should handle this other complicated combination of styles and text' do
|
132
|
+
style = Scc::CharacterStyle.default
|
133
|
+
grid = Scc::Grid.new
|
134
|
+
style.color = Scc::Color::RED
|
135
|
+
style.italics = true
|
136
|
+
grid.insert_text(0, 0, 'xyz', style.dup)
|
137
|
+
style.underline = true
|
138
|
+
style.flash = true
|
139
|
+
grid.insert_text(0, 3, 'abc', style.dup)
|
140
|
+
style.color = Scc::Color::YELLOW
|
141
|
+
style.flash = false
|
142
|
+
style.italics = false
|
143
|
+
grid.insert_text(0, 6, 'jkl', style.dup)
|
144
|
+
transformed = @transformer.transform(single_scc_caption_with_grid(grid))
|
145
|
+
expect(transformed).to eq(single_caption_with_content(
|
146
|
+
[
|
147
|
+
ColorNode.new(:red, [
|
148
|
+
ItalicsNode.new([
|
149
|
+
TextNode.new('xyz'),
|
150
|
+
UnderlineNode.new([
|
151
|
+
FlashNode.new([
|
152
|
+
TextNode.new('abc')
|
153
|
+
])
|
154
|
+
])
|
155
|
+
])
|
156
|
+
]),
|
157
|
+
ColorNode.new(:yellow, [
|
158
|
+
UnderlineNode.new([
|
159
|
+
TextNode.new('jkl')
|
160
|
+
])
|
161
|
+
])
|
162
|
+
]
|
163
|
+
)
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|