mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-21 18:52:36 +01:00
Add format "Timed Text IMSC 1.1"
This commit is contained in:
parent
471d278fea
commit
723160beb3
@ -42,6 +42,7 @@
|
|||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stbl/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stbl/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tahoma/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tahoma/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tesseract/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tesseract/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ttml/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ukranian/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ukranian/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unbreak/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unbreak/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Undocked/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Undocked/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
@ -8,7 +8,7 @@ using System.Xml;
|
|||||||
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IMSC 1.1 Viewer: http://sandflow.com/imsc1_1/
|
/// IMSC 1.1 Viewer: https://www.sandflow.com/imsc1_1/
|
||||||
/// More about bouten/furigana: https://www.japanesewithanime.com/2018/03/furigana-dots-bouten.html
|
/// More about bouten/furigana: https://www.japanesewithanime.com/2018/03/furigana-dots-bouten.html
|
||||||
/// Netflix blog entry: https://medium.com/netflix-techblog/implementing-japanese-subtitles-on-netflix-c165fbe61989
|
/// Netflix blog entry: https://medium.com/netflix-techblog/implementing-japanese-subtitles-on-netflix-c165fbe61989
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -223,6 +223,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|||||||
new TimedText200604CData(),
|
new TimedText200604CData(),
|
||||||
new TimedText200604Ooyala(),
|
new TimedText200604Ooyala(),
|
||||||
new TimedText(),
|
new TimedText(),
|
||||||
|
new TimedTextImsc11(),
|
||||||
new TitleExchangePro(),
|
new TitleExchangePro(),
|
||||||
new Titra(),
|
new Titra(),
|
||||||
new TmpegEncText(),
|
new TmpegEncText(),
|
||||||
|
@ -31,7 +31,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
lines.ForEach(line => sb.AppendLine(line));
|
lines.ForEach(line => sb.AppendLine(line));
|
||||||
string xmlAsString = sb.ToString().Trim();
|
var xmlAsString = sb.ToString().Trim();
|
||||||
|
|
||||||
if (xmlAsString.Contains("xmlns:tts=\"http://www.w3.org/2006/04"))
|
if (xmlAsString.Contains("xmlns:tts=\"http://www.w3.org/2006/04"))
|
||||||
{
|
{
|
||||||
@ -41,6 +41,16 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|||||||
if (xmlAsString.Contains("http://www.w3.org/ns/ttml"))
|
if (xmlAsString.Contains("http://www.w3.org/ns/ttml"))
|
||||||
{
|
{
|
||||||
xmlAsString = xmlAsString.RemoveControlCharactersButWhiteSpace();
|
xmlAsString = xmlAsString.RemoveControlCharactersButWhiteSpace();
|
||||||
|
|
||||||
|
if (xmlAsString.Contains("profile/imsc1"))
|
||||||
|
{
|
||||||
|
var f = new TimedTextImsc11();
|
||||||
|
if (f.IsMine(lines, fileName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var xml = new XmlDocument { XmlResolver = null };
|
var xml = new XmlDocument { XmlResolver = null };
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -79,6 +89,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
lines.ForEach(line => sb.AppendLine(line));
|
lines.ForEach(line => sb.AppendLine(line));
|
||||||
string xmlAsString = sb.ToString().Replace("http://www.w3.org/2006/04/ttaf1#styling\"xml:lang", "http://www.w3.org/2006/04/ttaf1#styling\" xml:lang").Trim();
|
var xmlAsString = sb.ToString().Replace("http://www.w3.org/2006/04/ttaf1#styling\"xml:lang", "http://www.w3.org/2006/04/ttaf1#styling\" xml:lang").Trim();
|
||||||
|
|
||||||
if (xmlAsString.Contains("http://www.w3.org/2006/10"))
|
if (xmlAsString.Contains("http://www.w3.org/2006/10"))
|
||||||
{
|
{
|
||||||
|
546
src/libse/SubtitleFormats/TimedTextImsc11.cs
Normal file
546
src/libse/SubtitleFormats/TimedTextImsc11.cs
Normal file
@ -0,0 +1,546 @@
|
|||||||
|
using Nikse.SubtitleEdit.Core.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IMSC 1.1 Viewer: https://www.sandflow.com/imsc1_1/
|
||||||
|
/// </summary>
|
||||||
|
public class TimedTextImsc11 : SubtitleFormat
|
||||||
|
{
|
||||||
|
public override string Extension => ".xml";
|
||||||
|
public override string Name => "Timed Text IMSC 1.1";
|
||||||
|
|
||||||
|
private static string GetXmlStructure()
|
||||||
|
{
|
||||||
|
return @"<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||||
|
<tt xml:lang='en' xmlns='http://www.w3.org/ns/ttml' ttp:contentProfiles='http://www.w3.org/ns/ttml/profile/imsc1.1/text' xmlns:tts='http://www.w3.org/ns/ttml#styling' xmlns:ttm='http://www.w3.org/ns/ttml#metadata' xmlns:ttp='http://www.w3.org/ns/ttml#parameter' ttp:timeBase='media' ttp:frameRate='24' ttp:frameRateMultiplier='1000 1001' ttp:tickRate='10000000' xmlns:ebutts='urn:ebu:tt:style' xmlns:itts='http://www.w3.org/ns/ttml/profile/imsc1#styling' xmlns:ittp='http://www.w3.org/ns/ttml/profile/imsc1#parameter' xmlns:ittm='http://www.w3.org/ns/ttml/profile/imsc1#metadata' ittp:aspectRatio='16 9'>
|
||||||
|
<head>
|
||||||
|
<styling>
|
||||||
|
<style xml:id='style.center' tts:backgroundColor='transparent' tts:color='white' tts:fontFamily='Arial' tts:fontSize='100%' tts:textAlign='center' tts:textOutline='black 2px' />
|
||||||
|
<style xml:id='style.italic' tts:shear='16.6667%' tts:backgroundColor='transparent' tts:color='white' tts:fontFamily='Arial' tts:fontSize='100%' tts:textAlign='center' tts:textOutline='black 2px' />
|
||||||
|
</styling>
|
||||||
|
<layout>
|
||||||
|
<region xml:id='region.topLeft' tts:extent='80% 40%' tts:origin='10% 10%' tts:displayAlign='before' tts:textAlign='start' />
|
||||||
|
<region xml:id='region.centerLeft' tts:extent='80% 40%' tts:origin='10% 30%' tts:displayAlign='center' tts:textAlign='start' />
|
||||||
|
<region xml:id='region.bottomLeft' tts:extent='80% 40%' tts:origin='10% 50%' tts:displayAlign='after' tts:textAlign='start' />
|
||||||
|
|
||||||
|
<region xml:id='region.topCenter' tts:extent='80% 40%' tts:origin='10% 10%' tts:displayAlign='before' tts:textAlign='center' />
|
||||||
|
<region xml:id='region.centerCenter' tts:extent='80% 40%' tts:origin='10% 30%' tts:displayAlign='center' tts:textAlign='center' />
|
||||||
|
<region xml:id='region.bottomCenter' tts:extent='80% 40%' tts:origin='10% 50%' tts:displayAlign='after' tts:textAlign='center' />
|
||||||
|
|
||||||
|
<region xml:id='region.topRight' tts:extent='80% 40%' tts:origin='10% 10%' tts:displayAlign='before' tts:textAlign='end' />
|
||||||
|
<region xml:id='region.centerRight' tts:extent='80% 40%' tts:origin='10% 30%' tts:displayAlign='center' tts:textAlign='end' />
|
||||||
|
<region xml:id='region.bottomRight' tts:extent='80% 40%' tts:origin='10% 50%' tts:displayAlign='after' tts:textAlign='end' />
|
||||||
|
</layout>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</tt>
|
||||||
|
".Replace('\'', '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsMine(List<string> lines, string fileName)
|
||||||
|
{
|
||||||
|
if (fileName != null && !(fileName.EndsWith(Extension, StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
lines.ForEach(line => sb.AppendLine(line));
|
||||||
|
var text = sb.ToString();
|
||||||
|
if (text.Contains("lang=\"ja\"", StringComparison.Ordinal) && text.Contains("bouten-", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.Contains("profile/imsc1") && base.IsMine(lines, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToText(Subtitle subtitle, string title)
|
||||||
|
{
|
||||||
|
var xml = new XmlDocument { XmlResolver = null };
|
||||||
|
xml.LoadXml(GetXmlStructure());
|
||||||
|
var namespaceManager = new XmlNamespaceManager(xml.NameTable);
|
||||||
|
namespaceManager.AddNamespace("ttml", "http://www.w3.org/ns/ttml");
|
||||||
|
var div = xml.DocumentElement.SelectSingleNode("ttml:body", namespaceManager).SelectSingleNode("ttml:div", namespaceManager);
|
||||||
|
foreach (var p in subtitle.Paragraphs)
|
||||||
|
{
|
||||||
|
var paragraphNode = MakeParagraph(xml, p);
|
||||||
|
div.AppendChild(paragraphNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlString = ToUtf8XmlString(xml).Replace(" xmlns=\"\"", string.Empty);
|
||||||
|
subtitle.Header = xmlString;
|
||||||
|
return xmlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XmlNode MakeParagraph(XmlDocument xml, Paragraph p)
|
||||||
|
{
|
||||||
|
XmlNode paragraph = xml.CreateElement("p", "http://www.w3.org/ns/ttml");
|
||||||
|
string text = p.Text.RemoveControlCharactersButWhiteSpace();
|
||||||
|
|
||||||
|
XmlAttribute start = xml.CreateAttribute("begin");
|
||||||
|
start.InnerText = TimedText10.ConvertToTimeString(p.StartTime);
|
||||||
|
paragraph.Attributes.Append(start);
|
||||||
|
|
||||||
|
XmlAttribute dur = xml.CreateAttribute("dur");
|
||||||
|
dur.InnerText = TimedText10.ConvertToTimeString(p.Duration);
|
||||||
|
paragraph.Attributes.Append(dur);
|
||||||
|
|
||||||
|
XmlAttribute region = xml.CreateAttribute("region");
|
||||||
|
region.InnerText = GetRegionFromText(p.Text);
|
||||||
|
paragraph.Attributes.Append(region);
|
||||||
|
|
||||||
|
// Trying to parse and convert paragraph content
|
||||||
|
try
|
||||||
|
{
|
||||||
|
text = Utilities.RemoveSsaTags(text);
|
||||||
|
text = string.Join("<br/>", text.SplitToLines());
|
||||||
|
var paragraphContent = new XmlDocument();
|
||||||
|
paragraphContent.LoadXml($"<root>{text.Replace("&", "&")}</root>");
|
||||||
|
ConvertParagraphNodeToTtmlNode(paragraphContent.DocumentElement, xml, paragraph);
|
||||||
|
}
|
||||||
|
catch // Wrong markup, clear it
|
||||||
|
{
|
||||||
|
text = Regex.Replace(text, "[<>]", "");
|
||||||
|
paragraph.AppendChild(xml.CreateTextNode(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
return paragraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ConvertParagraphNodeToTtmlNode(XmlNode node, XmlDocument ttmlXml, XmlNode ttmlNode)
|
||||||
|
{
|
||||||
|
foreach (XmlNode child in node.ChildNodes)
|
||||||
|
{
|
||||||
|
if (child is XmlText)
|
||||||
|
{
|
||||||
|
ttmlNode.AppendChild(ttmlXml.CreateTextNode(child.Value));
|
||||||
|
}
|
||||||
|
else if (child.Name == "br")
|
||||||
|
{
|
||||||
|
XmlNode br = ttmlXml.CreateElement("br");
|
||||||
|
ttmlNode.AppendChild(br);
|
||||||
|
|
||||||
|
ConvertParagraphNodeToTtmlNode(child, ttmlXml, br);
|
||||||
|
}
|
||||||
|
else if (child.Name == "i")
|
||||||
|
{
|
||||||
|
XmlNode span = ttmlXml.CreateElement("span");
|
||||||
|
XmlAttribute attr = ttmlXml.CreateAttribute("style");
|
||||||
|
attr.InnerText = "italic";
|
||||||
|
span.Attributes.Append(attr);
|
||||||
|
ttmlNode.AppendChild(span);
|
||||||
|
|
||||||
|
ConvertParagraphNodeToTtmlNode(child, ttmlXml, span);
|
||||||
|
}
|
||||||
|
else // Default - skip node
|
||||||
|
{
|
||||||
|
ConvertParagraphNodeToTtmlNode(child, ttmlXml, ttmlNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRegionFromText(string text)
|
||||||
|
{
|
||||||
|
if (text.StartsWith(@"{\an7", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.topLeft";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an8", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.topCenter";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an9", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.topRight";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an4", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.centerLeft";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an5", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.centerCenter";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an6", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.centerRight";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an1", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.bottomLeft";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.StartsWith(@"{\an3", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return "region.bottomRight";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "region.bottomCenter";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetAssStyleFromRegion(string region)
|
||||||
|
{
|
||||||
|
switch (region)
|
||||||
|
{
|
||||||
|
case "region.topLeft": return @"{\an7}";
|
||||||
|
case "region.topCenter": return @"{\an8}";
|
||||||
|
case "region.topRight": return @"{\an9}";
|
||||||
|
case "region.centerLeft": return @"{\an4}";
|
||||||
|
case "region.centerCenter": return @"{\an5}";
|
||||||
|
case "region.centerRight": return @"{\an6}";
|
||||||
|
case "region.bottomLeft": return @"{\an1}";
|
||||||
|
case "region.bottomRight": return @"{\an3}";
|
||||||
|
default: return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetStyles()
|
||||||
|
{
|
||||||
|
return TimedText10.GetStylesFromHeader(GetXmlStructure());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
|
||||||
|
{
|
||||||
|
_errorCount = 0;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
lines.ForEach(line => sb.AppendLine(line));
|
||||||
|
var xml = new XmlDocument { XmlResolver = null, PreserveWhitespace = true };
|
||||||
|
try
|
||||||
|
{
|
||||||
|
xml.LoadXml(sb.ToString().RemoveControlCharactersButWhiteSpace().Trim());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
xml.LoadXml(sb.ToString().Replace(" & ", " & ").Replace("Q&A", "Q&A").RemoveControlCharactersButWhiteSpace().Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
var frameRateAttr = xml.DocumentElement.Attributes["ttp:frameRate"];
|
||||||
|
if (frameRateAttr != null)
|
||||||
|
{
|
||||||
|
if (double.TryParse(frameRateAttr.Value, out var fr))
|
||||||
|
{
|
||||||
|
if (fr > 20 && fr < 100)
|
||||||
|
{
|
||||||
|
Configuration.Settings.General.CurrentFrameRate = fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frameRateMultiplier = xml.DocumentElement.Attributes["ttp:frameRateMultiplier"];
|
||||||
|
if (frameRateMultiplier != null)
|
||||||
|
{
|
||||||
|
if (frameRateMultiplier.InnerText == "999 1000" && Math.Abs(fr - 30) < 0.01)
|
||||||
|
{
|
||||||
|
Configuration.Settings.General.CurrentFrameRate = 29.97;
|
||||||
|
}
|
||||||
|
else if (frameRateMultiplier.InnerText == "999 1000" && Math.Abs(fr - 24) < 0.01)
|
||||||
|
{
|
||||||
|
Configuration.Settings.General.CurrentFrameRate = 23.976;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var arr = frameRateMultiplier.InnerText.Split();
|
||||||
|
if (arr.Length == 2 && Utilities.IsInteger(arr[0]) && Utilities.IsInteger(arr[1]) && int.Parse(arr[1]) > 0)
|
||||||
|
{
|
||||||
|
fr = double.Parse(arr[0]) / double.Parse(arr[1]);
|
||||||
|
if (fr > 20 && fr < 100)
|
||||||
|
{
|
||||||
|
Configuration.Settings.General.CurrentFrameRate = fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BatchSourceFrameRate.HasValue)
|
||||||
|
{
|
||||||
|
Configuration.Settings.General.CurrentFrameRate = BatchSourceFrameRate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration.Settings.SubtitleSettings.TimedText10TimeCodeFormatSource = null;
|
||||||
|
subtitle.Header = sb.ToString();
|
||||||
|
|
||||||
|
var namespaceManager = new XmlNamespaceManager(xml.NameTable);
|
||||||
|
namespaceManager.AddNamespace("ttml", "http://www.w3.org/ns/ttml");
|
||||||
|
var body = xml.DocumentElement.SelectSingleNode("ttml:body", namespaceManager);
|
||||||
|
foreach (XmlNode node in body.SelectNodes("//ttml:p", namespaceManager))
|
||||||
|
{
|
||||||
|
TimedText10.ExtractTimeCodes(node, subtitle, out var begin, out var end);
|
||||||
|
var assStyle = string.Empty;
|
||||||
|
var region = node.Attributes?["region"];
|
||||||
|
if (region != null)
|
||||||
|
{
|
||||||
|
assStyle = GetAssStyleFromRegion(region.InnerText);
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = assStyle + ReadParagraph(node, xml);
|
||||||
|
var p = new Paragraph(begin, end, text);
|
||||||
|
subtitle.Paragraphs.Add(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
subtitle.Renumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadParagraph(XmlNode node, XmlDocument xml)
|
||||||
|
{
|
||||||
|
var pText = new StringBuilder();
|
||||||
|
var styles = GetStyles();
|
||||||
|
foreach (XmlNode child in node.ChildNodes)
|
||||||
|
{
|
||||||
|
if (child.NodeType == XmlNodeType.Text)
|
||||||
|
{
|
||||||
|
pText.Append(child.Value);
|
||||||
|
}
|
||||||
|
else if (child.Name == "br" || child.Name == "tt:br")
|
||||||
|
{
|
||||||
|
pText.AppendLine();
|
||||||
|
}
|
||||||
|
else if (child.Name == "#significant-whitespace" || child.Name == "tt:#significant-whitespace")
|
||||||
|
{
|
||||||
|
pText.Append(child.InnerText);
|
||||||
|
}
|
||||||
|
else if (child.Name == "span" || child.Name == "tt:span")
|
||||||
|
{
|
||||||
|
var isItalic = false;
|
||||||
|
var isBold = false;
|
||||||
|
var isUnderlined = false;
|
||||||
|
string fontFamily = null;
|
||||||
|
string color = null;
|
||||||
|
|
||||||
|
|
||||||
|
// Composing styles
|
||||||
|
|
||||||
|
if (child.Attributes["style"] != null)
|
||||||
|
{
|
||||||
|
var styleName = child.Attributes["style"].Value;
|
||||||
|
|
||||||
|
if (styles.Contains(styleName))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var nsmgr = new XmlNamespaceManager(xml.NameTable);
|
||||||
|
nsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml");
|
||||||
|
XmlNode head = xml.DocumentElement.SelectSingleNode("ttml:head", nsmgr);
|
||||||
|
foreach (XmlNode styleNode in head.SelectNodes("//ttml:style", nsmgr))
|
||||||
|
{
|
||||||
|
string currentStyle = null;
|
||||||
|
if (styleNode.Attributes["xml:id"] != null)
|
||||||
|
{
|
||||||
|
currentStyle = styleNode.Attributes["xml:id"].Value;
|
||||||
|
}
|
||||||
|
else if (styleNode.Attributes["id"] != null)
|
||||||
|
{
|
||||||
|
currentStyle = styleNode.Attributes["id"].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStyle == styleName)
|
||||||
|
{
|
||||||
|
if (styleNode.Attributes["tts:fontStyle"] != null && styleNode.Attributes["tts:fontStyle"].Value == "italic")
|
||||||
|
{
|
||||||
|
isItalic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleNode.Attributes["tts:fontWeight"] != null && styleNode.Attributes["tts:fontWeight"].Value == "bold")
|
||||||
|
{
|
||||||
|
isBold = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleNode.Attributes["tts:textDecoration"] != null && styleNode.Attributes["tts:textDecoration"].Value == "underline")
|
||||||
|
{
|
||||||
|
isUnderlined = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleNode.Attributes["tts:fontFamily"] != null)
|
||||||
|
{
|
||||||
|
fontFamily = styleNode.Attributes["tts:fontFamily"].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleNode.Attributes["tts:color"] != null)
|
||||||
|
{
|
||||||
|
color = styleNode.Attributes["tts:color"].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.Attributes["tts:fontStyle"] != null && child.Attributes["tts:fontStyle"].Value == "italic")
|
||||||
|
{
|
||||||
|
isItalic = true;
|
||||||
|
}
|
||||||
|
else if (child.Attributes["style"] != null && child.Attributes["style"].Value == "italic")
|
||||||
|
{
|
||||||
|
isItalic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (child.Attributes["tts:fontWeight"] != null && child.Attributes["tts:fontWeight"].Value == "bold")
|
||||||
|
{
|
||||||
|
isBold = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.Attributes["tts:textDecoration"] != null && child.Attributes["tts:textDecoration"].Value == "underline")
|
||||||
|
{
|
||||||
|
isUnderlined = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.Attributes["tts:fontFamily"] != null)
|
||||||
|
{
|
||||||
|
fontFamily = child.Attributes["tts:fontFamily"].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.Attributes["tts:color"] != null)
|
||||||
|
{
|
||||||
|
color = child.Attributes["tts:color"].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Applying styles
|
||||||
|
if (isItalic)
|
||||||
|
{
|
||||||
|
pText.Append("<i>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBold)
|
||||||
|
{
|
||||||
|
pText.Append("<b>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUnderlined)
|
||||||
|
{
|
||||||
|
pText.Append("<u>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(fontFamily) || !string.IsNullOrEmpty(color))
|
||||||
|
{
|
||||||
|
pText.Append("<font");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(fontFamily))
|
||||||
|
{
|
||||||
|
pText.Append($" face=\"{fontFamily}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(color))
|
||||||
|
{
|
||||||
|
pText.Append($" color=\"{color}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
pText.Append(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
pText.Append(ReadParagraph(child, xml));
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(fontFamily) || !string.IsNullOrEmpty(color))
|
||||||
|
{
|
||||||
|
pText.Append("</font>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUnderlined)
|
||||||
|
{
|
||||||
|
pText.Append("</u>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBold)
|
||||||
|
{
|
||||||
|
pText.Append("</b>");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isItalic)
|
||||||
|
{
|
||||||
|
pText.Append("</i>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pText.ToString().TrimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemoveTags(string text)
|
||||||
|
{
|
||||||
|
return text
|
||||||
|
.Replace("<bouten-dot-before>", string.Empty)
|
||||||
|
.Replace("</bouten-dot-before>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-dot-after>", string.Empty)
|
||||||
|
.Replace("</bouten-dot-after>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-dot-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-dot-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-filled-circle-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-filled-circle-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-open-circle-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-open-circle-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-open-dot-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-open-dot-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-filled-sesame-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-filled-sesame-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-open-sesame-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-open-sesame-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-auto-outside>", string.Empty)
|
||||||
|
.Replace("</bouten-auto-outside>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<bouten-auto>", string.Empty)
|
||||||
|
.Replace("</bouten-auto>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<horizontalDigit>", string.Empty)
|
||||||
|
.Replace("</horizontalDigit>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-container>", string.Empty)
|
||||||
|
.Replace("</ruby-container>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-base>", string.Empty)
|
||||||
|
.Replace("</ruby-base>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-base-italic>", string.Empty)
|
||||||
|
.Replace("</ruby-base-italic>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-text>", string.Empty)
|
||||||
|
.Replace("</ruby-text>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-text-after>", string.Empty)
|
||||||
|
.Replace("</ruby-text-after>", string.Empty)
|
||||||
|
|
||||||
|
.Replace("<ruby-text-italic>", string.Empty)
|
||||||
|
.Replace("</ruby-text-italic>", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveNativeFormatting(Subtitle subtitle, SubtitleFormat newFormat)
|
||||||
|
{
|
||||||
|
foreach (var p in subtitle.Paragraphs)
|
||||||
|
{
|
||||||
|
p.Text = RemoveTags(p.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2337,7 +2337,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
styles = AdvancedSubStationAlpha.GetStylesFromHeader(AdvancedSubStationAlpha.DefaultHeader);
|
styles = AdvancedSubStationAlpha.GetStylesFromHeader(AdvancedSubStationAlpha.DefaultHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText))
|
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
styles = TimedText10.GetStylesFromHeader(_subtitle.Header);
|
styles = TimedText10.GetStylesFromHeader(_subtitle.Header);
|
||||||
}
|
}
|
||||||
@ -2373,7 +2373,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
{
|
{
|
||||||
SubtitleListview1.ShowExtraColumn(_languageGeneral.Class);
|
SubtitleListview1.ShowExtraColumn(_languageGeneral.Class);
|
||||||
}
|
}
|
||||||
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText))
|
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
SubtitleListview1.ShowExtraColumn(_languageGeneral.StyleLanguage);
|
SubtitleListview1.ShowExtraColumn(_languageGeneral.StyleLanguage);
|
||||||
}
|
}
|
||||||
@ -9294,7 +9294,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (((formatType == typeof(TimedText10) && Configuration.Settings.SubtitleSettings.TimedText10ShowStyleAndLanguage) || formatType == typeof(ItunesTimedText)) && SubtitleListview1.SelectedItems.Count > 0)
|
else if (((formatType == typeof(TimedText10) && Configuration.Settings.SubtitleSettings.TimedText10ShowStyleAndLanguage) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11)) && SubtitleListview1.SelectedItems.Count > 0)
|
||||||
{
|
{
|
||||||
toolStripMenuItemWebVTT.Visible = false;
|
toolStripMenuItemWebVTT.Visible = false;
|
||||||
toolStripMenuItemAssStyles.Text = _language.Menu.ContextMenu.TimedTextStyles;
|
toolStripMenuItemAssStyles.Text = _language.Menu.ContextMenu.TimedTextStyles;
|
||||||
@ -9857,7 +9857,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
|
|
||||||
var format = GetCurrentSubtitleFormat();
|
var format = GetCurrentSubtitleFormat();
|
||||||
var formatType = format.GetType();
|
var formatType = format.GetType();
|
||||||
if ((formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText)))
|
if ((formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11)))
|
||||||
{
|
{
|
||||||
foreach (int index in SubtitleListview1.SelectedIndices)
|
foreach (int index in SubtitleListview1.SelectedIndices)
|
||||||
{
|
{
|
||||||
@ -10684,7 +10684,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
{
|
{
|
||||||
styles = AdvancedSubStationAlpha.GetStylesFromHeader(_subtitle.Header);
|
styles = AdvancedSubStationAlpha.GetStylesFromHeader(_subtitle.Header);
|
||||||
}
|
}
|
||||||
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText))
|
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
styles = TimedText10.GetStylesFromHeader(_subtitle.Header);
|
styles = TimedText10.GetStylesFromHeader(_subtitle.Header);
|
||||||
}
|
}
|
||||||
@ -10702,7 +10702,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
if (useExtraForStyle)
|
if (useExtraForStyle)
|
||||||
{
|
{
|
||||||
newParagraph.Extra = style;
|
newParagraph.Extra = style;
|
||||||
if (format.GetType() == typeof(TimedText10) || format.GetType() == typeof(ItunesTimedText))
|
if (format.GetType() == typeof(TimedText10) || format.GetType() == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
if (styles.Count > 0)
|
if (styles.Count > 0)
|
||||||
{
|
{
|
||||||
@ -25451,7 +25451,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
toolStripMenuItemFileFormatProperties.Text = string.Format(_language.Menu.File.FormatXProperties, format.Name);
|
toolStripMenuItemFileFormatProperties.Text = string.Format(_language.Menu.File.FormatXProperties, format.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ft == typeof(TimedText10) || ft == typeof(ItunesTimedText))
|
if (ft == typeof(TimedText10) || ft == typeof(ItunesTimedText) || ft == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
toolStripMenuItemFileFormatProperties.Visible = true;
|
toolStripMenuItemFileFormatProperties.Visible = true;
|
||||||
toolStripMenuItemFileFormatProperties.Text = string.Format(_language.Menu.File.FormatXProperties, format.Name);
|
toolStripMenuItemFileFormatProperties.Text = string.Format(_language.Menu.File.FormatXProperties, format.Name);
|
||||||
@ -31995,7 +31995,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText))
|
else if (formatType == typeof(TimedText10) || formatType == typeof(ItunesTimedText) || formatType == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
using (var styles = new TimedTextStyles(_subtitle))
|
using (var styles = new TimedTextStyles(_subtitle))
|
||||||
{
|
{
|
||||||
@ -32435,7 +32435,7 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ft == typeof(TimedText10))
|
if (ft == typeof(TimedText10) || ft == typeof(TimedTextImsc11))
|
||||||
{
|
{
|
||||||
using (var properties = new TimedTextProperties(_subtitle))
|
using (var properties = new TimedTextProperties(_subtitle))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user