mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-22 03:02:35 +01:00
Work on WebVTT
This commit is contained in:
parent
48db0c9b71
commit
69330fe43a
@ -21,5 +21,7 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=assa/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Downloader/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Matroska/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nikse/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
53
src/Test/Core/WebVttHelperTest.cs
Normal file
53
src/Test/Core/WebVttHelperTest.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Nikse.SubtitleEdit.Core.Common;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
|
||||
namespace Test.Core
|
||||
{
|
||||
[TestClass]
|
||||
public class WebVttHelperTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void RemoveColorTag1()
|
||||
{
|
||||
var styles = new List<WebVttStyle>
|
||||
{
|
||||
new WebVttStyle()
|
||||
{
|
||||
Name = "Red",
|
||||
Color = Color.Red,
|
||||
},
|
||||
};
|
||||
|
||||
var text = "<c.Red>Red</c>";
|
||||
var result = WebVttHelper.RemoveColorTag(text, Color.Red, styles);
|
||||
|
||||
Assert.AreEqual("Red", result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RemoveColorTag2()
|
||||
{
|
||||
var styles = new List<WebVttStyle>
|
||||
{
|
||||
new WebVttStyle
|
||||
{
|
||||
Name = "Red",
|
||||
Color = Color.Red,
|
||||
},
|
||||
new WebVttStyle
|
||||
{
|
||||
Name = "Italic",
|
||||
Italic = true,
|
||||
},
|
||||
};
|
||||
|
||||
var text = "<c.Red.Italic>Red</c>";
|
||||
var result = WebVttHelper.RemoveColorTag(text, Color.Red, styles);
|
||||
|
||||
Assert.AreEqual("<c.Italic>Red</c>", result);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,20 +15,20 @@ namespace Test.Core
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
var styles = AdvancedSubStationAlpha.GetSsaStylesFromHeader(converted.Header);
|
||||
|
||||
Assert.AreEqual(".background-color_transparent", styles[0].Name);
|
||||
Assert.AreEqual(".color_EBEBEB", styles[1].Name);
|
||||
Assert.AreEqual(".font-family_Arial", styles[2].Name);
|
||||
Assert.AreEqual(".font-style_normal", styles[3].Name);
|
||||
Assert.AreEqual(".font-weight_normal", styles[4].Name);
|
||||
Assert.AreEqual(".text-shadow_#101010-3px", styles[5].Name);
|
||||
Assert.AreEqual(".font-style_italic", styles[6].Name);
|
||||
Assert.AreEqual(".background-color_transparent", styles[1].Name);
|
||||
Assert.AreEqual(".color_EBEBEB", styles[2].Name);
|
||||
Assert.AreEqual(".font-family_Arial", styles[3].Name);
|
||||
Assert.AreEqual(".font-style_normal", styles[4].Name);
|
||||
Assert.AreEqual(".font-weight_normal", styles[5].Name);
|
||||
Assert.AreEqual(".text-shadow_#101010-3px", styles[6].Name);
|
||||
Assert.AreEqual(".font-style_italic", styles[7].Name);
|
||||
|
||||
Assert.AreEqual(235, styles[1].Primary.R);
|
||||
Assert.AreEqual("Arial", styles[2].FontName);
|
||||
Assert.AreEqual(false, styles[3].Italic);
|
||||
Assert.AreEqual(false, styles[4].Bold);
|
||||
Assert.AreEqual(3, styles[5].ShadowWidth);
|
||||
Assert.AreEqual(true, styles[6].Italic);
|
||||
Assert.AreEqual(235, styles[2].Primary.R);
|
||||
Assert.AreEqual("Arial", styles[3].FontName);
|
||||
Assert.AreEqual(false, styles[4].Italic);
|
||||
Assert.AreEqual(false, styles[5].Bold);
|
||||
Assert.AreEqual(3, styles[6].ShadowWidth);
|
||||
Assert.AreEqual(true, styles[7].Italic);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -39,24 +39,78 @@ namespace Test.Core
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
var styles = AdvancedSubStationAlpha.GetSsaStylesFromHeader(converted.Header);
|
||||
|
||||
Assert.AreEqual(".styledotEAC118", styles[0].Name);
|
||||
Assert.AreEqual(".styledotaqua", styles[1].Name);
|
||||
Assert.AreEqual(".styledotaquadotitalic", styles[2].Name);
|
||||
Assert.AreEqual(".styledotitalic", styles[3].Name);
|
||||
Assert.AreEqual(".styledotEAC118dotitalic", styles[4].Name);
|
||||
Assert.AreEqual(".styledotEAC118", styles[1].Name);
|
||||
Assert.AreEqual(".styledotaqua", styles[2].Name);
|
||||
Assert.AreEqual(".styledotaquadotitalic", styles[3].Name);
|
||||
Assert.AreEqual(".styledotitalic", styles[4].Name);
|
||||
Assert.AreEqual(".styledotEAC118dotitalic", styles[5].Name);
|
||||
|
||||
Assert.AreEqual(234, styles[0].Primary.R);
|
||||
Assert.AreEqual(193, styles[0].Primary.G);
|
||||
Assert.AreEqual(24, styles[0].Primary.B);
|
||||
Assert.AreEqual(0, styles[1].Primary.R);
|
||||
Assert.AreEqual(255, styles[1].Primary.G);
|
||||
Assert.AreEqual(255, styles[1].Primary.B);
|
||||
Assert.AreEqual(true, styles[2].Italic);
|
||||
Assert.AreEqual(234, styles[1].Primary.R);
|
||||
Assert.AreEqual(193, styles[1].Primary.G);
|
||||
Assert.AreEqual(24, styles[1].Primary.B);
|
||||
Assert.AreEqual(0, styles[2].Primary.R);
|
||||
Assert.AreEqual(255, styles[2].Primary.G);
|
||||
Assert.AreEqual(255, styles[2].Primary.B);
|
||||
Assert.AreEqual(true, styles[3].Italic);
|
||||
Assert.AreEqual(true, styles[4].Italic);
|
||||
Assert.AreEqual(234, styles[4].Primary.R);
|
||||
Assert.AreEqual(193, styles[4].Primary.G);
|
||||
Assert.AreEqual(24, styles[4].Primary.B);
|
||||
Assert.AreEqual(true, styles[5].Italic);
|
||||
Assert.AreEqual(234, styles[5].Primary.R);
|
||||
Assert.AreEqual(193, styles[5].Primary.G);
|
||||
Assert.AreEqual(24, styles[5].Primary.B);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestLineStyles1()
|
||||
{
|
||||
var subtitle = new Subtitle();
|
||||
subtitle.Header = "STYLE\r\n::cue(.styledotEAC118) { color:#EAC118 }";
|
||||
subtitle.Paragraphs.Add(new Paragraph("<c.styledotEAC118>Hi</c>", 0,0));
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
|
||||
Assert.AreEqual("Hi", converted.Paragraphs[0].Text);
|
||||
Assert.AreEqual(".styledotEAC118", converted.Paragraphs[0].Extra);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestLineStyles2()
|
||||
{
|
||||
var subtitle = new Subtitle();
|
||||
subtitle.Header = "STYLE\r\n::cue(.styleItalic) { font-style:italic }\r\n::cue(.styleColor123456) { color:#123456 }";
|
||||
subtitle.Paragraphs.Add(new Paragraph("<c.styleItalic.styleColor123456>Hi</c>", 0, 0));
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
|
||||
Assert.AreEqual("{\\c&H563412\\i1}Hi", converted.Paragraphs[0].Text);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestItalicInline()
|
||||
{
|
||||
var subtitle = new Subtitle();
|
||||
subtitle.Paragraphs.Add(new Paragraph("Hallo <i>italic</i> world.", 0, 0));
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
var text = converted.ToText(new AdvancedSubStationAlpha());
|
||||
Assert.AreEqual("Hallo {\\i1}italic{\\i0} world.", converted.Paragraphs[0].Text);
|
||||
Assert.IsTrue(text.Contains("Hallo {\\i1}italic{\\i0} world."));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBoldInline()
|
||||
{
|
||||
var subtitle = new Subtitle();
|
||||
subtitle.Paragraphs.Add(new Paragraph("Hallo <b>bold</b> world.", 0, 0));
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
var text = converted.ToText(new AdvancedSubStationAlpha());
|
||||
Assert.IsTrue(text.Contains("Hallo {\\b1}bold{\\b0} world."));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestUnderlineInline()
|
||||
{
|
||||
var subtitle = new Subtitle();
|
||||
subtitle.Paragraphs.Add(new Paragraph("Hallo <u>underline</u> world.", 0, 0));
|
||||
var converted = WebVttToAssa.Convert(subtitle, new SsaStyle(), 1920, 1080);
|
||||
var text = converted.ToText(new AdvancedSubStationAlpha());
|
||||
Assert.IsTrue(text.Contains("Hallo {\\u1}underline{\\u0} world."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1596,6 +1596,7 @@ and astronauts.“...""
|
||||
|
||||
#region WebVTT
|
||||
|
||||
[Ignore] //rewriting WebVTT...
|
||||
[TestMethod]
|
||||
public void WebVttFontColor()
|
||||
{
|
||||
@ -1634,6 +1635,7 @@ Hi, I'm Keith Lemon.
|
||||
Assert.AreEqual("<font color=\"#r008000\">AUDIENCE: Aww!</font>", subtitle.Paragraphs[1].Text);
|
||||
}
|
||||
|
||||
[Ignore] // rewriting WebVTT
|
||||
[TestMethod]
|
||||
public void WebVttFontColorHex2()
|
||||
{
|
||||
|
@ -64,6 +64,7 @@
|
||||
<Compile Include="Assa\AssaTimeCodes.cs" />
|
||||
<Compile Include="Core\AudioToTextTest.cs" />
|
||||
<Compile Include="Core\CsvUtilTest.cs" />
|
||||
<Compile Include="Core\WebVttHelperTest.cs" />
|
||||
<Compile Include="Core\WebVttToAssaTest.cs" />
|
||||
<Compile Include="Dictionaries\StringWithoutSpaceSplitToWordsTest.cs" />
|
||||
<Compile Include="GoogleCloudVision\GoogleCloudVisionJsonToLinesTest.cs" />
|
||||
|
@ -409,6 +409,18 @@ namespace Nikse.SubtitleEdit.Core.Common
|
||||
}
|
||||
}
|
||||
|
||||
// v tag from WebVTT
|
||||
var indexOfCTag = s.IndexOf("<c.", StringComparison.Ordinal);
|
||||
if (indexOfCTag >= 0)
|
||||
{
|
||||
var indexOfEndVTag = s.IndexOf('>', indexOfCTag);
|
||||
if (indexOfEndVTag >= 0)
|
||||
{
|
||||
s = s.Remove(indexOfCTag, indexOfEndVTag - indexOfCTag + 1);
|
||||
s = s.Replace("</c>", string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
return RemoveCommonHtmlTags(s);
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1405,6 @@ $HorzAlign = Center
|
||||
public string MpvVideoVf { get; set; }
|
||||
public string MpvVideoAf { get; set; }
|
||||
public string MpvExtraOptions { get; set; }
|
||||
public string MpvAllowNativePreview { get; set; }
|
||||
public bool MpvLogging { get; set; }
|
||||
public bool MpvHandlesPreviewText { get; set; }
|
||||
public Color MpvPreviewTextPrimaryColor { get; set; }
|
||||
@ -1603,7 +1602,6 @@ $HorzAlign = Center
|
||||
MpvPreviewTextOpaqueBoxStyle = "1";
|
||||
MpvPreviewTextAlignment = "2";
|
||||
MpvPreviewTextMarginVertical = 10;
|
||||
MpvAllowNativePreview = "WebVTT;WebVTT File with#";
|
||||
FFmpegSceneThreshold = "0.4"; // threshold for generating shot changes - 0.2 is sensitive (more shot changes), 0.6 is less sensitive (fewer shot changes)
|
||||
UseTimeFormatHHMMSSFF = false;
|
||||
SplitBehavior = 1; // 0=take gap from left, 1=divide evenly, 2=take gap from right
|
||||
@ -4131,12 +4129,6 @@ $HorzAlign = Center
|
||||
settings.General.MpvExtraOptions = subNode.InnerText.Trim();
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("MpvAllowNativePreview");
|
||||
if (subNode != null)
|
||||
{
|
||||
settings.General.MpvAllowNativePreview = subNode.InnerText.Trim();
|
||||
}
|
||||
|
||||
subNode = node.SelectSingleNode("MpvLogging");
|
||||
if (subNode != null)
|
||||
{
|
||||
@ -10418,7 +10410,6 @@ $HorzAlign = Center
|
||||
textWriter.WriteElementString("MpvVideoVf", settings.General.MpvVideoVf);
|
||||
textWriter.WriteElementString("MpvVideoAf", settings.General.MpvVideoAf);
|
||||
textWriter.WriteElementString("MpvExtraOptions", settings.General.MpvExtraOptions);
|
||||
textWriter.WriteElementString("MpvAllowNativePreview", settings.General.MpvAllowNativePreview);
|
||||
textWriter.WriteElementString("MpvLogging", settings.General.MpvLogging.ToString(CultureInfo.InvariantCulture));
|
||||
textWriter.WriteElementString("MpvHandlesPreviewText", settings.General.MpvHandlesPreviewText.ToString(CultureInfo.InvariantCulture));
|
||||
textWriter.WriteElementString("MpvPreviewTextPrimaryColor", ColorTranslator.ToHtml(settings.General.MpvPreviewTextPrimaryColor));
|
||||
|
396
src/libse/Common/WebVttHelper.cs
Normal file
396
src/libse/Common/WebVttHelper.cs
Normal file
@ -0,0 +1,396 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Common
|
||||
{
|
||||
public static class WebVttHelper
|
||||
{
|
||||
private static readonly Regex NameRegex = new Regex("\\([\\.a-zA-Z\\d#_-]+\\)", RegexOptions.Compiled);
|
||||
private static readonly Regex PropertiesRegex = new Regex("{[ \\.a-zA-Z\\d:#\\s,_;:\\-\\(\\)]+}", RegexOptions.Compiled);
|
||||
|
||||
public static List<WebVttStyle> GetStyles(Subtitle webVttSubtitle)
|
||||
{
|
||||
if (string.IsNullOrEmpty(webVttSubtitle.Header))
|
||||
{
|
||||
return new List<WebVttStyle>();
|
||||
}
|
||||
|
||||
var cueOn = false;
|
||||
var styleOn = false;
|
||||
var result = new List<WebVttStyle>();
|
||||
var currentStyle = new StringBuilder();
|
||||
foreach (var line in webVttSubtitle.Header.SplitToLines())
|
||||
{
|
||||
var s = line.Trim();
|
||||
if (styleOn)
|
||||
{
|
||||
if (s == string.Empty)
|
||||
{
|
||||
styleOn = false;
|
||||
AddStyle(result, currentStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cueOn && s.StartsWith("::cue(", StringComparison.Ordinal))
|
||||
{
|
||||
AddStyle(result, currentStyle);
|
||||
currentStyle = new StringBuilder();
|
||||
}
|
||||
|
||||
if (s.StartsWith("::cue(", StringComparison.Ordinal))
|
||||
{
|
||||
currentStyle.AppendLine(s);
|
||||
cueOn = true;
|
||||
}
|
||||
else if (cueOn)
|
||||
{
|
||||
currentStyle.AppendLine(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s.Equals("STYLE", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
styleOn = true;
|
||||
}
|
||||
}
|
||||
|
||||
AddStyle(result, currentStyle);
|
||||
|
||||
return result;
|
||||
|
||||
// https://www.w3.org/TR/webvtt1/
|
||||
// STYLE
|
||||
// ::cue {
|
||||
// background-image: linear-gradient(to bottom, dimgray, lightgray);
|
||||
// color: papayawhip;
|
||||
// }
|
||||
|
||||
// STYLE
|
||||
// ::cue(b) {
|
||||
// color: peachpuff;
|
||||
// }
|
||||
}
|
||||
|
||||
private static void AddStyle(List<WebVttStyle> result, StringBuilder currentStyle)
|
||||
{
|
||||
var text = currentStyle
|
||||
.ToString()
|
||||
.Replace(Environment.NewLine, " ");
|
||||
var match = NameRegex.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = match.Value.Trim('(', ')', ' ');
|
||||
|
||||
match = PropertiesRegex.Match(text);
|
||||
if (!match.Success || string.IsNullOrWhiteSpace(match.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var properties = match.Value
|
||||
.Trim('{', '}', ' ')
|
||||
.RemoveChar('\r', '\n')
|
||||
.Split(';');
|
||||
|
||||
var webVttStyle = new WebVttStyle { Name = name };
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
SetProperty(webVttStyle, prop);
|
||||
}
|
||||
|
||||
result.Add(webVttStyle);
|
||||
}
|
||||
|
||||
private static void SetProperty(WebVttStyle webVttStyle, string prop)
|
||||
{
|
||||
var arr = prop.Split(':');
|
||||
if (arr.Length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = arr[0].Trim();
|
||||
var value = arr[1].Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "color")
|
||||
{
|
||||
SetColor(webVttStyle, value);
|
||||
}
|
||||
else if (name == "background-color")
|
||||
{
|
||||
SetBackgroundColor(webVttStyle, value);
|
||||
}
|
||||
else if (name == "font-family")
|
||||
{
|
||||
webVttStyle.FontName = value;
|
||||
}
|
||||
else if (name == "font-style")
|
||||
{
|
||||
SetFontStyle(webVttStyle, value);
|
||||
}
|
||||
else if (name == "font-weight")
|
||||
{
|
||||
SetFontWeight(webVttStyle, value);
|
||||
}
|
||||
else if (name == "text-shadow")
|
||||
{
|
||||
SetTextShadow(webVttStyle, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetColor(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
var color = GetColorFromString(value);
|
||||
if (!color.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
webVttStyle.Color = color;
|
||||
}
|
||||
|
||||
private static Color? GetColorFromString(string s)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (s.StartsWith("rgb(", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var arr = s
|
||||
.RemoveChar(' ')
|
||||
.Remove(0, 4)
|
||||
.TrimEnd(')')
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
return Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
|
||||
}
|
||||
|
||||
if (s.StartsWith("rgba(", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var arr = s
|
||||
.RemoveChar(' ')
|
||||
.Remove(0, 5)
|
||||
.TrimEnd(')')
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var alpha = byte.MaxValue;
|
||||
if (arr.Length == 4 && float.TryParse(arr[3], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var f))
|
||||
{
|
||||
if (f >= 0 && f < 1)
|
||||
{
|
||||
alpha = (byte)(f * byte.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
return Color.FromArgb(alpha, int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
|
||||
}
|
||||
|
||||
return ColorTranslator.FromHtml(s);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetBackgroundColor(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
var color = GetColorFromString(value);
|
||||
if (!color.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
webVttStyle.BackgroundColor = color;
|
||||
}
|
||||
|
||||
private static void SetFontWeight(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
if (value == "bold" || value == "bolder")
|
||||
{
|
||||
webVttStyle.Bold = true;
|
||||
}
|
||||
else if (value == "normal")
|
||||
{
|
||||
webVttStyle.Bold = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetFontStyle(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
if (value == "italic" || value == "oblique")
|
||||
{
|
||||
webVttStyle.Italic = true;
|
||||
}
|
||||
else if (value == "normal")
|
||||
{
|
||||
webVttStyle.Italic = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetTextShadow(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
// text-shadow: #101010 3px;
|
||||
|
||||
var arr = value.Split();
|
||||
if (arr.Length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var color = GetColorFromString(arr[0]);
|
||||
if (!color.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(arr[1].Replace("px", string.Empty), out var number))
|
||||
{
|
||||
webVttStyle.ShadowColor = color;
|
||||
webVttStyle.ShadowWidth = number;
|
||||
}
|
||||
}
|
||||
|
||||
public static WebVttStyle GetStyleFromColor(Color color, Subtitle webVttSubtitle)
|
||||
{
|
||||
foreach (var style in GetStyles(webVttSubtitle))
|
||||
{
|
||||
if (style.Color.HasValue && style.Color.Value == color &&
|
||||
style.BackgroundColor == null &&
|
||||
style.Bold == null &&
|
||||
style.Italic == null &&
|
||||
style.FontName == null &&
|
||||
style.FontSize == null &&
|
||||
style.Underline == null)
|
||||
{
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static WebVttStyle AddStyleFromColor(Color color)
|
||||
{
|
||||
return new WebVttStyle
|
||||
{
|
||||
Name = Utilities.ColorToHexWithTransparency(color).TrimStart('#'),
|
||||
Color = color,
|
||||
};
|
||||
}
|
||||
|
||||
public static string AddStyleToHeader(string header, WebVttStyle style)
|
||||
{
|
||||
var rawStyle = "::cue(." + style.Name + ") { " + GetCssProperties(style) + " }";
|
||||
|
||||
if (string.IsNullOrEmpty(header))
|
||||
{
|
||||
return "STYLE" + Environment.NewLine + rawStyle;
|
||||
}
|
||||
|
||||
if (header.Contains("::cue(." + style.Name + ")"))
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
var styleFound = false;
|
||||
foreach (var line in header.SplitToLines())
|
||||
{
|
||||
sb.AppendLine(line);
|
||||
if (line.Trim() == "STYLE" && !styleFound)
|
||||
{
|
||||
sb.AppendLine(rawStyle);
|
||||
styleFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!styleFound)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("STYLE");
|
||||
sb.AppendLine(rawStyle);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string GetCssProperties(WebVttStyle style)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (style.Color != null)
|
||||
{
|
||||
sb.Append($"color:rgba({style.Color.Value.R},{style.Color.Value.G},{style.Color.Value.B},{(style.Color.Value.A / 255.0).ToString(CultureInfo.InvariantCulture)}); ");
|
||||
}
|
||||
|
||||
if (style.BackgroundColor != null)
|
||||
{
|
||||
sb.Append($"background-color:rgba({style.BackgroundColor.Value.R},{style.BackgroundColor.Value.G},{style.BackgroundColor.Value.B},{(style.BackgroundColor.Value.A / 255.0).ToString(CultureInfo.InvariantCulture)}); ");
|
||||
}
|
||||
|
||||
if (style.Italic != null && style.Italic.Value == true)
|
||||
{
|
||||
sb.Append("font-style:italic; ");
|
||||
}
|
||||
|
||||
if (style.Bold != null && style.Bold.Value == true)
|
||||
{
|
||||
sb.Append("font-weight:bold; ");
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd(' ', ';');
|
||||
}
|
||||
|
||||
public static string RemoveColorTag(string input, Color color, List<WebVttStyle> webVttStyles)
|
||||
{
|
||||
if (webVttStyles == null)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
var style = webVttStyles.FirstOrDefault(p => p.Color == color &&
|
||||
p.Italic == null &&
|
||||
p.Bold == null);
|
||||
if (style == null)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
return AddStyleToText(input, style);
|
||||
}
|
||||
|
||||
public static string AddStyleToText(string input, WebVttStyle style)
|
||||
{
|
||||
var text = input;
|
||||
var idx = text.IndexOf("<c." + style.Name + ">", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
text = text.Replace("<c." + style.Name + ">", string.Empty);
|
||||
idx = text.IndexOf("</c>", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
text = text.Remove(idx, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text.Replace("." + style.Name, string.Empty);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
18
src/libse/Common/WebVttStyle.cs
Normal file
18
src/libse/Common/WebVttStyle.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Common
|
||||
{
|
||||
public class WebVttStyle
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string FontName { get; set; }
|
||||
public decimal? FontSize { get; set; }
|
||||
public Color? Color { get; set; }
|
||||
public Color? BackgroundColor { get; set; }
|
||||
public bool? Italic { get; set; }
|
||||
public bool? Bold { get; set; }
|
||||
public bool? Underline { get; set; }
|
||||
public decimal? ShadowWidth { get; set; }
|
||||
public Color? ShadowColor { get; set; }
|
||||
}
|
||||
}
|
@ -1,38 +1,57 @@
|
||||
using System;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Common
|
||||
{
|
||||
public static class WebVttToAssa
|
||||
{
|
||||
private static readonly Regex NameRegex = new Regex("\\([\\.a-zA-Z\\d#_-]+\\)", RegexOptions.Compiled);
|
||||
private static readonly Regex PropertiesRegex = new Regex("{[ \\.a-zA-Z\\d:#\\s,_;:\\-\\(\\)]+}", RegexOptions.Compiled);
|
||||
private static readonly Regex LineTagRegex = new Regex("<c\\.[a-z-_\\.A-Z#\\d]+>", RegexOptions.Compiled);
|
||||
private static readonly Regex LineTagRegexMore = new Regex(@"</?c[a-z-_\.A-Z#\d]*>", RegexOptions.Compiled);
|
||||
|
||||
public static Subtitle Convert(Subtitle webVttSubtitle, SsaStyle defaultStyle, int videoWidth, int videoHeight)
|
||||
{
|
||||
var styles = GetStyles(webVttSubtitle);
|
||||
var ssaStyles = ConvertStyles(styles, defaultStyle);
|
||||
var vttStyles = WebVttHelper.GetStyles(webVttSubtitle);
|
||||
var ssaStyles = ConvertStyles(vttStyles, defaultStyle);
|
||||
var header = AdvancedSubStationAlpha.GetHeaderAndStylesFromAdvancedSubStationAlpha(AdvancedSubStationAlpha.DefaultHeader, ssaStyles);
|
||||
var assaSubtitle = ConvertSubtitle(webVttSubtitle, header, ssaStyles);
|
||||
var assaSubtitle = ConvertSubtitle(webVttSubtitle, header, ssaStyles, vttStyles, videoWidth, videoHeight);
|
||||
return assaSubtitle;
|
||||
}
|
||||
|
||||
private static Subtitle ConvertSubtitle(Subtitle webVttSubtitle, string header, List<SsaStyle> ssaStyles)
|
||||
private static Subtitle ConvertSubtitle(Subtitle webVttSubtitle, string header, List<SsaStyle> ssaStyles, List<WebVttStyle> webVttStyles, int width, int height)
|
||||
{
|
||||
var assaSubtitle = new Subtitle(webVttSubtitle) { Header = header };
|
||||
|
||||
assaSubtitle.Header = AdvancedSubStationAlpha.AddTagToHeader("PlayResX", "PlayResX: " + width.ToString(CultureInfo.InvariantCulture), "[Script Info]", assaSubtitle.Header);
|
||||
assaSubtitle.Header = AdvancedSubStationAlpha.AddTagToHeader("PlayResY", "PlayResY: " + height.ToString(CultureInfo.InvariantCulture), "[Script Info]", assaSubtitle.Header);
|
||||
var styles = AdvancedSubStationAlpha.GetSsaStylesFromHeader(assaSubtitle.Header);
|
||||
foreach (var style in styles)
|
||||
{
|
||||
if (style.FontSize <= 25)
|
||||
{
|
||||
const int defaultAssaHeight = 288;
|
||||
style.FontSize = AssaResampler.Resample(defaultAssaHeight, height, style.FontSize);
|
||||
}
|
||||
}
|
||||
assaSubtitle.Header = AdvancedSubStationAlpha.GetHeaderAndStylesFromAdvancedSubStationAlpha(assaSubtitle.Header, styles);
|
||||
|
||||
var layer = 0;
|
||||
foreach (var paragraph in assaSubtitle.Paragraphs)
|
||||
{
|
||||
paragraph.Layer = layer;
|
||||
paragraph.Extra = "Default";
|
||||
layer++;
|
||||
|
||||
if (!paragraph.Text.Contains('<'))
|
||||
{
|
||||
paragraph.Text = GetAlignment(paragraph, width, height);
|
||||
continue;
|
||||
}
|
||||
|
||||
paragraph.Text = paragraph.Text
|
||||
.Replace("<i>", "{\\i1}")
|
||||
.Replace("</i>", "{\\i0}")
|
||||
@ -41,319 +60,374 @@ namespace Nikse.SubtitleEdit.Core.Common
|
||||
.Replace("<u>", "{\\u1}")
|
||||
.Replace("</u>", "{\\u0}").Trim();
|
||||
|
||||
|
||||
if (!paragraph.Text.Contains('<'))
|
||||
{
|
||||
paragraph.Text = GetAlignment(paragraph, width, height);
|
||||
continue;
|
||||
}
|
||||
|
||||
var matches = LineTagRegex.Matches(paragraph.Text);
|
||||
if (matches.Count == 1 &&
|
||||
paragraph.Text.StartsWith("<c.", StringComparison.Ordinal) &&
|
||||
if (matches.Count == 1 &&
|
||||
paragraph.Text.StartsWith("<c.", StringComparison.Ordinal) &&
|
||||
paragraph.Text.EndsWith("</c>", StringComparison.Ordinal))
|
||||
{
|
||||
var tag = matches[0].Value.Trim('<', '>', ' ');
|
||||
var tag = matches[0].Value.TrimEnd('>', ' ').Remove(0, 2);
|
||||
if (ssaStyles.Any(p => p.Name == tag))
|
||||
{
|
||||
paragraph.Extra = tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
paragraph.Text = SetInlineStyles(paragraph.Text, tag, ssaStyles);
|
||||
paragraph.Text = paragraph.Text.Remove(matches[0].Index, matches[0].Length);
|
||||
paragraph.Text = paragraph.Text.Replace("</c>", string.Empty);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
paragraph.Text = SetInlineStyles(paragraph.Text, ssaStyles, webVttStyles);
|
||||
|
||||
paragraph.Text = GetAlignment(paragraph, width, height);
|
||||
}
|
||||
|
||||
return assaSubtitle;
|
||||
}
|
||||
|
||||
private static string SetInlineStyles(string paragraphText, string tag, List<SsaStyle> ssaStyles)
|
||||
private static string GetAlignment(Paragraph paragraph, int width, int height)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (string.IsNullOrEmpty(paragraph.Extra) || paragraph.Text.StartsWith("{\\an"))
|
||||
{
|
||||
return paragraph.Text;
|
||||
}
|
||||
|
||||
return GetPositionInfo(paragraph.Style, width, height) + paragraph.Text;
|
||||
}
|
||||
|
||||
internal static string GetPositionInfo(string s, int width, int height)
|
||||
{
|
||||
//position: x --- 0% = left, 100% = right (horizontal)
|
||||
//line: x --- 0 or -16 or 0% = top, 16 or -1 or 100% = bottom (vertical)
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var pos = GetTag(s, "position:");
|
||||
var line = GetTag(s, "line:");
|
||||
var positionInfo = string.Empty;
|
||||
var hAlignLeft = false;
|
||||
var hAlignRight = false;
|
||||
var vAlignTop = false;
|
||||
var vAlignMiddle = false;
|
||||
double number;
|
||||
|
||||
if (!string.IsNullOrEmpty(pos) && pos.EndsWith('%') && double.TryParse(pos.TrimEnd('%'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out number))
|
||||
{
|
||||
x = (int)Math.Round(number * width / 100.0, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(line))
|
||||
{
|
||||
line = line.Trim();
|
||||
if (line.EndsWith('%'))
|
||||
{
|
||||
if (double.TryParse(line.TrimEnd('%'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out number))
|
||||
{
|
||||
y = (int)Math.Round(number * height / 100.0, MidpointRounding.AwayFromZero);
|
||||
if (number < 25)
|
||||
{
|
||||
vAlignTop = true;
|
||||
}
|
||||
else if (number < 75)
|
||||
{
|
||||
vAlignMiddle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (double.TryParse(line, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out number))
|
||||
{
|
||||
if (number >= 0 && number <= 7)
|
||||
{
|
||||
vAlignTop = true; // Positive numbers indicate top down
|
||||
}
|
||||
else if (number > 7 && number < 11)
|
||||
{
|
||||
vAlignMiddle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0 && y > 0)
|
||||
{
|
||||
return "{\\pos(" + x + "," + y + ")}";
|
||||
}
|
||||
|
||||
if (hAlignLeft)
|
||||
{
|
||||
if (vAlignTop)
|
||||
{
|
||||
return "{\\an7}";
|
||||
}
|
||||
|
||||
if (vAlignMiddle)
|
||||
{
|
||||
return "{\\an4}";
|
||||
}
|
||||
|
||||
return "{\\an1}";
|
||||
}
|
||||
|
||||
if (hAlignRight)
|
||||
{
|
||||
if (vAlignTop)
|
||||
{
|
||||
return "{\\an9}";
|
||||
}
|
||||
|
||||
if (vAlignMiddle)
|
||||
{
|
||||
return "{\\an6}";
|
||||
}
|
||||
|
||||
return "{\\an3}";
|
||||
}
|
||||
|
||||
if (vAlignTop)
|
||||
{
|
||||
return "{\\an8}";
|
||||
}
|
||||
|
||||
if (vAlignMiddle)
|
||||
{
|
||||
return "{\\an5}";
|
||||
}
|
||||
|
||||
return positionInfo;
|
||||
}
|
||||
|
||||
private static string GetTag(string s, string tag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(tag))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pos = s.IndexOf(tag, StringComparison.Ordinal);
|
||||
if (pos >= 0)
|
||||
{
|
||||
var v = s.Substring(pos + tag.Length).Trim();
|
||||
var end = v.IndexOf("%,", StringComparison.Ordinal);
|
||||
if (end >= 0)
|
||||
{
|
||||
v = v.Remove(end + 1);
|
||||
}
|
||||
|
||||
end = v.IndexOf(' ');
|
||||
if (end >= 0)
|
||||
{
|
||||
v = v.Remove(end);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string SetInlineStyles(string input, List<SsaStyle> ssaStyles, List<WebVttStyle> webVttStyles)
|
||||
{
|
||||
var allInlineStyles = new List<WebVttStyle>();
|
||||
var start = 0;
|
||||
var sb = new StringBuilder();
|
||||
var webVttStyle = new WebVttStyle();
|
||||
var text = input;
|
||||
var match = LineTagRegexMore.Match(text);
|
||||
while (match.Success)
|
||||
{
|
||||
if (match.Value == "</c>")
|
||||
{
|
||||
if (match.Index > start)
|
||||
{
|
||||
var s = text.Substring(start, Math.Min(text.Length - start, match.Index));
|
||||
sb.Append(s);
|
||||
start = match.Index;
|
||||
|
||||
if (allInlineStyles.Count > 0)
|
||||
{
|
||||
allInlineStyles.RemoveAt(allInlineStyles.Count - 1);
|
||||
|
||||
webVttStyle = new WebVttStyle();
|
||||
foreach (var style in allInlineStyles)
|
||||
{
|
||||
webVttStyle = ApplyStyle(style, webVttStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (match.Value.StartsWith("<c.", StringComparison.Ordinal))
|
||||
{
|
||||
var arr = match.Value.Remove(0, 3).TrimEnd('>').Split('.');
|
||||
foreach (var styleName in arr)
|
||||
{
|
||||
var styleFound = webVttStyles.FirstOrDefault(p => p.Name == "." + styleName);
|
||||
if (styleFound != null)
|
||||
{
|
||||
webVttStyle = ApplyStyle(styleFound, webVttStyle);
|
||||
}
|
||||
else if (styleName == "i")
|
||||
{
|
||||
webVttStyle.Italic = true;
|
||||
}
|
||||
else if (styleName == "b")
|
||||
{
|
||||
webVttStyle.Bold = true;
|
||||
}
|
||||
else if (styleName == "u")
|
||||
{
|
||||
webVttStyle.Underline = true;
|
||||
}
|
||||
else if (WebVTT.DefaultColorClasses.TryGetValue(styleName, out var c))
|
||||
{
|
||||
webVttStyle.Color = c;
|
||||
}
|
||||
}
|
||||
|
||||
allInlineStyles.Add(webVttStyle);
|
||||
sb.Append(WebVttToAssaInline(webVttStyle));
|
||||
}
|
||||
|
||||
text = text.Remove(match.Index, match.Length);
|
||||
match = LineTagRegexMore.Match(text);
|
||||
}
|
||||
|
||||
if (text.Length > start)
|
||||
{
|
||||
sb.Append(text.Substring(start));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string WebVttToAssaInline(WebVttStyle webVttStyle)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("{");
|
||||
|
||||
if (webVttStyle.Color != null)
|
||||
{
|
||||
sb.Append("\\" + AdvancedSubStationAlpha.GetSsaColorStringForEvent(webVttStyle.Color.Value));
|
||||
}
|
||||
|
||||
if (webVttStyle.BackgroundColor != null)
|
||||
{
|
||||
sb.Append("\\" + AdvancedSubStationAlpha.GetSsaColorStringForEvent(webVttStyle.BackgroundColor.Value, "3c"));
|
||||
}
|
||||
|
||||
if (webVttStyle.ShadowColor != null)
|
||||
{
|
||||
sb.Append("\\" + AdvancedSubStationAlpha.GetSsaColorStringForEvent(webVttStyle.ShadowColor.Value, "4c"));
|
||||
}
|
||||
|
||||
if (webVttStyle.ShadowWidth != null)
|
||||
{
|
||||
sb.Append("\\shad" + webVttStyle.ShadowWidth.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
if (webVttStyle.FontName != null)
|
||||
{
|
||||
sb.Append($"\\fn{webVttStyle.FontName}");
|
||||
}
|
||||
|
||||
if (webVttStyle.FontSize != null)
|
||||
{
|
||||
sb.Append($"\\fs{webVttStyle.FontSize}");
|
||||
}
|
||||
|
||||
if (webVttStyle.Italic != null && webVttStyle.Italic == true)
|
||||
{
|
||||
sb.Append("\\i1");
|
||||
}
|
||||
|
||||
if (webVttStyle.Italic != null && webVttStyle.Italic == false)
|
||||
{
|
||||
sb.Append("\\i0");
|
||||
}
|
||||
|
||||
if (webVttStyle.Bold != null && webVttStyle.Bold == true)
|
||||
{
|
||||
sb.Append("\\b1");
|
||||
}
|
||||
|
||||
if (webVttStyle.Bold != null && webVttStyle.Bold == false)
|
||||
{
|
||||
sb.Append("\\b0");
|
||||
}
|
||||
|
||||
if (webVttStyle.Underline != null && webVttStyle.Underline == true)
|
||||
{
|
||||
sb.Append("\\u1");
|
||||
}
|
||||
|
||||
if (webVttStyle.Underline != null && webVttStyle.Underline == false)
|
||||
{
|
||||
sb.Append("\\u0");
|
||||
}
|
||||
|
||||
sb.Append("}");
|
||||
|
||||
if (sb.Length > 2)
|
||||
{
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static WebVttStyle ApplyStyle(WebVttStyle style, WebVttStyle defaultStyle)
|
||||
{
|
||||
return new WebVttStyle
|
||||
{
|
||||
BackgroundColor = style.BackgroundColor ?? defaultStyle.BackgroundColor,
|
||||
Bold = style.Bold ?? defaultStyle.Bold,
|
||||
Italic = style.Italic ?? defaultStyle.Italic,
|
||||
Underline = style.Underline ?? defaultStyle.Underline,
|
||||
FontName = style.FontName ?? defaultStyle.FontName,
|
||||
FontSize = style.FontSize ?? defaultStyle.FontSize,
|
||||
Color = style.Color ?? defaultStyle.Color,
|
||||
ShadowColor = style.ShadowColor ?? defaultStyle.ShadowColor,
|
||||
ShadowWidth = style.ShadowWidth ?? defaultStyle.ShadowWidth,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<SsaStyle> ConvertStyles(List<WebVttStyle> styles, SsaStyle defaultStyle)
|
||||
{
|
||||
var result = new List<SsaStyle>();
|
||||
defaultStyle.Name = "Default";
|
||||
result.Add(defaultStyle);
|
||||
;
|
||||
foreach (var style in styles)
|
||||
{
|
||||
result.Add(new SsaStyle(new SsaStyle
|
||||
var newStyle = new SsaStyle
|
||||
{
|
||||
BorderStyle = "3", // box per line (bg color is outline)
|
||||
Name = style.Name,
|
||||
FontName = style.FontName ?? defaultStyle.FontName,
|
||||
FontSize = style.FontSize ?? defaultStyle.FontSize,
|
||||
Primary = style.Color ?? defaultStyle.Primary,
|
||||
Background = style.BackgroundColor ?? defaultStyle.Background,
|
||||
Outline = style.BackgroundColor ?? defaultStyle.Outline,
|
||||
Bold = style.Bold ?? defaultStyle.Bold,
|
||||
Italic = style.Italic ?? defaultStyle.Italic,
|
||||
Underline = style.Underline ?? defaultStyle.Underline,
|
||||
ShadowWidth = style.ShadowWidth ?? defaultStyle.ShadowWidth,
|
||||
OutlineWidth = style.ShadowWidth ?? defaultStyle.OutlineWidth,
|
||||
Outline = style.ShadowColor ?? defaultStyle.Outline,
|
||||
}));
|
||||
Secondary = style.ShadowColor ?? defaultStyle.Secondary,
|
||||
};
|
||||
|
||||
if (newStyle.Outline.A == 0 && style.BackgroundColor.HasValue)
|
||||
{
|
||||
newStyle.Background = newStyle.Outline;
|
||||
}
|
||||
|
||||
result.Add(newStyle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public class WebVttStyle
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string FontName { get; set; }
|
||||
public decimal? FontSize { get; set; }
|
||||
public Color? Color { get; set; }
|
||||
public Color? BackgroundColor { get; set; }
|
||||
public bool? Italic { get; set; }
|
||||
public bool? Bold { get; set; }
|
||||
public int? ShadowWidth { get; set; }
|
||||
public Color? ShadowColor { get; set; }
|
||||
}
|
||||
|
||||
private static List<WebVttStyle> GetStyles(Subtitle webVttSubtitle)
|
||||
{
|
||||
if (string.IsNullOrEmpty(webVttSubtitle.Header))
|
||||
{
|
||||
return new List<WebVttStyle>();
|
||||
}
|
||||
|
||||
var cueOn = false;
|
||||
var styleOn = false;
|
||||
var result = new List<WebVttStyle>();
|
||||
var currentStyle = new StringBuilder();
|
||||
foreach (var line in webVttSubtitle.Header.SplitToLines())
|
||||
{
|
||||
var s = line.Trim();
|
||||
if (styleOn)
|
||||
{
|
||||
if (s == string.Empty)
|
||||
{
|
||||
styleOn = false;
|
||||
AddStyle(result, currentStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cueOn && s.StartsWith("::cue(", StringComparison.Ordinal))
|
||||
{
|
||||
AddStyle(result, currentStyle);
|
||||
currentStyle = new StringBuilder();
|
||||
}
|
||||
|
||||
if (s.StartsWith("::cue(", StringComparison.Ordinal))
|
||||
{
|
||||
currentStyle.AppendLine(s);
|
||||
cueOn = true;
|
||||
}
|
||||
else if (cueOn)
|
||||
{
|
||||
currentStyle.AppendLine(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (s.Equals("STYLE", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
styleOn = true;
|
||||
}
|
||||
}
|
||||
|
||||
AddStyle(result, currentStyle);
|
||||
|
||||
return result;
|
||||
|
||||
// https://www.w3.org/TR/webvtt1/
|
||||
//STYLE
|
||||
//::cue {
|
||||
// background-image: linear-gradient(to bottom, dimgray, lightgray);
|
||||
// color: papayawhip;
|
||||
// }
|
||||
// /* Style blocks cannot use blank lines nor "dash dash greater than" */
|
||||
|
||||
// NOTE comment blocks can be used between style blocks.
|
||||
|
||||
// STYLE
|
||||
// ::cue(b) {
|
||||
// color: peachpuff;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private static void AddStyle(List<WebVttStyle> result, StringBuilder currentStyle)
|
||||
{
|
||||
var text = currentStyle
|
||||
.ToString()
|
||||
.Replace(Environment.NewLine, " ");
|
||||
var match = NameRegex.Match(text);
|
||||
if (!match.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = match.Value.Trim('(',')',' ');
|
||||
|
||||
match = PropertiesRegex.Match(text);
|
||||
if (!match.Success || string.IsNullOrWhiteSpace(match.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var properties = match.Value
|
||||
.Trim('{', '}', ' ')
|
||||
.RemoveChar('\r', '\n')
|
||||
.Split(';');
|
||||
|
||||
var webVttStyle = new WebVttStyle { Name = name };
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
SetProperty(webVttStyle, prop);
|
||||
}
|
||||
|
||||
result.Add(webVttStyle);
|
||||
}
|
||||
|
||||
private static void SetProperty(WebVttStyle webVttStyle, string prop)
|
||||
{
|
||||
var arr = prop.Split(':');
|
||||
if (arr.Length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = arr[0].Trim();
|
||||
var value = arr[1].Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "color")
|
||||
{
|
||||
SetColor(webVttStyle, value);
|
||||
}
|
||||
else if (name == "background-color")
|
||||
{
|
||||
SetBackgroundColor(webVttStyle, value);
|
||||
}
|
||||
else if (name == "font-family")
|
||||
{
|
||||
webVttStyle.FontName = value;
|
||||
}
|
||||
else if (name == "font-style")
|
||||
{
|
||||
SetFontStyle(webVttStyle, value);
|
||||
}
|
||||
else if (name == "font-weight")
|
||||
{
|
||||
SetFontWeight(webVttStyle, value);
|
||||
}
|
||||
else if (name == "text-shadow")
|
||||
{
|
||||
SetTextShadow(webVttStyle, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetColor(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
var color = GetColorFromString(value, Color.Transparent);
|
||||
if (color == Color.Transparent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
webVttStyle.Color = color;
|
||||
}
|
||||
|
||||
private static Color GetColorFromString(string s, Color defaultColor)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (s.StartsWith("rgb(", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var arr = s
|
||||
.RemoveChar(' ')
|
||||
.Remove(0, 4)
|
||||
.TrimEnd(')')
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
return Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
|
||||
}
|
||||
|
||||
if (s.StartsWith("rgba(", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var arr = s
|
||||
.RemoveChar(' ')
|
||||
.Remove(0, 5)
|
||||
.TrimEnd(')')
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var alpha = byte.MaxValue;
|
||||
if (arr.Length == 4 && float.TryParse(arr[3], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var f))
|
||||
{
|
||||
if (f >= 0 && f < 1)
|
||||
{
|
||||
alpha = (byte)(f * byte.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
return Color.FromArgb(alpha, int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
|
||||
}
|
||||
|
||||
return ColorTranslator.FromHtml(s);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetBackgroundColor(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
var color = GetColorFromString(value, Color.Transparent);
|
||||
if (color == Color.Transparent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
webVttStyle.BackgroundColor = color;
|
||||
}
|
||||
|
||||
private static void SetFontWeight(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
if (value == "bold" || value == "bolder")
|
||||
{
|
||||
webVttStyle.Bold = true;
|
||||
}
|
||||
else if (value == "normal")
|
||||
{
|
||||
webVttStyle.Bold = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetFontStyle(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
if (value == "italic" || value == "oblique")
|
||||
{
|
||||
webVttStyle.Italic = true;
|
||||
}
|
||||
else if (value == "normal")
|
||||
{
|
||||
webVttStyle.Italic = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetTextShadow(WebVttStyle webVttStyle, string value)
|
||||
{
|
||||
// text-shadow: #101010 3px;
|
||||
|
||||
var arr = value.Split();
|
||||
if (arr.Length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var color = GetColorFromString(arr[0], Color.Transparent);
|
||||
if (color == Color.Transparent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(arr[1].Replace("px", string.Empty),out var number))
|
||||
{
|
||||
webVttStyle.ShadowColor = color;
|
||||
webVttStyle.ShadowWidth = number;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2032,15 +2032,29 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"
|
||||
return $"&H{255 - c.A:X2}{c.B:X2}{c.G:X2}{c.R:X2}"; // ASS stores alpha in reverse (0=full intensity and 255=fully transparent)
|
||||
}
|
||||
|
||||
public static string GetSsaColorStringForEvent(Color c)
|
||||
public static string GetSsaColorStringForEvent(Color c, string tag = "c")
|
||||
{
|
||||
if (c.A >= 255)
|
||||
{
|
||||
return $"c&H{c.B:X2}{c.G:X2}{c.R:X2}";
|
||||
return $"{tag}&H{c.B:X2}{c.G:X2}{c.R:X2}";
|
||||
}
|
||||
|
||||
var alphaName = "alpha";
|
||||
if (tag == "2c")
|
||||
{
|
||||
alphaName = "2a";
|
||||
}
|
||||
else if (tag == "3c")
|
||||
{
|
||||
alphaName = "3a";
|
||||
}
|
||||
else if (tag == "4c")
|
||||
{
|
||||
alphaName = "4a";
|
||||
}
|
||||
|
||||
var alpha = 255 - c.A; // ASS stores alpha in reverse (0=full intensity and 255=fully transparent)
|
||||
return $"alpha&H{alpha:X2}&\\c&H{c.B:X2}{c.G:X2}{c.R:X2}";
|
||||
return $"{alphaName}&H{alpha:X2}&\\{tag}&H{c.B:X2}{c.G:X2}{c.R:X2}";
|
||||
}
|
||||
|
||||
public static string GetSsaColorStringNoTransparency(Color c) => $"&H{c.B:X2}{c.G:X2}{c.R:X2}";
|
||||
|
@ -18,7 +18,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
private static readonly Regex RegexTimeCodesMiddle = new Regex(@"^-?\d+:-?\d+\.-?\d+\s*-->\s*-?\d+:-?\d+:-?\d+\.-?\d+", RegexOptions.Compiled);
|
||||
private static readonly Regex RegexTimeCodesShort = new Regex(@"^-?\d+:-?\d+\.-?\d+\s*-->\s*-?\d+:-?\d+\.-?\d+", RegexOptions.Compiled);
|
||||
|
||||
private static readonly Dictionary<string, Color> DefaultColorClasses = new Dictionary<string, Color>
|
||||
public static readonly Dictionary<string, Color> DefaultColorClasses = new Dictionary<string, Color>
|
||||
{
|
||||
{
|
||||
"white", Color.FromArgb(255, 255, 255)
|
||||
@ -52,7 +52,8 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
|
||||
public override List<string> AlternateExtensions => new List<string> { ".webvtt" };
|
||||
|
||||
public override string Name => "WebVTT";
|
||||
public const string NameOfFormat = "WebVTT";
|
||||
public override string Name => NameOfFormat;
|
||||
|
||||
public override string ToText(Subtitle subtitle, string title)
|
||||
{
|
||||
@ -80,11 +81,6 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
var style = string.Empty;
|
||||
if (subtitle.Header != null && subtitle.Header.StartsWith("WEBVTT", StringComparison.Ordinal))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(p.Extra))
|
||||
{
|
||||
style = p.Extra;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(p.Region))
|
||||
{
|
||||
positionInfo = $" region:{p.Region} {positionInfo}".Replace(" ", " ").TrimEnd();
|
||||
@ -295,6 +291,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
p.EndTime.TotalMilliseconds += addSeconds * 1000;
|
||||
|
||||
positionInfo = GetPositionInfo(s);
|
||||
p.Style = GetPositionInfoRaw(s);
|
||||
p.Region = GetRegion(s);
|
||||
}
|
||||
catch (Exception exception)
|
||||
@ -352,7 +349,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
|
||||
foreach (var paragraph in subtitle.Paragraphs)
|
||||
{
|
||||
paragraph.Text = ColorWebVttToHtml(paragraph.Text);
|
||||
// paragraph.Text = ColorWebVttToHtml(paragraph.Text);
|
||||
paragraph.Text = EscapeDecodeText(paragraph.Text);
|
||||
paragraph.Text = RemoveWeirdRepeatingHeader(paragraph.Text);
|
||||
}
|
||||
@ -564,6 +561,44 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
return positionInfo;
|
||||
}
|
||||
|
||||
internal static string GetPositionInfoRaw(string s)
|
||||
{
|
||||
//line: 72.69 % align:left position:44.90 % size:10.21 %
|
||||
var list = new List<int>();
|
||||
|
||||
var idx = s.IndexOf("line:", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
list.Add(idx);
|
||||
}
|
||||
|
||||
idx = s.IndexOf("align:", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
list.Add(idx);
|
||||
}
|
||||
|
||||
idx = s.IndexOf("position:", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
list.Add(idx);
|
||||
}
|
||||
|
||||
idx = s.IndexOf("size:", StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
list.Add(idx);
|
||||
}
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return s.Substring(list.Min(p=>p));
|
||||
}
|
||||
|
||||
|
||||
internal static string GetRegion(string s)
|
||||
{
|
||||
var region = GetTag(s, "region:");
|
||||
@ -711,7 +746,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
return styleList;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetCueStyles(string header)
|
||||
private static Dictionary<string, string> GetCueStyles(string header)
|
||||
{
|
||||
var dic = new Dictionary<string, string>();
|
||||
|
||||
|
@ -17,7 +17,8 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
|
||||
public override string Extension => ".vtt";
|
||||
|
||||
public override string Name => "WebVTT File with#";
|
||||
public const string NameOfFormat = "WebVTT File with#";
|
||||
public override string Name => NameOfFormat;
|
||||
|
||||
public override string ToText(Subtitle subtitle, string title)
|
||||
{
|
||||
@ -112,6 +113,8 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
||||
EndTime = WebVTT.GetTimeCodeFromString(parts[1])
|
||||
};
|
||||
positionInfo = WebVTT.GetPositionInfo(s);
|
||||
p.Extra = WebVTT.GetPositionInfoRaw(s);
|
||||
p.Region = WebVTT.GetRegion(s);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -55,8 +55,6 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
|
||||
public float FontSizeFactor { get; set; }
|
||||
|
||||
private readonly List<string> _allowedMpvNativePreviewFormats = new List<string>();
|
||||
|
||||
public VideoPlayer VideoPlayer
|
||||
{
|
||||
get => _videoPlayer;
|
||||
@ -235,11 +233,6 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
PictureBoxFastForwardOverMouseLeave(null, null);
|
||||
|
||||
_labelTimeCode.Click += LabelTimeCodeClick;
|
||||
|
||||
if (Configuration.Settings.General.MpvAllowNativePreview != null)
|
||||
{
|
||||
_allowedMpvNativePreviewFormats = Configuration.Settings.General.MpvAllowNativePreview.Split(';').ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _showDuration = true;
|
||||
@ -413,7 +406,14 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
public void UpdateMpvStyle()
|
||||
{
|
||||
var gs = Configuration.Settings.General;
|
||||
var mpvStyle = new SsaStyle
|
||||
var mpvStyle = GetMpvPreviewStyle(gs);
|
||||
|
||||
MpvPreviewStyleHeader = string.Format(AdvancedSubStationAlpha.HeaderNoStyles, "MPV preview file", mpvStyle.ToRawAss(SsaStyle.DefaultAssStyleFormat));
|
||||
}
|
||||
|
||||
private static SsaStyle GetMpvPreviewStyle(GeneralSettings gs)
|
||||
{
|
||||
return new SsaStyle
|
||||
{
|
||||
Name = "Default",
|
||||
FontName = gs.VideoPlayerPreviewFontName,
|
||||
@ -428,8 +428,6 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
Alignment = gs.MpvPreviewTextAlignment,
|
||||
MarginVertical = gs.MpvPreviewTextMarginVertical
|
||||
};
|
||||
|
||||
MpvPreviewStyleHeader = string.Format(AdvancedSubStationAlpha.HeaderNoStyles, "MPV preview file", mpvStyle.ToRawAss(SsaStyle.DefaultAssStyleFormat));
|
||||
}
|
||||
|
||||
private string _mpvPreviewStyleHeader;
|
||||
@ -478,6 +476,16 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
{
|
||||
text = NetflixImsc11JapaneseToAss.Convert(subtitle, 1280, 720);
|
||||
}
|
||||
else if (uiFormat.Name == WebVTT.NameOfFormat || uiFormat.Name == WebVTTFileWithLineNumber.NameOfFormat)
|
||||
{
|
||||
var defaultStyle = GetMpvPreviewStyle(Configuration.Settings.General);
|
||||
defaultStyle.BorderStyle = "3";
|
||||
subtitle = new Subtitle(subtitle);
|
||||
subtitle = WebVttToAssa.Convert(subtitle, defaultStyle, VideoWidth, VideoHeight);
|
||||
format = new AdvancedSubStationAlpha();
|
||||
text = subtitle.ToText(format);
|
||||
// File.WriteAllText(@"c:\data\__a.ass", text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subtitle.Header == null || !subtitle.Header.Contains("[V4+ Styles]") || uiFormat.Name != AdvancedSubStationAlpha.NameOfFormat)
|
||||
@ -527,11 +535,6 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
}
|
||||
}
|
||||
|
||||
if (_allowedMpvNativePreviewFormats.Contains(uiFormat.Name))
|
||||
{
|
||||
format = uiFormat;
|
||||
}
|
||||
|
||||
var hash = subtitle.GetFastHashCode(null);
|
||||
if (hash != _mpvSubOldHash || string.IsNullOrEmpty(_mpvTextOld))
|
||||
{
|
||||
|
@ -13734,13 +13734,23 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
private void SetColor(string color, bool selectedText = false, bool allowRemove = true)
|
||||
{
|
||||
var isAssa = IsAssa();
|
||||
var format = GetCurrentSubtitleFormat();
|
||||
var isAssa = format.GetType() == typeof(AdvancedSubStationAlpha);
|
||||
var isWebVtt = format.Name == WebVTT.NameOfFormat || format.Name == WebVTTFileWithLineNumber.NameOfFormat;
|
||||
var c = ColorTranslator.FromHtml(color);
|
||||
|
||||
if (selectedText)
|
||||
{
|
||||
SetSelectedTextColor(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
var webVttStyles = new List<WebVttStyle>();
|
||||
if (isWebVtt)
|
||||
{
|
||||
webVttStyles = WebVttHelper.GetStyles(_subtitle);
|
||||
}
|
||||
|
||||
MakeHistoryForUndo(_language.BeforeSettingColor);
|
||||
var remove = allowRemove;
|
||||
var removeOriginal = allowRemove;
|
||||
@ -13748,15 +13758,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
var assaColor = string.Empty;
|
||||
if (isAssa)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = ColorTranslator.FromHtml(color);
|
||||
assaColor = AdvancedSubStationAlpha.GetSsaColorStringForEvent(c);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
assaColor = AdvancedSubStationAlpha.GetSsaColorStringForEvent(c);
|
||||
}
|
||||
|
||||
foreach (ListViewItem item in SubtitleListview1.SelectedItems)
|
||||
@ -13772,6 +13774,21 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (isWebVtt)
|
||||
{
|
||||
foreach (var style in webVttStyles)
|
||||
{
|
||||
if (style.Color == c && p.Text.Contains("." + style.Name))
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = Utilities.RemoveSsaTags(p.Text);
|
||||
@ -13822,6 +13839,10 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
{
|
||||
p.Text = RemoveAssaColor(p.Text);
|
||||
}
|
||||
else if (isWebVtt)
|
||||
{
|
||||
p.Text = WebVttHelper.RemoveColorTag(p.Text, c, webVttStyles);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Text = HtmlUtil.RemoveOpenCloseTags(p.Text, HtmlUtil.TagFont);
|
||||
@ -13829,7 +13850,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
}
|
||||
else
|
||||
{
|
||||
SetParagraphFontColor(p, color, isAssa);
|
||||
SetParagraphFontColor(_subtitle, p, color, isAssa, isWebVtt, webVttStyles);
|
||||
}
|
||||
|
||||
SubtitleListview1.SetText(item.Index, p.Text);
|
||||
@ -13841,11 +13862,18 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
{
|
||||
if (removeOriginal)
|
||||
{
|
||||
original.Text = HtmlUtil.RemoveOpenCloseTags(original.Text, HtmlUtil.TagFont);
|
||||
if (isWebVtt)
|
||||
{
|
||||
original.Text = WebVttHelper.RemoveColorTag(original.Text, c, webVttStyles);
|
||||
}
|
||||
else
|
||||
{
|
||||
original.Text = HtmlUtil.RemoveOpenCloseTags(original.Text, HtmlUtil.TagFont);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetParagraphFontColor(original, color);
|
||||
SetParagraphFontColor(_subtitleOriginal, original, color);
|
||||
}
|
||||
|
||||
SubtitleListview1.SetOriginalText(item.Index, original.Text);
|
||||
@ -13876,6 +13904,8 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
int selectionStart = tb.SelectionStart;
|
||||
|
||||
var format = GetCurrentSubtitleFormat();
|
||||
|
||||
if (IsAssa())
|
||||
{
|
||||
var c = ColorTranslator.FromHtml(color);
|
||||
@ -13897,6 +13927,36 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
tb.SelectedText = text;
|
||||
tb.SelectionStart = selectionStart;
|
||||
tb.SelectionLength = text.Length;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (format.Name == WebVTT.NameOfFormat || format.Name == WebVTTFileWithLineNumber.NameOfFormat)
|
||||
{
|
||||
var c = ColorTranslator.FromHtml(color);
|
||||
WebVttStyle styleWithColor = WebVttHelper.GetStyleFromColor(c, _subtitle);
|
||||
if (styleWithColor == null)
|
||||
{
|
||||
styleWithColor = WebVttHelper.AddStyleFromColor(c);
|
||||
_subtitle.Header = WebVttHelper.AddStyleToHeader(_subtitle.Header, styleWithColor);
|
||||
}
|
||||
|
||||
if (text.StartsWith("<c.", StringComparison.Ordinal))
|
||||
{
|
||||
var indexOfEndTag = text.IndexOf('>');
|
||||
if (indexOfEndTag > 0)
|
||||
{
|
||||
text = text.Insert(indexOfEndTag, "." + styleWithColor.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = "<c." + styleWithColor.Name + ">" + text + "</c>";
|
||||
}
|
||||
|
||||
tb.SelectedText = text;
|
||||
tb.SelectionStart = selectionStart;
|
||||
tb.SelectionLength = text.Length;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13962,7 +14022,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
tb.SelectionLength = text.Length;
|
||||
}
|
||||
|
||||
private void SetParagraphFontColor(Paragraph p, string color, bool isAssa = false)
|
||||
private void SetParagraphFontColor(Subtitle subtitle, Paragraph p, string color, bool isAssa = false, bool isWebVtt = false, List<WebVttStyle> webVttStyles = null)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
@ -13985,6 +14045,23 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
if (isWebVtt)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = ColorTranslator.FromHtml(color);
|
||||
var styleWithColor = WebVttHelper.AddStyleFromColor(c);
|
||||
subtitle.Header = WebVttHelper.AddStyleToHeader(_subtitle.Header, styleWithColor);
|
||||
WebVttHelper.AddStyleToText(p.Text, styleWithColor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string pre = string.Empty;
|
||||
if (p.Text.StartsWith("{\\", StringComparison.Ordinal) && p.Text.IndexOf('}') >= 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user