Esempio n. 1
0
    def set_bad_body(self):
        d = model.Document()

        b = model.Body()

        with self.assertRaises(ValueError):
            d.set_body(b)
Esempio n. 2
0
    def test_tts_writing_extent_when_body_has_extents(self):

        doc = model.ContentDocument()
        body = model.Body(doc)
        div = model.Div(doc)

        div.set_style(
            styles.StyleProperties.Extent,
            get_extent_from_dimensions(123, 456, styles.LengthType.Units.px))

        p = model.P(doc)
        span = model.Span(doc)
        text = model.Text(doc)
        text.set_text("asdf")

        span.push_child(text)
        p.push_child(span)
        div.push_child(p)
        body.push_child(div)
        doc.set_body(body)

        r = model.Region("hello", doc)
        r.set_style(
            styles.StyleProperties.Extent,
            get_extent_from_dimensions(123, 456, styles.LengthType.Units.px))

        doc.put_region(r)

        tree_from_model = imsc_writer.from_model(doc)

        extent = tree_from_model.getroot().attrib.get(
            f"{{{imsc_styles.StyleProperties.Extent.ns}}}{imsc_styles.StyleProperties.Extent.local_name}"
        )

        self.assertEqual(extent, '1920px 1080px')
Esempio n. 3
0
    def test_push_child(self):
        b = model.Body()

        b.push_child(model.Div())

        with self.assertRaises(TypeError):
            b.push_child(model.P())
Esempio n. 4
0
 def from_xml(
   parent_ctx: typing.Optional[TTMLElement.ParsingContext],
   xml_elem: et.Element
 ) -> typing.Optional[BodyElement.ParsingContext]:
   body_ctx = BodyElement.ParsingContext(BodyElement, parent_ctx, model.Body(parent_ctx.doc))
   body_ctx.process(parent_ctx, xml_elem)
   return body_ctx
Esempio n. 5
0
  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")
Esempio n. 6
0
  def setUp(self):
    self.doc = model.ContentDocument()

    r1 = model.Region("r1", self.doc)
    r1.set_style(styles.StyleProperties.ShowBackground, styles.ShowBackgroundType.whenActive)
    self.doc.put_region(r1)

    b = model.Body(self.doc)
    b.set_region(r1)
    self.doc.set_body(b)

    div1 = model.Div(self.doc)
    b.push_child(div1)

    p1 = model.P(self.doc)
    p1.set_begin(1)
    p1.set_end(3)
    div1.push_child(p1)

    span1 = model.Span(self.doc)
    span1.push_child(model.Text(self.doc, "hello"))
    p1.push_child(span1)

    span2 = model.Span(self.doc)
    span2.set_begin(1)
    span2.push_child(model.Text(self.doc, "bye"))
    p1.push_child(span2)
Esempio n. 7
0
  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)
Esempio n. 8
0
    def process(context, inherited_space, inherited_lang, ttml_element):

        element = model.Body(context.doc)

        # process attributes

        element.set_space(
            XMLSpaceAttribute.extract(ttml_element) or inherited_space)

        element.set_lang(
            XMLLangAttribute.extract(ttml_element) or inherited_lang)

        ContentElement.process_region_property(context, ttml_element, element)

        ContentElement.process_style_properties(context, ttml_element, element)

        # process children elements

        for ttml_child_element in ttml_element:
            child_element = ContentElement.process(context,
                                                   element.get_space(),
                                                   element.get_lang(),
                                                   ttml_child_element)

            if child_element is not None:
                if not isinstance(child_element, model.Div):
                    LOGGER.error("Children of body must be div instances")
                else:
                    element.push_child(child_element)

        return element
Esempio n. 9
0
    def set_body(self):
        d = model.Document()

        b = model.Body(d)

        d.set_body(b)

        self.assertEqual(d.get_body(), b)

        d.set_body(None)

        self.assertIsNone(d.get_body())
Esempio n. 10
0
  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
      )
    )
