2 Copyright (C) 2016-2021 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "compose.hpp"
23 #include "exceptions.h"
24 #include "ssa_reader.h"
27 #include <boost/test/unit_test.hpp>
28 #include <boost/filesystem.hpp>
39 BOOST_AUTO_TEST_CASE (ssa_reader_test)
41 boost::filesystem::path p = private_test / "example.ssa";
42 FILE* f = fopen (p.string().c_str(), "r");
43 sub::SSAReader reader (f);
45 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
47 auto i = subs.begin ();
49 /* Convert a font size in points to a proportional size for this file */
51 return static_cast<float>(x) / 1024;
54 BOOST_REQUIRE (i != subs.end ());
55 BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 40, 650));
56 BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 41, 790));
57 auto j = i->lines.begin();
58 BOOST_REQUIRE (j != i->lines.end ());
59 BOOST_REQUIRE_EQUAL (j->blocks.size(), 1);
60 sub::Block b = j->blocks.front ();
61 BOOST_CHECK_EQUAL (b.text, "Et les enregistrements de ses ondes delta ?");
62 BOOST_CHECK_EQUAL (b.font.get(), "Wolf_Rain");
63 BOOST_CHECK_CLOSE(b.font_size.proportional().get(), fs(56), 0.1);
64 BOOST_CHECK_EQUAL (b.bold, false);
65 BOOST_CHECK_EQUAL (b.italic, false);
66 BOOST_CHECK_EQUAL (b.underline, false);
69 BOOST_REQUIRE (i != subs.end ());
70 BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 42, 420));
71 BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 44, 150));
73 BOOST_REQUIRE (j != i->lines.end ());
74 BOOST_REQUIRE_EQUAL (j->blocks.size(), 1);
75 b = j->blocks.front ();
76 BOOST_CHECK_EQUAL (b.text, "Toujours rien.");
77 BOOST_CHECK_EQUAL (b.font.get(), "Wolf_Rain");
78 BOOST_CHECK_CLOSE(b.font_size.proportional().get(), fs(56), 0.1);
79 BOOST_CHECK_EQUAL (b.bold, false);
80 BOOST_CHECK_EQUAL (b.italic, false);
81 BOOST_CHECK_EQUAL (b.underline, false);
84 BOOST_CHECK (i == subs.end());
88 BOOST_AUTO_TEST_CASE (ssa_reader_line_test1)
90 sub::RawSubtitle base;
91 auto r = sub::SSAReader::parse_line (
93 "This is a line with some {\\i1}italics{\\i0} and then\\nthere is a new line.",
99 BOOST_CHECK_EQUAL (i->text, "This is a line with some ");
100 BOOST_CHECK_EQUAL (i->italic, false);
102 BOOST_REQUIRE (i != r.end ());
104 BOOST_CHECK_EQUAL (i->text, "italics");
105 BOOST_CHECK_EQUAL (i->italic, true);
107 BOOST_REQUIRE (i != r.end ());
109 BOOST_CHECK_EQUAL (i->text, " and then");
110 BOOST_CHECK_EQUAL (i->italic, false);
112 BOOST_REQUIRE (i != r.end ());
114 BOOST_CHECK_EQUAL (i->text, "there is a new line.");
116 BOOST_REQUIRE (i == r.end ());
120 BOOST_AUTO_TEST_CASE (ssa_reader_line_test2)
122 sub::RawSubtitle base;
123 auto r = sub::SSAReader::parse_line (
125 "{\\i1}It's all just italics{\\i0}",
130 /* Convert a font size in points to a vertical position for this file */
131 auto vp = [](int x) {
132 return x * 1.2 / 1080;
136 BOOST_CHECK_EQUAL (i->text, "It's all just italics");
137 BOOST_CHECK_EQUAL (i->italic, true);
139 BOOST_REQUIRE (i == r.end ());
141 r = sub::SSAReader::parse_line (
143 "{\\i1}Italic{\\i0}\\Nand new line",
149 BOOST_CHECK_EQUAL (i->text, "Italic");
150 BOOST_CHECK_EQUAL (i->italic, true);
151 BOOST_CHECK(fabs(vp(72) - i->vertical_position.proportional.get()) < 1e-5);
153 BOOST_CHECK_EQUAL (i->text, "and new line");
154 BOOST_CHECK_EQUAL (i->italic, false);
155 BOOST_CHECK (i->vertical_position.proportional.get() < 1e-5);
160 test (boost::filesystem::path p)
162 p = private_test / p;
163 FILE* f = fopen (p.string().c_str(), "r");
165 sub::SSAReader r (f);
169 /** Test of reading some typical .ssa files */
170 BOOST_AUTO_TEST_CASE (ssa_reader_test2)
172 test ("DKH_UT_EN20160601def.ssa");
173 test ("dcpsubtest-en.ssa");
174 test ("dcpsubtest-en.ssa");
175 test ("W_GERMAN_SUBS_grey.ass");
176 test ("XxxHolic (2022) ITA 071223.ass");
179 #define SUB_START(f, t) \
180 BOOST_REQUIRE (i != subs.end ()); \
181 BOOST_CHECK_EQUAL (i->from, f); \
182 BOOST_CHECK_EQUAL (i->to, t); \
183 j = i->lines.begin ();
185 #define LINE(vp, vr, hp, hr) \
186 BOOST_REQUIRE (j != i->lines.end ()); \
187 BOOST_CHECK (j->vertical_position.proportional); \
188 BOOST_CHECK (fabs (j->vertical_position.proportional.get() - vp) < 1e-5); \
189 BOOST_CHECK (j->vertical_position.reference); \
190 BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), vr); \
191 BOOST_CHECK (fabs (j->horizontal_position.proportional - hp) < 1e-5); \
192 BOOST_CHECK_EQUAL (j->horizontal_position.reference, hr); \
193 k = j->blocks.begin (); \
196 #define BLOCK(t, f, s, b, i, u) \
197 BOOST_REQUIRE (k != j->blocks.end ()); \
198 BOOST_CHECK_EQUAL (k->text, t); \
199 BOOST_CHECK_EQUAL (k->font.get(), f); \
200 BOOST_CHECK_CLOSE(k->font_size.proportional().get(), s, 0.1); \
201 BOOST_CHECK_EQUAL (k->bold, b); \
202 BOOST_CHECK_EQUAL (k->italic, i); \
203 BOOST_CHECK_EQUAL (k->underline, u); \
209 /** Test reading of a file within the libsub tree which exercises the parser */
210 BOOST_AUTO_TEST_CASE (ssa_reader_test3)
212 boost::filesystem::path p = "test/data/test.ssa";
213 FILE* f = fopen (p.string().c_str(), "r");
214 sub::SSAReader reader (f);
216 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
218 /* Convert a font size in points to a proportional size for this file */
219 auto fs = [](int x) {
220 return static_cast<float>(x) / 1080;
223 /* Convert a font size in points to a vertical position for this file */
224 auto vp = [&fs](int x) {
228 auto i = subs.begin();
229 vector<sub::Line>::iterator j;
230 vector<sub::Block>::iterator k;
233 SUB_START (sub::Time::from_hms (0, 0, 1, 230), sub::Time::from_hms (0, 0, 4, 550));
234 LINE((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
235 BLOCK("Hello world", "Arial", fs(20), false, false, false);
238 /* This is vertically moved\nand has two lines. */
239 SUB_START (sub::Time::from_hms (0, 0, 5, 740), sub::Time::from_hms (0, 0, 11, 0));
240 /* The first line should be 900 pixels and one line (20
241 points, 1.2 times spaced, as a proportion of the total
242 screen height 729 points) up.
244 LINE((900.0 / 1080) - vp(20), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
245 BLOCK("This is vertically moved", "Arial", fs(20), false, false, false);
246 LINE((900.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
247 BLOCK("and has two lines.", "Arial", fs(20), false, false, false);
250 /* Some {\i1}italics{\i} are here. */
251 SUB_START (sub::Time::from_hms (0, 0, 7, 740), sub::Time::from_hms (0, 0, 9, 0));
252 LINE((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
253 BLOCK("Some ", "Arial", fs(20), false, false, false);
254 BLOCK("italics", "Arial", fs(20), false, true, false);
255 BLOCK(" are here.", "Arial", fs(20), false, false, false);
260 SUB_START (sub::Time::from_hms (0, 0, 9, 230), sub::Time::from_hms (0, 0, 11, 560));
261 LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
262 BLOCK("bottom left", "Arial", fs(20), false, false, false);
265 SUB_START (sub::Time::from_hms (0, 0, 9, 240), sub::Time::from_hms (0, 0, 11, 560));
266 LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
267 BLOCK("bottom centre", "Arial", fs(20), false, false, false);
270 SUB_START (sub::Time::from_hms (0, 0, 9, 250), sub::Time::from_hms (0, 0, 11, 560));
271 LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
272 BLOCK("bottom right", "Arial", fs(20), false, false, false);
275 SUB_START (sub::Time::from_hms (0, 0, 9, 260), sub::Time::from_hms (0, 0, 11, 560));
276 /* Position is half of a 20pt line (with line spacing) above vertical centre */
277 LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
278 BLOCK("middle left", "Arial", fs(20), false, false, false);
281 SUB_START (sub::Time::from_hms (0, 0, 9, 270), sub::Time::from_hms (0, 0, 11, 560));
282 LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
283 BLOCK("middle centre", "Arial", fs(20), false, false, false);
286 SUB_START (sub::Time::from_hms (0, 0, 9, 280), sub::Time::from_hms (0, 0, 11, 560));
287 LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
288 BLOCK("middle right", "Arial", fs(20), false, false, false);
291 SUB_START (sub::Time::from_hms (0, 0, 9, 290), sub::Time::from_hms (0, 0, 11, 560));
292 LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
293 BLOCK("top left", "Arial", fs(20), false, false, false);
296 SUB_START (sub::Time::from_hms (0, 0, 9, 300), sub::Time::from_hms (0, 0, 11, 560));
297 LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
298 BLOCK("top centre", "Arial", fs(20), false, false, false);
301 SUB_START (sub::Time::from_hms (0, 0, 9, 310), sub::Time::from_hms (0, 0, 11, 560));
302 LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
303 BLOCK("top right", "Arial", fs(20), false, false, false);
306 BOOST_REQUIRE (i == subs.end ());
310 /** Test reading of a file within the libsub-test-private tree which exercises the parser */
311 BOOST_AUTO_TEST_CASE (ssa_reader_test4)
313 boost::filesystem::path p = private_test / "dcpsubtest2-en.ssa";
314 FILE* f = fopen (p.string().c_str(), "r");
315 sub::SSAReader reader (f);
317 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
319 auto i = subs.begin();
320 vector<sub::Line>::iterator j;
321 vector<sub::Block>::iterator k;
323 BOOST_REQUIRE (i != subs.end ());
325 /* Convert a font size in points to a proportional size for this file */
326 auto fs = [](int x) {
327 return static_cast<float>(x) / 288;
330 /* Convert a font size in points to a vertical position for this file */
331 auto vp = [&fs](int x) {
335 SUB_START (sub::Time::from_hms (0, 0, 1, 0), sub::Time::from_hms (0, 0, 3, 0));
336 /* The first line should be one line (50 points, 1.2 times
337 spaced, as a proportion of the total screen height 729
340 LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
341 BLOCK("1st line: This is normal", "Verdana", fs(50), false, false, false);
342 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
343 BLOCK("2d line: this is bold", "Verdana", fs(50), true, false, false);
346 SUB_START (sub::Time::from_hms (0, 0, 3, 100), sub::Time::from_hms (0, 0, 5, 100));
347 LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
348 BLOCK("1st line: this is bold", "Verdana", fs(50), true, false, false);
349 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
350 BLOCK("2nd line: This is normal", "Verdana", fs(50), false, false, false);
353 SUB_START (sub::Time::from_hms (0, 0, 5, 200), sub::Time::from_hms (0, 0, 7, 200));
354 LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
355 BLOCK("1st line: this is bold", "Verdana", fs(50), true, false, false);
356 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
357 BLOCK("2nd line: this is italics", "Verdana", fs(50), false, true, false);
360 SUB_START (sub::Time::from_hms (0, 0, 7, 300), sub::Time::from_hms (0, 0, 9, 300));
361 LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
362 BLOCK("1st line: this is italics", "Verdana", fs(50), false, true, false);
363 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
364 BLOCK("2nd line: this is bold", "Verdana", fs(50), true, false, false);
369 /** Test reading of a .ass file */
370 BOOST_AUTO_TEST_CASE (ssa_reader_test5)
372 boost::filesystem::path p = private_test / "dcpsubtest-en.ass";
373 FILE* f = fopen (p.string().c_str(), "r");
374 sub::SSAReader reader (f);
376 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
378 /* Convert a font size in points to a proportional size for this file */
379 auto fs = [](int x) {
380 return static_cast<float>(x) / 288;
383 /* Convert a font size in points to a vertical position for this file */
384 auto vp = [&fs](int x) {
388 auto i = subs.begin ();
389 vector<sub::Line>::iterator j;
390 vector<sub::Block>::iterator k;
392 BOOST_REQUIRE (i != subs.end ());
394 SUB_START (sub::Time::from_hms (0, 0, 1, 0), sub::Time::from_hms (0, 0, 3, 0));
395 /* The first line should be one line (26 points, 1.2 times
396 spaced, as a proportion of the total screen height 729
399 LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
400 BLOCK("1st subtitle, 1st line", "arial", fs(26), true, false, false);
401 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
402 BLOCK("2nd subtitle, 2nd line", "arial", fs(26), true, false, false);
405 SUB_START (sub::Time::from_hms (0, 0, 3, 100), sub::Time::from_hms (0, 0, 5, 100));
406 LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
407 BLOCK("2nd subtitle, 1st line", "arial", fs(26), true, false, false);
408 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
409 BLOCK("2nd subtitle, 2nd line", "arial", fs(26), true, false, false);
412 SUB_START (sub::Time::from_hms (0, 0, 5, 200), sub::Time::from_hms (0, 0, 7, 200));
413 LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
414 BLOCK("3rd subtitle, 1st line", "arial", fs(26), true, false, false);
415 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
416 BLOCK("3rd subtitle, 2nd line", "arial", fs(26), true, false, false);
419 SUB_START (sub::Time::from_hms (0, 0, 7, 300), sub::Time::from_hms (0, 0, 9, 300));
420 LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
421 BLOCK("4th subtitle, 1st line", "arial", fs(26), true, false, false);
422 LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
423 BLOCK("4th subtitle, 2nd line", "arial", fs(26), true, false, false);
428 /** Test reading of another .ass file */
429 BOOST_AUTO_TEST_CASE (ssa_reader_test6)
431 boost::filesystem::path p = private_test / "DCP-o-matic_test_subs_1.ass";
432 auto f = fopen (p.string().c_str(), "r");
434 sub::SSAReader reader (f);
436 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
438 /* Convert a font size in points to a proportional size for this file */
439 auto fs = [](int x) {
440 return static_cast<float>(x) / 288;
443 /* Convert a font size in points to a vertical position for this file */
444 auto vp = [&fs](int x) {
448 auto i = subs.begin ();
449 vector<sub::Line>::iterator j;
450 vector<sub::Block>::iterator k;
452 BOOST_REQUIRE (i != subs.end ());
454 SUB_START (sub::Time::from_hms (0, 0, 0, 70), sub::Time::from_hms (0, 0, 1, 110));
455 /* The first line should be one line (30 points, 1.2 times
456 spaced, as a proportion of the total screen height 792
457 points) up. There's also a 10 pixel (with respect to a
458 288-pixel-high screen) margin.
460 LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
461 BLOCK("This line is normal", "Arial", fs(30), false, false, false);
462 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
463 BLOCK("This line is bold", "Arial", fs(30), true, false, false);
466 SUB_START (sub::Time::from_hms (0, 0, 1, 200), sub::Time::from_hms (0, 0, 2, 240));
467 LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
468 BLOCK("This line is bold", "Arial", fs(30), true, false, false);
469 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
470 BLOCK("This line is normal", "Arial", fs(30), false, false, false);
473 SUB_START (sub::Time::from_hms (0, 0, 2, 300), sub::Time::from_hms (0, 0, 3, 380));
474 LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
475 BLOCK("This line is bold", "Arial", fs(30), true, false, false);
476 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
477 BLOCK("This line is italic", "Arial", fs(30), false, true, false);
480 SUB_START (sub::Time::from_hms (0, 0, 3, 400), sub::Time::from_hms (0, 0, 4, 480));
481 LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
482 BLOCK("This line is italic", "Arial", fs(30), false, true, false);
483 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
484 BLOCK("This line is bold", "Arial", fs(30), true, false, false);
487 SUB_START (sub::Time::from_hms (0, 0, 4, 510), sub::Time::from_hms (0, 0, 5, 600));
488 LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
489 BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
490 BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
491 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
492 BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
493 BLOCK("italic AND bold", "Arial", fs(30), true, true, false);
496 SUB_START (sub::Time::from_hms (0, 0, 5, 620), sub::Time::from_hms (0, 0, 6, 710));
497 LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
498 BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
499 BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
500 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
501 BLOCK("First three words", "Arial", fs(30), true, true, false);
502 BLOCK(" are italic AND bold", "Arial", fs(30), false, false, false);
505 SUB_START (sub::Time::from_hms (0, 0, 6, 730), sub::Time::from_hms (0, 0, 8, 30));
506 LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
507 BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
508 BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
509 LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
510 BLOCK("This line is normal", "Arial", fs(30), false, false, false);
513 SUB_START (sub::Time::from_hms (0, 0, 8, 90), sub::Time::from_hms (0, 0, 9, 210));
514 LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
515 BLOCK("Both lines are bold AND italic", "Arial", fs(30), true, true, false);
516 LINE((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
517 BLOCK("Both lines are bold AND italic", "Arial", fs(30), true, true, false);
522 BOOST_AUTO_TEST_CASE (ssa_reader_test7)
524 auto p = boost::filesystem::path("test") / "data" / "test3.ssa";
525 auto f = fopen(p.string().c_str(), "r");
527 sub::SSAReader reader(f);
529 auto subs = sub::collect<vector<sub::Subtitle>>(reader.subtitles());
531 /* Convert a font size in points to a proportional size for this file */
532 auto fs = [](int x) {
533 return static_cast<float>(x) / 1080;
536 /* Convert a font size in points to a vertical position for this file */
537 auto vp = [&fs](int x) {
541 auto i = subs.begin();
542 vector<sub::Line>::iterator j;
543 vector<sub::Block>::iterator k;
545 BOOST_REQUIRE (i != subs.end());
547 SUB_START(sub::Time::from_hms(0, 0, 1, 0), sub::Time::from_hms(0, 0, 3, 0));
548 LINE((vp(60) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
549 BLOCK("Helvetica Neue 60pt - Default", "Helvetica Neue", fs(60), false, false, false);
550 LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
551 BLOCK("Bottom 100 pt off edge", "Helvetica Neue", fs(60), false, false, false);
554 SUB_START(sub::Time::from_hms(0, 0, 4, 0), sub::Time::from_hms(0, 0, 6, 0));
555 LINE((vp(30) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
556 BLOCK("Helvetica Neue 30pt", "Helvetica Neue", fs(30), false, false, false);
557 LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
558 BLOCK("Bottom 100pt off edge", "Helvetica Neue", fs(30), false, false, false);
561 SUB_START(sub::Time::from_hms(0, 0, 7, 0), sub::Time::from_hms(0, 0, 9, 0));
562 LINE((vp(120) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
563 BLOCK("Helvetica Neue 120pt", "Helvetica Neue", fs(120), false, false, false);
564 LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
565 BLOCK("Bottom 100pt off edge", "Helvetica Neue", fs(120), false, false, false);
568 SUB_START(sub::Time::from_hms(0, 0, 10, 0), sub::Time::from_hms(0, 0, 12, 0));
569 LINE((100.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
570 BLOCK("Helvetica Neue 60pt", "Helvetica Neue", fs(60), false, false, false);
571 LINE((vp(60) + (100.0 / 1080)), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
572 BLOCK("Top Alignment 100pt off edge", "Helvetica Neue", fs(60), false, false, false);
575 SUB_START(sub::Time::from_hms(0, 0, 13, 0), sub::Time::from_hms(0, 0, 15, 0));
576 LINE(vp(-60), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
577 BLOCK("Helvetica Neue 60pt", "Helvetica Neue 60 Center", fs(60), false, false, false);
578 LINE(0, sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
579 BLOCK(" Vertical Center Alignment", "Helvetica Neue 60 Center", fs(60), false, false, false);
585 BOOST_AUTO_TEST_CASE (ssa_reader_pos)
587 boost::filesystem::path p = "test/data/test2.ssa";
588 FILE* f = fopen (p.string().c_str(), "r");
589 sub::SSAReader reader (f);
591 auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
593 /* Convert a font size in points to a proportional size for this file */
594 auto fs = [](int x) {
595 return static_cast<float>(x) / 1080;
598 auto i = subs.begin ();
599 vector<sub::Line>::iterator j;
600 vector<sub::Block>::iterator k;
603 SUB_START (sub::Time::from_hms (0, 0, 1, 230), sub::Time::from_hms (0, 0, 4, 550));
604 LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
605 BLOCK ("Hello world this is ", "Arial", fs(20), false, false, false);
606 LINE ((310.0 / 1080), sub::TOP_OF_SCREEN, 400.0 / 1920, sub::LEFT_OF_SCREEN);
607 BLOCK ("positioning.", "Arial", fs(20), false, false, false);
613 BOOST_AUTO_TEST_CASE (ssa_reader_fs)
615 sub::RawSubtitle base;
616 auto r = sub::SSAReader::parse_line (
618 "This is a line with some {\\fs64}font sizing.",
624 BOOST_CHECK_EQUAL (i->text, "This is a line with some ");
626 BOOST_REQUIRE (i != r.end ());
628 BOOST_CHECK_EQUAL (i->text, "font sizing.");
629 BOOST_REQUIRE(i->font_size.proportional());
630 BOOST_CHECK_CLOSE(i->font_size.proportional().get(), 64.0 / 1080, 0.1);
632 BOOST_REQUIRE (i == r.end ());
637 test_c(string command, string colour)
639 sub::RawSubtitle base;
640 auto r = sub::SSAReader::parse_line (
642 String::compose("{\\c%1}Hello world", command),
648 BOOST_CHECK_EQUAL (i->text, "Hello world");
649 BOOST_CHECK (i->colour == sub::Colour::from_rgb_hex(colour));
650 BOOST_REQUIRE(std::next(i) == r.end());
654 /** Test a valid \c */
655 BOOST_AUTO_TEST_CASE (ssa_reader_c)
657 test_c("&H00FFFF&", "ffff00");
658 test_c("&H123456&", "563412");
659 test_c("&H0&", "000000");
660 test_c("&HFF&", "ff0000");
661 test_c("&HFF00&", "00ff00");
662 test_c("&HFF0000&", "0000ff");
663 test_c("&HFFFFFF&", "ffffff");
664 /* \c with no parameter seems to be parsed as "return to primary colour" */
665 test_c("", "ff00ff");