Added "Advanced Sub Station Alpha" as a separate format (no longer treated as ssa)

git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@484 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
niksedk 2011-06-10 12:54:40 +00:00
parent 67d8e4602c
commit dcff9b7324
5 changed files with 383 additions and 10 deletions

View File

@ -28,6 +28,8 @@ namespace Nikse.SubtitleEdit.Logic
public bool Forced { get; set; }
public string Extra { get; set; }
public Paragraph()
{
StartTime = new TimeCode(TimeSpan.FromSeconds(0));

View File

@ -0,0 +1,345 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
{
class AdvancedSubStationAlpha : SubtitleFormat
{
public override string Extension
{
get { return ".ass"; }
}
public override string Name
{
get { return "Advanced Sub Station Alpha"; }
}
public override bool HasLineNumber
{
get { return false; }
}
public override bool IsTimeBased
{
get { return true; }
}
public override bool IsMine(List<string> lines, string fileName)
{
var subtitle = new Subtitle();
var sb = new StringBuilder();
lines.ForEach(line => sb.AppendLine(line));
string all = sb.ToString();
if (!all.Contains("[V4+ Styles]"))
return false;
LoadSubtitle(subtitle, lines, fileName);
return subtitle.Paragraphs.Count > _errorCount;
}
public override string ToText(Subtitle subtitle, string title)
{
const string header =
@"[Script Info]
; This is an Advanced Sub Station Alpha v4+ script.
Title: {0}
ScriptType: v4.00
Collisions: Normal
PlayDepth: 0
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Tahoma,25,&H00FFFFFF,&HF0000000,&H001509AE,&H32270EA8,-1,0,0,0,100,100,0,0.00,1,2,1,2,30,30,10,1
[Events]
Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text";
const string timeCodeFormat = "{0}:{1:00}:{2:00}.{3:00}"; // h:mm:ss.cc
const string paragraphWriteFormat = "Dialogue: Marked=0,{0},{1},{3},NTP,0000,0000,0000,,{2}";
var sb = new StringBuilder();
System.Drawing.Color fontColor = System.Drawing.Color.FromArgb(Configuration.Settings.SsaStyle.FontColorArgb);
bool isValidAssHeader =!string.IsNullOrEmpty(subtitle.Header) && subtitle.Header.Contains("[V4+ Styles]");
List<string> styles = new List<string>();
if (isValidAssHeader)
{
sb.AppendLine(subtitle.Header.Trim());
sb.AppendLine("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text");
styles = GetStylesFromHeader(subtitle.Header);
}
else
{
sb.AppendLine(string.Format(header,
title,
Configuration.Settings.SsaStyle.FontName,
(int)Configuration.Settings.SsaStyle.FontSize,
System.Drawing.ColorTranslator.ToWin32(fontColor)));
}
foreach (Paragraph p in subtitle.Paragraphs)
{
string start = string.Format(timeCodeFormat, p.StartTime.Hours, p.StartTime.Minutes, p.StartTime.Seconds, p.StartTime.Milliseconds / 10);
string end = string.Format(timeCodeFormat, p.EndTime.Hours, p.EndTime.Minutes, p.EndTime.Seconds, p.EndTime.Milliseconds / 10);
string style = "Default";
if (!string.IsNullOrEmpty(p.Extra) && isValidAssHeader && styles.Contains(p.Extra))
style = p.Extra;
sb.AppendLine(string.Format(paragraphWriteFormat, start, end, FormatText(p), style));
}
return sb.ToString().Trim();
}
public static List<string> GetStylesFromHeader(string headerLines)
{
List<string> list = new List<string>();
foreach (string line in headerLines.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
{
if (line.StartsWith("Style:"))
{
int end = line.IndexOf(",");
if (end > 0)
list.Add(line.Substring(6, end - 6).Trim());
}
}
return list;
}
private static string FormatText(Paragraph p)
{
string text = p.Text.Replace(Environment.NewLine, "\\N");
text = text.Replace("<i>", @"{\i1}");
text = text.Replace("</i>", @"{\i0}");
text = text.Replace("<u>", @"{\u1}");
text = text.Replace("</u>", @"{\u0}");
text = text.Replace("<b>", @"{\b1}");
text = text.Replace("</b>", @"{\b0}");
if (text.Contains("<font "))
{
int start = text.IndexOf(@"<font ");
int end = text.IndexOf('>', start);
if (end > 0)
{
string fontTag = text.Substring(start + 4, end - (start + 4));
text = text.Remove(start, end - start + 1);
text = text.Replace("</font>", string.Empty);
fontTag = FormatTag(ref text, start, fontTag, "face=\"", "\"", "fn", "}");
fontTag = FormatTag(ref text, start, fontTag, "face='", "'", "fn", "}");
fontTag = FormatTag(ref text, start, fontTag, "size=\"", "\"", "fs", "}");
fontTag = FormatTag(ref text, start, fontTag, "size='", "'", "fs", "}");
fontTag = FormatTag(ref text, start, fontTag, "color=\"", "\"", "c&H", "&}");
fontTag = FormatTag(ref text, start, fontTag, "color='", "'", "c&H", "&}");
}
}
return text;
}
private static string FormatTag(ref string text, int start, string fontTag, string tag, string endSign, string ssaTagName, string endSsaTag)
{
if (fontTag.Contains(tag))
{
int fontStart = fontTag.IndexOf(tag);
int fontEnd = fontTag.IndexOf(endSign, fontStart + tag.Length);
if (fontEnd > 0)
{
string subTag = fontTag.Substring(fontStart + tag.Length, fontEnd - (fontStart + tag.Length));
if (tag.Contains("color"))
subTag = subTag.Replace("#", string.Empty);
fontTag = fontTag.Remove(fontStart, fontEnd - fontStart + 1);
text = text.Insert(start, @"{\" + ssaTagName + subTag + endSsaTag);
}
}
return fontTag;
}
private static string GetFormattedText(string text)
{
text = text.Replace("\\N", Environment.NewLine).Replace("\\n", Environment.NewLine);
text = text.Replace(@"{\i1}", "<i>");
text = text.Replace(@"{\i0}", "</i>");
if (Utilities.CountTagInText(text, "<i>") > Utilities.CountTagInText(text, "</i>"))
text += "</i>";
text = text.Replace(@"{\u1}", "<u>");
text = text.Replace(@"{\u0}", "</u>");
if (Utilities.CountTagInText(text, "<u>") > Utilities.CountTagInText(text, "</u>"))
text += "</u>";
text = text.Replace(@"{\b1}", "<b>");
text = text.Replace(@"{\b0}", "</b>");
if (Utilities.CountTagInText(text, "<b>") > Utilities.CountTagInText(text, "</b>"))
text += "</b>";
for (int i = 0; i < 5; i++) // just look five times...
{
if (text.Contains(@"{\fn"))
{
int start = text.IndexOf(@"{\fn");
int end = text.IndexOf('}', start);
if (end > 0)
{
string fontName = text.Substring(start + 4, end - (start + 4));
text = text.Remove(start, end - start + 1);
text = text.Insert(start, "<font name=\"" + fontName + "\">");
text += "</font>";
}
}
if (text.Contains(@"{\fs"))
{
int start = text.IndexOf(@"{\fs");
int end = text.IndexOf('}', start);
if (end > 0)
{
string fontSize = text.Substring(start + 4, end - (start + 4));
if (Utilities.IsInteger(fontSize))
{
text = text.Remove(start, end - start + 1);
text = text.Insert(start, "<font size=\"" + fontSize + "\">");
text += "</font>";
}
}
}
if (text.Contains(@"{\c"))
{
int start = text.IndexOf(@"{\c");
int end = text.IndexOf('}', start);
if (end > 0)
{
string color = text.Substring(start + 4, end - (start + 4));
color = color.Replace("&", string.Empty).TrimStart('H');
text = text.Remove(start, end - start + 1);
text = text.Insert(start, "<font color=\"" + color + "\">");
text += "</font>";
}
}
}
return text;
}
public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
{
_errorCount = 0;
bool eventsStarted = false;
subtitle.Paragraphs.Clear();
string[] format = "Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text".Split(',');
int indexStart = 1;
int indexEnd = 2;
int indexStyle = 3;
int indexText = 9;
var header = new StringBuilder();
foreach (string line in lines)
{
if (!eventsStarted)
header.AppendLine(line);
if (line.Trim().ToLower() == "[events]")
{
eventsStarted = true;
}
else if (eventsStarted)
{
string s = line.Trim().ToLower();
if (s.StartsWith("format:"))
{
if (line.Length > 10)
{
format = line.ToLower().Substring(8).Split(',');
for (int i = 0; i < format.Length; i++)
{
if (format[i].Trim().ToLower() == "start")
indexStart = i;
else if (format[i].Trim().ToLower() == "end")
indexEnd = i;
else if (format[i].Trim().ToLower() == "text")
indexText = i;
else if (format[i].Trim().ToLower() == "style")
indexStyle = i;
}
}
}
else
{
string text = string.Empty;
string start = string.Empty;
string end = string.Empty;
string style = string.Empty;
string[] splittedLine;
if (s.StartsWith("dialogue:"))
splittedLine = line.Substring(10).Split(',');
else
splittedLine = line.Split(',');
for (int i = 0; i < splittedLine.Length; i++)
{
if (i == indexStart)
start = splittedLine[i].Trim();
else if (i == indexEnd)
end = splittedLine[i].Trim();
else if (i == indexStyle)
style = splittedLine[i].Trim();
else if (i == indexText)
text = splittedLine[i];
else if (i > indexText)
text += "," + splittedLine[i];
}
try
{
var p = new Paragraph();
p.StartTime = GetTimeCodeFromString(start);
p.EndTime = GetTimeCodeFromString(end);
p.Text = GetFormattedText(text);
if (!string.IsNullOrEmpty(style))
p.Extra = style;
subtitle.Paragraphs.Add(p);
}
catch
{
_errorCount++;
}
}
}
}
if (header.Length > 0)
subtitle.Header = header.ToString();
subtitle.Renumber(1);
}
private static TimeCode GetTimeCodeFromString(string time)
{
// h:mm:ss.cc
string[] timeCode = time.Split(':', '.');
return new TimeCode(int.Parse(timeCode[0]),
int.Parse(timeCode[1]),
int.Parse(timeCode[2]),
int.Parse(timeCode[3]) * 10);
}
public override void RemoveNativeFormatting(Subtitle subtitle)
{
foreach (Paragraph p in subtitle.Paragraphs)
{
int indexOfBegin = p.Text.IndexOf("{");
while (indexOfBegin >= 0 && p.Text.IndexOf("}") > indexOfBegin)
{
int indexOfEnd = p.Text.IndexOf("}");
p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1);
indexOfBegin = p.Text.IndexOf("{");
}
}
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using Nikse.SubtitleEdit.Forms;
namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
{
@ -52,21 +51,34 @@ Style: Default,{1},{2},{3},65535,65535,-2147483640,-1,0,1,3,0,2,30,30,30,0,0
Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
const string timeCodeFormat = "{0}:{1:00}:{2:00}.{3:00}"; // h:mm:ss.cc
const string paragraphWriteFormat = "Dialogue: Marked=0,{0},{1},Default,NTP,0000,0000,0000,!Effect,{2}";
const string paragraphWriteFormat = "Dialogue: Marked=0,{0},{1},{3},NTP,0000,0000,0000,!Effect,{2}";
var sb = new StringBuilder();
System.Drawing.Color fontColor = System.Drawing.Color.FromArgb(Configuration.Settings.SsaStyle.FontColorArgb);
sb.AppendLine(string.Format(header,
title,
Configuration.Settings.SsaStyle.FontName,
(int)Configuration.Settings.SsaStyle.FontSize,
System.Drawing.ColorTranslator.ToWin32(fontColor)));
bool isValidAssHeader =!string.IsNullOrEmpty(subtitle.Header) && subtitle.Header.Contains("[V4+ Styles]");
List<string> styles = new List<string>();
if (isValidAssHeader)
{
sb.AppendLine(subtitle.Header.Trim());
sb.AppendLine("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text");
styles = AdvancedSubStationAlpha.GetStylesFromHeader(subtitle.Header);
}
else
{
sb.AppendLine(string.Format(header,
title,
Configuration.Settings.SsaStyle.FontName,
(int)Configuration.Settings.SsaStyle.FontSize,
System.Drawing.ColorTranslator.ToWin32(fontColor)));
}
foreach (Paragraph p in subtitle.Paragraphs)
{
string start = string.Format(timeCodeFormat, p.StartTime.Hours, p.StartTime.Minutes, p.StartTime.Seconds, p.StartTime.Milliseconds / 10);
string end = string.Format(timeCodeFormat, p.EndTime.Hours, p.EndTime.Minutes, p.EndTime.Seconds, p.EndTime.Milliseconds / 10);
sb.AppendLine(string.Format(paragraphWriteFormat, start, end, FormatText(p)));
string style = "Default";
if (!string.IsNullOrEmpty(p.Extra) && isValidAssHeader && styles.Contains(p.Extra))
style = p.Extra;
sb.AppendLine(string.Format(paragraphWriteFormat, start, end, FormatText(p), style));
}
return sb.ToString().Trim();
}
@ -197,10 +209,15 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
string[] format = "Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text".Split(',');
int indexStart = 1;
int indexEnd = 2;
int indexText = 9;
int indexStyle = 3;
int indexText = 9;
var header = new StringBuilder();
foreach (string line in lines)
{
if (!eventsStarted)
header.AppendLine(line);
if (line.Trim().ToLower() == "[events]")
{
eventsStarted = true;
@ -221,6 +238,8 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
indexEnd = i;
else if (format[i].Trim().ToLower() == "text")
indexText = i;
else if (format[i].Trim().ToLower() == "style")
indexStyle = i;
}
}
}
@ -229,6 +248,7 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
string text = string.Empty;
string start = string.Empty;
string end = string.Empty;
string style = string.Empty;
string[] splittedLine;
@ -256,6 +276,8 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
p.StartTime = GetTimeCodeFromString(start);
p.EndTime = GetTimeCodeFromString(end);
p.Text = GetFormattedText(text);
if (!string.IsNullOrEmpty(style))
p.Extra = style;
subtitle.Paragraphs.Add(p);
}
catch
@ -265,6 +287,8 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
}
}
}
if (header.Length > 0)
subtitle.Header = header.ToString();
subtitle.Renumber(1);
}

View File

@ -19,6 +19,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
new AdobeEncore(),
new AdobeEncoreTab(),
new AdobeEncoreWithLineNumbers(),
new AdvancedSubStationAlpha(),
new AQTitle(),
new Captionate(),
new CaraokeXml(),

View File

@ -537,6 +537,7 @@
<Compile Include="Logic\SubtitleFormats\AdobeEncore.cs" />
<Compile Include="Logic\SubtitleFormats\AdobeEncoreTabs.cs" />
<Compile Include="Logic\SubtitleFormats\AdobeEncoreWithLineNumbers.cs" />
<Compile Include="Logic\SubtitleFormats\AdvancedSubStationAlpha.cs" />
<Compile Include="Logic\SubtitleFormats\AQTitle.cs" />
<Compile Include="Logic\SubtitleFormats\BdnXml.cs" />
<Compile Include="Logic\SubtitleFormats\Captionate.cs" />