Ejemplo n.º 1
0
        internal static void WriteTrack(string fileName, string outputFolder, bool overwrite, int count, StreamWriter stdOutWriter, CommandLineConverter.BatchConvertProgress progressCallback, Point?resolution, ProgramMapTableParser programMapTableParser, int pid, TransportStreamParser tsParser)
        {
            var overrideScreenSize = Configuration.Settings.Tools.BatchConvertTsOverrideScreenSize &&
                                     Configuration.Settings.Tools.BatchConvertTsScreenHeight > 0 &&
                                     Configuration.Settings.Tools.BatchConvertTsScreenWidth > 0 ||
                                     resolution.HasValue;

            using (var form = new ExportPngXml())
            {
                form.Initialize(new Subtitle(), new SubRip(), BatchConvert.BluRaySubtitle, fileName, null, fileName);


                var language       = GetFileNameEnding(programMapTableParser, pid);
                var outputFileName = CommandLineConverter.FormatOutputFileNameForBatchConvert(Utilities.GetPathAndFileNameWithoutExtension(fileName) + language + Path.GetExtension(fileName), ".sup", outputFolder, overwrite);
                stdOutWriter?.Write($"{count}: {Path.GetFileName(fileName)} -> PID {pid} to {outputFileName}...");
                var sub = tsParser.GetDvbSubtitles(pid);
                progressCallback?.Invoke($"Save PID {pid}");
                var subtitleScreenSize = GetSubtitleScreenSize(sub, overrideScreenSize, resolution);
                using (var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create))
                {
                    for (int index = 0; index < sub.Count; index++)
                    {
                        var p        = sub[index];
                        var pos      = p.GetPosition();
                        var bmp      = sub[index].GetBitmap();
                        var tsWidth  = bmp.Width;
                        var tsHeight = bmp.Height;
                        var nBmp     = new NikseBitmap(bmp);
                        pos.Top  += nBmp.CropTopTransparent(0);
                        pos.Left += nBmp.CropSidesAndBottom(0, Color.FromArgb(0, 0, 0, 0), true);
                        bmp.Dispose();
                        bmp = nBmp.GetBitmap();
                        var mp = form.MakeMakeBitmapParameter(index, subtitleScreenSize.X, subtitleScreenSize.Y);

                        if (overrideScreenSize)
                        {
                            var widthFactor  = (double)subtitleScreenSize.X / tsWidth;
                            var heightFactor = (double)subtitleScreenSize.Y / tsHeight;
                            var resizeBmp    = ResizeBitmap(bmp, (int)Math.Round(bmp.Width * widthFactor), (int)Math.Round(bmp.Height * heightFactor));
                            bmp.Dispose();
                            bmp      = resizeBmp;
                            pos.Left = (int)Math.Round(pos.Left * widthFactor);
                            pos.Top  = (int)Math.Round(pos.Top * heightFactor);
                            progressCallback?.Invoke($"Save PID {pid}: {(index + 1) * 100 / sub.Count}%");
                        }

                        mp.Bitmap       = bmp;
                        mp.P            = new Paragraph(string.Empty, p.StartMilliseconds, p.EndMilliseconds);
                        mp.ScreenWidth  = subtitleScreenSize.X;
                        mp.ScreenHeight = subtitleScreenSize.Y;
                        if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition || Configuration.Settings.Tools.BatchConvertTsOverrideYPosition)
                        {
                            var overrideMarginX = (int)Math.Round(Configuration.Settings.Tools.BatchConvertTsOverrideHMargin * subtitleScreenSize.X / 100.0);
                            var overrideMarginY = (int)Math.Round(Configuration.Settings.Tools.BatchConvertTsOverrideBottomMargin * subtitleScreenSize.Y / 100.0);
                            if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition && Configuration.Settings.Tools.BatchConvertTsOverrideYPosition)
                            {
                                var x = (int)Math.Round(subtitleScreenSize.X / 2.0 - mp.Bitmap.Width / 2.0);
                                if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase))
                                {
                                    x = overrideMarginX;
                                }
                                else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase))
                                {
                                    x = subtitleScreenSize.X - overrideMarginX - mp.Bitmap.Width;
                                }

                                var y = subtitleScreenSize.Y - overrideMarginY - mp.Bitmap.Height;
                                mp.OverridePosition = new Point(x, y);
                            }
                            else if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition)
                            {
                                var x = (int)Math.Round(subtitleScreenSize.X / 2.0 - mp.Bitmap.Width / 2.0);
                                if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase))
                                {
                                    x = overrideMarginX;
                                }
                                else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase))
                                {
                                    x = subtitleScreenSize.X - overrideMarginX - mp.Bitmap.Width;
                                }

                                mp.OverridePosition = new Point(x, pos.Top);
                            }
                            else
                            {
                                var y = subtitleScreenSize.Y - overrideMarginY - mp.Bitmap.Height;
                                mp.OverridePosition = new Point(pos.Left, y);
                            }
                        }
                        else
                        {
                            mp.OverridePosition = new Point(pos.Left, pos.Top); // use original position (can be scaled)
                        }

                        ExportPngXml.MakeBluRaySupImage(mp);
                        binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
                        mp.Bitmap?.Dispose();
                        mp.Bitmap = null;
                    }
                }
            }
            stdOutWriter?.WriteLine(" done.");
        }
