diff --git a/pycaption/scenarist.py b/pycaption/scenarist.py index 1414d1ef..a8b10876 100644 --- a/pycaption/scenarist.py +++ b/pycaption/scenarist.py @@ -1,16 +1,11 @@ import os import tempfile import zipfile -from collections import OrderedDict from datetime import timedelta from io import BytesIO -from PIL import Image, ImageFont, ImageDraw -from fontTools.ttLib import TTFont -from langcodes import Language, tag_distance - -from pycaption.base import BaseWriter, CaptionSet, Caption, CaptionNode -from pycaption.geometry import UnitEnum, Size +from pycaption.base import CaptionSet +from pycaption.subtitler_image_based import SubtitleImageBasedWriter def get_sst_pixel_display_params(video_width, video_height): @@ -74,35 +69,13 @@ def _zippy(base_path, path, archive): archive.write(p, os.path.relpath(p, base_path)) -class ScenaristDVDWriter(BaseWriter): - VALID_POSITION = ['top', 'bottom', 'source'] - - paColor = (255, 255, 255) # letter body - e1Color = (190, 190, 190) # antialiasing color - e2Color = (0, 0, 0) # border color - bgColor = (0, 255, 0) # background color - - palette = [paColor, e1Color, e2Color, bgColor] +class ScenaristDVDWriter(SubtitleImageBasedWriter): - palette_image = Image.new("P", (1, 1)) - palette_image.putpalette([*paColor, *e1Color, *e2Color, *bgColor] + [0, 0, 0] * 252) - - font_langs = { - Language.get('en'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-Regular-Note-Math.ttf"}, - Language.get('ru'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-Regular-Note-Math.ttf"}, - Language.get('ar'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-RegularAndArabic.ttf", 'align': 'right'}, - Language.get('he'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansHebrew-Regular.ttf", 'align': 'right'}, - Language.get('hi'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDevanagari-Regular.ttf"}, - Language.get('ja-JP'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansJP+Math-Regular.ttf"}, - Language.get('zh-TW'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansTC+Math-Regular.ttf"}, - Language.get('zh-CN'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansSC+Math-Regular.ttf"}, - Language.get('ko-KR'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansKR+Math-Regular.ttf"}, - Language.get('th'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansThai-Regular.ttf"}, - } + tiff_compression = None def __init__(self, relativize=True, video_width=720, video_height=480, fit_to_screen=True, tape_type='NON_DROP', frame_rate=25, compat=False): - super().__init__(relativize, video_width, video_height, fit_to_screen) + super().__init__(relativize, video_width, video_height, fit_to_screen, frame_rate) self.tape_type = tape_type self.frame_rate = frame_rate @@ -113,107 +86,8 @@ def __init__(self, relativize=True, video_width=720, video_height=480, fit_to_sc self.color = '(0 1 2 3)' self.contrast = '(7 7 7 7)' - def get_characters(self, captions): - all_characters = [] - for caption_list in captions: - for caption in caption_list: - all_characters.extend([char for char in caption.get_text() if char and char.strip()]) - unique_characters = list(set(all_characters)) - return unique_characters - - def get_characters_with_captions(self, captions): # -> dict[str, list[int]]: - chars_with_captions = {} - for caption_list in captions: - for caption in caption_list: - current_caption_chars = [char for char in caption.get_text() if char and char.strip()] - for char in current_caption_chars: - if char not in chars_with_captions: - chars_with_captions[char] = [] - chars_with_captions[char].append(caption) - return chars_with_captions - - def get_missing_glyphs(self, font, characters): - ttf_font = TTFont(font) - glyphs = {c: self._has_glyph(ttf_font, c) for c in characters} - - missing_glyphs = {k: v for k, v in glyphs.items() if not v} - - return missing_glyphs - - @staticmethod - def _has_glyph(fnt, glyph): - NOT_ACTUAL_GLYPHS = [ - '\u202A', # Left-to-Right Embedding (LRE) - '\u202B', # Right-to-Left Embedding (RLE) - '\u202C', # Pop Directional Formatting (PDF) - '\u202D', # Left-to-Right Override (LRO) - '\u202E', # Right-to-Left Override (RLO) - '\u200E', # Left-to-Right Mark (LRM) - '\u200F' # Right-to-Left Mark (RLM) - ] - - if glyph in NOT_ACTUAL_GLYPHS: - return True - - for table in fnt['cmap'].tables: - if ord(glyph) in table.cmap.keys(): - return True - - return False - - def get_missing_glyphs_with_timestamps( - self, font, characters_with_timestamps # : dict[str, list[int]] - ): # -> dict[str, list[int]]: - ttf_font = TTFont(font) - - missing_glyphs_with_timestamps = {} - for glyph, timestamps in characters_with_timestamps.items(): - is_glyph_in_font = self._has_glyph(ttf_font, glyph) - if not is_glyph_in_font: - missing_glyphs_with_timestamps[glyph] = timestamps - - return missing_glyphs_with_timestamps - - @staticmethod - def group_captions_by_start_time(caps): - # group captions that have the same start time - caps_start_time = OrderedDict() - for i, cap in enumerate(caps): - if cap.start not in caps_start_time: - caps_start_time[cap.start] = [cap] - else: - caps_start_time[cap.start].append(cap) - - # order by start timestamp - caps_start_time = OrderedDict(sorted(caps_start_time.items(), key=lambda item: item[0])) - return caps_start_time - - def check_overlapping_subs(self, captions_by_start_time): - caps_final = [] - overlapping = [] - for start_time, caps_list in captions_by_start_time.items(): - if len(caps_list) == 1: - caps_final.append(caps_list) - else: - end_times = list(set([c.end for c in caps_list])) - if len(end_times) != 1: - overlapping.append(caps_list) - else: - caps_final.append(caps_list) - return caps_final, overlapping - - def get_distances(self, lang, font_langs): - requested_lang = Language.get(lang) - distances = [ - (tag_distance(requested_lang, l), fnt) - for l, fnt in font_langs.items() - if tag_distance(requested_lang, l) < 100 - ] - if not distances: - return distances - - distances.sort(key=lambda l: l[0]) - return distances + def save_image(self, tmp_dir, index, img): + img.save(tmp_dir + '/subtitle%04d.tif' % index, compression=self.tiff_compression) def write( self, @@ -221,57 +95,16 @@ def write( position='bottom', avoid_same_next_start_prev_end=False, tiff_compression='tiff_deflate', - align='center', + align='center' ): - if tiff_compression not in ['tiff_deflate', 'raw']: - raise ValueError('Unknown tiff_compression. Supported: {}'.format('tiff_deflate, raw')) - - position = position.lower().strip() - if position not in ScenaristDVDWriter.VALID_POSITION: - raise ValueError('Unknown position. Supported: {}'.format(','.join(ScenaristDVDWriter.VALID_POSITION))) - + self.tiff_compression = tiff_compression lang = caption_set.get_languages().pop() caps = caption_set.get_captions(lang) - # group captions that have the same start time - caps_start_time = self.group_captions_by_start_time(caps) - - # check if captions with the same start time also have the same end time - # fail if different end times are found - this is not (yet?) supported - caps_final, overlapping = self.check_overlapping_subs(caps_start_time) - if overlapping: - raise ValueError('Unsupported subtitles - overlapping subtitles with different end times found') - - if avoid_same_next_start_prev_end: - min_diff = (1 / self.frame_rate) * 1000000 - for i, caps_list in enumerate(caps_final): - if i == 0: - continue - - prev_end_time = caps_final[i - 1][0].end - current_start_time = caps_list[0].start - - if (current_start_time == prev_end_time) or ((current_start_time - prev_end_time) < min_diff): - for c in caps_list: - c.start = min(c.start + min_diff, c.end) - - distances = self.get_distances(lang, self.font_langs) - if not distances: - raise ValueError('Cannot find appropriate font for selected language') - - fnt = distances[0][1]['fontfile'] - align = distances[0][1].get('align') or align - missing_glyphs = self.get_missing_glyphs(fnt, self.get_characters(caps_final)) - - if missing_glyphs: - raise ValueError(f'Selected font was missing glyphs: {" ".join(missing_glyphs.keys())}') - - font_size = int(self.video_width * 0.05 * 0.6) # rough estimate but should work - - fnt = ImageFont.truetype(fnt, font_size) buf = BytesIO() with tempfile.TemporaryDirectory() as tmpDir: + caps_final, overlapping = self.write_images(caps, lang, tmpDir, position, align, avoid_same_next_start_prev_end) with open(tmpDir + '/subtitles.sst', 'w+') as sst: index = 1 py0, py1, dy0, dy1, dx0, dx1 = get_sst_pixel_display_params(self.video_width, self.video_height) @@ -292,15 +125,6 @@ def write( self.format_ts(cap_list[0].end), index )) - - img = Image.new('RGB', (self.video_width, self.video_height), self.bgColor) - draw = ImageDraw.Draw(img) - self.printLine(draw, cap_list, fnt, position, align) - - # quantize the image to our palette - img_quant = img.quantize(palette=self.palette_image, dither=0) - img_quant.save(tmpDir + '/subtitle%04d.tif' % index, compression=tiff_compression) - index = index + 1 zipit(tmpDir, buf) buf.seek(0) @@ -315,73 +139,3 @@ def format_ts(self, value): str_value = str_value + ':%02d' % (int((int(value / 1000) % 1000) / int(1000 / self.frame_rate))) return str_value - - def printLine(self, draw: ImageDraw, caption_list: Caption, fnt: ImageFont, position: str = 'bottom', align: str = 'center'): - ascender, descender = fnt.getmetrics() - line_spacing = ascender + abs(descender) # Basic line height without extra padding - lines_written = 0 - for caption in caption_list[::-1]: - text = caption.get_text() - l, t, r, b = draw.textbbox((0, 0), text, font=fnt, align=align) - - x = None - y = None - - # if position is specified as source, get the layout info - # fall back to "bottom" position if we can't get it - if position == 'source': - try: - x_ = caption.layout_info.origin.x - y_ = caption.layout_info.origin.y - - if isinstance(x_, Size) \ - and isinstance(y_, Size) \ - and x_.unit == UnitEnum.PERCENT \ - and y_.unit == UnitEnum.PERCENT: - x = self.video_width * (x_.value / 100) - y = self.video_height * (y_.value / 100) - - # make sure the text doesn't go out of the screen - box_rightmost_edge = x + r - if box_rightmost_edge > self.video_width: - x = float(self.video_width) - float(r) - float(10) - - # padding for readability - if y_.value > 70: - y = y - 10 - else: - position = 'bottom' - except: - position = 'bottom' - - if position != 'source': - x = self.video_width / 2 - r / 2 - if position == 'bottom': - y = self.video_height - b - 10 - lines_written * line_spacing # padding for readability - elif position == 'top': - y = 10 + lines_written * line_spacing - else: - raise ValueError('Unknown "position": {}'.format(position)) - - borderColor = self.e2Color - fontColor = self.paColor - for adj in range(2): - # move right - draw.text((x - adj, y), text, font=fnt, fill=borderColor, align=align) - # move left - draw.text((x + adj, y), text, font=fnt, fill=borderColor, align=align) - # move up - draw.text((x, y + adj), text, font=fnt, fill=borderColor, align=align) - # move down - draw.text((x, y - adj), text, font=fnt, fill=borderColor, align=align) - # diagnal left up - draw.text((x - adj, y + adj), text, font=fnt, fill=borderColor, align=align) - # diagnal right up - draw.text((x + adj, y + adj), text, font=fnt, fill=borderColor, align=align) - # diagnal left down - draw.text((x - adj, y - adj), text, font=fnt, fill=borderColor, align=align) - # diagnal right down - draw.text((x + adj, y - adj), text, font=fnt, fill=borderColor, align=align) - - draw.text((x, y), text, font=fnt, fill=fontColor, align=align) - lines_written += 1 \ No newline at end of file diff --git a/pycaption/subtitler_image_based.py b/pycaption/subtitler_image_based.py new file mode 100644 index 00000000..d9d423e5 --- /dev/null +++ b/pycaption/subtitler_image_based.py @@ -0,0 +1,309 @@ +import os +import tempfile +import zipfile +from collections import OrderedDict +from datetime import timedelta +from io import BytesIO + +from PIL import Image, ImageFont, ImageDraw +from fontTools.ttLib import TTFont +from langcodes import Language, tag_distance + +from pycaption.base import BaseWriter, CaptionSet, Caption, CaptionNode, CaptionList +from pycaption.geometry import UnitEnum, Size + + +def get_sst_pixel_display_params(video_width, video_height): + py0 = 2 + py1 = video_height - 1 + + dx0 = 0 + dy0 = 2 + + dx1 = video_width - 1 + dy1 = video_height - 1 + + return py0, py1, dy0, dy1, dx0, dx1 + + + +class SubtitleImageBasedWriter(BaseWriter): + VALID_POSITION = ['top', 'bottom', 'source'] + + paColor = (255, 255, 255) # letter body + e1Color = (190, 190, 190) # antialiasing color + e2Color = (0, 0, 0) # border color + bgColor = (0, 255, 0) # background color + + palette_image = Image.new("P", (1, 1)) + palette_image.putpalette([*paColor, *e1Color, *e2Color, *bgColor] + [0, 0, 0] * 252) + + def __init__(self, relativize=True, video_width=720, video_height=480, fit_to_screen=True, frame_rate=25): + super().__init__(relativize, video_width, video_height, fit_to_screen) + self.palette = [self.paColor, self.e1Color, self.e2Color, self.bgColor] + self.frame_rate = frame_rate + + palette_image = Image.new("P", (1, 1)) + palette_image.putpalette([*self.paColor, *self.e1Color, *self.e2Color, *self.bgColor] + [0, 0, 0] * 252) + + self.font_langs = { + Language.get('en'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-Regular-Note-Math.ttf"}, + Language.get('ru'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-Regular-Note-Math.ttf"}, + Language.get('ar'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDisplay-RegularAndArabic.ttf", + 'align': 'right'}, + Language.get('he'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansHebrew-Regular.ttf", + 'align': 'right'}, + Language.get('hi'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansDevanagari-Regular.ttf"}, + Language.get('ja-JP'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansJP+Math-Regular.ttf"}, + Language.get('zh-TW'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansTC+Math-Regular.ttf"}, + Language.get('zh-CN'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansSC+Math-Regular.ttf"}, + Language.get('ko-KR'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansKR+Math-Regular.ttf"}, + Language.get('th'): {'fontfile': f"{os.path.dirname(__file__)}/NotoSansThai-Regular.ttf"}, + } + + + + def save_image(self, tmp_dir, index, img): + pass + + + def get_characters(self, captions): + all_characters = [] + for caption_list in captions: + for caption in caption_list: + all_characters.extend([char for char in caption.get_text() if char and char.strip()]) + unique_characters = list(set(all_characters)) + return unique_characters + + def get_characters_with_captions(self, captions): # -> dict[str, list[int]]: + chars_with_captions = {} + for caption_list in captions: + for caption in caption_list: + current_caption_chars = [char for char in caption.get_text() if char and char.strip()] + for char in current_caption_chars: + if char not in chars_with_captions: + chars_with_captions[char] = [] + chars_with_captions[char].append(caption) + return chars_with_captions + + def get_missing_glyphs(self, font, characters): + ttf_font = TTFont(font) + glyphs = {c: self._has_glyph(ttf_font, c) for c in characters} + + missing_glyphs = {k: v for k, v in glyphs.items() if not v} + + return missing_glyphs + + @staticmethod + def _has_glyph(fnt, glyph): + NOT_ACTUAL_GLYPHS = [ + '\u202A', # Left-to-Right Embedding (LRE) + '\u202B', # Right-to-Left Embedding (RLE) + '\u202C', # Pop Directional Formatting (PDF) + '\u202D', # Left-to-Right Override (LRO) + '\u202E', # Right-to-Left Override (RLO) + '\u200E', # Left-to-Right Mark (LRM) + '\u200F' # Right-to-Left Mark (RLM) + ] + + if glyph in NOT_ACTUAL_GLYPHS: + return True + + for table in fnt['cmap'].tables: + if ord(glyph) in table.cmap.keys(): + return True + + return False + + def get_missing_glyphs_with_timestamps( + self, font, characters_with_timestamps # : dict[str, list[int]] + ): # -> dict[str, list[int]]: + ttf_font = TTFont(font) + + missing_glyphs_with_timestamps = {} + for glyph, timestamps in characters_with_timestamps.items(): + is_glyph_in_font = self._has_glyph(ttf_font, glyph) + if not is_glyph_in_font: + missing_glyphs_with_timestamps[glyph] = timestamps + + return missing_glyphs_with_timestamps + + @staticmethod + def group_captions_by_start_time(caps): + # group captions that have the same start time + caps_start_time = OrderedDict() + for i, cap in enumerate(caps): + if cap.start not in caps_start_time: + caps_start_time[cap.start] = [cap] + else: + caps_start_time[cap.start].append(cap) + + # order by start timestamp + caps_start_time = OrderedDict(sorted(caps_start_time.items(), key=lambda item: item[0])) + return caps_start_time + + def check_overlapping_subs(self, captions_by_start_time): + caps_final = [] + overlapping = [] + for start_time, caps_list in captions_by_start_time.items(): + if len(caps_list) == 1: + caps_final.append(caps_list) + else: + end_times = list(set([c.end for c in caps_list])) + if len(end_times) != 1: + overlapping.append(caps_list) + else: + caps_final.append(caps_list) + return caps_final, overlapping + + def get_distances(self, lang, font_langs): + requested_lang = Language.get(lang) + distances = [ + (tag_distance(requested_lang, l), fnt) + for l, fnt in font_langs.items() + if tag_distance(requested_lang, l) < 100 + ] + if not distances: + return distances + + distances.sort(key=lambda l: l[0]) + return distances + + + + def write_images( + self, + caption_list: CaptionList, + lang: str, + tmpDir, + position='bottom', + align='center', + avoid_same_next_start_prev_end=False): + + position = position.lower().strip() + if position not in SubtitleImageBasedWriter.VALID_POSITION: + raise ValueError('Unknown position. Supported: {}'.format(','.join(SubtitleImageBasedWriter.VALID_POSITION))) + + # group captions that have the same start time + caps_start_time = self.group_captions_by_start_time(caption_list) + + # check if captions with the same start time also have the same end time + # fail if different end times are found - this is not (yet?) supported + caps_final, overlapping = self.check_overlapping_subs(caps_start_time) + if overlapping: + raise ValueError('Unsupported subtitles - overlapping subtitles with different end times found') + + if avoid_same_next_start_prev_end: + min_diff = (1 / self.frame_rate) * 1000000 + for i, caps_list in enumerate(caps_final): + if i == 0: + continue + + prev_end_time = caps_final[i - 1][0].end + current_start_time = caps_list[0].start + + if (current_start_time == prev_end_time) or ((current_start_time - prev_end_time) < min_diff): + for c in caps_list: + c.start = min(c.start + min_diff, c.end) + + distances = self.get_distances(lang, self.font_langs) + if not distances: + raise ValueError('Cannot find appropriate font for selected language') + + fnt = distances[0][1]['fontfile'] + align = distances[0][1].get('align') or align + missing_glyphs = self.get_missing_glyphs(fnt, self.get_characters(caps_final)) + + if missing_glyphs: + raise ValueError(f'Selected font was missing glyphs: {" ".join(missing_glyphs.keys())}') + + font_size = int(self.video_width * 0.05 * 0.6) # rough estimate but should work + + fnt = ImageFont.truetype(fnt, font_size) + index = 1 + + for i, cap_list in enumerate(caps_final): + + img = Image.new('RGB', (self.video_width, self.video_height), self.bgColor) + draw = ImageDraw.Draw(img) + self.printLine(draw, cap_list, fnt, position, align) + + # quantize the image to our palette + img_quant = img.quantize(palette=self.palette_image, dither=0) + self.save_image(tmpDir, index, img_quant) + + + index = index + 1 + + return caps_final, overlapping + + def printLine(self, draw: ImageDraw, caption_list: Caption, fnt: ImageFont, position: str = 'bottom', + align: str = 'left'): + ascender, descender = fnt.getmetrics() + line_spacing = ascender + abs(descender) # Basic line height without extra padding + lines_written = 0 + for caption in caption_list[::-1]: + text = caption.get_text() + l, t, r, b = draw.textbbox((0, 0), text, font=fnt, align=align) + + x = None + y = None + + # if position is specified as source, get the layout info + # fall back to "bottom" position if we can't get it + if position == 'source': + try: + x_ = caption.layout_info.origin.x + y_ = caption.layout_info.origin.y + + if isinstance(x_, Size) \ + and isinstance(y_, Size) \ + and x_.unit == UnitEnum.PERCENT \ + and y_.unit == UnitEnum.PERCENT: + x = self.video_width * (x_.value / 100) + y = self.video_height * (y_.value / 100) + + # make sure the text doesn't go out of the screen + box_rightmost_edge = x + r + if box_rightmost_edge > self.video_width: + x = float(self.video_width) - float(r) - float(10) + + # padding for readability + if y_.value > 70: + y = y - 10 + else: + position = 'bottom' + except: + position = 'bottom' + + if position != 'source': + x = self.video_width / 2 - r / 2 + if position == 'bottom': + y = self.video_height - b - 10 - lines_written * line_spacing # padding for readability + elif position == 'top': + y = 10 + lines_written * line_spacing + else: + raise ValueError('Unknown "position": {}'.format(position)) + + borderColor = self.e2Color + fontColor = self.paColor + for adj in range(2): + # move right + draw.text((x - adj, y), text, font=fnt, fill=borderColor, align=align) + # move left + draw.text((x + adj, y), text, font=fnt, fill=borderColor, align=align) + # move up + draw.text((x, y + adj), text, font=fnt, fill=borderColor, align=align) + # move down + draw.text((x, y - adj), text, font=fnt, fill=borderColor, align=align) + # diagnal left up + draw.text((x - adj, y + adj), text, font=fnt, fill=borderColor, align=align) + # diagnal right up + draw.text((x + adj, y + adj), text, font=fnt, fill=borderColor, align=align) + # diagnal left down + draw.text((x - adj, y - adj), text, font=fnt, fill=borderColor, align=align) + # diagnal right down + draw.text((x + adj, y - adj), text, font=fnt, fill=borderColor, align=align) + + draw.text((x, y), text, font=fnt, fill=fontColor, align=align) + lines_written += 1 diff --git a/pycaption/ttml_background.py b/pycaption/ttml_background.py new file mode 100644 index 00000000..1be44967 --- /dev/null +++ b/pycaption/ttml_background.py @@ -0,0 +1,102 @@ +import base64 +import tempfile +from datetime import timedelta +from io import BytesIO + +from PIL import Image + +from pycaption.base import CaptionSet +from pycaption.subtitler_image_based import SubtitleImageBasedWriter + +HEADER_A = """ + + + + + + +""" + +IMG_DEF = """{png}""" + +HEADER_B = """ + + + +""" + +SUB = """
+""" + +FOOTER = """ +""" + + +class TTMLBackgroundWriter(SubtitleImageBasedWriter): + + def __init__(self, relativize=True, video_width=720, video_height=480, fit_to_screen=True, tape_type='NON_DROP', + frame_rate=25, compat=False): + super().__init__(relativize, video_width, video_height, fit_to_screen, frame_rate) + self.tape_type = tape_type + self.frame_rate = frame_rate + + def save_image(self, tmp_dir, index, img): + # Jetzt speichern mit Transparenz + img.save(tmp_dir + '/subtitle%04d.png' % index, transparency=3) + + def to_ttml_timestamp(self, ms: int) -> str: + hours = ms // 3_600_000 + ms -= hours * 3_600_000 + minutes = ms // 60_000 + ms -= minutes * 60_000 + seconds = ms // 1000 + ms -= seconds * 1000 + return f"{hours:02d}:{minutes:02d}:{seconds:02d}.{ms:03d}" + + def write( + self, + caption_set: CaptionSet, + position='bottom', + avoid_same_next_start_prev_end=False, + align='center' + ): + lang = caption_set.get_languages().pop() + caps = caption_set.get_captions(lang) + + with tempfile.TemporaryDirectory() as tmpDir: + caps_final, overlapping = self.write_images(caps, lang, tmpDir, position, align, + avoid_same_next_start_prev_end) + + subtitles = "" + subtitles += HEADER_A + + for i, cap_list in enumerate(caps_final, 1): + sub_img = open(tmpDir + "/subtitle%04d.png" % i, "rb").read() + subtitles += IMG_DEF.format( + index=i, + png=base64.b64encode(sub_img).decode() + ) + + subtitles += HEADER_B + + for i, cap_list in enumerate(caps_final, 1): + subtitles += SUB.format( + begin=cap_list[0].format_start(), + end=cap_list[0].format_end(), + index=i, + ) + + subtitles += FOOTER + + return subtitles diff --git a/tests/test_ttml_background.py b/tests/test_ttml_background.py new file mode 100644 index 00000000..c3920dce --- /dev/null +++ b/tests/test_ttml_background.py @@ -0,0 +1,77 @@ +from pycaption import (DFXPReader, SRTReader) +from pycaption.ttml_background import TTMLBackgroundWriter + + +class TestTTMLBackgroundWriterTestCase: + + def setup_class(self): + self.writer = TTMLBackgroundWriter() + + def test_arabic(self, sample_srt_arabic): + caption_set = SRTReader().read(sample_srt_arabic, lang='ar') + results = self.writer.write(caption_set) + print(results) + assert results == """ + + + + + + +iVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAACXBJREFUeJzt3Qly2kgAQFEk3//OE6MFgdkEsafy/V5lsoDUTqq+242Meg4fEHL4v/8C8DcJmhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQIerfxj52HH8/Ycd71Q3d+4N9J0LuNh2FX0MPw+WPXedcP3fmBfydB77Y36HH4/PFW0NPULOgnCHq3vV2tS443gh52DvB7CXq3/V39haB3TvG/l6B3W7ra8RpvOFhy/BBB7zZ3NU7rgMeH/znw8HLQ82eNoJ8l6KfNS+E16OF2X5sLbMect0GPV6++nT94+iIwTIuNva8qfy9BP2uJ61Tbn4XEjUK3M+xn95slx3GYYTnj9Ouwne9PXwT+fC78+e30oQT9BEE/aRzniXYzfS6FHobtwmAc19bn6s+CPk7Y6xlLudNj6wfbfBE4Bj39LOjHBP3YdI3iWObZUnZ+6E+Jh8N0yFTsOJ6WI+MywZ5m6HFaVc9X4qbPkc/5+XA4rVMO69eCzbmCfoKgHzu++tusItZYl+DmfpfJdHv0MdMvVzku1xLj9JkxnAe9nd0/fxb0EwT90LjOshfXk6egP//brgvOl7vHufjiKsc8Ra/nHBfQH7eCXn8r6GcI+qF1Fh3Gda5eFg5L0PNcemz7bLb9jHVeM8/PjNNDw7J+OUyX9S5m6OWB+SlLjmcJ+qFxqm+cw/yYOxuGYV5OHKfgudv15811u2WdfXzm1Pf05GF2fs4y/vqUqxxPEvRD08x7XCOsb6mY5t3jfD0Oa5PzQmJYL2KsQ0yFfo40jbI8/fnIMI+3OWeZ19eqvZfjWYJ+aFkmLB2OG8sf11XI9pkvY3x5crMMufjOyrykOY39cfnNF64S9JNuxjSOZ1fc9g1557uN62XBwby8g6DfNK0OXut5ONxdRIyba348SdBvWtbS+40PT1y/q/ji3+03EvSbxtMbM3af+fDEeen+yui/laDf9PoLtWfOvPL6krsETYqgSRE0KYImRdCkCPp9xysRz12OuHPUwwFc73iGoN+3fW/ng+rufB97+9ajq6N4b9IzBP2+s6Dvfx9kun379ij3jhL0MwT9vvOg71d3Z8mxCfp8kOW904J+gqDfMa17dyw5rq6UN6Osf94eNno79PME/Yblhr+z+6PuJX31vRnbUaYHlg14lwOmN/8L+hmCfsN26jxtP3NnFb3cG3tzlPmo482L55svnd1zyE2CfsN4OG3UsdlP6c4OYccbtC6e344yHzbfsHJW9DC89K7r30bQL1hmz3mDpPOgx9vhbfYluDHK5cGnjzjM+zZxn6BfMN9EMt5YQ9+cojfbKN0YZXmBOG0ntl1Hj4fX7ov5bQT9gnHZtfHKGvpiaj0/b1oKr0F/HeVj2XNmvPjEeHi/FhNBv2DzTZQva+izKfriisey48F4c5SzvfA2NxOO034HpuiHBP2C+S7vZQ18M+j1dd1py4Nh2OzjeGWU60GfNmn6wX/lv0nQL5g3/VqvRiwX1dY/b7Yn/XLCdqfdr6Nc207sY31Y0A8J+gXLPkrDvLPRtL3ROG52CJuO2wQ97wO2WQlfH+XadmLj4XxcbhP0K8Z1r67DtKPSFNu8DeNwCvE83sP2yeujXN1ObFzP/eF/5z9I0K8ZtzZr5LO3YVzsCH35Ho2ro5w9cnnYT/3r/mGC/kZTxB8fDzf94q8R9Dcal514X94ujL0E/Z3O9trV808Q9Lcap/+L22AB/FME/c28nPtZgv5mgv5Zgv5ml7ef8L0E/c3m20/+77/GryHob2bF8bMETYqgSRE0KYImRdCkCJoUQZMiaFIETcp/DZbDi9OwJmsAAAAASUVORK5CYII=iVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAACyxJREFUeJzt3e1Cm9gCQFHA93/nO4ZvTK7adjpld60f0xpDwHHneDiJdHiDkOG/PgD4lQRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQI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0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQI+ldMf/z2OTQJ+jdM0zAI+kcI+jdMgxn6hwj6N0zjqOifIejfMI3DMAr6J7x10NPi5nPfMc7dwbYDDzP0cw98/jze/XrzvYP+09V4mimnf5g6Px8z3rvKOw+2PeGh//vPt372S23+OXge+73n/vcOeho//7v+3M8GPT/lvOZ4Kujx+aKndR0j6Dd2b8nxo0Fvz/d00M+ezJzz8Nm/oN/aTwW9jHs72BeD/usEfTj3dXqe/vEvEPL2QZ9n1u8Kev7/2xl6HL+y5Dg0e2f1cZi//4y3fV3Q72uaJ7a9nH+e4M5B7+PerqGH5X7d00HvzU7DTdGH9f/nK49/HfBtvHPQy7pzmD72H9kfhx725fWDW3LHga6Dvox7imtaDvy8crsN+upZLkEP20kMl2Yv45mhz9446GmuYFka/MllHK+CnrZG5mXC3+82XAd9HHeZjvdvjc88p/tBz/fcpuOIy2e3xfQw3Cl6OWQ9cEtf0G9qyWsJb/7wuOSYE99WB8Mw3P7AP450HfRh3Dneffq8tHwT9FLsYQmxz9vDtuaehnsvL27rjr1oQb+rw1Q5nVNa8lh+3s+pz00+CuUU9PW4y7fGMtIwz9B3g/6cn+8thJdV9DzQeG+O3t+3t6xlBP3bJ/B7lrwu4W2f3S7apumQ1VLT9sg7t/qOQV+POw7TdDXZ3wl6noiPz3d45mG9ufw57n4Oh7sfW+Tbkwj6Tc3XgevdiGUCnrbXJeZZddpjWaboY93X1403S4593LnDcUt1fnH63kXh+qL1g6CX48dxu6I8nsLhQesML+h39VnRujqep9DP1qZ9fh2WyXXpfFxetjhMiusH4/L180XhPu4e9LpIXz+6Cnp9vpsZej9++dIw7DP98bbfOsByGpfvnbf1xkGvM+x8f2NNcJkLhznfYf5zGC917g/bbg4vS4hxTW26GXfYYp2/Icb1eU73oZfnG9ZZ/Rj0eHn28xHH11SG/W+wHubddu9svWm8zrXb/Dpui4yl6es70cdbx3vtN684bi9GT9vKedjG+rgKenu+8XIreZuhx/0Hxfy45Y/rU5g/HPehp/HNexb09h7ly4JiW0wfXT/iUNO6lrjz6sv+wG1RchzrcPTd57k9g9NJXq+x9y/ensa7EfQzTjP0OOypXq7SHi5dl/XH93Z2OIXxzafkE0E/4/ptnNvV17Im2F6fezQ1Ho/6vhO6nMJ7XwPeEPQzTm91uyyLD++gePTDfjwc9Y1nNJ3PgJmgn3FnfTyO4/Ficb7vd7esH/oN78MpfPvY/2eC/jfni8VpePQGph8r7s7lKoL+JuJ6EYImRdCkCJoUQZMi6Nd3ep3y8dXn8qX3vjwV9Ou7flX9L28PnbzDX9D/A4L+AkG/PkF/gaBfxeOlr6C/QNCv4s7GjNsbqgX9PEG/ipuNfffGBf0Fgn4Zt0uO6bif6HR3vl4feNw0SdC8jtP7rvdOp31HstP2Yh/nnZkEzetY1x2HXz38uPwK+HDZof8S8WHTMkF/CPrFrFsjbYvnadg63X61fN+4Zt9e7LhpmaAF/RKOv/hy2Pl/3exgWuJdt1a63V5s/a1yQX8S9As4b+y177u43eXYJuM96H2LpKtNywQt6JdwZ6fHdYux4fjHuivY9fZiV5uWCVrQr+C0sdf629zbLmDrhmTjusvXZZew5YuXTcu2iVzQ/K7zxl7rFmSXmxtr4dPW6/U+CvumZf4ZLEG/hAcbe93fB+yy5dd66Me9A96WoF/AaWOv8xYJ9x4xff/2Yg2CfgGnjb3u/RPk5wf8wPZiDYJ+Bdcbe+3/IvhDP7O9WIKgX8LVxl5PrDhsAfaIoF/Elzb2UvNDgiZF0KQImhRBkyJoUgRNiqBJETQpgiblP1yzwCZ1jcuQAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAAB8FJREFUeJzt2guS2lYUAFEk73/PAf0BmZlywHHa51TFZiQhkanm+fK5/ICQy3/9AOCdBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmC/o7x6k85Cy8J+mvXDofhHUG/5Sy8JOgvXXO+XN4S9CjojxP0F6acrz1/meI35gkjx+cJ+rVlef5GiOPXRxmiP0/Qr117XkMdZ48HrFu+nJBvk/jr6M+vsO759mP+qwn6tfFyORb7FO04Hnr/4lTz7PLyiJMrbHu+/Zj/aoL+iWWtPK7Qw1bveFiXl0Z/urjuJ7weOZwVvd3zcIXDznXP851+5f+rTtCnbu/UzSWP2xq9Jzu9jbcXPd28zRPDq8imA8dD0OO2tK9PmpMnxfLOyMmo85Y3XnoEfWZ+KXhZWtqmjq3nyz48rI1O2y4vkp6Ou1V9t2E+27Cfbdz+muJeZ429/uWH9YnEPUGfWNbMJb59qlgTvy3Fe+VzWdPiOrxIerrH7Y/jhvX5si3z0xXmZXlqeXkQ16OWhzDvWf4F+ehv4f9J0CduYd76XGeNLeQlt3nnwxI93RwPr/seyp5eE16OQU8Vz5PIeH+FqeLjkr49uaZt0wMzc5wS9LMpy0Oz63K8FDivnMeg9yF7OM4i+xixDArXKftuhp6W88va7XaFOd9xvNuxjifbNkGfEvSz2zp5WWaO2TxJLH8NW+3jcc443FrPst1YD70ffJdhY7nUcHeh9VXpvmO5/7D9IOgzgn42ZXfr7PbfbVW9DMu4sN0ahiXGYd4wH3Y3QB+DXo64/07IuL6O3C/1cIXpj+3y6zWG/QH8/t/NH0/Qz8Z1IR7WFpcfh209XdbNYV9fL4/v2h1H62F9NtwdcLvP/aUOV1g2TR+1rFu2w779efzfR9DPlldeRw8/LmPxyaaHsyw39+HlsH8dI87O/S2/8Vfy/yHoZ++ZTueIf2wf0jzs9b7bZwj62fHTj39xlvUV3ngy777tO9Y8EPSz9wS9j84n8+5oBv4QQT9716fK0+I8v1Z8+ibGy6998OsE/ex9b/H+9NWbnD9F0Cc+HzSfIugTb/s6/c+/sc+HCPrE21bVs2/s81GC/iQTx28naFIETYqgSRE0KYImRdCkCJoUQZMiaFL+AaVuyauPhcHlAAAAAElFTkSuQmCC + + + +
+
+
+
+ +""" + + def test_styling(self, sample_dfxp_from_sami_with_positioning): + caption_set = DFXPReader().read(sample_dfxp_from_sami_with_positioning) + results = self.writer.write(caption_set) + print(results) + assert results == """ + + + + + + +iVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAAB0NJREFUeJzt29FymzgAQFGb/P8/b2IMFjFulGyn7dw55yFjI4HzcEMFuJc3CLn87V8AfidBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgv6xZVm+ObK8nPXqSHyXoKcsz40uy+X6otsXI8t1PMg46zgy9/mcEvSU5Xr5P0Hfcnw/xvU86E8jZ4f8agJ3gp5xFu83gl6uH++Xl2fo5esz9PsflKJnCHrGsaf13/89yHE5cHt9GvQyLJqfZo0jb5+3rW+coucIesIhp/fQPvpc7hu3t4ehj5FleWy9rDusG05m7T+W6zBp3+PNKXqaoCeMNb2Hdnl33YPc3o5Dt5FtYbxu3TafzboXf9lGbn9Ct1fDqsQpeoqgJ4yXhGuBjzPs+natcB/atn06Q7+atQV9/7lsr6+XYVUi6CmCnnC4wXaP8+0Q5McpfB9aR7ae97Pr4ZR8mLUHvWxH2Q87BP10n4UTgp5wDPre6Rb0foG4D93ePXre9t+Dfpq1BX39dKhD0M83Djkh6AnLWVd7eduMfehj5HK4LfIp6M+zxqDHQy2nH8yvCHrCcvYv/33JsAV92V/vV3Sf9r8HfTLrOeiLoH9I0BN+cIY+3GZ7eYY+rFicoX8HQU/4yRp6GRYdr9fQ66zToK2hf0TQE4aYxockjzvI612Ox9DjVt6603Db7mzWWdDPdznctpsh6AmHByvvkX0Y7kO/2+8wr0OHByuPe32vZj0FvW7ejns7hKDnCHrC8WsXs08KD9ePL58Urnefn4K+TRqfFHr0PUfQM8anGvuXMvYvXYzf2jh+Z2M57nPcY5i1/Xjbd3usSp5/A35B0DP+0vnxsWqx4pgl6CnrN5r/4OfdT9D7okXPkwQ9ZVg+/JnPWy81h2tCK+g5gv4nLdfbReFX/5GFJ4L+J42XmnyHoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCn/AS7ayVFsyVPGAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAACwtJREFUeJzt3et2mzAChVGQ3/+dpzaSEOALbchk5mTvH62DgXp1fWZxVaYbBJl++gPAlQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0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RdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0KYImRdCkCJoUQZMiaFIETYqgSRE0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NCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2K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ETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF0EQRNFEETRRBE0XQRBE0UQRNFEETRdBEETRRBE0UQRNF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FEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTImhSBE2KoEkRNCmCJkXQpAiaFEGTIujPmL6cXx6HnQYtI+4/8gmC/ozp8Xiu8T4fj2l9tQzc3v42aG/824jfBiv6kwT9Gd+KfcxpTu+X66s96PntIehvtX+zTsZnCPozpsdz3wYv0c6v5pePpe1xC/2c3lvpb8PteHyMoD9j+trcTuurLejpMQ6cxqBf8xb7a4x3279nvXME/Rl7sdNjifbd6l753PYQ9DzdO+htX5tfJejPOBS7BP1V+LLP8W77vXNxDvop6I8S9GfMxU7Di6/95mla9jne2+H3z8eg3wOPB/P4JYL+jKXjr4KXaNe948cW9LIxPgT9dJDjswT9GfMmeA52Cfq5Br1st4f3tqnsa3yaoD9ji3nbCn8dqXt7LkEv3xKHoOfmf+NaBwn6M9aQn+t+8rLHMe171uMXxnmaSc8fJ+jPmPOdD0FP6x/TfuZkDvrr1OFwHHrr2XfCjxH0Z0zLMbn10Nx6eGPO9rUe7Hiup8Vf+yZ8cmLlgwT9GVvQ07QegF4v4xjy3q/zmK9XmjkO/UGC/oxp/+73Oh7NmL/57dvrIeiFoD9I0J8xnxrZ/xxOlRx+PF02Pfg9650jaFIETYqgSRE0KYImRdCkCJoUQZMiaFL++KDXc3vfeeff4X5Vfmr1/jWf5W9WDPp65vlH4y7XfV7GuR34ewyrMpwq/6lL9P6Y6/mSQc+X/CzbtfN91qdxfzXo/2c7/rPTjEFvt8H88Iqm8xL+nMufkkGvt/M9//6g1wdv/NT6/ew0x6DXa05/sNG9LOHPueK6GPRyL/XX/9X90S6nPY/96rdL0NP2jLrn+Vmhd4s6lDKOc9lKbtfZPe/uVJm+P+wQ9HPb5Riu2zut43UJNyM3dYM+3NQ3b6/HKzef66Wex6D3t5b7Xbem1hlM+5B9IdfZ7q+3Gc8z2Kc5znNaS10nO63KMpv9r946j3Ghz+dhrU5rfV2rnm7Qz31fc1p/2q+5327HPge9vTXfIbiNtryctt3R5bbYdYzztNNzeGeYwT7WMGge/Xmc7Lgql6DXNR/m8tzuF7hZwnHkrG7Q42ZqGbBXuz0x4xr0cxt9bmK9q2r9GrYEvc5+3ELfT7uu0vp3a/inYxv0eC5zGyY7zO6yy7Gt+TbF9iG/s4SbtQqKB70OmLet477ma32Q7WkfentrqWR/muK0bey3oE/fHC/TjjcWrqGt0wyDltFfp8nG2Z2/FB6n3G7zmj/k7RJu1qqoG/Rhd/P8RJfpUNchy2ls4PWaH1G3PVn0eQz6dQj6PO0+33XbfHpIx/aXZC34ONl5VV6Hw3bnBQ0f8n4Jl7Uq+kOCfm/Yxg30++H5N0Hvb22VDbe8/jjom2nHLfTyvP4ht3XQKejtKR7n2a1rcNjl2Hfo9w95v4TLWhX9GUEvX5j2Q3WP7wQ9vHUIev0lE/st2teg76bd5rs/s2DLbXiMwV3QN7Mb53gNeviQ90sQ9H/VNej35m77LSj7d7NL0OPXtuMux/vtH22hb6c9zXcactsH3Qd9nd3rx0HvH/J+CYL+r7oJ+jXumu5fmS5Bj9+mDrunl33o5yXoy7SnoF/nEafpuGbHoK+ze/1F0Nss7pdwqf+j/9H/JeJBD6c8piHo/cv+Jej9oMHx9X6UY3u9Bj3dTXvT2biF3ufz3S30dXavYR/6utEdZnW/hPP+SbLoYtDbtRxbbMuWdd/l+PrlJ7dB7299Dfz6YTsOvUwx/87B7YdhIcdpj/+4r1/QxsNpz8cP96Gvs3sN+8U3Qe8f8n4J19n/k/9X/iHJoJcTZtvvUnvt5/neP03zb7y8C3p/a1rOqz3nnY19DuPkr3Ehh2nPQR/PTg7n8R7fC/o6u+2znQ/bDactl1W8W4Kg/6PWf9vXf+K3IdNxhGm7tv/2rWmc6u71dsXFccdm2s/h3Cxzfz0MGuawT3ad3XX9xin+agnTdfZ/y3/+36sYNH8wQZMiaFIETYqgSRE0KYImRdCkCJoUQZPyP4tZub1NYHASAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAAtAAAAHgCAMAAAC7G6qeAAADAFBMVEX///++vr4AAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACDvjs2AAAABHRSTlP///8AQCqp9AAACJ9JREFUeJzt2u1yqsgCQFEh7//ON8pXg+bk1K2pmprNWj/mBJXGTDbYtj6+IOTxbz8B+CcJmhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUgRNiqBJETQpgiZF0KQImhRBkyJoUu4c9Pztw9bnH+Zl63zndvMfdxnG/3S88d+fxzkN8ukYH57iLd066Mc0Bjatm/vN2w/z911P0zPd053z6/bXv+tDp8fbLvvwz4fO4/FeW/Nj+Pdy6O9hpmGY6+ZyiGmpeL3n+D3uSdDbxhble1XTs5pvj/egX/UsYc/rY9922Yafnreegp7m8bjPkc6HnrdxltEvm6/T6FX485q83jOvz/+2F+mbBr28PJ+C/u5rzeZa1VLM+np+uXPd5/HY43/bZRt+nk8Xz3kfYTvMe9Cv02XJdZ6vm8spsJ5T+13rQNNdi75l0K8K3oOej7KWm5bt80Thh6DXi/Ea9GmXffhz0K9HPe+Yln1Oz+hy6GXHy+bphLu8FszjbOdWbhj0fEwULtfL6UPQ5+x/DvrYvu5yjL/NsNeb9jnMevm9Bn30v+09bh5Tok9Br5fsf/B/23/E7YIe/tanoKetih+r2m8b5itD0NP66B/elj1vvAy1PI/1XNj/c4w+VnqJdrm4D3OVo99tDn3TpO8W9OlPPwb92C6Q70Fva2Hz8vZvWlyDXkZYgx532Q782N7anS6l24m0rZoMo48FT+egpy3obR6zTMXH9wD7C9G93C7oYXI5BL2/Tv8Y9LYo9thdg562ScVll+0AS9DP92vHc3kuxB1RX0b/PehllWNaht3W847nP8/jsso93C7o/Up2Dnragv4wkZ23926P66TgFPQW3XWX11DLKvN2Dd8Pup5IrxnLcc39MOX4Iei3RerjrcE8bwsot3K3oJe/+9scej4ujHvQ83XKsQW97nEJ+mvv8rLL69HrqfIYL5qvs2h/YzidLq5/O4c+z2qmYzY+j6fujdwu6G1yOQ1xbjOO82re+5T6z0G/Nq6Tlsf4w2s17TzP2ZfsPgf9N6sc42/2eorrzPqOOd8y6K/3dej1ArrOg49P/c6Lwb8G/er1bZfhhzWz/Xk858DLKOM4x+h/sw59+sVeT3G55t/v/eDLLYPeViD2Gevporx/6rZHeHw+98egl+9rzNddvoZBptP3OYZPCddjvY3+2yeFp99neydwmojczE2DftkXyYYX8+XKvX5jYtquh+sXM96CvnxEc4Q57vK13rOsxo1LafP4rYxPQc+/fJdjeA+wHe7yceTt3DzoxbHysK92DN+U27bP8+5t3fgxZr5f1cdd1kG2Mc+T6Mc4h7gG/eu37cZVmv37gIK+q3l03Hbc8fbAr///+9CfDnb+LvR199Nul1HODzof7r7Tjac7B02QoEkRNCmCJkXQpAiaFEGTImhSBE2KoEn5H/VQwYklqsiwAAAAAElFTkSuQmCC + + + +
+
+
+
+
+
+
+ +"""