/// <summary> /// Speed - max 17 (for most languages) characters per second /// </summary> public void Check(Subtitle subtitle, NetflixQualityController controller) { var oldIgnoreWhiteSpace = Configuration.Settings.General.CharactersPerSecondsIgnoreWhiteSpace; try { Configuration.Settings.General.CharactersPerSecondsIgnoreWhiteSpace = false; foreach (Paragraph p in subtitle.Paragraphs) { var jp = new Paragraph(p); if (controller.Language == "ja") { jp.Text = HtmlUtil.RemoveHtmlTags(jp.Text, true); jp.Text = NetflixImsc11Japanese.RemoveTags(jp.Text); } var charactersPerSeconds = Utilities.GetCharactersPerSecond(jp); if (charactersPerSeconds > controller.CharactersPerSecond) { var fixedParagraph = new Paragraph(p, false); while (Utilities.GetCharactersPerSecond(fixedParagraph) > controller.CharactersPerSecond) { fixedParagraph.EndTime.TotalMilliseconds++; } string comment = "Maximum " + controller.CharactersPerSecond + " characters per second"; controller.AddRecord(p, fixedParagraph, comment, charactersPerSeconds.ToString(CultureInfo.InvariantCulture)); } } } finally { Configuration.Settings.General.CharactersPerSecondsIgnoreWhiteSpace = oldIgnoreWhiteSpace; } }
public void Check(Subtitle subtitle, NetflixQualityController controller) { ICalcLength calc = CalcFactory.MakeCalculator(nameof(CalcAll)); var charactersPerSecond = controller.CharactersPerSecond; var comment = "Maximum " + charactersPerSecond + " characters per second"; foreach (var p in subtitle.Paragraphs) { var jp = new Paragraph(p); if (controller.Language == "ja") { jp.Text = HtmlUtil.RemoveHtmlTags(jp.Text, true); jp.Text = NetflixImsc11Japanese.RemoveTags(jp.Text); } if (controller.Language == "ko") { calc = CalcFactory.MakeCalculator(nameof(CalcCjk)); } var charactersPerSeconds = Utilities.GetCharactersPerSecond(jp, calc); if (charactersPerSeconds > charactersPerSecond && !p.StartTime.IsMaxTime) { var fixedParagraph = new Paragraph(p, false); while (Utilities.GetCharactersPerSecond(fixedParagraph) > charactersPerSecond) { fixedParagraph.EndTime.TotalMilliseconds++; } controller.AddRecord(p, fixedParagraph, comment, FormattableString.Invariant($"CPS={charactersPerSeconds:0.##}")); } } }
public void Check(Subtitle subtitle, NetflixQualityController controller) { foreach (var p in subtitle.Paragraphs) { foreach (var line in p.Text.SplitToLines()) { if (controller.Language == "ja") { var vertical = p.Text.Contains("{\\an7", StringComparison.Ordinal) || p.Text.Contains("{\\an9", StringComparison.Ordinal); var text = HtmlUtil.RemoveHtmlTags(line, true); text = NetflixImsc11Japanese.RemoveTags(text); if (vertical) // Vertical subtitles - Maximum 11 full-width characters per line { if (CalculateJapaneseLength(text) > 11) { var comment = "Single vertical line length > 11"; controller.AddRecord(p, p.StartTime.ToHHMMSSFF(), comment, line.Length.ToString(CultureInfo.InvariantCulture)); } } else // Horizontal subtitles - Maximum 13 full-width characters per line { if (CalculateJapaneseLength(text) > 13) { var comment = "Single horizontal line length > 13"; controller.AddRecord(p, p.StartTime.ToHHMMSSFF(), comment, line.Length.ToString(CultureInfo.InvariantCulture)); } } } else if (controller.Language == "ko" && line.CountCharacters(nameof(CalcCjk)) > controller.SingleLineMaxLength) { var fixedParagraph = new Paragraph(p, false); fixedParagraph.Text = Utilities.AutoBreakLine(fixedParagraph.Text, controller.SingleLineMaxLength, controller.SingleLineMaxLength - 3, controller.Language); var comment = "Single line length > " + controller.SingleLineMaxLength; controller.AddRecord(p, fixedParagraph, comment, line.CountCharacters(nameof(CalcCjk)).ToString(CultureInfo.InvariantCulture)); } else if (line.CountCharacters() > controller.SingleLineMaxLength) { var fixedParagraph = new Paragraph(p, false); fixedParagraph.Text = Utilities.AutoBreakLine(fixedParagraph.Text, controller.SingleLineMaxLength, controller.SingleLineMaxLength - 3, controller.Language); var comment = "Single line length > " + controller.SingleLineMaxLength; controller.AddRecord(p, fixedParagraph, comment, line.Length.ToString(CultureInfo.InvariantCulture)); } } } }
private static List <Paragraph> MakeHorizontalParagraphs(Paragraph p, int width, int height) { var lines = p.Text.SplitToLines(); var adjustment = 34; var startY = height - lines.Count * 2 * adjustment + 30; if (p.Text.StartsWith("{\\an8", StringComparison.Ordinal)) { startY = 40; } var list = new List <Paragraph>(); var furiganaList = new List <Paragraph>(); var rubyOn = false; var italinOn = false; int startX; using (var g = Graphics.FromHwnd(IntPtr.Zero)) { var actualText = NetflixImsc11Japanese.RemoveTags(HtmlUtil.RemoveHtmlTags(p.Text, true)); var actualTextSize = g.MeasureString(actualText, new Font(SystemFonts.DefaultFont.FontFamily, 20)); startX = (int)(width / 2.0 - actualTextSize.Width / 2.0); if (p.Text.StartsWith("{\\an5", StringComparison.Ordinal)) { startY = (int)(height / 2.0 - actualTextSize.Height / 2.0); } } for (var index = 0; index < lines.Count; index++) { var line = lines[index]; if (italinOn) { line = "<i>" + line; } var actual = new StringBuilder(); int i = 0; while (i < line.Length) { if (line.Substring(i).StartsWith("{\\")) { var end = line.IndexOf('}', i); if (end < 0) { break; } i = end + 1; } else if (line.Substring(i).StartsWith("<i>", StringComparison.Ordinal) || line.Substring(i).StartsWith("<u>", StringComparison.Ordinal) || line.Substring(i).StartsWith("<b>", StringComparison.Ordinal)) { actual.Append("{\\i1}"); i += 3; italinOn = true; } else if (line.Substring(i).StartsWith("</i>", StringComparison.Ordinal) || line.Substring(i).StartsWith("</u>", StringComparison.Ordinal) || line.Substring(i).StartsWith("</b>", StringComparison.Ordinal)) { actual.Append("{\\i0}"); i += 4; italinOn = false; } else if (line.Substring(i).StartsWith("<bouten-", StringComparison.Ordinal)) { var end = line.IndexOf('>', i); if (end < 0) { break; } if (end + 1 >= line.Length) { break; } var endTagStart = line.IndexOf("</", end, StringComparison.Ordinal); if (endTagStart < 0) { break; } var tag = line.Substring(i + 1, end - i - 1); var text = line.Substring(end + 1, endTagStart - end - 1); foreach (var ch in text) { var furiganaChar = BoutenTagToUnicode(tag); if (!string.IsNullOrWhiteSpace(furiganaChar)) { furiganaList.Add(new Paragraph($"{{\\alpha&FF&}}{actual}{{\\alpha&0&}}{furiganaChar}", p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); } actual.Append(ch); } var endTagEnd = line.IndexOf('>', endTagStart); if (endTagEnd < 0) { break; } i = endTagEnd + 1; } else if (line.Substring(i).StartsWith("<ruby-container>", StringComparison.Ordinal)) { var baseTextStart = line.IndexOf("<ruby-base>", i, StringComparison.Ordinal); var baseTextEnd = line.IndexOf("</ruby-base>", i, StringComparison.Ordinal); if (baseTextStart < 0 || baseTextEnd < 0) { baseTextStart = line.IndexOf("<ruby-base-italic>", i, StringComparison.Ordinal); baseTextEnd = line.IndexOf("</ruby-base-italic>", i, StringComparison.Ordinal); if (baseTextStart < 0 || baseTextEnd < 0) { break; } } baseTextStart += "<ruby-base>".Length; var baseText = line.Substring(baseTextStart, baseTextEnd - baseTextStart); var extraText = string.Empty; var extraTextStart = line.IndexOf("<ruby-text>", i, StringComparison.Ordinal); var extraTextEnd = line.IndexOf("</ruby-text>", i, StringComparison.Ordinal); if (extraTextStart >= 0 || extraTextEnd >= 0 && extraTextStart < extraTextEnd) { extraTextStart += "<ruby-text>".Length; extraText = line.Substring(extraTextStart, extraTextEnd - extraTextStart); } if (string.IsNullOrEmpty(extraText)) { extraTextStart = line.IndexOf("<ruby-text-italic>", i, StringComparison.Ordinal); extraTextEnd = line.IndexOf("</ruby-text-italic>", i, StringComparison.Ordinal); if (extraTextStart >= 0 || extraTextEnd >= 0 && extraTextStart < extraTextEnd) { extraTextStart += "<ruby-text-italic>".Length; extraText = line.Substring(extraTextStart, extraTextEnd - extraTextStart); } } var extraTextAfter = string.Empty; var extraTextStartAfter = line.IndexOf("<ruby-text-after>", i, StringComparison.Ordinal); var extraTextEndAfter = line.IndexOf("</ruby-text-after>", i, StringComparison.Ordinal); if (extraTextStartAfter >= 0 || extraTextEndAfter >= 0 && extraTextStartAfter < extraTextEndAfter) { extraTextStartAfter += "<ruby-text-after>".Length; extraText = line.Substring(extraTextStartAfter, extraTextEndAfter - extraTextStartAfter); } var preFurigana = string.Empty; if (actual.Length > 0) { preFurigana = $"{{\\alpha&FF&}}{actual.ToString().TrimEnd()}{{\\alpha&0&}}"; } if (!string.IsNullOrWhiteSpace(extraText)) { furiganaList.Add(new Paragraph($"{preFurigana}{{\\fs20}}{extraText}", p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); } if (!string.IsNullOrWhiteSpace(extraTextAfter)) { furiganaList.Add(new Paragraph($"{preFurigana}{{\\fs20}} {extraTextAfter}", p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); } actual.Append(baseText); var endTagEnd = line.IndexOf("</ruby-container>", i, StringComparison.Ordinal); if (endTagEnd < 0) { break; } i = endTagEnd + "</ruby-container>".Length; rubyOn = true; } else { actual.Append(line.Substring(i, 1)); i++; } } var actualText = actual.ToString().TrimEnd(); bool displayBefore = lines.Count == 2 && index == 0 || lines.Count == 1; if (displayBefore && furiganaList.Count > 0) { foreach (var fp in furiganaList) { var beforeText = "{\\an1}{\\pos(" + startX + "," + startY + ")}" + fp.Text; list.Add(new Paragraph(beforeText, p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); } startY += adjustment; if (rubyOn && index == 0 && lines.Count == 2) { startY += 3; } } actualText = "{\\an1}{\\pos(" + startX + "," + startY + ")}" + actualText; list.Add(new Paragraph(actualText, p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); startY += adjustment; if (!displayBefore && furiganaList.Count > 0) { if (rubyOn && index == 1 && lines.Count == 2) { startY = (int)(startY - adjustment * 0.4); } foreach (var fp in furiganaList) { var beforeText = "{\\an1}{\\pos(" + startX + "," + startY + ")}" + fp.Text; list.Add(new Paragraph(beforeText, p.StartTime.TotalMilliseconds, p.EndTime.TotalMilliseconds)); } startY += adjustment; } furiganaList.Clear(); } return(list); }