def test_default_region(self): doc = model.ContentDocument() b = model.Body(doc) doc.set_body(b) div1 = model.Div(doc) b.push_child(div1) p1 = model.P(doc) div1.push_child(p1) span1 = model.Span(doc) span1.push_child(model.Text(doc, "hello")) p1.push_child(span1) isd = ISD.from_model(doc, 0) self.assertEqual(len(isd), 1) regions = list(isd.iter_regions()) self.assertEqual(regions[0].get_id(), ISD.DEFAULT_REGION_ID) p = regions[0][0][0][0] self.assertEqual(len(p), 1) self.assertEqual(p[0][0].get_text(), "hello")
def test_imsc_1_1_test_suite(self): for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name), self.assertLogs() as logs: logging.getLogger().info("*****dummy*****") # dummy log tree = et.parse(os.path.join(root, filename)) m = imsc_reader.to_model(tree) self.assertIsNotNone(m) sig_times = ISD.significant_times(m) for t in sig_times: isd = ISD.from_model(m, t) self.assertIsNotNone(isd) if len(logs.output) > 1: self.fail(logs.output)
def test_compute_padding(self): doc = model.ContentDocument() r1 = model.Region("r1", doc) r1.set_style(styles.StyleProperties.ShowBackground, styles.ShowBackgroundType.always) r1.set_style( styles.StyleProperties.Extent, styles.ExtentType( width=styles.LengthType(50, styles.LengthType.Units.pct), height=styles.LengthType(25, styles.LengthType.Units.pct) ) ) r1.set_style( styles.StyleProperties.Padding, styles.PaddingType( before=styles.LengthType(5, styles.LengthType.Units.pct), after=styles.LengthType(10, styles.LengthType.Units.pct), start=styles.LengthType(15, styles.LengthType.Units.pct), end=styles.LengthType(20, styles.LengthType.Units.pct) ) ) doc.put_region(r1) isd = ISD.from_model(doc, 0) region = list(isd.iter_regions())[0] padding: styles.PaddingType = region.get_style(styles.StyleProperties.Padding) self.assertAlmostEqual(padding.before.value, 25 * 0.05) self.assertAlmostEqual(padding.after.value, 25 * 0.10) self.assertAlmostEqual(padding.start.value, 50 * 0.15) self.assertAlmostEqual(padding.end.value, 50 * 0.2)
def test_compute_extent_pct(self): doc = model.ContentDocument() r1 = model.Region("r1", doc) r1.set_style(styles.StyleProperties.ShowBackground, styles.ShowBackgroundType.always) r1.set_style( styles.StyleProperties.Extent, styles.ExtentType( width=styles.LengthType(50, styles.LengthType.Units.pct), height=styles.LengthType(25, styles.LengthType.Units.pct) ) ) doc.put_region(r1) isd = ISD.from_model(doc, 0) region = list(isd.iter_regions())[0] extent: styles.ExtentType = region.get_style(styles.StyleProperties.Extent) self.assertEqual(extent.height.value, 25) self.assertEqual(extent.height.units, styles.LengthType.Units.rh) self.assertEqual(extent.width.value, 50) self.assertEqual(extent.width.units, styles.LengthType.Units.rw)
def from_model(doc: model.ContentDocument, config = None, progress_callback=lambda _: None) -> str: """Converts the data model to a VTT document""" # split progress between ISD construction and VTT writing def _isd_progress(progress: float): progress_callback(progress / 2) # create context vtt = VttContext(config if config is not None else VTTWriterConfiguration()) # Compute ISDs isds = ISD.generate_isd_sequence(doc, _isd_progress) # process ISDs for i, (begin, isd) in enumerate(isds): end = isds[i + 1][0] if i + 1 < len(isds) else None vtt.add_isd(isd, begin, end) progress_callback(0.5 + (i + 1) / len(isds) / 2) vtt.finish() return str(vtt)
def from_model(doc: model.ContentDocument, isd_config: Optional[ISDConfiguration] = None, progress_callback=lambda _: None) -> str: """Converts the data model to a SRT document""" srt = SrtContext() # split progress between ISD construction and SRT writing def _isd_progress(progress: float): progress_callback(progress / 2) # Compute ISDs isds = ISD.generate_isd_sequence(doc, _isd_progress, is_multithreaded=isd_config.multi_thread if isd_config is not None else True) # process ISDs for i, (offset, isd) in enumerate(isds): for srt_filter in srt.filters: srt_filter.process(isd) srt.add_isd(isd, offset) progress_callback(0.5 + (i + 1) / len(isds) / 2) srt.finish() return str(srt)
def add_isd(self, isd: ISD, begin: Fraction, end: Optional[Fraction]): """Converts and appends ISD content to VTT content""" LOGGER.debug( "Append ISD from %ss to %ss to VTT content.", float(begin), float(end) if end is not None else "unbounded" ) # filter the ISD to remove unsupported features for vtt_filter in self._filters: vtt_filter.process(isd) # process the ISD regions is_isd_empty = True for region in isd.iter_regions(): if len(region) > 0: is_isd_empty = False for body in region: for div in list(body): for p in list(div): self.process_p(region, p, begin, end) if is_isd_empty: LOGGER.debug("Skipping empty paragraph.")
def test_compute_style_property(self): doc = model.ContentDocument() r1 = model.Region("r1", doc) r1.set_style(styles.StyleProperties.FontSize, styles.LengthType(value=50, units=styles.LengthType.Units.pct)) doc.put_region(r1) b = model.Body(doc) b.set_style(styles.StyleProperties.FontSize, styles.LengthType(value=50, units=styles.LengthType.Units.pct)) b.set_region(r1) doc.set_body(b) div1 = model.Div(doc) b.push_child(div1) p1 = model.P(doc) div1.push_child(p1) span1 = model.Span(doc) p1.push_child(span1) t1 = model.Text(doc, "hello") span1.push_child(t1) isd = ISD.from_model(doc, 0) region = list(isd.iter_regions())[0] span = region[0][0][0][0] fs: styles.LengthType = span.get_style(styles.StyleProperties.FontSize) self.assertAlmostEqual(fs.value, 25 / doc.get_cell_resolution().rows) self.assertEqual(fs.units, styles.LengthType.Units.rh)
def test_lwsp_default(self): tree = et.parse('src/test/resources/ttml/lwsp_default.ttml') doc = imsc_reader.to_model(tree) isd = ISD.from_model(doc, 0) p0 = list(isd.iter_regions())[0][0][0][0] spans = list(p0) self.assertEqual(len(spans), 3) self.assertEqual(spans[0][0].get_text(), "hello ") self.assertEqual(spans[1][0].get_text(), "my name") self.assertEqual(spans[2][0].get_text(), " is Mathilda") p1 = list(isd.iter_regions())[0][0][0][1] spans = list(p1) self.assertEqual(len(spans), 4) self.assertEqual(spans[0][0].get_text(), "bonjour") self.assertEqual(spans[1][0].get_text(), " mon nom") self.assertIsInstance(spans[2], model.Br) self.assertEqual(spans[3][0].get_text(), "est")
def test_compute_extent_em(self): doc = model.ContentDocument() r1 = model.Region("r1", doc) r1.set_style(styles.StyleProperties.ShowBackground, styles.ShowBackgroundType.always) r1.set_style( styles.StyleProperties.Extent, styles.ExtentType( width=styles.LengthType(20, styles.LengthType.Units.em), height=styles.LengthType(3, styles.LengthType.Units.em) ) ) doc.put_region(r1) isd = ISD.from_model(doc, 0) region = list(isd.iter_regions())[0] extent: styles.ExtentType = region.get_style(styles.StyleProperties.Extent) self.assertAlmostEqual(extent.width.value, 100*20/doc.get_cell_resolution().rows) self.assertEqual(extent.width.units, styles.LengthType.Units.rh) self.assertAlmostEqual(extent.height.value, 100*3/doc.get_cell_resolution().rows) self.assertEqual(extent.height.units, styles.LengthType.Units.rh)
def from_model(doc: model.ContentDocument) -> str: """Converts the data model to a SRT document""" srt = SrtContext() significant_times = ISD.significant_times(doc) for offset in significant_times: isd = ISD.from_model(doc, offset) for srt_filter in srt.filters: srt_filter.process(isd) srt.add_isd(isd, offset) srt.finish() return str(srt)
def test_merging_regions(self): paragraphs_merging_filter = ParagraphsMergingFilter() isd = ISD(None) r1 = ISD.Region("r1", isd) b1 = self._get_filled_body(isd, ["Hello", "world"], ["Is there", "anyone here?"]) r1.push_child(b1) isd.put_region(r1) regions = list(isd.iter_regions()) self.assertEqual(1, len(regions)) body = list(regions[0]) self.assertEqual(1, len(body)) divs = list(body[0]) self.assertEqual(2, len(divs)) paragraphs_1 = list(divs[0]) self.assertEqual(2, len(paragraphs_1)) paragraphs_2 = list(divs[1]) self.assertEqual(2, len(paragraphs_2)) paragraphs_merging_filter.process(isd) regions = list(isd.iter_regions()) self.assertEqual(1, len(regions)) body = list(regions[0]) self.assertEqual(1, len(body)) divs = list(body[0]) self.assertEqual(1, len(divs)) paragraphs = list(divs[0]) self.assertEqual(1, len(paragraphs)) spans_and_brs = list(paragraphs[0]) text = self._get_text_from_children(spans_and_brs[0]) self.assertEqual("Hello", text) self.assertIsInstance(spans_and_brs[1], Br) text = self._get_text_from_children(spans_and_brs[2]) self.assertEqual("world", text) self.assertIsInstance(spans_and_brs[3], Br) text = self._get_text_from_children(spans_and_brs[4]) self.assertEqual("Is there", text) self.assertIsInstance(spans_and_brs[5], Br) text = self._get_text_from_children(spans_and_brs[6]) self.assertEqual("anyone here?", text)
def test_isd_1(self): isd = ISD.from_model(self.doc, 1) self.assertEqual(len(isd), 1) p = list(isd.iter_regions())[0][0][0][0] self.assertEqual(len(p), 1) self.assertEqual(p[0][0].get_text(), "hello")
def test_isd_10(self): isd = ISD.from_model(self.doc, 0) regions = list(isd.iter_regions()) self.assertEqual(len(regions), 1) r1 = regions[0] self.assertEqual(r1.get_id(), "r1") self.assertEqual(len(r1), 0)
def test_display_none_handling(self): xml_doc = et.parse("src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/MediaParTiming002.ttml") doc = imsc_reader.to_model(xml_doc) isd = ISD.from_model(doc, 0) regions = list(isd.iter_regions()) # single default region self.assertEqual(len(regions), 1) # no content self.assertEqual(len(regions[0]), 0)
def test_isd_2(self): isd = ISD.from_model(self.doc, 2) regions = list(isd.iter_regions()) self.assertEqual(len(regions), 2) r1 = regions[0] self.assertEqual(r1.get_id(), "r1") self.assertEqual(len(r1), 0) r2 = regions[1] self.assertEqual(r2.get_id(), "r2") r2_children = list(r2) self.assertEqual(len(r2_children), 1) body = r2_children[0] self.assertIsInstance(body, model.Body) self.assertEqual(len(body), 1) div = list(body)[0] self.assertIsInstance(div, model.Div) self.assertEqual(len(div), 1) p = list(div)[0] self.assertIsInstance(p, model.P) self.assertEqual(len(p), 1) span = list(p)[0] self.assertIsInstance(span, model.Span) self.assertEqual(len(span), 1) text = list(span)[0] self.assertIsInstance(text, model.Text) self.assertEqual(text.get_text(), "hello")
def test_text_decoration_inheritance(self): doc = model.ContentDocument() r1 = model.Region("r1", doc) r1.set_style( styles.StyleProperties.TextDecoration, styles.TextDecorationType( line_through=False, underline=True, overline=True ) ) doc.put_region(r1) b = model.Body(doc) b.set_style( styles.StyleProperties.TextDecoration, styles.TextDecorationType( overline=False ) ) b.set_region(r1) doc.set_body(b) div1 = model.Div(doc) b.push_child(div1) p1 = model.P(doc) div1.push_child(p1) span1 = model.Span(doc) p1.push_child(span1) t1 = model.Text(doc, "hello") span1.push_child(t1) isd = ISD.from_model(doc, 0) region = list(isd.iter_regions())[0] span = region[0][0][0][0] self.assertEqual( span.get_style(styles.StyleProperties.TextDecoration), styles.TextDecorationType( line_through=False, underline=True, overline=False ) )
def test_lwsp_preserve(self): tree = et.parse('src/test/resources/ttml/lwsp_preserve.ttml') doc = imsc_reader.to_model(tree) isd = ISD.from_model(doc, 0) p0 = list(isd.iter_regions())[0][0][0][0] spans = list(p0) self.assertEqual(len(spans), 3) self.assertEqual(spans[0][0].get_text(), "hello ") self.assertEqual(spans[1][0].get_text(), " my \nname ") self.assertEqual(spans[2][0].get_text(), "is Mathilda")
def test_merging_regions(self): regions_merging_filter = RegionsMergingFilter() isd = ISD(None) r1 = ISD.Region("r1", isd) b1 = self._get_filled_body(isd, "Hello world") r1.push_child(b1) r2 = ISD.Region("r2", isd) b2 = self._get_filled_body(isd, "Is there anyone here?") r2.push_child(b2) isd.put_region(r1) isd.put_region(r2) self.assertEqual(2, len(list(isd.iter_regions()))) regions_merging_filter.process(isd) self.assertEqual(1, len(list(isd.iter_regions()))) merged_region = isd.get_region("r1_r2") self.assertIsNotNone(merged_region) body = list(merged_region) self.assertEqual(1, len(body)) divs = list(body[0]) self.assertEqual(2, len(divs)) text = self._get_text_from_children(divs[0]) self.assertEqual("Hello world", text) text = self._get_text_from_children(divs[1]) self.assertEqual("Is there anyone here?", text)
def process(self, isd: ISD): """Merges the ISD document paragraphs for each regions""" LOGGER.debug("Apply paragraphs merging filter to ISD.") for region in isd.iter_regions(): for body in region: target_div = Div(isd) target_paragraph = P(isd) target_div.push_child(target_paragraph) original_divs = list(body) paragraphs = [] for div in original_divs: paragraphs += self._get_paragraphs(div) if len(paragraphs) <= 1: continue LOGGER.warning("Merging ISD paragraphs.") for div in original_divs: div.remove() for (index, p) in enumerate(paragraphs): for span in list(p): # Remove child from its parent body span.remove() # Add it to the target paragraph target_paragraph.push_child(span) # Separate each merged paragraph by a Br element if index < len(paragraphs) - 1: target_paragraph.push_child(Br(isd)) body.push_child(target_div)
def process(self, isd: ISD): """Merges the ISD document regions""" LOGGER.debug("Apply regions merging filter to ISD.") original_regions = list(isd.iter_regions()) not_empty_regions = 0 for region in original_regions: not_empty_regions += len(region) if len(original_regions) <= 1 or not_empty_regions <= 1: return LOGGER.warning("Merging ISD regions.") target_body = Body(isd) region_ids = [] for region in original_regions: region_id = region.get_id() for body in region: for child in body: # Remove child from its parent body child.remove() # Add it to the target body target_body.push_child(child) region_ids.append(region_id) isd.remove_region(region_id) target_region = ISD.Region("_".join(region_ids), isd) target_region.push_child(target_body) isd.put_region(target_region)
def test_process_isd(self): supported_style_properties = SupportedStylePropertiesFilter({ StyleProperties.BackgroundColor: [NamedColors.red.value], StyleProperties.Extent: [] }) doc = ContentDocument() r1 = Region("r1", doc) r1.set_style(StyleProperties.BackgroundColor, NamedColors.red.value) r1.set_style(StyleProperties.LuminanceGain, 2.0) doc.put_region(r1) b = Body(doc) b.set_begin(Fraction(1)) b.set_end(Fraction(10)) doc.set_body(b) div1 = Div(doc) div1.set_region(r1) b.push_child(div1) p1 = P(doc) p1.set_style(StyleProperties.BackgroundColor, NamedColors.white.value) p1.set_style(StyleProperties.Direction, DirectionType.rtl) div1.push_child(p1) span1 = Span(doc) span1.set_style(StyleProperties.BackgroundColor, NamedColors.red.value) span1.set_style(StyleProperties.FontStyle, FontStyleType.italic) span1.set_style(StyleProperties.Direction, DirectionType.ltr) p1.push_child(span1) t1 = Text(doc, "hello") span1.push_child(t1) significant_times = sorted(ISD.significant_times(doc)) self.assertEqual(3, len(significant_times)) isd = ISD.from_model(doc, significant_times[1]) r1 = isd.get_region("r1") self.assertEqual(len(Region._applicableStyles), len(r1._styles)) self.assertEqual(NamedColors.red.value, r1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(2.0, r1.get_style(StyleProperties.LuminanceGain)) body1 = list(r1)[0] div1 = list(body1)[0] p1 = list(div1)[0] span1 = list(p1)[0] self.assertEqual(len(P._applicableStyles), len(p1._styles)) self.assertEqual(NamedColors.white.value, p1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(DirectionType.rtl, p1.get_style(StyleProperties.Direction)) self.assertEqual(len(Span._applicableStyles), len(span1._styles)) self.assertEqual(NamedColors.red.value, span1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(FontStyleType.italic, span1.get_style(StyleProperties.FontStyle)) self.assertEqual(DirectionType.ltr, span1.get_style(StyleProperties.Direction)) supported_style_properties.process(isd) self.assertEqual(2, len(r1._styles)) self.assertEqual(NamedColors.red.value, r1.get_style(StyleProperties.BackgroundColor)) self.assertEqual( ExtentType(height=LengthType(value=0.0, units=LengthType.Units.rh), width=LengthType(value=0.0, units=LengthType.Units.rw)), r1.get_style(StyleProperties.Extent)) self.assertEqual(0, len(p1._styles)) self.assertIsNone(p1.get_style(StyleProperties.BackgroundColor)) self.assertIsNone(p1.get_style(StyleProperties.Direction)) self.assertEqual(1, len(span1._styles)) self.assertEqual(NamedColors.red.value, span1.get_style(StyleProperties.BackgroundColor)) self.assertIsNone(span1.get_style(StyleProperties.FontStyle)) self.assertIsNone(span1.get_style(StyleProperties.Direction))
def process(self, isd: ISD): """Filter ISD document style properties""" LOGGER.debug("Apply default style properties filter to ISD.") for region in isd.iter_regions(): self._process_element(region)
def test_process_isd(self): default_style_value_filter = DefaultStylePropertyValuesFilter({ StyleProperties.BackgroundColor: NamedColors.red.value, StyleProperties.Direction: DirectionType.ltr }) doc = ContentDocument() r1 = Region("r1", doc) r1.set_style(StyleProperties.BackgroundColor, NamedColors.red.value) r1.set_style(StyleProperties.LuminanceGain, 2.0) doc.put_region(r1) b = Body(doc) b.set_begin(Fraction(1)) b.set_end(Fraction(10)) doc.set_body(b) div1 = Div(doc) div1.set_region(r1) b.push_child(div1) p1 = P(doc) p1.set_style(StyleProperties.BackgroundColor, NamedColors.white.value) p1.set_style(StyleProperties.Direction, DirectionType.rtl) div1.push_child(p1) span1 = Span(doc) span1.set_style(StyleProperties.BackgroundColor, NamedColors.red.value) span1.set_style(StyleProperties.FontStyle, FontStyleType.italic) span1.set_style(StyleProperties.Direction, DirectionType.ltr) p1.push_child(span1) t1 = Text(doc, "hello") span1.push_child(t1) significant_times = sorted(ISD.significant_times(doc)) self.assertEqual(3, len(significant_times)) isd = ISD.from_model(doc, significant_times[1]) r1 = isd.get_region("r1") self.assertEqual(len(Region._applicableStyles), len(r1._styles)) self.assertEqual(NamedColors.red.value, r1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(2.0, r1.get_style(StyleProperties.LuminanceGain)) body1 = list(r1)[0] div1 = list(body1)[0] p1 = list(div1)[0] span1 = list(p1)[0] self.assertEqual(len(P._applicableStyles), len(p1._styles)) self.assertEqual(NamedColors.white.value, p1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(DirectionType.rtl, p1.get_style(StyleProperties.Direction)) self.assertEqual(len(Span._applicableStyles), len(span1._styles)) self.assertEqual(NamedColors.red.value, span1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(FontStyleType.italic, span1.get_style(StyleProperties.FontStyle)) self.assertEqual(DirectionType.ltr, span1.get_style(StyleProperties.Direction)) default_style_value_filter.process(isd) self.assertEqual(len(Region._applicableStyles) - 1, len(r1._styles)) self.assertIsNone(r1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(len(P._applicableStyles), len(p1._styles)) self.assertEqual(NamedColors.white.value, p1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(DirectionType.rtl, p1.get_style(StyleProperties.Direction)) self.assertEqual(len(Span._applicableStyles) - 1, len(span1._styles)) self.assertIsNone(span1.get_style(StyleProperties.BackgroundColor)) self.assertEqual(FontStyleType.italic, span1.get_style(StyleProperties.FontStyle)) self.assertEqual(DirectionType.ltr, span1.get_style(StyleProperties.Direction))
def test_significant_times(self): self.assertSequenceEqual(ISD.significant_times(self.doc), sorted((0, 2, 3, 9, 1, 10, 4)))
def test_sig_times(self): self.assertEqual(ISD.significant_times(self.doc), sorted((0, 1, 2, 3)))
def test_isd_3(self): isd = ISD.from_model(self.doc, 0) self.assertEqual(len(isd), 0)