subconv 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|