Ejemplo n.º 2
0
        internal static bool BatchConvertSave(string toFormat, string offset, Encoding targetEncoding, string outputFolder, int count, ref int converted, ref int errors, IList <SubtitleFormat> formats, string fileName, Subtitle sub, SubtitleFormat format, bool overwrite, string pacCodePage, double?targetFrameRate, bool removeTextForHi, bool fixCommonErrors, bool redoCasing)
        {
            double oldFrameRate = Configuration.Settings.General.CurrentFrameRate;

            try
            {
                // adjust offset
                if (!string.IsNullOrEmpty(offset) && (offset.StartsWith("/offset:", StringComparison.Ordinal) || offset.StartsWith("offset:", StringComparison.Ordinal)))
                {
                    string[] parts = offset.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length == 5)
                    {
                        try
                        {
                            var ts = new TimeSpan(0, int.Parse(parts[1].TrimStart('-')), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]));
                            if (parts[1].StartsWith('-'))
                            {
                                sub.AddTimeToAllParagraphs(ts.Negate());
                            }
                            else
                            {
                                sub.AddTimeToAllParagraphs(ts);
                            }
                        }
                        catch
                        {
                            Console.Write(" (unable to read offset " + offset + ")");
                        }
                    }
                }

                // adjust frame rate
                if (targetFrameRate.HasValue)
                {
                    sub.ChangeFrameRate(Configuration.Settings.General.CurrentFrameRate, targetFrameRate.Value);
                    Configuration.Settings.General.CurrentFrameRate = targetFrameRate.Value;
                }

                if (removeTextForHi)
                {
                    var hiSettings = new Core.Forms.RemoveTextForHISettings();
                    var hiLib      = new Core.Forms.RemoveTextForHI(hiSettings);
                    foreach (var p in sub.Paragraphs)
                    {
                        p.Text = hiLib.RemoveTextFromHearImpaired(p.Text);
                    }
                }
                if (fixCommonErrors)
                {
                    using (var fce = new FixCommonErrors {
                        BatchMode = true
                    })
                    {
                        for (int i = 0; i < 3; i++)
                        {
                            fce.RunBatch(sub, format, targetEncoding, Configuration.Settings.Tools.BatchConvertLanguage);
                            sub = fce.FixedSubtitle;
                        }
                    }
                }
                if (redoCasing)
                {
                    using (var changeCasing = new ChangeCasing())
                    {
                        changeCasing.FixCasing(sub, LanguageAutoDetect.AutoDetectGoogleLanguage(sub));
                    }
                    using (var changeCasingNames = new ChangeCasingNames())
                    {
                        changeCasingNames.Initialize(sub);
                        changeCasingNames.FixCasing();
                    }
                }

                bool   targetFormatFound = false;
                string outputFileName;
                foreach (SubtitleFormat sf in formats)
                {
                    if (sf.IsTextBased && (sf.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase) || sf.Name.Replace(" ", string.Empty).Equals(toFormat.Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase)))
                    {
                        targetFormatFound = true;
                        sf.BatchMode      = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, sf.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        if (sf.IsFrameBased && !sub.WasLoadedWithFrameNumbers)
                        {
                            sub.CalculateFrameNumbersFromTimeCodesNoCheck(Configuration.Settings.General.CurrentFrameRate);
                        }
                        else if (sf.IsTimeBased && sub.WasLoadedWithFrameNumbers)
                        {
                            sub.CalculateTimeCodesFromFrameNumbers(Configuration.Settings.General.CurrentFrameRate);
                        }

                        if ((sf.GetType() == typeof(WebVTT) || sf.GetType() == typeof(WebVTTFileWithLineNumber)))
                        {
                            targetEncoding = Encoding.UTF8;
                        }

                        if (sf.GetType() == typeof(ItunesTimedText) || sf.GetType() == typeof(ScenaristClosedCaptions) || sf.GetType() == typeof(ScenaristClosedCaptionsDropFrame))
                        {
                            Encoding outputEnc = new UTF8Encoding(false);                         // create encoding with no BOM
                            using (var file = new StreamWriter(outputFileName, false, outputEnc)) // open file with encoding
                            {
                                file.Write(sub.ToText(sf));
                            } // save and close it
                        }
                        else if (targetEncoding == Encoding.UTF8 && (format.GetType() == typeof(TmpegEncAW5) || format.GetType() == typeof(TmpegEncXml)))
                        {
                            Encoding outputEnc = new UTF8Encoding(false);                         // create encoding with no BOM
                            using (var file = new StreamWriter(outputFileName, false, outputEnc)) // open file with encoding
                            {
                                file.Write(sub.ToText(sf));
                            } // save and close it
                        }
                        else
                        {
                            try
                            {
                                File.WriteAllText(outputFileName, sub.ToText(sf), targetEncoding);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                errors++;
                                return(false);
                            }
                        }

                        if (format.GetType() == typeof(Sami) || format.GetType() == typeof(SamiModern))
                        {
                            var sami = (Sami)format;
                            foreach (string className in Sami.GetStylesFromHeader(sub.Header))
                            {
                                var newSub = new Subtitle();
                                foreach (Paragraph p in sub.Paragraphs)
                                {
                                    if (p.Extra != null && p.Extra.Trim().Equals(className.Trim(), StringComparison.OrdinalIgnoreCase))
                                    {
                                        newSub.Paragraphs.Add(p);
                                    }
                                }
                                if (newSub.Paragraphs.Count > 0 && newSub.Paragraphs.Count < sub.Paragraphs.Count)
                                {
                                    string s = fileName;
                                    if (s.LastIndexOf('.') > 0)
                                    {
                                        s = s.Insert(s.LastIndexOf('.'), "_" + className);
                                    }
                                    else
                                    {
                                        s += "_" + className + format.Extension;
                                    }
                                    outputFileName = FormatOutputFileNameForBatchConvert(s, sf.Extension, outputFolder, overwrite);
                                    File.WriteAllText(outputFileName, newSub.ToText(sf), targetEncoding);
                                }
                            }
                        }
                        Console.WriteLine(" done.");
                        break;
                    }
                }
                if (!targetFormatFound)
                {
                    var ebu = new Ebu();
                    if (ebu.Name.Replace(" ", string.Empty).Equals(toFormat.Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, ebu.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        Ebu.Save(outputFileName, sub, true);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    var pac = new Pac();
                    if (pac.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase) || toFormat.Equals("pac", StringComparison.OrdinalIgnoreCase) || toFormat.Equals(".pac", StringComparison.OrdinalIgnoreCase))
                    {
                        pac.BatchMode = true;
                        int codePage;
                        if (!string.IsNullOrEmpty(pacCodePage) && int.TryParse(pacCodePage, out codePage))
                        {
                            pac.CodePage = codePage;
                        }
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, pac.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        pac.Save(outputFileName, sub);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    var cavena890 = new Cavena890();
                    if (cavena890.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, cavena890.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        cavena890.Save(outputFileName, sub);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    var cheetahCaption = new CheetahCaption();
                    if (cheetahCaption.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, cheetahCaption.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        CheetahCaption.Save(outputFileName, sub);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    var ayato = new Ayato();
                    if (ayato.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, ayato.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        ayato.Save(outputFileName, null, sub);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    var capMakerPlus = new CapMakerPlus();
                    if (capMakerPlus.Name.Replace(" ", string.Empty).Equals(toFormat, StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, capMakerPlus.Extension, outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        CapMakerPlus.Save(outputFileName, sub);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    if (Configuration.Settings.Language.BatchConvert.PlainText == toFormat || Configuration.Settings.Language.BatchConvert.PlainText.Replace(" ", string.Empty).Equals(toFormat.Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase))
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, ".txt", outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        File.WriteAllText(outputFileName, ExportText.GeneratePlainText(sub, false, false, false, false, false, false, string.Empty, true, false, true, true, false), targetEncoding);
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    if (string.Compare(BatchConvert.BluRaySubtitle, toFormat, StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(BatchConvert.BluRaySubtitle.Replace(" ", string.Empty), toFormat, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, ".sup", outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        using (var form = new ExportPngXml())
                        {
                            form.Initialize(sub, format, "BLURAYSUP", fileName, null, null);
                            var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create);
                            int width  = 1920;
                            int height = 1080;
                            var parts  = Configuration.Settings.Tools.ExportBluRayVideoResolution.Split('x');
                            if (parts.Length == 2 && Utilities.IsInteger(parts[0]) && Utilities.IsInteger(parts[1]))
                            {
                                width  = int.Parse(parts[0]);
                                height = int.Parse(parts[1]);
                            }
                            for (int index = 0; index < sub.Paragraphs.Count; index++)
                            {
                                var mp = form.MakeMakeBitmapParameter(index, width, height);
                                mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin;
                                mp.Bitmap   = ExportPngXml.GenerateImageFromTextWithStyle(mp);
                                ExportPngXml.MakeBluRaySupImage(mp);
                                binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
                            }
                            binarySubtitleFile.Close();
                        }
                        Console.WriteLine(" done.");
                    }
                    else if (string.Compare(BatchConvert.VobSubSubtitle, toFormat, StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(BatchConvert.VobSubSubtitle.Replace(" ", string.Empty), toFormat, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        targetFormatFound = true;
                        outputFileName    = FormatOutputFileNameForBatchConvert(fileName, ".sub", outputFolder, overwrite);
                        Console.Write("{0}: {1} -> {2}...", count, Path.GetFileName(fileName), outputFileName);
                        using (var form = new ExportPngXml())
                        {
                            form.Initialize(sub, format, "VOBSUB", fileName, null, null);
                            int width  = 720;
                            int height = 576;
                            var parts  = Configuration.Settings.Tools.ExportVobSubVideoResolution.Split('x');
                            if (parts.Length == 2 && Utilities.IsInteger(parts[0]) && Utilities.IsInteger(parts[1]))
                            {
                                width  = int.Parse(parts[0]);
                                height = int.Parse(parts[1]);
                            }

                            var cfg           = Configuration.Settings.Tools;
                            var languageIndex = IfoParser.LanguageCodes.IndexOf(LanguageAutoDetect.AutoDetectGoogleLanguageOrNull(sub));
                            if (languageIndex < 0)
                            {
                                languageIndex = IfoParser.LanguageCodes.IndexOf("en");
                            }
                            using (var vobSubWriter = new VobSubWriter(outputFileName, width, height, cfg.ExportBottomMargin, cfg.ExportBottomMargin, 32, cfg.ExportFontColor, cfg.ExportBorderColor, !cfg.ExportVobAntiAliasingWithTransparency, IfoParser.LanguageNames[languageIndex], IfoParser.LanguageCodes[languageIndex]))
                            {
                                for (int index = 0; index < sub.Paragraphs.Count; index++)
                                {
                                    var mp = form.MakeMakeBitmapParameter(index, width, height);
                                    mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin;
                                    mp.Bitmap   = ExportPngXml.GenerateImageFromTextWithStyle(mp);
                                    vobSubWriter.WriteParagraph(mp.P, mp.Bitmap, mp.Alignment);
                                }
                                vobSubWriter.WriteIdxFile();
                            }
                        }
                        Console.WriteLine(" done.");
                    }
                }
                if (!targetFormatFound)
                {
                    Console.WriteLine("{0}: {1} - target format '{2}' not found!", count, fileName, toFormat);
                    errors++;
                    return(false);
                }
                converted++;
                return(true);
            }
            finally
            {
                Configuration.Settings.General.CurrentFrameRate = oldFrameRate;
            }
        }
Ejemplo n.º 3
0
        public static bool ConvertFromTsToBluRaySup(string fileName, string outputFolder, bool overwrite, StreamWriter stdOutWriter, CommandLineConverter.BatchConvertProgress progressCallback)
        {
            var tsParser = new TransportStreamParser();

            tsParser.Parse(fileName, (position, total) =>
            {
                var percent = (int)Math.Round(position * 100.0 / total);
                stdOutWriter?.Write("\rParsing transport stream: {0}%", percent);
                progressCallback?.Invoke($"{percent}%");
            });
            stdOutWriter?.Write("\r".PadRight(32, ' '));
            stdOutWriter?.Write("\r");
            var videoInfo = UiUtil.GetVideoInfo(fileName);
            int width     = 720;
            int height    = 576;

            if (videoInfo.Success && videoInfo.Width > 0 && videoInfo.Height > 0)
            {
                width  = videoInfo.Width;
                height = videoInfo.Height;
            }

            var overrideScreenSize = Configuration.Settings.Tools.BatchConvertTsOverrideScreenSize &&
                                     Configuration.Settings.Tools.BatchConvertTsScreenWidth > 0 &&
                                     Configuration.Settings.Tools.BatchConvertTsScreenHeight > 0;

            if (overrideScreenSize)
            {
                width  = Configuration.Settings.Tools.BatchConvertTsScreenWidth;
                height = Configuration.Settings.Tools.BatchConvertTsScreenHeight;
            }
            using (var form = new ExportPngXml())
            {
                if (tsParser.SubtitlePacketIds.Count == 0)
                {
                    stdOutWriter?.WriteLine($"No subtitles found");
                    progressCallback?.Invoke($"No subtitles found");
                    return(false);
                }
                form.Initialize(new Subtitle(), new SubRip(), BatchConvert.BluRaySubtitle, fileName, videoInfo, fileName);
                foreach (int pid in tsParser.SubtitlePacketIds)
                {
                    var outputFileName = CommandLineConverter.FormatOutputFileNameForBatchConvert(Utilities.GetPathAndFileNameWithoutExtension(fileName) + "-" + pid + Path.GetExtension(fileName), ".sup", outputFolder, overwrite);
                    stdOutWriter?.WriteLine($"Saving PID {pid} to {outputFileName}...");
                    var sub = tsParser.GetDvbSubtitles(pid);
                    progressCallback?.Invoke($"Save PID {pid}");
                    using (var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create))
                    {
                        for (int index = 0; index < sub.Count; index++)
                        {
                            var p   = sub[index];
                            var pos = p.GetPosition();
                            var bmp = sub[index].GetBitmap();
                            if (!overrideScreenSize)
                            {
                                width            = bmp.Width;
                                height           = bmp.Height;
                                videoInfo.Width  = bmp.Width;
                                videoInfo.Height = bmp.Height;
                            }
                            var tsWidth  = bmp.Width;
                            var tsHeight = bmp.Height;
                            var nbmp     = new NikseBitmap(bmp);
                            pos.Top  += nbmp.CropTopTransparent(0);
                            pos.Left += nbmp.CropSidesAndBottom(0, Color.FromArgb(0, 0, 0, 0), true);
                            bmp.Dispose();
                            bmp = nbmp.GetBitmap();
                            var mp = form.MakeMakeBitmapParameter(index, width, height);

                            if (overrideScreenSize)
                            {
                                var widthFactor  = (double)width / tsWidth;
                                var heightFactor = (double)height / tsHeight;
                                var resizeBmp    = ResizeBitmap(bmp, (int)Math.Round(bmp.Width * widthFactor), (int)Math.Round(bmp.Height * heightFactor));
                                bmp.Dispose();
                                bmp      = resizeBmp;
                                pos.Left = (int)Math.Round(pos.Left * widthFactor);
                                pos.Top  = (int)Math.Round(pos.Top * heightFactor);
                                progressCallback?.Invoke($"Save PID {pid}: {(index + 1) * 100 / sub.Count}%");
                            }

                            mp.Bitmap       = bmp;
                            mp.P            = new Paragraph(string.Empty, p.StartMilliseconds, p.EndMilliseconds);
                            mp.ScreenWidth  = width;
                            mp.ScreenHeight = height;
                            if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition || Configuration.Settings.Tools.BatchConvertTsOverrideYPosition)
                            {
                                var overrideMarginX = (int)Math.Round(Configuration.Settings.Tools.BatchConvertTsOverrideHMargin * width / 100.0);
                                var overrideMarginY = (int)Math.Round(Configuration.Settings.Tools.BatchConvertTsOverrideBottomMargin * width / 100.0);
                                if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition && Configuration.Settings.Tools.BatchConvertTsOverrideYPosition)
                                {
                                    var x = (int)Math.Round((width / 2.0) - mp.Bitmap.Width / 2.0);
                                    if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase))
                                    {
                                        x = overrideMarginX;
                                    }
                                    else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase))
                                    {
                                        x = width - overrideMarginX - mp.Bitmap.Width;
                                    }
                                    var y = height - overrideMarginY - mp.Bitmap.Height;
                                    mp.OverridePosition = new Point(x, y);
                                }
                                else if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition)
                                {
                                    var x = (int)Math.Round((width / 2.0) - mp.Bitmap.Width / 2.0);
                                    if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase))
                                    {
                                        x = overrideMarginX;
                                    }
                                    else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase))
                                    {
                                        x = width - overrideMarginX - mp.Bitmap.Width;
                                    }
                                    mp.OverridePosition = new Point(x, pos.Top);
                                }
                                else
                                {
                                    var y = height - overrideMarginY - mp.Bitmap.Height;
                                    mp.OverridePosition = new Point(pos.Left, y);
                                }
                            }
                            else
                            {
                                mp.OverridePosition = new Point(pos.Left, pos.Top); // use original position (can be scaled)
                            }
                            ExportPngXml.MakeBluRaySupImage(mp);
                            binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
                            if (mp.Bitmap != null)
                            {
                                mp.Bitmap.Dispose();
                                mp.Bitmap = null;
                            }
                        }
                    }
                }
            }
            return(true);
        }