From 6e556022a0e39f106f2e91216dde3e688d76bf2c Mon Sep 17 00:00:00 2001 From: niksedk Date: Tue, 17 Jan 2023 19:11:14 +0100 Subject: [PATCH] Fix ssa to assa style issue - thx Alain :) --- src/libse/Common/SsaStyle.cs | 158 ++++++++++++++++++ .../AdvancedSubStationAlpha.cs | 134 ++++++++++----- src/libse/SubtitleFormats/SubStationAlpha.cs | 83 +++++---- src/ui/Controls/VideoPlayerContainer.cs | 5 +- src/ui/Forms/Styles/SubStationAlphaStyles.cs | 29 +--- 5 files changed, 305 insertions(+), 104 deletions(-) diff --git a/src/libse/Common/SsaStyle.cs b/src/libse/Common/SsaStyle.cs index 3dda7c87f..8d5226f62 100644 --- a/src/libse/Common/SsaStyle.cs +++ b/src/libse/Common/SsaStyle.cs @@ -318,5 +318,163 @@ namespace Nikse.SubtitleEdit.Core.Common var s = sb.ToString().Trim(); return s.Substring(0, s.Length - 1); } + + public static SsaStyle FromRawSsa(string header, string styleLine) + { + var result = new SsaStyle(); + var styleArray = styleLine.Split(','); + var format = GetSsaFormatList(header); + + if (styleArray.Length != format.Length) + { + return result; + } + + for (var i = 0; i < format.Length; i++) + { + var f = format[i].Trim(); + var v = styleArray[i].Trim(); + + if (f == "name") + { + result.Name = v; + } + else if (f == "fontname") + { + result.FontName = v; + } + else if (f == "fontsize") + { + if (decimal.TryParse(v, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var d)) + { + result.FontSize = d; + } + } + else if (f == "primarycolour") + { + result.Primary = AdvancedSubStationAlpha.GetSsaColor(v, Color.White); + } + else if (f == "secondarycolour") + { + result.Secondary = AdvancedSubStationAlpha.GetSsaColor(v, Color.Yellow); + } + else if (f == "tertiarycolour") + { + result.Tertiary = AdvancedSubStationAlpha.GetSsaColor(v, Color.Yellow); + } + else if (f == "backcolour") + { + result.Outline = AdvancedSubStationAlpha.GetSsaColor(v, Color.Black); + } + else if (f == "bold") + { + result.Bold = v != "0"; + } + else if (f == "italic") + { + result.Italic = v != "0"; + } + else if (f == "outline") + { + if (decimal.TryParse(f, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number)) + { + result.OutlineWidth = number; + } + } + else if (f == "shadow") + { + if (decimal.TryParse(f, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var number)) + { + result.ShadowWidth = number; + } + } + else if (f == "marginl") + { + if (int.TryParse(f, out var number)) + { + result.MarginLeft = number; + } + } + else if (f == "marginr") + { + if (int.TryParse(f, out var number)) + { + result.MarginRight = number; + } + } + else if (f == "marginv") + { + if (int.TryParse(f, out var number)) + { + result.MarginVertical = number; + } + } + else if (f == "borderstyle") + { + result.BorderStyle = v; + } + else if (f == "alignment") + { + switch (v) + { + case "1": + result.Alignment = "1"; // bottom left + break; + case "2": + result.Alignment = "2"; // bottom center + break; + case "3": + result.Alignment = "3"; // bottom right + break; + case "9": + result.Alignment = "4"; // middle left + break; + case "10": + result.Alignment = "5"; // middle center + break; + case "11": + result.Alignment = "6"; // middle right + break; + case "5": + result.Alignment = "7"; // top left + break; + case "6": + result.Alignment = "8"; // top center + break; + case "7": + result.Alignment = "9"; // top right + break; + default: + result.Alignment = "2"; + break; + } + } + } + + return result; + } + + private static string[] GetSsaFormatList(string header) + { + if (string.IsNullOrEmpty(header)) + { + header = SubStationAlpha.DefaultHeader; + } + + foreach (var line in header.SplitToLines()) + { + var s = line.Trim().ToLowerInvariant(); + if (s.StartsWith("format:")) + { + s = s.Remove(0, "format:".Length).TrimStart().Replace(" ", string.Empty); + return s.Split(','); + } + } + + return "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding" + .Replace(" ", string.Empty) + .ToLowerInvariant() + .Split(); + } } } diff --git a/src/libse/SubtitleFormats/AdvancedSubStationAlpha.cs b/src/libse/SubtitleFormats/AdvancedSubStationAlpha.cs index b8b839631..a5aecffa7 100644 --- a/src/libse/SubtitleFormats/AdvancedSubStationAlpha.cs +++ b/src/libse/SubtitleFormats/AdvancedSubStationAlpha.cs @@ -94,7 +94,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats public static string HeaderNoStyles = @"[Script Info] ; This is an Advanced Sub Station Alpha v4+ script. Title: {0} -ScriptType: v4.00+" + +ScriptType: v4.00+" + (Configuration.Settings.SubtitleSettings.AssaShowPlayDepth ? Environment.NewLine + "PlayDepth: 0" : string.Empty) + (Configuration.Settings.SubtitleSettings.AssaShowScaledBorderAndShadow ? Environment.NewLine + "ScaledBorderAndShadow: Yes" : string.Empty) + @" @@ -180,7 +180,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" style = p.Style; } - var actor = ""; + var actor = string.Empty; if (!string.IsNullOrEmpty(p.Actor)) { actor = p.Actor; @@ -204,7 +204,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" marginV = p.MarginV; } - var effect = ""; + var effect = string.Empty; if (!string.IsNullOrEmpty(p.Effect)) { effect = p.Effect; @@ -246,12 +246,12 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" public static string GetHeaderAndStylesFromSubStationAlpha(string header) { var scriptInfo = string.Empty; - header = FixScriptType(header); if (header != null && header.Contains("[Script Info]") && header.Contains("ScriptType: v4.00") && !header.Contains("ScriptType: v4.00+")) { + header = FixScriptType(header); var sb = new StringBuilder(); var scriptInfoOn = false; foreach (var line in header.SplitToLines()) @@ -266,6 +266,12 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" scriptInfoOn = true; } + if (line.Length > 10 && line.TrimStart().StartsWith("format:", StringComparison.OrdinalIgnoreCase)) + { + var s = line.Trim().Remove(0, 7); + var arr = line.Split(','); + } + if (scriptInfoOn) { if (line.StartsWith("ScriptType:", StringComparison.OrdinalIgnoreCase)) @@ -282,21 +288,28 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" } } } + scriptInfo = sb.ToString(); } + else + { + header = FixScriptType(header); + } - var style = GetStyle(header); - - if (string.IsNullOrEmpty(scriptInfo) || string.IsNullOrEmpty(style)) + var stylesContent = GetStyleContentFromHeader(header); + if (string.IsNullOrEmpty(scriptInfo) || stylesContent.Count == 0) { return DefaultHeader; } - return string.Format($@"{scriptInfo.Trim() + Environment.NewLine} -[V4+ Styles] -{SsaStyle.DefaultAssStyleFormat} -{style.Trim() + Environment.NewLine} -[Events]"); + var styles = new List(); + foreach (var styleAsString in stylesContent) + { + styles.Add(SsaStyle.FromRawSsa(header, styleAsString)); + } + + header = GetHeaderAndStylesFromAdvancedSubStationAlpha(header, styles); + return header; } public static string GetHeaderAndStylesFromAdvancedSubStationAlpha(string header, List styles) @@ -919,6 +932,37 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" return list; } + public static List GetStyleContentFromHeader(string headerLines) + { + var list = new List(); + + if (headerLines == null) + { + headerLines = DefaultStyle; + } + + if (headerLines.Contains("http://www.w3.org/ns/ttml")) + { + var subtitle = new Subtitle { Header = headerLines }; + LoadStylesFromTimedText10(subtitle, string.Empty, headerLines, HeaderNoStyles, new StringBuilder()); + headerLines = subtitle.Header; + } + + foreach (var line in headerLines.SplitToLines()) + { + if (line.StartsWith("style:", StringComparison.OrdinalIgnoreCase)) + { + var end = line.IndexOf(','); + if (end > 0) + { + list.Add(line.Remove(0, 6).Trim()); + } + } + } + + return list; + } + public static string FormatText(string input) { var text = input; @@ -2396,46 +2440,46 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" { var style = new SsaStyle { Name = styleName }; - int nameIndex = -1; - int fontNameIndex = -1; - int fontsizeIndex = -1; - int primaryColourIndex = -1; - int secondaryColourIndex = -1; - int tertiaryColourIndex = -1; - int outlineColourIndex = -1; - int backColourIndex = -1; - int boldIndex = -1; - int italicIndex = -1; - int underlineIndex = -1; - int strikOutIndex = -1; - int outlineIndex = -1; - int shadowIndex = -1; - int alignmentIndex = -1; - int marginLIndex = -1; - int marginRIndex = -1; - int marginVIndex = -1; - int scaleXIndex = -1; - int scaleYIndex = -1; - int spacingIndex = -1; - int angleIndex = -1; - int borderStyleIndex = -1; + var nameIndex = -1; + var fontNameIndex = -1; + var fontSizeIndex = -1; + var primaryColourIndex = -1; + var secondaryColourIndex = -1; + var tertiaryColourIndex = -1; + var outlineColourIndex = -1; + var backColourIndex = -1; + var boldIndex = -1; + var italicIndex = -1; + var underlineIndex = -1; + var strikeOutIndex = -1; + var outlineIndex = -1; + var shadowIndex = -1; + var alignmentIndex = -1; + var marginLIndex = -1; + var marginRIndex = -1; + var marginVIndex = -1; + var scaleXIndex = -1; + var scaleYIndex = -1; + var spacingIndex = -1; + var angleIndex = -1; + var borderStyleIndex = -1; if (header == null) { header = DefaultHeader; } - foreach (string line in header.SplitToLines()) + foreach (var line in header.SplitToLines()) { - string s = line.Trim().ToLowerInvariant(); + var s = line.Trim().ToLowerInvariant(); if (s.StartsWith("format:", StringComparison.Ordinal)) { if (line.Length > 10) { var format = line.ToLowerInvariant().Substring(8).Split(','); - for (int i = 0; i < format.Length; i++) + for (var i = 0; i < format.Length; i++) { - string f = format[i].Trim().ToLowerInvariant(); + var f = format[i].Trim().ToLowerInvariant(); if (f == "name") { nameIndex = i; @@ -2446,7 +2490,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" } else if (f == "fontsize") { - fontsizeIndex = i; + fontSizeIndex = i; } else if (f == "primarycolour") { @@ -2482,7 +2526,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" } else if (f == "strikeout") { - strikOutIndex = i; + strikeOutIndex = i; } else if (f == "outline") { @@ -2537,9 +2581,9 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" { style.RawLine = line; var format = line.Substring(6).Split(','); - for (int i = 0; i < format.Length; i++) + for (var i = 0; i < format.Length; i++) { - string f = format[i].Trim(); + var f = format[i].Trim(); if (i == nameIndex) { style.Name = format[i].Trim(); @@ -2548,7 +2592,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" { style.FontName = f; } - else if (i == fontsizeIndex) + else if (i == fontSizeIndex) { if (decimal.TryParse(f, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var fOut)) { @@ -2587,7 +2631,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" { style.Underline = f == "-1" || f == "1"; } - else if (i == strikOutIndex) + else if (i == strikeOutIndex) { style.Strikeout = f == "-1" || f == "1"; } diff --git a/src/libse/SubtitleFormats/SubStationAlpha.cs b/src/libse/SubtitleFormats/SubStationAlpha.cs index c44b56b6d..7b8e0bd67 100644 --- a/src/libse/SubtitleFormats/SubStationAlpha.cs +++ b/src/libse/SubtitleFormats/SubStationAlpha.cs @@ -143,13 +143,13 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text marginR = p.MarginR.PadLeft(4, '0'); } - string marginV = "0000"; + var marginV = "0000"; if (!string.IsNullOrEmpty(p.MarginV) && Utilities.IsInteger(p.MarginV)) { marginV = p.MarginV.PadLeft(4, '0'); } - string effect = ""; + var effect = string.Empty; if (!string.IsNullOrEmpty(p.Effect)) { effect = p.Effect; @@ -210,25 +210,25 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text private static string GetStyle(string header) { var ttStyles = new StringBuilder(); - foreach (string styleName in AdvancedSubStationAlpha.GetStylesFromHeader(header)) + foreach (var styleName in AdvancedSubStationAlpha.GetStylesFromHeader(header)) { try { var ssaStyle = AdvancedSubStationAlpha.GetSsaStyle(styleName, header); - string bold = "0"; + var bold = "0"; if (ssaStyle.Bold) { bold = "-1"; } - string italic = "0"; + var italic = "0"; if (ssaStyle.Italic) { italic = "-1"; } - string newAlignment = "2"; + var newAlignment = "2"; switch (ssaStyle.Alignment) { case "1": @@ -306,25 +306,25 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text { stylexmlCount++; - string fontFamily = "Arial"; + var fontFamily = "Arial"; if (node.Attributes["tts:fontFamily"] != null) { fontFamily = node.Attributes["tts:fontFamily"].Value; } - string fontWeight = "normal"; + var fontWeight = "normal"; if (node.Attributes["tts:fontWeight"] != null) { fontWeight = node.Attributes["tts:fontWeight"].Value; } - string fontStyle = "normal"; + var fontStyle = "normal"; if (node.Attributes["tts:fontStyle"] != null) { fontStyle = node.Attributes["tts:fontStyle"].Value; } - string color = "#ffffff"; + var color = "#ffffff"; if (node.Attributes["tts:color"] != null) { color = node.Attributes["tts:color"].Value.Trim(); @@ -335,7 +335,7 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text { if (color.StartsWith("rgb(", StringComparison.Ordinal)) { - string[] arr = color.Remove(0, 4).TrimEnd(')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var arr = color.Remove(0, 4).TrimEnd(')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); c = Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2])); } else @@ -348,7 +348,7 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text c = Color.White; } - string fontSize = "20"; + var fontSize = "20"; if (node.Attributes["tts:fontSize"] != null) { fontSize = node.Attributes["tts:fontSize"].Value.Replace("px", string.Empty).Replace("em", string.Empty); @@ -385,29 +385,29 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text { _errorCount = 0; Errors = null; - bool eventsStarted = false; + var eventsStarted = false; var fontsStarted = false; var graphicsStarted = false; subtitle.Paragraphs.Clear(); // "Marked", " Start", " End", " Style", " Name", " MarginL", " MarginR", " MarginV", " Effect", " Text" - int indexLayer = 0; - int indexStart = 1; - int indexEnd = 2; - int indexStyle = 3; + var indexLayer = 0; + var indexStart = 1; + var indexEnd = 2; + var indexStyle = 3; const int indexName = 4; - int indexMarginL = 5; - int indexMarginR = 6; - int indexMarginV = 7; - int indexEffect = 8; - int indexText = 9; + var indexMarginL = 5; + var indexMarginR = 6; + var indexMarginV = 7; + var indexEffect = 8; + var indexText = 9; var errors = new StringBuilder(); - int lineNumber = 0; + var lineNumber = 0; var header = new StringBuilder(); var footer = new StringBuilder(); - for (int i1 = 0; i1 < lines.Count; i1++) + for (var i1 = 0; i1 < lines.Count; i1++) { - string line = lines[i1]; + var line = lines[i1]; lineNumber++; if (!eventsStarted) { @@ -442,11 +442,11 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text } else if (eventsStarted && !string.IsNullOrWhiteSpace(line)) { - string s = line.Trim().ToLowerInvariant(); + var s = line.Trim().ToLowerInvariant(); if (line.Length > 10 && s.StartsWith("format:", StringComparison.Ordinal)) { var format = s.Substring(8).Split(','); - for (int i = 0; i < format.Length; i++) + for (var i = 0; i < format.Length; i++) { var formatTrimmed = format[i].Trim(); if (formatTrimmed.Equals("layer", StringComparison.Ordinal)) @@ -532,7 +532,7 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text splitLine = line.Split(','); } - for (int i = 0; i < splitLine.Length; i++) + for (var i = 0; i < splitLine.Length; i++) { if (i == indexStart) { @@ -656,7 +656,7 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text private static TimeCode GetTimeCodeFromString(string time) { // h:mm:ss.cc - string[] timeCode = time.Split(':', '.'); + var timeCode = time.Split(':', '.'); return new TimeCode(int.Parse(timeCode[0]), int.Parse(timeCode[1]), int.Parse(timeCode[2]), @@ -671,13 +671,13 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text } else { - foreach (Paragraph p in subtitle.Paragraphs) + foreach (var p in subtitle.Paragraphs) { - int indexOfBegin = p.Text.IndexOf('{'); - string pre = string.Empty; + var indexOfBegin = p.Text.IndexOf('{'); + var pre = string.Empty; while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin) { - string s = p.Text.Substring(indexOfBegin); + var s = p.Text.Substring(indexOfBegin); if (s.StartsWith("{\\an1}", StringComparison.Ordinal) || s.StartsWith("{\\an2}", StringComparison.Ordinal) || s.StartsWith("{\\an3}", StringComparison.Ordinal) || @@ -731,11 +731,13 @@ Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text { pre = "{\\an9}"; } - int indexOfEnd = p.Text.IndexOf('}'); + + var indexOfEnd = p.Text.IndexOf('}'); p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1); indexOfBegin = p.Text.IndexOf('{'); } + p.Text = pre + p.Text; } } @@ -796,5 +798,18 @@ Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour {style.Trim() + Environment.NewLine} [Events]"); } + + public static string DefaultHeader + { + get + { + var format = new SubStationAlpha(); + var sub = new Subtitle(); + var text = format.ToText(sub, string.Empty); + var lines = text.SplitToLines(); + format.LoadSubtitle(sub, lines, string.Empty); + return sub.Header; + } + } } } diff --git a/src/ui/Controls/VideoPlayerContainer.cs b/src/ui/Controls/VideoPlayerContainer.cs index b5ef87d54..bd5716251 100644 --- a/src/ui/Controls/VideoPlayerContainer.cs +++ b/src/ui/Controls/VideoPlayerContainer.cs @@ -500,7 +500,10 @@ namespace Nikse.SubtitleEdit.Controls } } - subtitle.Header = MpvPreviewStyleHeader; + if (subtitle.Header == null || !(subtitle.Header.Contains("[V4+ Styles]") && uiFormat.Name == SubStationAlpha.NameOfFormat)) + { + subtitle.Header = MpvPreviewStyleHeader; + } if (oldSub.Header != null && oldSub.Header.Length > 20 && oldSub.Header.Substring(3, 3) == "STL") { diff --git a/src/ui/Forms/Styles/SubStationAlphaStyles.cs b/src/ui/Forms/Styles/SubStationAlphaStyles.cs index de2933815..edb32fc38 100644 --- a/src/ui/Forms/Styles/SubStationAlphaStyles.cs +++ b/src/ui/Forms/Styles/SubStationAlphaStyles.cs @@ -328,7 +328,7 @@ namespace Nikse.SubtitleEdit.Forms.Styles } } - private List GetFontNames(byte[] fontBytes) + private static List GetFontNames(byte[] fontBytes) { var privateFontCollection = new PrivateFontCollection(); var handle = GCHandle.Alloc(fontBytes, GCHandleType.Pinned); @@ -572,25 +572,6 @@ namespace Nikse.SubtitleEdit.Forms.Styles } } - private static string FixDuplicateStyleName(string newStyleName, List existingStyles) - { - if (existingStyles.All(p => p.Name != newStyleName)) - { - return newStyleName; - } - - for (int i = 1; i < int.MaxValue; i++) - { - var name = $"{newStyleName}_{i}"; - if (existingStyles.All(p => p.Name != name)) - { - return name; - } - } - - return Guid.NewGuid().ToString(); - } - public static void AddStyle(ListView lv, SsaStyle ssaStyle, Subtitle subtitle, bool isSubstationAlpha) { AddStyle(lv, ssaStyle, subtitle, isSubstationAlpha, lv.Items.Count); @@ -848,7 +829,7 @@ namespace Nikse.SubtitleEdit.Forms.Styles return sb.ToString(); } - private void UpdateSelectedIndices(ListView listview, int startingIndex = -1, int numberOfSelectedItems = 1) + private static void UpdateSelectedIndices(ListView listview, int startingIndex = -1, int numberOfSelectedItems = 1) { if (numberOfSelectedItems == 0) { @@ -866,7 +847,7 @@ namespace Nikse.SubtitleEdit.Forms.Styles } listview.SelectedItems.Clear(); - for (int i = 0; i < numberOfSelectedItems; i++) + for (var i = 0; i < numberOfSelectedItems; i++) { listview.Items[startingIndex - i].Selected = true; listview.Items[startingIndex - i].EnsureVisible(); @@ -880,11 +861,11 @@ namespace Nikse.SubtitleEdit.Forms.Styles if (listViewStyles.SelectedItems.Count == 1) { - string styleName = listViewStyles.SelectedItems[0].Text; + var styleName = listViewStyles.SelectedItems[0].Text; _startName = styleName; _editedName = null; _oldSsaName = styleName; - SsaStyle style = GetSsaStyleFile(styleName); + var style = GetSsaStyleFile(styleName); SetControlsFromStyle(style); _doUpdate = true; groupBoxProperties.Enabled = true;