Esempio n. 11
0
    def test_body_only(self):

        doc = model.ContentDocument()
        body = model.Body(doc)
        div = model.Div(doc)
        p = model.P(doc)
        span = model.Span(doc)
        text = model.Text(doc)
        text.set_text("asdf")

        span.push_child(text)
        p.push_child(span)
        div.push_child(p)
        body.push_child(div)
        doc.set_body(body)

        # write the document out to a file
        imsc_writer.from_model(doc).write('build/BodyElement.out.ttml',
                                          encoding='utf-8',
                                          xml_declaration=True)
Esempio n. 12
0
    def test_tts_writing_no_extent_when_body_has_no_extents(self):

        doc = model.ContentDocument()
        body = model.Body(doc)
        div = model.Div(doc)
        p = model.P(doc)
        span = model.Span(doc)
        text = model.Text(doc)
        text.set_text("asdf")

        span.push_child(text)
        p.push_child(span)
        div.push_child(p)
        body.push_child(div)
        doc.set_body(body)

        tree_from_model = imsc_writer.from_model(doc)

        extent = tree_from_model.getroot().attrib.get(
            f"{{{imsc_styles.StyleProperties.Extent.ns}}}{imsc_styles.StyleProperties.Extent.local_name}"
        )

        self.assertEqual(extent, None)
Esempio n. 13
0
def to_model(data_file: typing.IO, _config = None, progress_callback=lambda _: None):
  """Converts an SRT document to the data model"""

  doc = model.ContentDocument()

  region = model.Region(_DEFAULT_REGION_ID, doc)
  region.set_style(
    styles.StyleProperties.Origin,
    styles.CoordinateType(
      x=styles.LengthType(5, styles.LengthType.Units.pct),
      y=styles.LengthType(5, styles.LengthType.Units.pct)
    )
  )
  region.set_style(
    styles.StyleProperties.Extent,
    styles.ExtentType(
      height=styles.LengthType(90, styles.LengthType.Units.pct),
      width=styles.LengthType(90, styles.LengthType.Units.pct)
    )
  )
  region.set_style(
    styles.StyleProperties.DisplayAlign,
    styles.DisplayAlignType.after
  )
  region.set_style(
    styles.StyleProperties.TextAlign,
    styles.TextAlignType.center
  )
  region.set_style(
    styles.StyleProperties.LineHeight,
    _DEFAULT_LINE_HEIGHT
  )
  region.set_style(
    styles.StyleProperties.FontFamily,
    _DEFAULT_FONT_STACK
  )
  region.set_style(
    styles.StyleProperties.FontSize,
    _DEFAULT_FONT_SIZE
  )
  region.set_style(
    styles.StyleProperties.Color,
    _DEFAULT_TEXT_COLOR
  )
  region.set_style(
    styles.StyleProperties.TextOutline,
    styles.TextOutlineType(
      _DEFAULT_OUTLINE_THICKNESS,
      _DEFAULT_OUTLINE_COLOR
    )
  )

  doc.put_region(region)

  body = model.Body(doc)
  body.set_region(region)

  doc.set_body(body)

  div = model.Div(doc)

  body.push_child(div)

  lines : str = data_file.readlines()

  state = _State.COUNTER
  current_p = None
 
  for line_index, line in enumerate(_none_terminated(lines)):

    if state is _State.COUNTER:
      if line is None:
        break

      if _EMPTY_RE.fullmatch(line):
        continue

      if _COUNTER_RE.search(line) is None:
        LOGGER.fatal("Missing subtitle counter at line %s", line_index)
        return None
      
      progress_callback(line_index/len(lines))

      state = _State.TC

      continue

    if state is _State.TC:
      if line is None:
        break

      m = _TIMECODE_RE.search(line)

      if m is None:
        LOGGER.fatal("Missing timecode at line %s", line_index)
        return None

      current_p = model.P(doc)

      current_p.set_begin(
        int(m.group('begin_h')) * 3600 + 
        int(m.group('begin_m')) * 60 + 
        int(m.group('begin_s')) +
        int(m.group('begin_ms')) / 1000
        )
    
      current_p.set_end(
        int(m.group('end_h')) * 3600 + 
        int(m.group('end_m')) * 60 + 
        int(m.group('end_s')) +
        int(m.group('end_ms')) / 1000
        )

      state = _State.TEXT

      continue

    if state in (_State.TEXT, _State.TEXT_MORE):

      if line is None or _EMPTY_RE.fullmatch(line):
        subtitle_text = subtitle_text.strip('\r\n')\
          .replace(r"\n\r", "\n")\
          .replace(r"{bold}", r"<bold>")\
          .replace(r"{/bold}", r"</bold>")\
          .replace(r"{italic}", r"<italic>")\
          .replace(r"{/italic}", r"</italic>")\
          .replace(r"{underline}", r"<underline>")\
          .replace(r"{/underline}", r"</underline>")

        parser = _TextParser(current_p, line_index)
        parser.feed(subtitle_text)
        parser.close()

        state = _State.COUNTER
        continue

      if state is _State.TEXT:
        div.push_child(current_p)
        subtitle_text = ""

      if state is _State.TEXT_MORE:
        current_p.push_child(model.Br(current_p.get_doc()))

      subtitle_text += line

      state = _State.TEXT_MORE

      continue

  return doc
