Work on bdsup writing in batch convert

This commit is contained in:
niksedk 2022-11-05 19:31:42 +01:00
parent 1b70c571f7
commit a3fc23b94a
5 changed files with 896 additions and 607 deletions

View File

@ -378,7 +378,7 @@ namespace Nikse.SubtitleEdit.Core.BluRaySup
bm.SetTransparentTo(Color.FromArgb(0, 0, 0, 0)); bm.SetTransparentTo(Color.FromArgb(0, 0, 0, 0));
var colorPalette = GetBitmapPalette(bm); var colorPalette = GetBitmapPalette(bm);
var pal = new BluRaySupPalette(colorPalette.Count); var pal = new BluRaySupPalette(colorPalette.Count);
for (int i = 0; i < colorPalette.Count; i++) for (var i = 0; i < colorPalette.Count; i++)
{ {
pal.SetColor(i, colorPalette[i]); pal.SetColor(i, colorPalette[i]);
} }

View File

@ -1090,7 +1090,7 @@ namespace Nikse.SubtitleEdit.Forms
labelError.Visible = false; labelError.Visible = false;
Refresh(); Refresh();
// var sw = Stopwatch.StartNew(); var sw = System.Diagnostics.Stopwatch.StartNew();
if (buttonConvert.Text == LanguageSettings.Current.General.Cancel) if (buttonConvert.Text == LanguageSettings.Current.General.Cancel)
{ {
@ -1722,7 +1722,7 @@ namespace Nikse.SubtitleEdit.Forms
SetControlState(true); SetControlState(true);
_bdLookup = new Dictionary<string, List<BluRaySupParser.PcsData>>(); _bdLookup = new Dictionary<string, List<BluRaySupParser.PcsData>>();
//SeLogger.Error($"Batch convert took {sw.ElapsedMilliseconds}"); SeLogger.Error($"Batch convert took {sw.ElapsedMilliseconds}");
} }
private Subtitle ApplyFixesStep1(Subtitle sub, List<BluRaySupParser.PcsData> bluRaySubtitles) private Subtitle ApplyFixesStep1(Subtitle sub, List<BluRaySupParser.PcsData> bluRaySubtitles)

View File

@ -3031,7 +3031,14 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine +
else else
{ {
baseLinePadding = (int)Math.Round(TextDraw.MeasureTextHeight(font, "yj[K)Ź,Ç", parameter.SubtitleFontBold) - TextDraw.MeasureTextHeight(font, "ac", parameter.SubtitleFontBold)); baseLinePadding = (int)Math.Round(TextDraw.MeasureTextHeight(font, "yj[K)Ź,Ç", parameter.SubtitleFontBold) - TextDraw.MeasureTextHeight(font, "ac", parameter.SubtitleFontBold));
PaddingDictionary.Add(paddingKey, baseLinePadding); try
{
PaddingDictionary.Add(paddingKey, baseLinePadding);
}
catch
{
// ignore
}
} }
// align lines with "gjpqy,ýęçÇ/()[]" a bit lower // align lines with "gjpqy,ýęçÇ/()[]" a bit lower

View File

