Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebVTT writer: add support for 'align' (proposed fix) #414

Merged
merged 4 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ Default: `true`

Default: `false`

#### text_align

`"text_align" : true | false`

`true` means that the VTT writer outputs text alignment cue settings

Default: `false`

#### cue_id

`"cue_id" : true | false`
Expand Down
3 changes: 3 additions & 0 deletions src/main/python/ttconv/vtt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@ def name(cls):
# outputs `line` and `line alignment` cue settings
line_position: bool = field(default=False, metadata={"decoder": bool})

# outputs `text alignment` cue settings
text_align: bool = field(default=False, metadata={"decoder": bool})

# outputs cue identifier
cue_id: bool = field(default=True, metadata={"decoder": bool})
25 changes: 20 additions & 5 deletions src/main/python/ttconv/vtt/cue.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ class LineAlignment(Enum):
center = "center"
end = "end"

class TextAlignment(Enum):
"""WebVTT text alignment cue setting"""
left = "left"
center = "center"
right = "right"

_EOL_SEQ_RE = re.compile(r"\n{2,}")

def __init__(self, identifier: Optional[int] = None):
Expand All @@ -50,7 +56,8 @@ def __init__(self, identifier: Optional[int] = None):
self._end: Optional[ClockTime] = None
self._text: str = ""
self._line: int = None
self._align: VttCue.LineAlignment = None
self._linealign: VttCue.LineAlignment = None
self._textalign: VttCue.TextAlignment = None

def set_begin(self, offset: Fraction):
"""Sets the paragraph begin time code"""
Expand Down Expand Up @@ -83,11 +90,15 @@ def get_line(self) -> Optional[int]:

def set_align(self, align: LineAlignment):
"""Sets the WebVTT line alignment cue setting"""
self._align = align
self._linealign = align

def get_align(self) -> Optional[LineAlignment]:
"""Return the WebVTT line alignment cue setting"""
return self._align
return self._linealign

def set_textalign(self, textalign: TextAlignment):
"""Sets the WebVTT text alignment cue setting"""
self._textalign = textalign

def is_only_whitespace_or_empty(self):
"""Returns whether the paragraph text contains only whitespace or is empty"""
Expand Down Expand Up @@ -123,12 +134,16 @@ def __str__(self) -> str:
# cue timing
t += f"{self._begin} --> {self._end}"

# cue text position
if self._textalign is not None:
t += f" align:{self._textalign.value}"

# cue line position
if self._line is not None:
t += f" line:{self._line}%"

if self._align is not None:
t += f",{self._align.value}"
if self._linealign is not None:
t += f",{self._linealign.value}"

t += "\n"

Expand Down
21 changes: 19 additions & 2 deletions src/main/python/ttconv/vtt/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
from ttconv.isd import ISD
from ttconv.vtt.cue import VttCue
from ttconv.vtt.css_class import CssClass
from ttconv.style_properties import ExtentType, PositionType, StyleProperties, FontStyleType, NamedColors, FontWeightType, TextDecorationType, DisplayAlignType
from ttconv.style_properties import DirectionType, ExtentType, PositionType, StyleProperties, FontStyleType, NamedColors, \
FontWeightType, TextDecorationType, DisplayAlignType, TextAlignType

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -84,7 +85,13 @@ def __init__(self, config: VTTWriterConfiguration):
StyleProperties.DisplayAlign: [],
StyleProperties.Extent: [],
})


if self._config.text_align:
supported_styles.update({
StyleProperties.TextAlign: [],
StyleProperties.Direction: [],
})

self._filters.append(SupportedStylePropertiesFilter(supported_styles))