Esempio n. 14
0
  def setUp(self):
    self.doc = model.ContentDocument()

    a1 = model.DiscreteAnimationStep(
      style_property=styles.StyleProperties.Color,
      begin=None,
      end=None,
      value=styles.NamedColors.red.value
    )

    a2 = model.DiscreteAnimationStep(
      style_property=styles.StyleProperties.Color,
      begin=Fraction(1),
      end=None,
      value=styles.NamedColors.green.value
    )

    a3 = model.DiscreteAnimationStep(
      style_property=styles.StyleProperties.Color,
      begin=Fraction(2),
      end=None,
      value=styles.NamedColors.blue.value
    )

    r1 = model.Region("r1", self.doc)
    self.doc.put_region(r1)

    # r2: sig times = {2, 9}

    r2 = model.Region("r2", self.doc)
    r2.set_begin(Fraction(2))
    r2.set_end(Fraction(9))
    r2.add_animation_step(a1)
    self.doc.put_region(r2)

    # b: sig times = {1, 10}

    b = model.Body(self.doc)
    b.set_begin(Fraction(1))
    b.set_end(Fraction(10))
    self.doc.set_body(b)

    # div1: offset = 1, sig times = {2, 4}

    div1 = model.Div(self.doc)
    div1.add_animation_step(a2)
    div1.set_begin(Fraction(3))
    div1.set_region(r1)
    b.push_child(div1)

    # div2: offset = 1, sig times = {10}

    div2 = model.Div(self.doc)
    div2.set_end(Fraction(12))
    div2.set_region(r2)
    b.push_child(div2)

    # p1: offset = 1, sig times = {}

    p1 = model.P(self.doc)
    div2.push_child(p1)

    # span1: offset = 1, sig times = {3}
    span1 = model.Span(self.doc)
    span1.add_animation_step(a3)
    p1.push_child(span1)

    t1 = model.Text(self.doc, "hello")
    span1.push_child(t1)