@ -1,53 +1,336 @@
using System.Collections.Generic; using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Core.Interfaces;
using Nikse.SubtitleEdit.Forms;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nikse.SubtitleEdit.Core.Common; using Nikse.SubtitleEdit.Core.SubtitleFormats;
using Nikse.SubtitleEdit.Core.Interfaces; using System;
using Nikse.SubtitleEdit.Forms; using System.Windows.Forms;
using static Nikse.SubtitleEdit.Forms.ExportPngXml;
namespace Nikse.SubtitleEdit.Logic.CommandLineConvert namespace Nikse.SubtitleEdit.Logic.CommandLineConvert
{ {
public static class BdSupSaver public static class BdSupSaver
{ {
public static void SaveBdSup(string fileName, Subtitle sub, IList<IBinaryParagraph> binaryParagraphs, ExportPngXml form, int width, int height, bool isImageBased, FileStream binarySubtitleFile, CancellationToken cancellationToken) public static void SaveBdSup(string fileName, Subtitle sub, IList<IBinaryParagraph> binaryParagraphs, ExportPngXml form, int width, int height, bool isImageBased, FileStream binarySubtitleFile, SubtitleFormat format, CancellationToken cancellationToken)
{ {
var queue = new Queue<Task<ExportPngXml.MakeBitmapParameter>>(); var generalBitmapParameter = form.MakeMakeBitmapParameter(0, width, height);
for (var index = 0; index < sub.Paragraphs.Count; index++) var language = LanguageAutoDetect.AutoDetectGoogleLanguage(sub);
var pms = new MakeBitmapParameter[sub.Paragraphs.Count];
var po = new ParallelOptions { CancellationToken = cancellationToken };
Application.DoEvents();
Parallel.For(0, sub.Paragraphs.Count, po, i =>
{ {
CheckQueue(binarySubtitleFile, queue, 2); Application.DoEvents();
var mp = MakeMakeBitmapParameter(sub, i, generalBitmapParameter, language, format, width, height);
pms[i] = GenerateImage(fileName, sub, binaryParagraphs, isImageBased, mp, i);
});
var mp = form.MakeMakeBitmapParameter(index, width, height); Application.DoEvents();
var task = GenerateImage(fileName, sub, binaryParagraphs, isImageBased, mp, index); if (cancellationToken.IsCancellationRequested)
queue.Enqueue(task); {
return;
}
if (index % 25 == 0) foreach (var x in pms)
{
Application.DoEvents();
binarySubtitleFile.Write(x.Buffer, 0, x.Buffer.Length);
}
}
private static MakeBitmapParameter MakeMakeBitmapParameter(Subtitle subtitle, int index, MakeBitmapParameter bp, string language, SubtitleFormat format, int width, int height)
{
var p = subtitle.GetParagraphOrDefault(index);
if (p == null)
{
return bp;
}
var parameter = new MakeBitmapParameter
{
Type = bp.Type,
SubtitleColor = bp.SubtitleColor,
SubtitleFontName = bp.SubtitleFontName,
SubtitleFontSize = bp.SubtitleFontSize,
SubtitleFontBold = bp.SubtitleFontBold,
BorderColor = bp.BorderColor,
BorderWidth = bp.BorderWidth,
SimpleRendering = bp.SimpleRendering,
AlignLeft = bp.AlignLeft,
AlignRight = bp.AlignRight,
JustifyLeft = GetJustifyLeft(p.Text, language), // center, left justify
JustifyTop = bp.JustifyTop,
JustifyRight = bp.JustifyRight,
ScreenWidth = bp.ScreenWidth,
ScreenHeight = bp.ScreenHeight,
VideoResolution = bp.VideoResolution,
Bitmap = null,
FramesPerSeconds = bp.FramesPerSeconds,
BottomMargin = GetBottomMarginInPixels(p, format, subtitle, height),
LeftMargin = GetLeftMarginInPixels(p, format, subtitle, width),
RightMargin = GetRightMarginInPixels(p, format, subtitle, width),
Saved = false,
Alignment = ContentAlignment.BottomCenter,
Type3D = bp.Type3D,
Depth3D = bp.Depth3D,
BackgroundColor = bp.BackgroundColor,
ShadowColor = bp.ShadowColor,
ShadowWidth = bp.ShadowWidth,
ShadowAlpha = bp.ShadowAlpha,
LineHeight = bp.LineHeight,
FullFrame = bp.FullFrame,
FullFrameBackgroundColor = bp.FullFrameBackgroundColor,
BoxSingleLine = bp.BoxSingleLine,
P = p,
};
parameter.Alignment = GetAlignmentFromParagraph(parameter, format, subtitle);
parameter.OverridePosition = GetAssPoint(parameter.P.Text);
if (format.HasStyleSupport && !string.IsNullOrEmpty(parameter.P.Extra))
{
if (format.GetType() == typeof(SubStationAlpha))
{ {
if (cancellationToken.IsCancellationRequested) var style = AdvancedSubStationAlpha.GetSsaStyle(parameter.P.Extra, subtitle.Header);
parameter.SubtitleColor = style.Primary;
parameter.SubtitleFontBold = style.Bold;
parameter.SubtitleFontSize = (float)style.FontSize;
parameter.SubtitleFontName = style.FontName;
parameter.BottomMargin = style.MarginVertical;
if (style.BorderStyle == "3")
{ {
return; parameter.BackgroundColor = style.Background;
} }
parameter.ShadowColor = style.Outline;
System.Windows.Forms.Application.DoEvents(); }
else if (format.GetType() == typeof(AdvancedSubStationAlpha))
{
var style = AdvancedSubStationAlpha.GetSsaStyle(parameter.P.Extra, subtitle.Header);
parameter.SubtitleColor = style.Primary;
parameter.SubtitleFontBold = style.Bold;
parameter.SubtitleFontSize = (float)style.FontSize;
parameter.SubtitleFontName = style.FontName;
parameter.BottomMargin = style.MarginVertical;
if (style.BorderStyle == "3")
{
parameter.BackgroundColor = style.Outline;
}
parameter.ShadowAlpha = style.Background.A;
parameter.ShadowColor = style.Background;
} }
} }
CheckQueue(binarySubtitleFile, queue, 0); return parameter;
} }
private static void CheckQueue(Stream binarySubtitleFile, Queue<Task<ExportPngXml.MakeBitmapParameter>> queue, int max) private static int GetBottomMarginInPixels(Paragraph p, SubtitleFormat format, Subtitle subtitle, int height)
{ {
while (queue.Count > max) if (!string.IsNullOrEmpty(p?.Extra) && (format.Name == AdvancedSubStationAlpha.NameOfFormat || format.Name == SubStationAlpha.NameOfFormat))
{ {
var t = queue.Dequeue(); var style = AdvancedSubStationAlpha.GetSsaStyle(p.Extra, subtitle.Header);
t.Wait(); return style.MarginVertical;
binarySubtitleFile.Write(t.Result.Buffer, 0, t.Result.Buffer.Length);
} }
if (Configuration.Settings.Tools.ExportBottomMarginUnit == "%")
{
return (int)Math.Round(Configuration.Settings.Tools.ExportBluRayBottomMarginPercent / 100.0 * height, MidpointRounding.AwayFromZero);
}
// pixels
return Configuration.Settings.Tools.ExportBluRayBottomMarginPixels;
} }
private static Task<ExportPngXml.MakeBitmapParameter> GenerateImage(string fileName, Subtitle sub, IList<IBinaryParagraph> binaryParagraphs, bool isImageBased, ExportPngXml.MakeBitmapParameter mp, int index) private static int GetLeftMarginInPixels(Paragraph p, SubtitleFormat format, Subtitle subtitle, int width)
{
if (!string.IsNullOrEmpty(p?.Extra) && (format.Name == AdvancedSubStationAlpha.NameOfFormat || format.Name == SubStationAlpha.NameOfFormat))
{
var style = AdvancedSubStationAlpha.GetSsaStyle(p.Extra, subtitle.Header);
return style.MarginLeft;
}
if (Configuration.Settings.Tools.ExportLeftRightMarginUnit == "%")
{
return (int)Math.Round(Configuration.Settings.Tools.ExportLeftRightMarginPercent / 100.0 * width, MidpointRounding.AwayFromZero);
}
// pixels
return Configuration.Settings.Tools.ExportLeftRightMarginPixels;
}
private static int GetRightMarginInPixels(Paragraph p, SubtitleFormat format, Subtitle subtitle, int width)
{
if (!string.IsNullOrEmpty(p?.Extra) && (format.Name == AdvancedSubStationAlpha.NameOfFormat || format.Name == SubStationAlpha.NameOfFormat))
{
var style = AdvancedSubStationAlpha.GetSsaStyle(p.Extra, subtitle.Header);
return style.MarginRight;
}
return GetLeftMarginInPixels(p, format, subtitle, width);
}
private static bool GetJustifyLeft(string text, string language)
{
if (Configuration.Settings.Tools.ExportHorizontalAlignment != 6 || string.IsNullOrEmpty(text))
{
return Configuration.Settings.Tools.ExportHorizontalAlignment == 3;
}
var s = Utilities.RemoveUnneededSpaces(text, language);
var dialogHelper = new DialogSplitMerge { TwoLetterLanguageCode = language };
var lines = s.SplitToLines();
return dialogHelper.IsDialog(lines) || HasTwoSpeakers(lines);
}
private static bool HasTwoSpeakers(List<string> lines)
{
return lines.Count == 2 && lines[0].HasSentenceEnding() && lines[0].Contains(':') && lines[1].Contains(':');
}
private static ContentAlignment GetAlignmentFromParagraph(MakeBitmapParameter p, SubtitleFormat format, Subtitle subtitle)
{
var alignment = ContentAlignment.BottomCenter;
if (p.AlignLeft)
{
alignment = ContentAlignment.BottomLeft;
}
else if (p.AlignRight)
{
alignment = ContentAlignment.BottomRight;
}
if (format.HasStyleSupport && !string.IsNullOrEmpty(p.P.Extra))
{
if (format.GetType() == typeof(SubStationAlpha))
{
var style = AdvancedSubStationAlpha.GetSsaStyle(p.P.Extra, subtitle.Header);
alignment = GetSsaAlignment("{\\a" + style.Alignment + "}", alignment);
}
else if (format.GetType() == typeof(AdvancedSubStationAlpha))
{
var style = AdvancedSubStationAlpha.GetSsaStyle(p.P.Extra, subtitle.Header);
alignment = GetAssAlignment("{\\an" + style.Alignment + "}", alignment);
}
}
var text = p.P.Text;
if (format.GetType() == typeof(SubStationAlpha) && text.Length > 5)
{
text = p.P.Text.Substring(0, 6);
alignment = GetSsaAlignment(text, alignment);
}
else if (text.Length > 6)
{
text = p.P.Text.Substring(0, 6);
alignment = GetAssAlignment(text, alignment);
}
return alignment;
}
private static ContentAlignment GetSsaAlignment(string text, ContentAlignment defaultAlignment)
{
//1: Bottom left
//2: Bottom center
//3: Bottom right
//9: Middle left
//10: Middle center
//11: Middle right
//5: Top left
//6: Top center
//7: Top right
switch (text)
{
case "{\\a1}":
return ContentAlignment.BottomLeft;
case "{\\a2}":
return ContentAlignment.BottomCenter;
case "{\\a3}":
return ContentAlignment.BottomRight;
case "{\\a9}":
return ContentAlignment.MiddleLeft;
case "{\\a10}":
return ContentAlignment.MiddleCenter;
case "{\\a11}":
return ContentAlignment.MiddleRight;
case "{\\a5}":
return ContentAlignment.TopLeft;
case "{\\a6}":
return ContentAlignment.TopCenter;
case "{\\a7}":
return ContentAlignment.TopRight;
}
return defaultAlignment;
}
private static ContentAlignment GetAssAlignment(string text, ContentAlignment defaultAlignment)
{
//1: Bottom left
//2: Bottom center
//3: Bottom right
//4: Middle left
//5: Middle center
//6: Middle right
//7: Top left
//8: Top center
//9: Top right
switch (text)
{
case "{\\an1}":
return ContentAlignment.BottomLeft;
case "{\\an2}":
return ContentAlignment.BottomCenter;
case "{\\an3}":
return ContentAlignment.BottomRight;
case "{\\an4}":
return ContentAlignment.MiddleLeft;
case "{\\an5}":
return ContentAlignment.MiddleCenter;
case "{\\an6}":
return ContentAlignment.MiddleRight;
case "{\\an7}":
return ContentAlignment.TopLeft;
case "{\\an8}":
return ContentAlignment.TopCenter;
case "{\\an9}":
return ContentAlignment.TopRight;
}
return defaultAlignment;
}
private static Point? GetAssPoint(string s)
{
var k = s.IndexOf("{\\", StringComparison.Ordinal);
while (k >= 0)
{
var l = s.IndexOf('}', k + 1);
if (l < k)
{
break;
}
var assTags = s.Substring(k + 1, l - k - 1).Split('\\');
foreach (var assTag in assTags)
{
if (assTag.StartsWith("pos(", StringComparison.Ordinal))
{
var numbers = assTag.Remove(0, 4).TrimEnd(')').Trim().Split(',');
if (numbers.Length == 2 && Utilities.IsInteger(numbers[0]) && Utilities.IsInteger(numbers[1]))
{
return new Point(int.Parse(numbers[0]), int.Parse(numbers[1]));
}
}
}
k = s.IndexOf("{\\", k + 1, StringComparison.Ordinal);
}
return null;
}
private static MakeBitmapParameter GenerateImage(string fileName, Subtitle sub, IList<IBinaryParagraph> binaryParagraphs, bool isImageBased, MakeBitmapParameter mp, int index)
{ {
mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin; mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin;
if (binaryParagraphs != null && binaryParagraphs.Count > 0) if (binaryParagraphs != null && binaryParagraphs.Count > 0)
@ -60,25 +343,19 @@ namespace Nikse.SubtitleEdit.Logic.CommandLineConvert
} }
else if (isImageBased) else if (isImageBased)
{ {
using (var ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(fileName), sub.Paragraphs[index].Text)))) using (var ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(fileName) ?? throw new InvalidOperationException(), sub.Paragraphs[index].Text))))
{ {
mp.Bitmap = (Bitmap)Image.FromStream(ms); mp.Bitmap = (Bitmap)Image.FromStream(ms);
} }
} }
else else
{ {
mp.Bitmap = ExportPngXml.GenerateImageFromTextWithStyle(mp); mp.Bitmap = GenerateImageFromTextWithStyle(mp);
} }
ExportPngXml.MakeBluRaySupImage(mp); MakeBluRaySupImage(mp);
mp.Bitmap?.Dispose();
if (mp.Bitmap != null) return mp;
{
mp.Bitmap.Dispose();
mp.Bitmap = null;
}
return Task.FromResult(mp);
} }
} }
} }

File diff suppressed because it is too large Load Diff