From 653287ff5a1e7c928cccf6351e4f7efd610595fd Mon Sep 17 00:00:00 2001 From: Nikolaj Olsson Date: Sat, 28 Dec 2019 11:32:12 +0100 Subject: [PATCH] Minor fixes for export to "Spumux" - thx Isak :) --- libse/NikseBitmap.cs | 165 ++++++++++-------- libse/VobSub/VobSubWriter.cs | 2 +- src/Forms/ExportPngXml.cs | 20 ++- .../CommandLineConverter.cs | 4 +- 4 files changed, 112 insertions(+), 79 deletions(-) diff --git a/libse/NikseBitmap.cs b/libse/NikseBitmap.cs index d8ad13c3c..61f10eb04 100644 --- a/libse/NikseBitmap.cs +++ b/libse/NikseBitmap.cs @@ -83,22 +83,6 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(input._bitmapData, 0, _bitmapData, 0, _bitmapData.Length); } - public void ReplaceNotDarkWithWhite() - { - var buffer = new byte[3]; - buffer[0] = 255; - buffer[1] = 255; - buffer[2] = 255; - for (int i = 0; i < _bitmapData.Length; i += 4) - { - if (_bitmapData[i + 3] > 200 && // Alpha - _bitmapData[i + 2] + _bitmapData[i + 1] + _bitmapData[i] > 200) - { - Buffer.BlockCopy(buffer, 0, _bitmapData, i, 3); - } - } - } - public void ReplaceYellowWithWhite() { var buffer = new byte[3]; @@ -118,7 +102,7 @@ namespace Nikse.SubtitleEdit.Core } public void ReplaceColor(int alpha, int red, int green, int blue, - int alphaTo, int redTo, int greenTo, int blueTo) + int alphaTo, int redTo, int greenTo, int blueTo) { var buffer = new byte[4]; buffer[0] = (byte)blueTo; @@ -141,12 +125,12 @@ namespace Nikse.SubtitleEdit.Core { for (int i = 0; i < _bitmapData.Length;) { - _bitmapData[i] = (byte) ~_bitmapData[i]; + _bitmapData[i] = (byte)~_bitmapData[i]; i++; _bitmapData[i] = (byte)~_bitmapData[i]; i++; _bitmapData[i] = (byte)~_bitmapData[i]; - i +=2; + i += 2; } } @@ -201,52 +185,6 @@ namespace Nikse.SubtitleEdit.Core } } - public int MakeOneColorRemoverOthers(Color c1, Color c2, int maxDif) - { - var buffer1 = new byte[4]; - buffer1[0] = c1.B; - buffer1[1] = c1.G; - buffer1[2] = c1.R; - buffer1[3] = c1.A; - - var buffer2 = new byte[4]; - buffer2[0] = c2.B; - buffer2[1] = c2.G; - buffer2[2] = c2.R; - buffer2[3] = c2.A; - - var bufferTransparent = new byte[4]; - bufferTransparent[0] = 0; - bufferTransparent[1] = 0; - bufferTransparent[2] = 0; - bufferTransparent[3] = 0; - int count = 0; - for (int i = 0; i < _bitmapData.Length; i += 4) - { - if (_bitmapData[i + 3] > 20) - { - if (Math.Abs(buffer1[0] - _bitmapData[i]) < maxDif && - Math.Abs(buffer1[1] - _bitmapData[i + 1]) < maxDif && - Math.Abs(buffer1[2] - _bitmapData[i + 2]) < maxDif || - Math.Abs(buffer2[0] - _bitmapData[i]) < maxDif && - Math.Abs(buffer2[1] - _bitmapData[i + 1]) < maxDif && - Math.Abs(buffer2[2] - _bitmapData[i + 2]) < maxDif) - { - count++; - } - else - { - Buffer.BlockCopy(bufferTransparent, 0, _bitmapData, i, 4); - } - } - else - { - Buffer.BlockCopy(bufferTransparent, 0, _bitmapData, i, 4); - } - } - return count; - } - private static Color GetOutlineColor(Color borderColor) { if (borderColor.R + borderColor.G + borderColor.B < 30) @@ -264,7 +202,7 @@ namespace Nikse.SubtitleEdit.Core /// Pattern color, normally white or yellow /// Emphasis 1, normally black or near black (border) /// - public Color ConverToFourColors(Color background, Color pattern, Color emphasis1, bool useInnerAntialize) + public Color ConvertToFourColors(Color background, Color pattern, Color emphasis1, bool useInnerAntialize) { var backgroundBuffer = new byte[4]; backgroundBuffer[0] = background.B; @@ -380,6 +318,7 @@ namespace Nikse.SubtitleEdit.Core } } } + return antializeColor; } @@ -429,6 +368,7 @@ namespace Nikse.SubtitleEdit.Core index = indexBufferUnEqual; buffer = bufferUnEqual; } + var indexHalfNibble = false; var lastColor = -1; var count = 0; @@ -453,6 +393,7 @@ namespace Nikse.SubtitleEdit.Core count = 1; } } + if (count > 0) { WriteRle(ref indexHalfNibble, lastColor, count, ref index, buffer); @@ -552,6 +493,7 @@ namespace Nikse.SubtitleEdit.Core index++; buffer[index] = (byte)((n & Helper.B00011111) << 4); } + indexHalfNibble = !indexHalfNibble; } @@ -587,6 +529,7 @@ namespace Nikse.SubtitleEdit.Core { buffer[index] = (byte)(n << 4); } + indexHalfNibble = !indexHalfNibble; } @@ -642,8 +585,10 @@ namespace Nikse.SubtitleEdit.Core leftStart = 0; } } + y++; } + x++; } @@ -670,8 +615,10 @@ namespace Nikse.SubtitleEdit.Core rightEnd = Width - 1; } } + y++; } + x--; } @@ -696,8 +643,10 @@ namespace Nikse.SubtitleEdit.Core newHeight = Height; } } + x++; } + y--; } } @@ -722,6 +671,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, newWidthX4); index += newWidthX4; } + Width = newWidth; Height = newHeight; _bitmapData = newBitmapData; @@ -751,8 +701,10 @@ namespace Nikse.SubtitleEdit.Core leftStart = 0; } } + y++; } + x++; } @@ -775,8 +727,10 @@ namespace Nikse.SubtitleEdit.Core rightEnd = Width - 1; } } + y++; } + x--; } @@ -801,8 +755,10 @@ namespace Nikse.SubtitleEdit.Core newHeight = Height; } } + x++; } + y--; } } @@ -827,6 +783,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, newWidthX4); index += newWidthX4; } + Width = newWidth; Height = newHeight; _bitmapData = newBitmapData; @@ -853,8 +810,10 @@ namespace Nikse.SubtitleEdit.Core newTop = 0; } } + x++; } + y++; } @@ -872,6 +831,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, _widthX4); index += _widthX4; } + Height = newHeight; _bitmapData = newBitmapData; } @@ -896,8 +856,10 @@ namespace Nikse.SubtitleEdit.Core newTop = 0; } } + x++; } + y++; } @@ -915,6 +877,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, _widthX4); index += _widthX4; } + Height = newHeight; _bitmapData = newBitmapData; return newTop; @@ -934,11 +897,14 @@ namespace Nikse.SubtitleEdit.Core { return cropping; } + x++; } + y--; cropping++; } + return cropping; } @@ -1029,13 +995,15 @@ namespace Nikse.SubtitleEdit.Core return smallestDiffIndex; } } + i++; } + maxDiff = smallestDiff; return smallestDiffIndex; } - public Bitmap ConverTo8BitsPerPixel() + public Bitmap ConvertTo8BitsPerPixel() { var newBitmap = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed); var palette = new List { Color.Transparent }; @@ -1091,6 +1059,7 @@ namespace Nikse.SubtitleEdit.Core } } } + Marshal.Copy(bytes, 0, data.Scan0, bytes.Length); newBitmap.UnlockBits(data); newBitmap.Palette = bPalette; @@ -1119,6 +1088,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, sectionWidthX4); index += sectionWidthX4; } + return new NikseBitmap(section.Width, section.Height, newBitmapData); } @@ -1138,6 +1108,7 @@ namespace Nikse.SubtitleEdit.Core brightest = c; } } + if (IsColorClose(Color.White, brightest, 40)) { return Color.Transparent; @@ -1167,6 +1138,7 @@ namespace Nikse.SubtitleEdit.Core brightest = c; } } + return brightest; } @@ -1297,6 +1269,7 @@ namespace Nikse.SubtitleEdit.Core Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, _widthX4); index += 4 * newWidth; } + Width = newWidth; _bitmapData = newBitmapData; for (int y = 0; y < Height; y++) @@ -1319,6 +1292,7 @@ namespace Nikse.SubtitleEdit.Core int index = marginX4 + (y + margin) * newWidthX4; Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, _widthX4); } + Width = newWidth; Height = newHeight; _bitmapData = newBitmapData; @@ -1346,7 +1320,7 @@ namespace Nikse.SubtitleEdit.Core var pixels = new byte[_bitmapData.Length]; int offsetDest = 0; - for (int y = Height - 1; y >= 0; y--) // takes lines from bottom lines to top (mirrowed horizontally) + for (int y = Height - 1; y >= 0; y--) // takes lines from bottom lines to top (mirrored horizontally) { for (int x = 0; x < Width; x++) { @@ -1376,8 +1350,61 @@ namespace Nikse.SubtitleEdit.Core return false; } } + return true; } + public void EnsureEvenLines(Color fillColor) + { + if (Width % 2 == 0 && Height % 2 == 0) + { + return; + } + + int newWidth = Width; + bool widthChanged = false; + if (Width % 2 != 0) + { + newWidth++; + widthChanged = true; + } + + int newHeight = Height; + bool heightChanged = false; + if (Height % 2 != 0) + { + newHeight++; + heightChanged = true; + } + + var newBitmapData = new byte[newWidth * newHeight * 4]; + var newWidthX4 = 4 * newWidth; + int index = 0; + for (int y = 0; y < Height; y++) + { + int pixelAddress = y * _widthX4; + Buffer.BlockCopy(_bitmapData, pixelAddress, newBitmapData, index, _widthX4); + index += newWidthX4; + } + Width = newWidth; + Height = newHeight; + _bitmapData = newBitmapData; + + if (widthChanged) + { + for (var y = 0; y < Height; y++) + { + SetPixel(Width - 1, y, fillColor); + } + } + + if (heightChanged) + { + for (var x = 0; x < Width; x++) + { + SetPixel(x, Height - 1, fillColor); + } + } + } } -} +} \ No newline at end of file diff --git a/libse/VobSub/VobSubWriter.cs b/libse/VobSub/VobSubWriter.cs index 07f7d97a4..1d1988650 100644 --- a/libse/VobSub/VobSubWriter.cs +++ b/libse/VobSub/VobSubWriter.cs @@ -143,7 +143,7 @@ namespace Nikse.SubtitleEdit.Core.VobSub _idx.AppendLine($"timestamp: {p.StartTime.Hours:00}:{p.StartTime.Minutes:00}:{p.StartTime.Seconds:00}:{p.StartTime.Milliseconds:000}, filepos: {_subFile.Position.ToString("X").PadLeft(9, '0').ToLowerInvariant()}"); var nbmp = new NikseBitmap(bmp); - _emphasis2 = nbmp.ConverToFourColors(_background, _pattern, _emphasis1, _useInnerAntiAliasing); + _emphasis2 = nbmp.ConvertToFourColors(_background, _pattern, _emphasis1, _useInnerAntiAliasing); var twoPartBuffer = nbmp.RunLengthEncodeForDvd(_background, _pattern, _emphasis1, _emphasis2); var imageBuffer = GetSubImageBuffer(twoPartBuffer, nbmp, p, alignment, overridePosition); diff --git a/src/Forms/ExportPngXml.cs b/src/Forms/ExportPngXml.cs index 437bc5d96..b1ffb4da5 100644 --- a/src/Forms/ExportPngXml.cs +++ b/src/Forms/ExportPngXml.cs @@ -1412,7 +1412,7 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + var parameters = new EncoderParameters { Param = { [0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 8) } }; var nbmp = new NikseBitmap(param.Bitmap); - var b = nbmp.ConverTo8BitsPerPixel(); + var b = nbmp.ConvertTo8BitsPerPixel(); b.Save(fileName, encoder, parameters); b.Dispose(); @@ -1421,8 +1421,8 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + } imagesSavedCount++; - const string paragraphWriteFormat = "\t\t"; - const string timeFormat = "{0:00}:{1:00}:{2:00}:{3:00}"; + const string paragraphWriteFormat = "\t\t"; + const string timeFormat = "{0:00}:{1:00}:{2:00}.{3:00}"; double factor = TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate; string startTime = string.Format(timeFormat, param.P.StartTime.Hours, param.P.StartTime.Minutes, param.P.StartTime.Seconds, (int)Math.Round(param.P.StartTime.Milliseconds / factor)); @@ -1724,7 +1724,7 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 8); var nbmp = new NikseBitmap(outBitmap); - var b = nbmp.ConverTo8BitsPerPixel(); + var b = nbmp.ConvertTo8BitsPerPixel(); b.Save(targetImageFileName, encoder, parameters); b.Dispose(); @@ -1794,7 +1794,7 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 8); var nbmp = new NikseBitmap(param.Bitmap); - var b = nbmp.ConverTo8BitsPerPixel(); + var b = nbmp.ConvertTo8BitsPerPixel(); b.Save(fileName, encoder, parameters); b.Dispose(); @@ -1881,7 +1881,7 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 8); var nbmp = new NikseBitmap(param.Bitmap); - var b = nbmp.ConverTo8BitsPerPixel(); + var b = nbmp.ConvertTo8BitsPerPixel(); b.Save(fileName, encoder, parameters); b.Dispose(); @@ -2284,7 +2284,13 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + if (_exportType == ExportFormats.VobSub || _exportType == ExportFormats.Stl || _exportType == ExportFormats.Spumux) { var nbmp = new NikseBitmap(bmp); - nbmp.ConverToFourColors(Color.Transparent, _subtitleColor, _borderColor, !checkBoxTransAntiAliase.Checked); + nbmp.ConvertToFourColors(Color.Transparent, _subtitleColor, _borderColor, !checkBoxTransAntiAliase.Checked); + + if (_exportType == ExportFormats.Spumux) + { + nbmp.EnsureEvenLines(mbp.BoxSingleLine ? Color.Transparent : mbp.BackgroundColor); + } + var temp = nbmp.GetBitmap(); bmp.Dispose(); return temp; diff --git a/src/Logic/CommandLineConvert/CommandLineConverter.cs b/src/Logic/CommandLineConvert/CommandLineConverter.cs index 89c396293..00a8df231 100644 --- a/src/Logic/CommandLineConvert/CommandLineConverter.cs +++ b/src/Logic/CommandLineConvert/CommandLineConverter.cs @@ -1482,7 +1482,7 @@ namespace Nikse.SubtitleEdit.Logic.CommandLineConvert { var sourceBitmap = binaryParagraphs[index].GetBitmap(); var nbmp = new NikseBitmap(sourceBitmap); - nbmp.ConverToFourColors(Color.Transparent, Color.White, Color.Black, true); + nbmp.ConvertToFourColors(Color.Transparent, Color.White, Color.Black, true); mp.Bitmap = nbmp.GetBitmap(); sourceBitmap.Dispose(); mp.Forced = binaryParagraphs[index].IsForced; @@ -1494,7 +1494,7 @@ namespace Nikse.SubtitleEdit.Logic.CommandLineConvert { var sourceBitmap = (Bitmap)Image.FromStream(ms); var nbmp = new NikseBitmap(sourceBitmap); - nbmp.ConverToFourColors(Color.Transparent, Color.White, Color.Black, true); + nbmp.ConvertToFourColors(Color.Transparent, Color.White, Color.Black, true); mp.Bitmap = nbmp.GetBitmap(); sourceBitmap.Dispose(); }