Esempio n. 15
0
    def __init__(self,
                 gsi_block: bytes,
                 disable_fill_line_gap: bool = False,
                 disable_line_padding: bool = False,
                 start_tc: typing.Optional[str] = None,
                 font_stack: typing.Tuple[typing.Union[
                     str, styles.GenericFontFamilyType]] = None,
                 max_row_count: typing.Optional[typing.Union[int,
                                                             str]] = None):

        self.gsi = _GSIBlock._make(
            struct.unpack(
                '3s8sc2s2s32s32s32s32s32s32s16s6s6s2s5s5s3s2s2s1s8s8s1s1s3s32s32s32s75x576s',
                gsi_block))

        self.doc = model.ContentDocument()

        self.doc.set_cell_resolution(
            model.CellResolutionType(
                columns=round(100 * DEFAULT_TELETEXT_COLS /
                              (100 - 2 * DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT)),
                rows=round(100 * DEFAULT_TELETEXT_ROWS /
                           (100 - 2 * DEFAULT_VERTICAL_SAFE_MARGIN_PCT))))

        self.doc.set_active_area(
            model.ActiveAreaType(
                left_offset=DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT / 100,
                top_offset=DEFAULT_VERTICAL_SAFE_MARGIN_PCT / 100,
                width=1 - 2 * DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT / 100,
                height=1 - 2 * DEFAULT_VERTICAL_SAFE_MARGIN_PCT / 100))

        self.body = model.Body(self.doc)

        if not disable_fill_line_gap:
            self.body.set_style(styles.StyleProperties.FillLineGap, True)

        if not disable_line_padding:
            self.body.set_style(
                styles.StyleProperties.LinePadding,
                styles.LengthType(LINE_PADDING_LENGTH_C,
                                  styles.LengthType.Units.c))

        if font_stack is not None:
            self.body.set_style(styles.StyleProperties.FontFamily, font_stack)
        else:
            self.body.set_style(styles.StyleProperties.FontFamily,
                                DEFAULT_FONT_STACK)

        self.doc.set_body(self.body)

        self.sgn_to_div_map = {}

        self.last_sn = None

        self.is_in_extension = False

        self.tti_tf = None

        self.fps = _DFC_FRACTION_MAP.get(self.gsi.DFC)
        if self.fps is None:
            LOGGER.error("Unknown GSI DFC value %s, defaulting to 25 fps",
                         self.gsi.DFC)
            self.fps = Fraction(25)
        else:
            LOGGER.debug("GSI DFC: %s", self.gsi.DFC)

        self.cct = self.gsi.CCT
        LOGGER.debug("GSI CCT: %s", self.gsi.CCT)

        try:
            self.tti_count = int(self.gsi.TNB)
            LOGGER.debug("GSI TNB: %s", self.gsi.TNB)
        except ValueError:
            LOGGER.error("Invalid TNB field value: %s", self.gsi.TNB)
            self.tti_count = sys.maxsize

        self.language = _LC_BCP47_MAP.get(self.gsi.LC)
        if self.language is None:
            LOGGER.warning(
                "Unknown LC value: %s, defaulting to 'unspecified''",
                self.gsi.LC)
            self.language = ""
        else:
            LOGGER.debug("GSI LC: %s", self.gsi.LC)

        self.doc.set_lang(self.language)

        if start_tc is None:
            self.start_offset = 0
        elif start_tc == "TCP":
            try:
                self.start_offset = SmpteTimeCode(
                    int(self.gsi.TCP[0:2]), int(self.gsi.TCP[2:4]),
                    int(self.gsi.TCP[4:6]), int(self.gsi.TCP[6:8]),
                    self.get_fps()).to_temporal_offset()
                LOGGER.debug("GSI TCP: %s", self.gsi.TCP)
            except ValueError:
                LOGGER.error("Invalid TCP value: %s", self.gsi.tcp)
                self.start_offset = 0
        else:
            try:
                self.start_offset = SmpteTimeCode.parse(
                    start_tc, self.get_fps()).to_temporal_offset()
            except ValueError:
                LOGGER.error("Invalid start_tc value")
                raise

        if max_row_count is None or self.is_teletext():
            self.max_row_count = DEFAULT_TELETEXT_ROWS
        elif isinstance(max_row_count, str) and max_row_count == "MNR":
            try:
                self.max_row_count = int(self.gsi.MNR)
                LOGGER.debug("GSI MNR: %s", self.gsi.MNR)
            except ValueError:
                LOGGER.error("Invalid MNR value: %s", self.gsi.MNR)
                self.start_offset = DEFAULT_TELETEXT_ROWS
        else:
            self.max_row_count = max_row_count

        # p_element for use across cumulative subtitles
        self.cur_p_element = None