SubtitleEdit/libse/SubtitleFormats/DCinemaInterop.cs

838 lines
40 KiB
C#
Raw Normal View History

2018-03-04 10:24:04 +01:00
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml;
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
{
//<?xml version="1.0" encoding="UTF-8"?>
//<DCSubtitle Version="1.0">
// <SubtitleID>4EB245B8-4D3A-4158-9516-95DD20E8322E</SubtitleID>
// <MovieTitle>Unknown</MovieTitle>
// <ReelNumber>1</ReelNumber>
// <Language>Swedish</Language>
// <Font Italic="no">
// <Subtitle SpotNumber="1" TimeIn="00:00:06:040" TimeOut="00:00:08:040" FadeUpTime="20" FadeDownTime="20">
// <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="6.0">DETTA HAR HÄNT...</Text>
// </Subtitle>
// </Font>
//</DCSubtitle>
public class DCinemaInterop : SubtitleFormat
{
internal class SubtitleLine
{
internal string Text { get; set; }
internal string VerticalPosition { get; set; }
internal string VerticalAlignment { get; set; }
internal SubtitleLine(string text, string verticalPosition, string verticalAlignment)
{
Text = text;
VerticalPosition = verticalPosition;
VerticalAlignment = verticalAlignment;
}
internal int GetVerticalPositionAsNumber()
{
double d;
if (double.TryParse(VerticalPosition, out d))
{
return (int)d;
}
return 0;
}
}
public override string Extension => ".xml";
public override string Name => "D-Cinema interop";
public override bool IsMine(List<string> lines, string fileName)
{
var sb = new StringBuilder();
lines.ForEach(line => sb.AppendLine(line));
string xmlAsString = sb.ToString().Trim();
if (xmlAsString.Contains("<DCSubtitle"))
{
var xml = new XmlDocument { XmlResolver = null };
try
{
xml.LoadXml(xmlAsString);
if (xml.DocumentElement != null)
{
var subtitles = xml.DocumentElement.SelectNodes("//Subtitle");
return subtitles != null && subtitles.Count > 0;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return false;
}
}
return false;
}
public override string ToText(Subtitle subtitle, string title)
{
string languageEnglishName;
try
{
string languageShortName = LanguageAutoDetect.AutoDetectGoogleLanguage(subtitle);
var ci = CultureInfo.CreateSpecificCulture(languageShortName);
languageEnglishName = ci.EnglishName;
int indexOfStartP = languageEnglishName.IndexOf('(');
if (indexOfStartP > 1)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
languageEnglishName = languageEnglishName.Remove(indexOfStartP).Trim();
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
catch
{
languageEnglishName = "English";
}
string hex = Guid.NewGuid().ToString().RemoveChar('-');
hex = hex.Insert(8, "-").Insert(13, "-").Insert(18, "-").Insert(23, "-");
string xmlStructure = "<DCSubtitle Version=\"1.0\">" + Environment.NewLine +
" <SubtitleID>" + hex.ToLowerInvariant() + "</SubtitleID>" + Environment.NewLine +
2018-03-04 10:24:04 +01:00
" <MovieTitle></MovieTitle>" + Environment.NewLine +
" <ReelNumber>1</ReelNumber>" + Environment.NewLine +
" <Language>" + languageEnglishName + "</Language>" + Environment.NewLine +
" <LoadFont URI=\"" + Configuration.Settings.SubtitleSettings.DCinemaFontFile + "\" Id=\"Font1\"/>" + Environment.NewLine +
" <Font Id=\"Font1\" Color=\"FFFFFFFF\" Effect=\"border\" EffectColor=\"FF000000\" Italic=\"no\" Underlined=\"no\" Script=\"normal\" Size=\"42\">" + Environment.NewLine +
" </Font>" + Environment.NewLine +
"</DCSubtitle>";
var xml = new XmlDocument();
xml.LoadXml(xmlStructure);
xml.PreserveWhitespace = true;
var ss = Configuration.Settings.SubtitleSettings;
string loadedFontId = "Font1";
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontId))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
loadedFontId = ss.CurrentDCinemaFontId;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (string.IsNullOrEmpty(ss.CurrentDCinemaMovieTitle))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaMovieTitle = title;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (ss.CurrentDCinemaFontSize == 0 || string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
Configuration.Settings.SubtitleSettings.InitializeDCinameSettings(true);
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
xml.DocumentElement.SelectSingleNode("MovieTitle").InnerText = ss.CurrentDCinemaMovieTitle;
xml.DocumentElement.SelectSingleNode("SubtitleID").InnerText = ss.CurrentDCinemaSubtitleId.Replace("urn:uuid:", string.Empty);
xml.DocumentElement.SelectSingleNode("ReelNumber").InnerText = ss.CurrentDCinemaReelNumber;
xml.DocumentElement.SelectSingleNode("Language").InnerText = ss.CurrentDCinemaLanguage;
xml.DocumentElement.SelectSingleNode("LoadFont").Attributes["URI"].InnerText = ss.CurrentDCinemaFontUri;
xml.DocumentElement.SelectSingleNode("LoadFont").Attributes["Id"].InnerText = loadedFontId;
int fontSize = ss.CurrentDCinemaFontSize;
xml.DocumentElement.SelectSingleNode("Font").Attributes["Id"].InnerText = loadedFontId;
xml.DocumentElement.SelectSingleNode("Font").Attributes["Color"].InnerText = "FF" + Utilities.ColorToHex(ss.CurrentDCinemaFontColor).TrimStart('#').ToUpperInvariant();
2018-03-04 10:24:04 +01:00
xml.DocumentElement.SelectSingleNode("Font").Attributes["Effect"].InnerText = ss.CurrentDCinemaFontEffect;
xml.DocumentElement.SelectSingleNode("Font").Attributes["EffectColor"].InnerText = "FF" + Utilities.ColorToHex(ss.CurrentDCinemaFontEffectColor).TrimStart('#').ToUpperInvariant();
2018-03-04 10:24:04 +01:00
xml.DocumentElement.SelectSingleNode("Font").Attributes["Size"].InnerText = ss.CurrentDCinemaFontSize.ToString();
var mainListFont = xml.DocumentElement.SelectSingleNode("Font");
int no = 0;
foreach (Paragraph p in subtitle.Paragraphs)
{
if (!string.IsNullOrEmpty(p.Text))
{
var subNode = xml.CreateElement("Subtitle");
var id = xml.CreateAttribute("SpotNumber");
id.InnerText = (no + 1).ToString();
subNode.Attributes.Append(id);
var fadeUpTime = xml.CreateAttribute("FadeUpTime");
fadeUpTime.InnerText = Configuration.Settings.SubtitleSettings.DCinemaFadeUpTime.ToString();
subNode.Attributes.Append(fadeUpTime);
var fadeDownTime = xml.CreateAttribute("FadeDownTime");
fadeDownTime.InnerText = Configuration.Settings.SubtitleSettings.DCinemaFadeDownTime.ToString();
subNode.Attributes.Append(fadeDownTime);
var start = xml.CreateAttribute("TimeIn");
start.InnerText = ConvertToTimeString(p.StartTime);
subNode.Attributes.Append(start);
var end = xml.CreateAttribute("TimeOut");
end.InnerText = ConvertToTimeString(p.EndTime);
subNode.Attributes.Append(end);
bool alignLeft = p.Text.StartsWith("{\\a1}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a5}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a9}", StringComparison.Ordinal) || // sub station alpha
p.Text.StartsWith("{\\an1}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an4}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an7}", StringComparison.Ordinal); // advanced sub station alpha
bool alignRight = p.Text.StartsWith("{\\a3}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a7}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a11}", StringComparison.Ordinal) || // sub station alpha
p.Text.StartsWith("{\\an3}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an6}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an9}", StringComparison.Ordinal); // advanced sub station alpha
bool alignVTop = p.Text.StartsWith("{\\a5}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a6}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a7}", StringComparison.Ordinal) || // sub station alpha
p.Text.StartsWith("{\\an7}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an8}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an9}", StringComparison.Ordinal); // advanced sub station alpha
bool alignVCenter = p.Text.StartsWith("{\\a9}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a10}", StringComparison.Ordinal) || p.Text.StartsWith("{\\a11}", StringComparison.Ordinal) || // sub station alpha
p.Text.StartsWith("{\\an4}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an5}", StringComparison.Ordinal) || p.Text.StartsWith("{\\an6}", StringComparison.Ordinal); // advanced sub station alpha
string text = Utilities.RemoveSsaTags(p.Text);
var lines = text.SplitToLines();
int vPos;
int vPosFactor = (int)Math.Round(fontSize / 7.4);
if (alignVTop)
{
vPos = Configuration.Settings.SubtitleSettings.DCinemaBottomMargin; // Bottom margin is normally 8
}
else if (alignVCenter)
{
vPos = (int)Math.Round((lines.Count * vPosFactor * -1) / 2.0);
}
else
{
vPos = (lines.Count * vPosFactor) - vPosFactor + Configuration.Settings.SubtitleSettings.DCinemaBottomMargin; // Bottom margin is normally 8
}
bool isItalic = false;
int fontNo = 0;
var fontColors = new Stack<string>();
foreach (string line in lines)
{
var textNode = xml.CreateElement("Text");
var vPosition = xml.CreateAttribute("VPosition");
vPosition.InnerText = vPos.ToString();
textNode.Attributes.Append(vPosition);
if (Math.Abs(Configuration.Settings.SubtitleSettings.DCinemaZPosition) > 0.01)
{
var zPosition = xml.CreateAttribute("ZPosition");
zPosition.InnerText = string.Format(CultureInfo.InvariantCulture, "{0:0.00}", Configuration.Settings.SubtitleSettings.DCinemaZPosition);
textNode.Attributes.Append(zPosition);
}
var vAlign = xml.CreateAttribute("VAlign");
if (alignVTop)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign.InnerText = "top";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else if (alignVCenter)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign.InnerText = "center";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign.InnerText = "bottom";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
textNode.Attributes.Append(vAlign);
var hAlign = xml.CreateAttribute("HAlign");
if (alignLeft)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign.InnerText = "left";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else if (alignRight)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign.InnerText = "right";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign.InnerText = "center";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
textNode.Attributes.Append(hAlign);
var direction = xml.CreateAttribute("Direction");
direction.InnerText = "horizontal";
textNode.Attributes.Append(direction);
int i = 0;
var txt = new StringBuilder();
var html = new StringBuilder();
XmlNode nodeTemp = xml.CreateElement("temp");
while (i < line.Length)
{
if (!isItalic && line.Substring(i).StartsWith("<i>", StringComparison.Ordinal))
{
if (txt.Length > 0)
{
nodeTemp.InnerText = txt.ToString();
html.Append(nodeTemp.InnerXml);
txt.Clear();
}
isItalic = true;
i += 2;
}
else if (isItalic && line.Substring(i).StartsWith("</i>", StringComparison.Ordinal))
{
if (txt.Length > 0)
{
var fontNode = xml.CreateElement("Font");
var italic = xml.CreateAttribute("Italic");
italic.InnerText = "yes";
fontNode.Attributes.Append(italic);
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
{
var fontEffect = xml.CreateAttribute("Effect");
fontEffect.InnerText = ss.CurrentDCinemaFontEffect;
fontNode.Attributes.Append(fontEffect);
}
if (line.Length > i + 5 && line.Substring(i + 4).StartsWith("</font>", StringComparison.Ordinal))
{
var fontColor = xml.CreateAttribute("Color");
fontColor.InnerText = fontColors.Pop();
fontNode.Attributes.Append(fontColor);
fontNo--;
i += 7;
}
fontNode.InnerText = HtmlUtil.RemoveHtmlTags(txt.ToString());
html.Append(fontNode.OuterXml);
txt.Clear();
}
isItalic = false;
i += 3;
}
else if (line.Substring(i).StartsWith("<font color=", StringComparison.Ordinal) && line.Substring(i + 3).Contains('>'))
{
int endOfFont = line.IndexOf('>', i);
if (txt.Length > 0)
{
nodeTemp.InnerText = txt.ToString();
html.Append(nodeTemp.InnerXml);
txt.Clear();
}
string c = line.Substring(i + 12, endOfFont - (i + 12));
c = c.Trim('"').Trim('\'').Trim();
if (c.StartsWith('#'))
2019-01-19 14:40:37 +01:00
{
c = c.TrimStart('#').ToUpperInvariant().PadLeft(8, 'F');
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
fontColors.Push(c);
fontNo++;
i = endOfFont;
2018-03-04 10:24:04 +01:00
}
else if (fontNo > 0 && line.Substring(i).StartsWith("</font>", StringComparison.Ordinal))
{
if (txt.Length > 0)
{
var fontNode = xml.CreateElement("Font");
var fontColor = xml.CreateAttribute("Color");
fontColor.InnerText = fontColors.Pop();
fontNode.Attributes.Append(fontColor);
if (line.Length > i + 9 && line.Substring(i + 7).StartsWith("</i>", StringComparison.Ordinal))
{
var italic = xml.CreateAttribute("Italic");
italic.InnerText = "yes";
fontNode.Attributes.Append(italic);
isItalic = false;
i += 4;
}
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
{
var fontEffect = xml.CreateAttribute("Effect");
fontEffect.InnerText = ss.CurrentDCinemaFontEffect;
fontNode.Attributes.Append(fontEffect);
}
fontNode.InnerText = HtmlUtil.RemoveHtmlTags(txt.ToString());
html.Append(fontNode.OuterXml);
txt.Clear();
}
fontNo--;
i += 6;
}
else
{
txt.Append(line[i]);
}
i++;
}
if (fontNo > 0)
{
if (txt.Length > 0)
{
var fontNode = xml.CreateElement("Font");
var fontColor = xml.CreateAttribute("Color");
fontColor.InnerText = fontColors.Peek();
fontNode.Attributes.Append(fontColor);
if (isItalic)
{
var italic = xml.CreateAttribute("Italic");
italic.InnerText = "yes";
fontNode.Attributes.Append(italic);
}
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
{
var fontEffect = xml.CreateAttribute("Effect");
fontEffect.InnerText = ss.CurrentDCinemaFontEffect;
fontNode.Attributes.Append(fontEffect);
}
fontNode.InnerText = HtmlUtil.RemoveHtmlTags(txt.ToString());
html.Append(fontNode.OuterXml);
}
else if (html.Length > 0 && html.ToString().StartsWith("<Font ", StringComparison.Ordinal))
{
var temp = new XmlDocument();
temp.LoadXml("<root>" + html + "</root>");
var fontNode = xml.CreateElement("Font");
fontNode.InnerXml = temp.DocumentElement.SelectSingleNode("Font").InnerXml;
foreach (XmlAttribute a in temp.DocumentElement.SelectSingleNode("Font").Attributes)
{
var newA = xml.CreateAttribute(a.Name);
newA.InnerText = a.InnerText;
fontNode.Attributes.Append(newA);
}
var fontColor = xml.CreateAttribute("Color");
fontColor.InnerText = fontColors.Peek();
fontNode.Attributes.Append(fontColor);
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
{
var fontEffect = xml.CreateAttribute("Effect");
fontEffect.InnerText = ss.CurrentDCinemaFontEffect;
fontNode.Attributes.Append(fontEffect);
}
html.Clear();
html.Append(fontNode.OuterXml);
}
}
else if (isItalic)
{
if (txt.Length > 0)
{
var fontNode = xml.CreateElement("Font");
var italic = xml.CreateAttribute("Italic");
italic.InnerText = "yes";
fontNode.Attributes.Append(italic);
if (!string.IsNullOrEmpty(ss.CurrentDCinemaFontEffect))
{
var fontEffect = xml.CreateAttribute("Effect");
fontEffect.InnerText = ss.CurrentDCinemaFontEffect;
fontNode.Attributes.Append(fontEffect);
}
fontNode.InnerText = HtmlUtil.RemoveHtmlTags(txt.ToString());
html.Append(fontNode.OuterXml);
}
}
else
{
if (txt.Length > 0)
{
nodeTemp.InnerText = txt.ToString();
html.Append(nodeTemp.InnerXml);
}
}
textNode.InnerXml = html.ToString();
subNode.AppendChild(textNode);
if (alignVTop)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vPos += vPosFactor;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vPos -= vPosFactor;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
mainListFont.AppendChild(subNode);
no++;
}
}
string s = ToUtf8XmlString(xml).Replace("encoding=\"utf-8\"", "encoding=\"UTF-8\"");
while (s.Contains("</Font> ") || s.Contains(" <Font ") || s.Contains(Environment.NewLine + "<Font ") || s.Contains("</Font>" + Environment.NewLine))
{
while (s.Contains(" Font"))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
s = s.Replace(" <Font ", " <Font ");
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
while (s.Contains("\tFont"))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
s = s.Replace("\t<Font ", " <Font ");
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
s = s.Replace("</Font> ", "</Font> ");
s = s.Replace(" <Font ", " <Font ");
s = s.Replace("\r\n<Font ", "<Font ");
s = s.Replace("\r\n <Font ", "<Font ");
s = s.Replace(Environment.NewLine + "<Font ", "<Font ");
s = s.Replace(Environment.NewLine + " <Font ", "<Font ");
s = s.Replace("</Font>\r\n", "</Font>");
s = s.Replace("</Font>" + Environment.NewLine, "</Font>");
s = s.Replace("><", "> <");
s = s.Replace("</Font> </Text>", "</Font></Text>");
s = s.Replace("horizontal\"> <Font", "horizontal\"><Font");
}
return s;
}
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 };
xml.LoadXml(sb.ToString().Trim());
if (xml.DocumentElement == null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
return;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
var ss = Configuration.Settings.SubtitleSettings;
try
{
ss.InitializeDCinameSettings(false);
XmlNode node = xml.DocumentElement.SelectSingleNode("SubtitleID");
if (node != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaSubtitleId = node.InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml.DocumentElement.SelectSingleNode("ReelNumber");
if (node != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaReelNumber = node.InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml.DocumentElement.SelectSingleNode("Language");
if (node != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaLanguage = node.InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml.DocumentElement.SelectSingleNode("MovieTitle");
if (node != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaMovieTitle = node.InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml.DocumentElement.SelectSingleNode("LoadFont");
if (node?.Attributes?["URI"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontUri = node.Attributes["URI"].InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml.DocumentElement.SelectSingleNode("Font");
if (node != null)
{
if (node.Attributes?["ID"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontId = node.Attributes["ID"].InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (node.Attributes?["Size"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontSize = Convert.ToInt32(node.Attributes["Size"].InnerText);
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (node.Attributes?["Color"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontColor = System.Drawing.ColorTranslator.FromHtml("#" + node.Attributes["Color"].InnerText);
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (node.Attributes?["Effect"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontEffect = node.Attributes["Effect"].InnerText;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (node.Attributes?["EffectColor"] != null)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss.CurrentDCinemaFontEffectColor = System.Drawing.ColorTranslator.FromHtml("#" + node.Attributes["EffectColor"].InnerText);
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(exception.Message);
}
foreach (XmlNode node in xml.DocumentElement.SelectNodes("//Subtitle"))
{
try
{
var textLines = new List<SubtitleLine>();
var pText = new StringBuilder();
var vAlignment = string.Empty;
string lastVPosition = string.Empty;
foreach (XmlNode innerNode in node.ChildNodes)
{
2019-01-19 12:29:38 +01:00
if (innerNode.Name == "Text")
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if (innerNode.Attributes["VPosition"] != null)
{
string vPosition = innerNode.Attributes["VPosition"].InnerText;
var vAlignmentNode = innerNode.Attributes["VAlign"];
if (vAlignmentNode != null)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
vAlignment = vAlignmentNode.InnerText;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
if (vPosition != lastVPosition)
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if (pText.Length > 0 && lastVPosition.Length > 0)
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
textLines.Add(new SubtitleLine(pText.ToString(), lastVPosition, vAlignment));
pText.Clear();
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
lastVPosition = vPosition;
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
}
2018-03-04 10:24:04 +01:00
2019-01-19 12:29:38 +01:00
bool alignLeft = false;
bool alignRight = false;
bool alignVTop = false;
bool alignVCenter = false;
if (innerNode.Attributes["HAlign"] != null)
{
string hAlign = innerNode.Attributes["HAlign"].InnerText;
if (hAlign == "left")
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignLeft = true;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if (hAlign == "right")
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignRight = true;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
2018-03-04 10:24:04 +01:00
2019-01-19 12:29:38 +01:00
if (innerNode.Attributes["VAlign"] != null)
{
string hAlign = innerNode.Attributes["VAlign"].InnerText;
if (hAlign == "top")
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignVTop = true;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if (hAlign == "center")
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignVCenter = true;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
if (alignLeft || alignRight || alignVCenter || alignVTop)
{
if (!pText.ToString().StartsWith("{\\an", StringComparison.Ordinal))
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
string pre = string.Empty;
if (alignVTop)
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if (alignLeft)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an7}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if (alignRight)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an9}";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an8}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else if (alignVCenter)
{
if (alignLeft)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an4}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if (alignRight)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an6}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an5}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else
{
if (alignLeft)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an1}";
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if (alignRight)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an3}";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
string temp = pre + pText;
pText.Clear();
pText.Append(temp);
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
}
if (innerNode.ChildNodes.Count == 0)
{
pText.Append(innerNode.InnerText);
}
else
{
foreach (XmlNode innerInnerNode in innerNode)
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if (innerInnerNode.Name == "Font" && innerInnerNode.Attributes["Italic"] != null &&
innerInnerNode.Attributes["Italic"].InnerText.Equals("yes", StringComparison.OrdinalIgnoreCase))
{
if (innerInnerNode.Attributes["Color"] != null)
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText.Append("<i><font color=\"" + GetColorStringFromDCinema(innerInnerNode.Attributes["Color"].Value) + "\">" + innerInnerNode.InnerText + "</font><i>");
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText.Append("<i>" + innerInnerNode.InnerText + "</i>");
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else if (innerInnerNode.Name == "Font" && innerInnerNode.Attributes["Color"] != null)
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if (innerInnerNode.Attributes["Italic"] != null && innerInnerNode.Attributes["Italic"].InnerText.Equals("yes", StringComparison.OrdinalIgnoreCase))
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText.Append("<i><font color=\"" + GetColorStringFromDCinema(innerInnerNode.Attributes["Color"].Value) + "\">" + innerInnerNode.InnerText + "</font><i>");
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText.Append("<font color=\"" + GetColorStringFromDCinema(innerInnerNode.Attributes["Color"].Value) + "\">" + innerInnerNode.InnerText + "</font>");
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else
{
pText.Append(innerInnerNode.InnerText);
2018-03-04 10:24:04 +01:00
}
}
2019-01-19 12:29:38 +01:00
}
}
else
{
pText.Append(innerNode.InnerText);
2018-03-04 10:24:04 +01:00
}
}
if (pText.Length > 0)
{
textLines.Add(new SubtitleLine(pText.ToString(), lastVPosition, vAlignment));
}
string text;
if (textLines.All(p => p.VerticalAlignment.ToLowerInvariant() == "top"))
{
text = string.Join(Environment.NewLine, textLines.OrderBy(p => p.GetVerticalPositionAsNumber()).Select(p => p.Text));
}
else
{
text = string.Join(Environment.NewLine, textLines.OrderByDescending(p => p.GetVerticalPositionAsNumber()).Select(p => p.Text));
}
text = text.Replace(Environment.NewLine + "{\\an1}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an2}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an3}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an4}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an5}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an6}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an7}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an8}", Environment.NewLine);
text = text.Replace(Environment.NewLine + "{\\an9}", Environment.NewLine);
string start = node.Attributes["TimeIn"].InnerText;
string end = node.Attributes["TimeOut"].InnerText;
if (node.ParentNode.Name == "Font" && node.ParentNode.Attributes["Italic"] != null && node.ParentNode.Attributes["Italic"].InnerText.Equals("yes", StringComparison.OrdinalIgnoreCase) &&
!text.Contains("<i>"))
{
if (text.StartsWith("{\\an", StringComparison.Ordinal) && text.Length > 6)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
text = text.Insert(6, "<i>") + "</i>";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
text = "<i>" + text + "</i>";
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
subtitle.Paragraphs.Add(new Paragraph(GetTimeCode(start), GetTimeCode(end), text));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
_errorCount++;
}
}
if (subtitle.Paragraphs.Count > 0)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
subtitle.Header = xml.OuterXml; // save id/language/font for later use
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
subtitle.Renumber();
}
internal static string GetColorStringFromDCinema(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return s;
}
var hex = s.TrimStart('#');
for (int i = s.Length - 1; i >= 0; i--)
{
if (!CharUtils.IsHexadecimal(s[i]))
{
return s;
}
}
return "#" + hex;
}
private static TimeCode GetTimeCode(string s)
{
var parts = s.Split(':', '.', ',');
int milliseconds = int.Parse(parts[3]) * 4; // 000 to 249
if (s.Contains('.'))
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
milliseconds = int.Parse(parts[3].PadRight(3, '0'));
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if (milliseconds > 999)
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
milliseconds = 999;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
return new TimeCode(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), milliseconds);
}
public static string ConvertToTimeString(TimeCode time)
{
return $"{time.Hours:00}:{time.Minutes:00}:{time.Seconds:00}:{time.Milliseconds / 4:000}";
}
}
}