self._filters.append(
Expand Down Expand Up @@ -175,6 +182,16 @@ def process_p(self, region: ISD.Region, element: model.P, begin: Fraction, end:
cue.set_line(round(position.v_offset.value + extent.height.value / 2))
cue.set_align(VttCue.LineAlignment.center)

if self._config.text_align:
direction = element.get_style(StyleProperties.Direction)
text_align = element.get_style(StyleProperties.TextAlign)
if text_align == TextAlignType.center:
cue.set_textalign(VttCue.TextAlignment.center)
elif text_align == TextAlignType.start:
cue.set_textalign(VttCue.TextAlignment.right if direction == DirectionType.rtl else VttCue.TextAlignment.left)
elif text_align == TextAlignType.end:
cue.set_textalign(VttCue.TextAlignment.left if direction == DirectionType.rtl else VttCue.TextAlignment.right)

self._paragraphs.append(cue)

for elem in list(element):
Expand Down
54 changes: 54 additions & 0 deletions src/test/python/test_vtt_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,60 @@ def test_position(self):
vtt_from_model = vtt_writer.from_model(model, config)
self.assertEqual(expected_vtt, vtt_from_model)

def test_align(self):
ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?>
<tt xml:lang="en-US" xmlns="http://www.w3.org/ns/ttml" xmlns:tts="http://www.w3.org/ns/ttml#styling" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" ttp:frameRate="24" ttp:frameRateMultiplier="1000 1001" ttp:profile="http://www.w3.org/ns/ttml/profile/imsc1/text" ttp:timeBase="media">
<head>
<styling>
<style xml:id="style.center" tts:fontFamily="Arial" tts:fontSize="100%" tts:fontStyle="normal" tts:fontWeight="normal" tts:backgroundColor="transparent" tts:color="white" tts:textAlign="center"/>
<style xml:id="style.start" tts:fontFamily="Arial" tts:fontSize="100%" tts:fontStyle="normal" tts:fontWeight="normal" tts:backgroundColor="transparent" tts:color="white" tts:textAlign="start"/>
<style xml:id="style.end" tts:fontFamily="Arial" tts:fontSize="100%" tts:fontStyle="normal" tts:fontWeight="normal" tts:backgroundColor="transparent" tts:color="white" tts:textAlign="end"/>
</styling>
<layout>
<region xml:id="lr" tts:backgroundColor="transparent" tts:origin="10% 10%" tts:extent="80% 80%"/>
<region xml:id="rl" tts:writingMode="rl" tts:backgroundColor="transparent" tts:origin="10% 10%" tts:extent="80% 80%"/>
</layout>
</head>
<body>
<div>
<p style="style.center" region="lr" begin="00:00:03:12" end="00:00:12:00">Only one or two short samples are needed<br/>to make sure the conversion basically works</p>
<p style="style.start" region="lr" begin="00:00:14:09" end="00:00:25:17">Cool, got it, will do it by end of next week.</p>
<p style="style.end" region="lr" begin="00:00:26:00" end="00:00:28:00">Yes.</p>
<p style="style.end" region="rl" begin="00:00:29:00" end="00:00:31:00">Good.</p>
</div>
</body>
</tt>"""

expected_vtt="""WEBVTT

1
00:00:03.501 --> 00:00:12.000 align:center
Only one or two short samples are needed
to make sure the conversion basically works

2
00:00:14.375 --> 00:00:25.709 align:left
Cool, got it, will do it by end of next week.

3
00:00:26.000 --> 00:00:28.000 align:right
Yes.

4
00:00:29.000 --> 00:00:31.000 align:left
Good.
"""

model = imsc_reader.to_model(et.ElementTree(et.fromstring(ttml_doc_str)))
config = VTTWriterConfiguration()
config.text_align = True
vtt_from_model = vtt_writer.from_model(model, config)
self.assertEqual(expected_vtt, vtt_from_model)

config = VTTWriterConfiguration.parse(json.loads('{"text_align":true}'))
vtt_from_model = vtt_writer.from_model(model, config)
self.assertEqual(expected_vtt, vtt_from_model)

def test_cue_id(self):
ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?>
<tt xml:lang="en-US" xmlns="http://www.w3.org/ns/ttml" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" ttp:frameRate="24" ttp:frameRateMultiplier="1000 1001">
Expand Down
Loading