private AssStyle GetStyleMatchingStructure(AssSection section) { HashSet <ShadowType> sectionShadowTypes = section.ShadowColors.Keys.ToHashSet(); foreach (AssStyle style in _styles.Values) { AssStyleOptions options = GetStyleOptions(style); if (style.HasOutlineBox != (section.BackColor.A > 0)) { continue; } HashSet <ShadowType> styleShadowTypes = new HashSet <ShadowType>(); if (style.HasOutline && !style.OutlineIsBox) { styleShadowTypes.Add(ShadowType.Glow); } if (options != null) { styleShadowTypes.UnionWith(options.ShadowTypes); } if (!styleShadowTypes.SetEquals(sectionShadowTypes)) { continue; } return(style); } return(null); }
private static string GetBackgroundImageUrl(AssStyleOptions options) { byte[] imageData; string mimeType; if (options?.HasExistingBackgroundImage ?? false) { try { imageData = File.ReadAllBytes(options.BackgroundImagePath); mimeType = ExtensionToMimeType.GetOrDefault(Path.GetExtension(options.BackgroundImagePath).ToLower()) ?? "image/png"; } catch { imageData = Resources.Checkers; mimeType = "image/png"; } } else { imageData = Resources.Checkers; mimeType = "image/png"; } return($"data:{mimeType};base64,{Convert.ToBase64String(imageData)}"); }
private void _lstStyles_SelectedIndexChanged(object sender, EventArgs e) { AssStyleOptions options = SelectedStyleOptions; if (options == null) { _spltStyleOptions.Panel2.Enabled = false; _brwPreview.DocumentText = string.Empty; return; } AssStyle style = _styles[options.Name]; _previewSuspended = true; _spltStyleOptions.Panel2.Enabled = true; _pnlOptions.Enabled = !_builtinStyleNames.Contains(style.Name); _pnlShadowType.Enabled = style.HasShadow; if (style.HasOutline && !style.HasOutlineBox) { _chkGlow.Checked = true; _chkGlow.Enabled = false; } else { _chkGlow.Checked = style.HasShadow && options.ShadowTypes.Contains(ShadowType.Glow); _chkGlow.Enabled = true; } _chkBevel.Checked = style.HasShadow && options.ShadowTypes.Contains(ShadowType.Bevel); _chkSoftShadow.Checked = style.HasShadow && options.ShadowTypes.Contains(ShadowType.SoftShadow); _chkHardShadow.Checked = style.HasShadow && options.ShadowTypes.Contains(ShadowType.HardShadow); Color currentWordTextColor = options.CurrentWordTextColor; Color currentWordOutlineColor = options.CurrentWordOutlineColor; Color currentWordShadowColor = options.CurrentWordShadowColor; _chkKaraoke.Checked = options.IsKaraoke; _chkHighlightCurrentWord.Checked = !currentWordTextColor.IsEmpty; _txtCurrentWordTextColor.Enabled = _chkHighlightCurrentWord.Checked; _txtCurrentWordTextColor.Text = _txtCurrentWordTextColor.Enabled ? ColorUtil.ToHtml(currentWordTextColor) : string.Empty; _btnPickTextColor.Enabled = _txtCurrentWordTextColor.Enabled; _txtCurrentWordOutlineColor.Enabled = _chkHighlightCurrentWord.Checked && style.HasOutline && !style.HasOutlineBox; _txtCurrentWordOutlineColor.Text = _txtCurrentWordOutlineColor.Enabled ? ColorUtil.ToHtml(currentWordOutlineColor) : string.Empty; _btnPickOutlineColor.Enabled = _txtCurrentWordOutlineColor.Enabled; _txtCurrentWordShadowColor.Enabled = _chkHighlightCurrentWord.Checked && style.HasShadow; _txtCurrentWordShadowColor.Text = _txtCurrentWordShadowColor.Enabled ? ColorUtil.ToHtml(currentWordShadowColor) : string.Empty; _btnPickShadowColor.Enabled = _txtCurrentWordShadowColor.Enabled; UpdateBackgroundImageButton(); _previewSuspended = false; UpdateStylePreview(); }
internal void ApplyStyle(AssSection section, AssStyle style, AssStyleOptions options) { section.Font = style.Font; section.Scale = style.LineHeight / DefaultStyle.LineHeight; section.Bold = style.Bold; section.Italic = style.Italic; section.Underline = style.Underline; section.ForeColor = style.PrimaryColor; section.SecondaryColor = style.SecondaryColor; if (options?.IsKaraoke ?? false) { section.CurrentWordForeColor = options.CurrentWordTextColor; section.CurrentWordOutlineColor = options.CurrentWordOutlineColor; section.CurrentWordShadowColor = options.CurrentWordShadowColor; } else { section.CurrentWordForeColor = Color.Empty; section.CurrentWordOutlineColor = Color.Empty; section.CurrentWordShadowColor = Color.Empty; } section.BackColor = Color.Empty; section.ShadowColors.Clear(); if (style.HasShadow) { foreach (ShadowType shadowType in options?.ShadowTypes ?? new List <ShadowType> { ShadowType.SoftShadow }) { section.ShadowColors[shadowType] = style.ShadowColor; } } if (style.HasOutline) { if (style.OutlineIsBox) { section.BackColor = style.OutlineColor; } else { section.ShadowColors[ShadowType.Glow] = style.OutlineColor; } } section.Blur = 0; }
private List <AssLine> ParseLine(AssDialogue dialogue, AssStyle style, AssStyleOptions styleOptions) { AssLine line = new AssLine( TimeUtil.RoundTimeToFrameCenter(dialogue.Start), TimeUtil.RoundTimeToFrameCenter(dialogue.End) ) { AnchorPoint = style.AnchorPoint }; string[] effects = dialogue.Effect.Split(';'); if (effects.Contains(EffectNames.NoAndroidDarkTextHack)) { line.AndroidDarkTextHackAllowed = false; } AssTagContext context = new AssTagContext { Document = this, InitialStyle = style, InitialStyleOptions = styleOptions, Style = style, StyleOptions = styleOptions, Line = line, Section = new AssSection() }; ApplyStyle(context.Section, style, styleOptions); CreateTagSections(line, dialogue.Text, context); CreateRubySections(line); List <AssLine> lines = new List <AssLine> { line }; foreach (AssTagContext.PostProcessor postProcessor in context.PostProcessors) { List <AssLine> extraLines = postProcessor(); if (extraLines != null) { lines.AddRange(extraLines); } } return(lines); }
private static string GetVerticalAlign(AssStyle style, AssStyleOptions options) { if (!(options?.HasExistingBackgroundImage ?? false)) { return("middle"); } if (AnchorPointUtil.IsTopAligned(style.AnchorPoint)) { return("top"); } if (AnchorPointUtil.IsBottomAligned(style.AnchorPoint)) { return("bottom"); } return("middle"); }
private static string GetTextAlign(AssStyle style, AssStyleOptions options) { if (!(options?.HasExistingBackgroundImage ?? false)) { return("center"); } if (AnchorPointUtil.IsLeftAligned(style.AnchorPoint)) { return("left"); } if (AnchorPointUtil.IsRightAligned(style.AnchorPoint)) { return("right"); } return("center"); }
public AssDocument(string filePath, List <AssStyleOptions> styleOptions = null) { RegisterTagHandlers(); Dictionary <string, AssDocumentSection> fileSections = ReadDocument(filePath); AssDocumentSection infoSection = fileSections["Script Info"]; VideoDimensions = new Size(infoSection.GetItemInt("PlayResX", 384), infoSection.GetItemInt("PlayResY", 288)); _styles = fileSections["V4+ Styles"].MapItems("Style", i => new AssStyle(i)) .ToDictionary(s => s.Name); if (styleOptions != null) { _styleOptions = styleOptions.ToDictionary(o => o.Name); } DefaultFontSize = (_styles.GetOrDefault("Default") ?? _styles.First().Value).FontSize; foreach (AssDialogue dialogue in fileSections["Events"].MapItems("Dialogue", i => new AssDialogue(i))) { AssStyle style = GetStyle(dialogue.Style); if (style == null) { throw new Exception($"Line \"{dialogue.Text}\" refers to style \"{dialogue.Style}\" which doesn't exist."); } AssStyleOptions options = GetStyleOptions(dialogue.Style); List <AssLine> lines = ParseLine(dialogue, style, options); Lines.AddRange(lines.SelectMany(ExpandLine)); } EmulateKaraokeForSimultaneousLines(); foreach (AssLine line in Lines) { MergeIdenticallyFormattedSections(line); line.NormalizeAlpha(); } }
private void _btnBackgroundImage_Click(object sender, EventArgs e) { AssStyleOptions options = SelectedStyleOptions; if (options.HasExistingBackgroundImage) { options.BackgroundImagePath = null; } else { if (_dlgOpenImage.ShowDialog() != DialogResult.OK) { return; } options.BackgroundImagePath = _dlgOpenImage.FileName; } UpdateBackgroundImageButton(); UpdateStylePreview(); }
private List <AssLine> ParseLine(AssDialogue dialogue, AssStyle style, AssStyleOptions styleOptions) { DateTime startTime = TimeUtil.SnapTimeToFrame(dialogue.Start.AddMilliseconds(32)); DateTime endTime = TimeUtil.SnapTimeToFrame(dialogue.End).AddMilliseconds(32); AssLine line = new AssLine(startTime, endTime) { AnchorPoint = style.AnchorPoint, KaraokeType = SimpleKaraokeType }; AssTagContext context = new AssTagContext { Document = this, InitialStyle = style, InitialStyleOptions = styleOptions, Style = style, StyleOptions = styleOptions, Line = line, Section = new AssSection(null) }; ApplyStyle(context.Section, style, styleOptions); CreateTagSections(line, dialogue.Text, context); CreateRubySections(line); List <AssLine> lines = new List <AssLine> { line }; foreach (AssTagContext.PostProcessor postProcessor in context.PostProcessors) { List <AssLine> extraLines = postProcessor(); if (extraLines != null) { lines.AddRange(extraLines); } } return(lines); }
public static string GenerateHtml(AssStyle style, AssStyleOptions options, AssStyle defaultStyle, float windowsScaleFactor) { StringBuilder html = new StringBuilder(); html.Append($@" <!DOCTYPE html> <html> <head> <meta http-equiv=""X-UA-Compatible"" content=""IE=edge"" /> <style> html, body {{ width: 100%; height: 100%; padding: 0; margin: 0; cursor: default; }} body {{ display: table; background-image: url({GetBackgroundImageUrl(options)}); background-position: {GetBackgroundImagePosition(options)}; background-repeat: {GetBackgroundImageRepeat(options)}; -ms-user-select: none; }} #wrapper {{ display: table-cell; height: 100%; padding: 10px; text-align: {GetTextAlign(style, options)}; vertical-align: {GetVerticalAlign(style, options)}; }} "); if (options != null) { GenerateBackgroundCss(html, "#background", style, defaultStyle, windowsScaleFactor); GenerateForegroundCss(html, "#regular", style, style.PrimaryColor, style.OutlineColor, style.ShadowColor, options.ShadowTypes); if (options.IsKaraoke) { GenerateForegroundCss( html, "#singing", style, !options.CurrentWordTextColor.IsEmpty ? options.CurrentWordTextColor : style.PrimaryColor, !options.CurrentWordOutlineColor.IsEmpty ? options.CurrentWordOutlineColor : style.OutlineColor, !options.CurrentWordShadowColor.IsEmpty ? options.CurrentWordShadowColor : style.ShadowColor, options.ShadowTypes ); GenerateForegroundCss(html, "#unsung", style, style.SecondaryColor, style.OutlineColor, style.ShadowColor, options.ShadowTypes); } } html.Append(@" </style> </head> <body> <div id=""wrapper""> "); if (options != null) { html.Append(@"<span id=""background"">"); if (options.IsKaraoke) { html.Append($@"<span id=""regular"">{Resources.PreviewSampleKaraoke1}</span>"); html.Append($@"<span id=""singing"">{Resources.PreviewSampleKaraoke2}</span>"); html.Append($@"<span id=""unsung"">{Resources.PreviewSampleKaraoke3}</span>"); } else { html.Append($@"<span id=""regular"">{Resources.PreviewSampleRegular}</span>"); } html.Append(@"</span>"); } html.Append(@" </div> </body> </html> "); return(html.ToString()); }
private static string GetBackgroundImageRepeat(AssStyleOptions options) { return(options?.HasExistingBackgroundImage ?? false ? "no-repeat" : "repeat"); }
private static string GetBackgroundImagePosition(AssStyleOptions options) { return(options?.HasExistingBackgroundImage ?? false ? "center center" : "left top"); }
private List <AssLine> ParseLine(AssDialogue dialogue, AssStyle style, AssStyleOptions styleOptions) { DateTime startTime = TimeUtil.SnapTimeToFrame(dialogue.Start.AddMilliseconds(32)); DateTime endTime = TimeUtil.SnapTimeToFrame(dialogue.End).AddMilliseconds(32); AssLine line = new AssLine(startTime, endTime) { AnchorPoint = style.AnchorPoint }; AssTagContext context = new AssTagContext { Document = this, Dialogue = dialogue, InitialStyle = style, InitialStyleOptions = styleOptions, Style = style, StyleOptions = styleOptions, Line = line, Section = new AssSection(null) }; ApplyStyle(context.Section, style, styleOptions); string text = Regex.Replace(dialogue.Text, @"(?:\\N)+$", ""); int start = 0; foreach (Match match in Regex.Matches(text, @"\{(?:\\(?<tag>fn|\d?[a-z]+)(?<arg>\([^\{\}\(\)]*\)|[^\{\}\(\)\\]*))+\}")) { int end = match.Index; if (end > start) { context.Section.Text = text.Substring(start, end - start).Replace("\\N", "\r\n"); line.Sections.Add(context.Section); context.Section = (AssSection)context.Section.Clone(); context.Section.Text = null; context.Section.Duration = TimeSpan.Zero; } CaptureCollection tags = match.Groups["tag"].Captures; CaptureCollection arguments = match.Groups["arg"].Captures; for (int i = 0; i < tags.Count; i++) { if (_tagHandlers.TryGetValue(tags[i].Value, out AssTagHandlerBase handler)) { handler.Handle(context, arguments[i].Value); } } start = match.Index + match.Length; } if (start < text.Length) { context.Section.Text = text.Substring(start, text.Length - start).Replace("\\N", "\r\n"); line.Sections.Add(context.Section); } if (line.RubyPosition != RubyPosition.None) { CreateRubySections(line); } List <AssLine> lines = new List <AssLine> { line }; foreach (AssTagContext.PostProcessor postProcessor in context.PostProcessors) { List <AssLine> extraLines = postProcessor(); if (extraLines != null) { lines.AddRange(extraLines); } } return(lines); }