//http://www.w3.org/TR/ttaf1-dfxp/ //Timed Text Markup Language (TTML) 1.0 //W3C Recommendation 18 November 2010 using System; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Xml; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { public class TimedText10 : SubtitleFormat { public override string Extension { get { return ".xml"; } } public override string Name { get { return "Timed Text 1.0"; } } public override bool IsTimeBased { get { return true; } } public override bool IsMine(List lines, string fileName) { var sb = new StringBuilder(); lines.ForEach(line => sb.AppendLine(line)); string xmlAsString = sb.ToString().Trim(); if (xmlAsString.Contains("xmlns:tts=\"http://www.w3.org/2006/04")) return false; if (xmlAsString.Contains("http://www.w3.org/ns/ttml")) { var xml = new XmlDocument { XmlResolver = null }; try { xml.LoadXml(xmlAsString); var nsmgr = new XmlNamespaceManager(xml.NameTable); nsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml"); var nds = xml.DocumentElement.SelectSingleNode("ttml:body", nsmgr); var paragraphs = nds.SelectNodes("//ttml:p", nsmgr); return paragraphs.Count > 0; } catch { try { xml.LoadXml(xmlAsString.Replace(" & ", " & ").Replace("Q&A", "Q&A")); var nsmgr = new XmlNamespaceManager(xml.NameTable); nsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml"); var nds = xml.DocumentElement.SelectSingleNode("ttml:body", nsmgr); var paragraphs = nds.SelectNodes("//ttml:p", nsmgr); return paragraphs.Count > 0; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } } return false; } internal static string ConvertToTimeString(TimeCode time) { var timeCodeFormat = Configuration.Settings.SubtitleSettings.TimedText10TimeCodeFormat.Trim().ToLowerInvariant(); if (timeCodeFormat == "source" && !string.IsNullOrWhiteSpace(Configuration.Settings.SubtitleSettings.TimedText10TimeCodeFormatSource)) { timeCodeFormat = Configuration.Settings.SubtitleSettings.TimedText10TimeCodeFormatSource.Trim().ToLowerInvariant(); } switch (timeCodeFormat) { case "seconds": return string.Format(CultureInfo.InvariantCulture, "{0:0.0#}s", time.TotalSeconds); case "milliseconds": return string.Format(CultureInfo.InvariantCulture, "{0}ms", time.TotalMilliseconds); case "ticks": return string.Format(CultureInfo.InvariantCulture, "{0}t", TimeSpan.FromMilliseconds(time.TotalMilliseconds).Ticks); case "hh:mm:ss.ms": return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00}:{2:00}.{3:000}", time.Hours, time.Minutes, time.Seconds, time.Milliseconds); default: return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00}:{2:00}:{3:00}", time.Hours, time.Minutes, time.Seconds, MillisecondsToFramesMaxFrameRate(time.Milliseconds)); } } public static void AddStyleToXml(XmlDocument xml, XmlNode head, XmlNamespaceManager nsmgr, string name, string fontFamily, string fontWeight, string fontStyle, string color, string fontSize) { var styleNode = xml.CreateNode(XmlNodeType.Element, string.Empty, "style", nsmgr.LookupNamespace("ttml")); XmlAttribute attr = xml.CreateAttribute("xml:id", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = name; styleNode.Attributes.Append(attr); attr = xml.CreateAttribute("tts:fontFamily", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = fontFamily; styleNode.Attributes.Append(attr); attr = xml.CreateAttribute("tts:fontWeight", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = fontWeight; styleNode.Attributes.Append(attr); attr = xml.CreateAttribute("tts:fontStyle", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = fontStyle; styleNode.Attributes.Append(attr); attr = xml.CreateAttribute("tts:color", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = color; styleNode.Attributes.Append(attr); attr = xml.CreateAttribute("tts:fontSize", "http://www.w3.org/ns/10/ttml#style"); attr.InnerText = fontSize; styleNode.Attributes.Append(attr); foreach (XmlNode innerNode in head.ChildNodes) { if (innerNode.Name == "styling") { innerNode.AppendChild(styleNode); break; } } } public override string ToText(Subtitle subtitle, string title) { XmlNode styleHead = null; if (subtitle.Header != null) { try { var x = new XmlDocument(); x.LoadXml(subtitle.Header); var xnsmgr = new XmlNamespaceManager(x.NameTable); xnsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml"); styleHead = x.DocumentElement.SelectSingleNode("ttml:head", xnsmgr); } catch { } if (styleHead == null && (subtitle.Header.Contains("[V4+ Styles]") || subtitle.Header.Contains("[V4 Styles]"))) { var x = new XmlDocument(); x.LoadXml(new TimedText10().ToText(new Subtitle(), "tt")); // load default xml var xnsmgr = new XmlNamespaceManager(x.NameTable); xnsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml"); styleHead = x.DocumentElement.SelectSingleNode("ttml:head", xnsmgr); styleHead.SelectSingleNode("ttml:styling", xnsmgr).RemoveAll(); foreach (string styleName in AdvancedSubStationAlpha.GetStylesFromHeader(subtitle.Header)) { try { var ssaStyle = AdvancedSubStationAlpha.GetSsaStyle(styleName, subtitle.Header); if (ssaStyle != null) { string fontStyle = "normal"; if (ssaStyle.Italic) fontStyle = "italic"; string fontWeight = "normal"; if (ssaStyle.Bold) fontWeight = "bold"; AddStyleToXml(x, styleHead, xnsmgr, ssaStyle.Name, ssaStyle.FontName, fontWeight, fontStyle, Utilities.ColorToHex(ssaStyle.Primary), ssaStyle.FontSize.ToString(CultureInfo.InvariantCulture)); } } catch { } } subtitle.Header = x.OuterXml; // save new xml with styles in header } } var xml = new XmlDocument(); var nsmgr = new XmlNamespaceManager(xml.NameTable); nsmgr.AddNamespace("ttml", "http://www.w3.org/ns/ttml"); nsmgr.AddNamespace("ttp", "http://www.w3.org/ns/10/ttml#parameter"); nsmgr.AddNamespace("tts", "http://www.w3.org/ns/10/ttml#style"); nsmgr.AddNamespace("ttm", "http://www.w3.org/ns/10/ttml#metadata"); string xmlStructure = "" + Environment.NewLine + "" + Environment.NewLine + " " + Environment.NewLine + " " + Environment.NewLine + " " + Environment.NewLine + " " + Environment.NewLine + " " + Environment.NewLine + "