mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-26 05:02:36 +01:00
Working on vobsub export (not working yet)
git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@935 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
parent
39e15a02db
commit
f49ceeb1c3
@ -31,6 +31,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
public byte[] Buffer { get; set; }
|
||||
public int ScreenWidth { get; set; }
|
||||
public int ScreenHeight { get; set; }
|
||||
public bool Saved { get; set; }
|
||||
}
|
||||
|
||||
Subtitle _subtitle;
|
||||
@ -90,6 +91,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
ScreenWidth = screenWidth,
|
||||
ScreenHeight = screenHeight,
|
||||
Bitmap = null,
|
||||
Saved = false,
|
||||
};
|
||||
if (index < _subtitle.Paragraphs.Count)
|
||||
{
|
||||
@ -104,6 +106,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
private void buttonExport_Click(object sender, EventArgs e)
|
||||
{
|
||||
buttonExport.Enabled = false;
|
||||
SetupImageParameters();
|
||||
|
||||
if (!string.IsNullOrEmpty(_fileName))
|
||||
@ -128,17 +131,6 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
_exportType == "VOBSUB" && saveFileDialog1.ShowDialog(this) == DialogResult.OK ||
|
||||
_exportType == "BDNXML" && folderBrowserDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
FileStream binarySubtitleFile = null;
|
||||
VobSubWriter vobSubWriter = null;
|
||||
if (_exportType == "BLURAYSUP")
|
||||
binarySubtitleFile = new FileStream(saveFileDialog1.FileName, FileMode.Create);
|
||||
else if (_exportType == "VOBSUB")
|
||||
vobSubWriter = new VobSubWriter(saveFileDialog1.FileName);
|
||||
|
||||
progressBar1.Value = 0;
|
||||
progressBar1.Maximum = _subtitle.Paragraphs.Count-1;
|
||||
progressBar1.Visible = true;
|
||||
|
||||
int width = 1920;
|
||||
int height = 1080;
|
||||
if (comboBoxResolution.SelectedIndex == 1)
|
||||
@ -162,6 +154,17 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
height = 480;
|
||||
}
|
||||
|
||||
FileStream binarySubtitleFile = null;
|
||||
VobSubWriter vobSubWriter = null;
|
||||
if (_exportType == "BLURAYSUP")
|
||||
binarySubtitleFile = new FileStream(saveFileDialog1.FileName, FileMode.Create);
|
||||
else if (_exportType == "VOBSUB")
|
||||
vobSubWriter = new VobSubWriter(saveFileDialog1.FileName, width, height, 15, 32, _subtitleColor, _borderColor);
|
||||
|
||||
progressBar1.Value = 0;
|
||||
progressBar1.Maximum = _subtitle.Paragraphs.Count-1;
|
||||
progressBar1.Visible = true;
|
||||
|
||||
const int border = 25;
|
||||
int imagesSavedCount = 0;
|
||||
var sb = new StringBuilder();
|
||||
@ -256,40 +259,49 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
MessageBox.Show(string.Format(Configuration.Settings.Language.ExportPngXml.XImagesSavedInY, imagesSavedCount, folderBrowserDialog1.SelectedPath));
|
||||
}
|
||||
}
|
||||
buttonExport.Enabled = true;
|
||||
}
|
||||
|
||||
private int WriteParagraph(int width, StringBuilder sb, int border, int height, int imagesSavedCount,
|
||||
VobSubWriter vobSubWriter, FileStream binarySubtitleFile, MakeBitmapParameter paramEqual,
|
||||
VobSubWriter vobSubWriter, FileStream binarySubtitleFile, MakeBitmapParameter param,
|
||||
int i)
|
||||
{
|
||||
if (paramEqual.Bitmap != null)
|
||||
if (param.Bitmap != null)
|
||||
{
|
||||
if (_exportType == "BLURAYSUP")
|
||||
{
|
||||
binarySubtitleFile.Write(paramEqual.Buffer, 0, paramEqual.Buffer.Length);
|
||||
if (!param.Saved)
|
||||
binarySubtitleFile.Write(param.Buffer, 0, param.Buffer.Length);
|
||||
param.Saved = true;
|
||||
}
|
||||
else if (_exportType == "VOBSUB")
|
||||
{
|
||||
vobSubWriter.WriteParagraph(paramEqual.P, paramEqual.Bitmap);
|
||||
if (!param.Saved)
|
||||
vobSubWriter.WriteParagraph(param.P, param.Bitmap);
|
||||
param.Saved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
string numberString = string.Format("{0:0000}", i);
|
||||
string fileName = Path.Combine(folderBrowserDialog1.SelectedPath, numberString + ".png");
|
||||
paramEqual.Bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
|
||||
imagesSavedCount++;
|
||||
if (!param.Saved)
|
||||
{
|
||||
string numberString = string.Format("{0:0000}", i);
|
||||
string fileName = Path.Combine(folderBrowserDialog1.SelectedPath, numberString + ".png");
|
||||
param.Bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
|
||||
imagesSavedCount++;
|
||||
|
||||
//<Event InTC="00:00:24:07" OutTC="00:00:31:13" Forced="False">
|
||||
// <Graphic Width="696" Height="111" X="612" Y="930">subtitle_exp_0001.png</Graphic>
|
||||
//</Event>
|
||||
sb.AppendLine("<Event InTC=\"" + BdnXmlTimeCode(paramEqual.P.StartTime) + "\" OutTC=\"" +
|
||||
BdnXmlTimeCode(paramEqual.P.EndTime) + "\" Forced=\"False\">");
|
||||
int x = (width - paramEqual.Bitmap.Width)/2;
|
||||
int y = height - (paramEqual.Bitmap.Height + border);
|
||||
sb.AppendLine(" <Graphic Width=\"" + paramEqual.Bitmap.Width.ToString() + "\" Height=\"" +
|
||||
paramEqual.Bitmap.Height.ToString() + "\" X=\"" + x.ToString() + "\" Y=\"" + y.ToString() +
|
||||
"\">" + numberString + ".png</Graphic>");
|
||||
sb.AppendLine("</Event>");
|
||||
//<Event InTC="00:00:24:07" OutTC="00:00:31:13" Forced="False">
|
||||
// <Graphic Width="696" Height="111" X="612" Y="930">subtitle_exp_0001.png</Graphic>
|
||||
//</Event>
|
||||
sb.AppendLine("<Event InTC=\"" + BdnXmlTimeCode(param.P.StartTime) + "\" OutTC=\"" +
|
||||
BdnXmlTimeCode(param.P.EndTime) + "\" Forced=\"False\">");
|
||||
int x = (width - param.Bitmap.Width) / 2;
|
||||
int y = height - (param.Bitmap.Height + border);
|
||||
sb.AppendLine(" <Graphic Width=\"" + param.Bitmap.Width.ToString() + "\" Height=\"" +
|
||||
param.Bitmap.Height.ToString() + "\" X=\"" + x.ToString() + "\" Y=\"" + y.ToString() +
|
||||
"\">" + numberString + ".png</Graphic>");
|
||||
sb.AppendLine("</Event>");
|
||||
param.Saved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return imagesSavedCount;
|
||||
@ -629,7 +641,10 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
comboBoxResolution.SelectedIndex = 0;
|
||||
|
||||
if (exportType == "VOBSUB")
|
||||
{
|
||||
comboBoxBorderWidth.SelectedIndex = 3;
|
||||
comboBoxResolution.SelectedIndex = 3;
|
||||
}
|
||||
|
||||
foreach (var x in FontFamily.Families)
|
||||
{
|
||||
|
1
src/Forms/Main.Designer.cs
generated
1
src/Forms/Main.Designer.cs
generated
@ -963,7 +963,6 @@
|
||||
this.vobSubsubidxToolStripMenuItem.Name = "vobSubsubidxToolStripMenuItem";
|
||||
this.vobSubsubidxToolStripMenuItem.Size = new System.Drawing.Size(245, 22);
|
||||
this.vobSubsubidxToolStripMenuItem.Text = "VobSub (sub/idx)...";
|
||||
this.vobSubsubidxToolStripMenuItem.Visible = false;
|
||||
this.vobSubsubidxToolStripMenuItem.Click += new System.EventHandler(this.vobSubsubidxToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripMenuItemCavena890
|
||||
|
@ -681,7 +681,7 @@
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAD2
|
||||
CAAAAk1TRnQBSQFMAgEBAgEAAbgBDgG4AQ4BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
CAAAAk1TRnQBSQFMAgEBAgEAAcABDgHAAQ4BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
||||
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
||||
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Nikse.SubtitleEdit.Logic.VobSub;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Logic
|
||||
{
|
||||
@ -93,47 +94,74 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
emphasis2Buffer[0] = (byte)emphasis2.B;
|
||||
emphasis2Buffer[1] = (byte)emphasis2.G;
|
||||
emphasis2Buffer[2] = (byte)emphasis2.R;
|
||||
emphasis2Buffer[3] = (byte)emphasis2.A;
|
||||
emphasis2Buffer[3] = (byte)emphasis2.A;
|
||||
|
||||
for (int i = 0; i < _bitmapData.Length; i += 4)
|
||||
{
|
||||
int smallestDiff = 10000; // Math.Abs(backgroundBuffer[0] - _bitmapData[i]) + Math.Abs(backgroundBuffer[1] - _bitmapData[i + 1]) + Math.Abs(backgroundBuffer[2] - _bitmapData[i + 2]) + Math.Abs(backgroundBuffer[3] - _bitmapData[i + 3]);
|
||||
{
|
||||
int smallestDiff = 10000;
|
||||
byte[] buffer = backgroundBuffer;
|
||||
if (backgroundBuffer[3] == 0 && _bitmapData[i+3] < 10) // transparent
|
||||
if (backgroundBuffer[3] == 0 && _bitmapData[i + 3] < 10) // transparent
|
||||
{
|
||||
smallestDiff = 0;
|
||||
|
||||
int patternDiff = Math.Abs(patternBuffer[0] - _bitmapData[i]) + Math.Abs(patternBuffer[1] - _bitmapData[i + 1]) + Math.Abs(patternBuffer[2] - _bitmapData[i + 2]) + Math.Abs(patternBuffer[3] - _bitmapData[i + 3]);
|
||||
if (patternDiff < smallestDiff)
|
||||
{
|
||||
smallestDiff = patternDiff;
|
||||
buffer = patternBuffer;
|
||||
}
|
||||
|
||||
int emphasis1Diff = Math.Abs(emphasis1Buffer[0] - _bitmapData[i]) + Math.Abs(emphasis1Buffer[1] - _bitmapData[i + 1]) + Math.Abs(emphasis1Buffer[2] - _bitmapData[i + 2]) + Math.Abs(emphasis1Buffer[3] - _bitmapData[i + 3]);
|
||||
if (emphasis1Diff < smallestDiff)
|
||||
else
|
||||
{
|
||||
smallestDiff = emphasis1Diff;
|
||||
buffer = emphasis1Buffer;
|
||||
}
|
||||
int patternDiff = Math.Abs(patternBuffer[0] - _bitmapData[i]) + Math.Abs(patternBuffer[1] - _bitmapData[i + 1]) + Math.Abs(patternBuffer[2] - _bitmapData[i + 2]) + Math.Abs(patternBuffer[3] - _bitmapData[i + 3]);
|
||||
if (patternDiff < smallestDiff)
|
||||
{
|
||||
smallestDiff = patternDiff;
|
||||
buffer = patternBuffer;
|
||||
}
|
||||
|
||||
int emphasis2Diff = Math.Abs(emphasis2Buffer[0] - _bitmapData[i]) + Math.Abs(emphasis2Buffer[1] - _bitmapData[i + 1]) + Math.Abs(emphasis2Buffer[2] - _bitmapData[i + 2]) + Math.Abs(emphasis2Buffer[3] - _bitmapData[i + 3]);
|
||||
if (emphasis2Diff < smallestDiff)
|
||||
{
|
||||
smallestDiff = emphasis2Diff;
|
||||
buffer = emphasis2Buffer;
|
||||
}
|
||||
else if (_bitmapData[i + 3] >= 10 && _bitmapData[i + 3] < 90) // anti-alias
|
||||
{
|
||||
smallestDiff = emphasis2Diff;
|
||||
buffer = emphasis2Buffer;
|
||||
}
|
||||
int emphasis1Diff = Math.Abs(emphasis1Buffer[0] - _bitmapData[i]) + Math.Abs(emphasis1Buffer[1] - _bitmapData[i + 1]) + Math.Abs(emphasis1Buffer[2] - _bitmapData[i + 2]) + Math.Abs(emphasis1Buffer[3] - _bitmapData[i + 3]);
|
||||
if (emphasis1Diff < smallestDiff)
|
||||
{
|
||||
smallestDiff = emphasis1Diff;
|
||||
buffer = emphasis1Buffer;
|
||||
}
|
||||
|
||||
int emphasis2Diff = Math.Abs(emphasis2Buffer[0] - _bitmapData[i]) + Math.Abs(emphasis2Buffer[1] - _bitmapData[i + 1]) + Math.Abs(emphasis2Buffer[2] - _bitmapData[i + 2]) + Math.Abs(emphasis2Buffer[3] - _bitmapData[i + 3]);
|
||||
if (emphasis2Diff < smallestDiff)
|
||||
{
|
||||
smallestDiff = emphasis2Diff;
|
||||
buffer = emphasis2Buffer;
|
||||
}
|
||||
else if (_bitmapData[i + 3] >= 10 && _bitmapData[i + 3] < 90) // anti-alias
|
||||
{
|
||||
smallestDiff = emphasis2Diff;
|
||||
buffer = emphasis2Buffer;
|
||||
}
|
||||
}
|
||||
Buffer.BlockCopy(buffer, 0, _bitmapData, i, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public RunLengthTwoParts RunLengthEncodeForDvd(Color background, Color pattern, Color emphasis1, Color emphasis2)
|
||||
{
|
||||
byte[] backgroundBuffer = new byte[4];
|
||||
backgroundBuffer[0] = (byte)background.B;
|
||||
backgroundBuffer[1] = (byte)background.G;
|
||||
backgroundBuffer[2] = (byte)background.R;
|
||||
backgroundBuffer[3] = (byte)background.A;
|
||||
|
||||
byte[] patternBuffer = new byte[4];
|
||||
patternBuffer[0] = (byte)pattern.B;
|
||||
patternBuffer[1] = (byte)pattern.G;
|
||||
patternBuffer[2] = (byte)pattern.R;
|
||||
patternBuffer[3] = (byte)pattern.A;
|
||||
|
||||
byte[] emphasis1Buffer = new byte[4];
|
||||
emphasis1Buffer[0] = (byte)emphasis1.B;
|
||||
emphasis1Buffer[1] = (byte)emphasis1.G;
|
||||
emphasis1Buffer[2] = (byte)emphasis1.R;
|
||||
emphasis1Buffer[3] = (byte)emphasis1.A;
|
||||
|
||||
byte[] emphasis2Buffer = new byte[4];
|
||||
emphasis2Buffer[0] = (byte)emphasis2.B;
|
||||
emphasis2Buffer[1] = (byte)emphasis2.G;
|
||||
emphasis2Buffer[2] = (byte)emphasis2.R;
|
||||
emphasis2Buffer[3] = (byte)emphasis2.A;
|
||||
|
||||
byte[] bufferEqual = new byte[Width * Height];
|
||||
byte[] bufferUnEqual = new byte[Width * Height];
|
||||
int indexBufferEqual = 0;
|
||||
@ -163,7 +191,7 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
int color = GetDvdColor(x, y, background, pattern, emphasis1, emphasis2);
|
||||
int color = GetDvdColor(x, y, backgroundBuffer, patternBuffer, emphasis1Buffer, emphasis2Buffer);
|
||||
|
||||
if (lastColor == -1)
|
||||
{
|
||||
@ -203,7 +231,7 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
twoParts.Buffer1 = new byte[indexBufferEqual];
|
||||
Buffer.BlockCopy(bufferEqual, 0, twoParts.Buffer1, 0, indexBufferEqual);
|
||||
twoParts.Buffer2 = new byte[indexBufferUnEqual];
|
||||
Buffer.BlockCopy(bufferEqual, 0, twoParts.Buffer2, 0, indexBufferUnEqual);
|
||||
Buffer.BlockCopy(bufferUnEqual, 0, twoParts.Buffer2, 0, indexBufferUnEqual);
|
||||
return twoParts;
|
||||
}
|
||||
|
||||
@ -252,22 +280,26 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
index++;
|
||||
byte secondNibble = (byte)(n & Nikse.SubtitleEdit.Logic.VobSub.Helper.B11111111);
|
||||
buffer[index] = (byte)secondNibble;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteThreeNibbles(byte[] buffer, int count, int color, ref int index, ref bool indexHalfNibble)
|
||||
{
|
||||
byte n = (byte)((count << 2) + color);
|
||||
//Value Bits n=length, c=color
|
||||
//16-63 12 0 0 0 0 n n n n n n c c (one and a half byte)
|
||||
ushort n = (ushort)((count << 2) + color);
|
||||
if (indexHalfNibble)
|
||||
{
|
||||
index++; // there should already zeroes in last nibble
|
||||
buffer[index] = (byte)n;
|
||||
index++;
|
||||
buffer[index] = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[index] = (byte)(n >> 4);
|
||||
index++;
|
||||
buffer[index] = (byte)(n << 4);
|
||||
buffer[index] = (byte)((n & Helper.B00011111) << 4);
|
||||
}
|
||||
indexHalfNibble = !indexHalfNibble;
|
||||
}
|
||||
@ -275,14 +307,16 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
|
||||
private void WriteTwoNibbles(byte[] buffer, int count, int color, ref int index, bool indexHalfNibble)
|
||||
{
|
||||
//Value Bits n=length, c=color
|
||||
//4-15 8 0 0 n n n n c c (one byte)
|
||||
byte n = (byte)((count << 2) + color);
|
||||
if (indexHalfNibble)
|
||||
{
|
||||
byte firstNibble = (byte)(n >> 4);
|
||||
buffer[index] = (byte)(buffer[index] & firstNibble);
|
||||
byte secondNibble = (byte)(n << 4);
|
||||
buffer[index] = (byte)(buffer[index] | firstNibble);
|
||||
byte secondNibble = (byte)((n & Helper.B00001111) << 4);
|
||||
index++;
|
||||
buffer[index] = (byte)secondNibble;
|
||||
buffer[index] = secondNibble;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -296,7 +330,7 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
byte n = (byte)((count << 2) + color);
|
||||
if (indexHalfNibble)
|
||||
{
|
||||
buffer[index] = (byte)(buffer[index] & n);
|
||||
buffer[index] = (byte)(buffer[index] | n);
|
||||
index++;
|
||||
}
|
||||
else
|
||||
@ -306,15 +340,20 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
indexHalfNibble = !indexHalfNibble;
|
||||
}
|
||||
|
||||
private int GetDvdColor(int x, int y, Color background, Color pattern, Color emphasis1, Color emphasis2)
|
||||
private int GetDvdColor(int x, int y, byte[] background, byte[] pattern, byte[] emphasis1, byte[] emphasis2)
|
||||
{
|
||||
Color c = GetPixelNext();
|
||||
if (emphasis2 == c)
|
||||
return 3;
|
||||
else if (emphasis1 == c)
|
||||
return 2;
|
||||
if (pattern == c)
|
||||
_pixelAddress += 4;
|
||||
int a = _bitmapData[_pixelAddress + 3];
|
||||
int r = _bitmapData[_pixelAddress + 2];
|
||||
int g = _bitmapData[_pixelAddress + 1];
|
||||
int b = _bitmapData[_pixelAddress];
|
||||
|
||||
if (pattern[0] == _bitmapData[_pixelAddress] && pattern[1] == _bitmapData[_pixelAddress + 1] && pattern[2] == _bitmapData[_pixelAddress + 2] && pattern[3] == _bitmapData[_pixelAddress + 3])
|
||||
return 1;
|
||||
if (emphasis1[0] == _bitmapData[_pixelAddress] && emphasis1[1] == _bitmapData[_pixelAddress + 1] && emphasis1[2] == _bitmapData[_pixelAddress + 2] && emphasis1[3] == _bitmapData[_pixelAddress + 3])
|
||||
return 2;
|
||||
if (emphasis2[0] == _bitmapData[_pixelAddress] && emphasis2[1] == _bitmapData[_pixelAddress + 1] && emphasis2[2] == _bitmapData[_pixelAddress + 2] && emphasis2[3] == _bitmapData[_pixelAddress + 3])
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
string[] colors = s.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string hex in colors)
|
||||
{
|
||||
if (hex.Length == 6)
|
||||
Palette.Add(HexToColor(hex));
|
||||
Palette.Add(HexToColor(hex));
|
||||
}
|
||||
}
|
||||
else if (line.ToLower().StartsWith("id:") && line.Length > 4)
|
||||
@ -63,10 +62,23 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
|
||||
private static Color HexToColor(string hex)
|
||||
{
|
||||
int r = Convert.ToInt32(hex.Substring(0, 2), 16);
|
||||
int g = Convert.ToInt32(hex.Substring(2, 2), 16);
|
||||
int b = Convert.ToInt32(hex.Substring(4, 2), 16);
|
||||
return Color.FromArgb(r, g, b);
|
||||
hex = hex.TrimStart('#').Trim();
|
||||
if (hex.Length == 6)
|
||||
{
|
||||
int r = Convert.ToInt32(hex.Substring(0, 2), 16);
|
||||
int g = Convert.ToInt32(hex.Substring(2, 2), 16);
|
||||
int b = Convert.ToInt32(hex.Substring(4, 2), 16);
|
||||
return Color.FromArgb(r, g, b);
|
||||
}
|
||||
else if (hex.Length == 8)
|
||||
{
|
||||
int a = Convert.ToInt32(hex.Substring(0, 2), 16);
|
||||
int r = Convert.ToInt32(hex.Substring(2, 2), 16);
|
||||
int g = Convert.ToInt32(hex.Substring(4, 2), 16);
|
||||
int b = Convert.ToInt32(hex.Substring(6, 2), 16);
|
||||
return Color.FromArgb(a, r, g, b);
|
||||
}
|
||||
return Color.Red;
|
||||
}
|
||||
|
||||
private static IdxParagraph GetTimeCodeAndFilePosition(string line)
|
||||
|
@ -142,11 +142,10 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
case (int)DisplayControlCommand.SetDisplayArea: // 5
|
||||
if (_data.Length > commandIndex + 6)
|
||||
{
|
||||
string binary = Helper.GetBinaryString(_data, commandIndex + 1, 6);
|
||||
int startingX = (int)Helper.GetUInt32FromBinaryString(binary.Substring(0, 12));
|
||||
int endingX = (int)Helper.GetUInt32FromBinaryString(binary.Substring(12, 12));
|
||||
int startingY = (int)Helper.GetUInt32FromBinaryString(binary.Substring(24, 12));
|
||||
int endingY = (int)Helper.GetUInt32FromBinaryString(binary.Substring(36, 12));
|
||||
int startingX = (_data[commandIndex + 1] << 8 | _data[commandIndex + 2]) >> 4;
|
||||
int endingX = (_data[commandIndex + 2] & Helper.B00001111) << 8 | _data[commandIndex + 3];
|
||||
int startingY = (_data[commandIndex + 4] << 8 | _data[commandIndex + 5]) >> 4;
|
||||
int endingY = (_data[commandIndex + 5] & Helper.B00001111) << 8 | _data[commandIndex + 6];
|
||||
ImageDisplayArea = new Rectangle(startingX, startingY, endingX - startingX, endingY - startingY);
|
||||
}
|
||||
commandIndex += 7;
|
||||
|
@ -7,6 +7,8 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
{
|
||||
public class VobSubWriter
|
||||
{
|
||||
private const int PacketizedElementaryStreamMaximumLength = 2028;
|
||||
|
||||
/// <summary>
|
||||
/// 14 bytes Mpeg 2 pack header
|
||||
/// </summary>
|
||||
@ -30,10 +32,9 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
0x00, 0x00, // 18-19=PES packet length
|
||||
0x81, // 20=Flags: PES scrambling control, PES priority, data alignment indicator, copyright, original or copy
|
||||
0x81, // 21=Flags: PTS DTS flags, ESCR flag, ES rate flag, DSM trick mode flag, additional copy info flag, PES CRC flag, PES extension flag
|
||||
0x05, // 22=PES header data length
|
||||
0x08, // 22=PES header data length
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 9 bytes packetized elementary stream header (PES)
|
||||
/// </summary>
|
||||
@ -60,88 +61,191 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
private string _subFileName;
|
||||
private FileStream _subFile;
|
||||
StringBuilder _idx = new StringBuilder();
|
||||
int _screenWidth = 720;
|
||||
int _screenHeight = 480;
|
||||
int _bottomMargin = 15;
|
||||
int _languageStreamId = 32;
|
||||
|
||||
public VobSubWriter(string subFileName)
|
||||
Color _background = Color.Transparent;
|
||||
Color _pattern = Color.White;
|
||||
Color _emphasis1 = Color.Black;
|
||||
Color _emphasis2 = Color.FromArgb(240, Color.Black);
|
||||
|
||||
|
||||
public VobSubWriter(string subFileName, int screenWidth, int screenHeight, int bottomMargin, int languageStreamId, Color pattern, Color emphasis1)
|
||||
{
|
||||
_subFileName = subFileName;
|
||||
_screenWidth = screenWidth;
|
||||
_screenHeight = screenHeight;
|
||||
_bottomMargin = bottomMargin;
|
||||
_languageStreamId = languageStreamId;
|
||||
_pattern = pattern;
|
||||
_emphasis1 = emphasis1;
|
||||
_emphasis2 = Color.FromArgb(240, emphasis1);
|
||||
_idx = CreateIdxHeader();
|
||||
_subFile = new FileStream(subFileName, FileMode.Create);
|
||||
}
|
||||
|
||||
public void WriteEndianWord(int i)
|
||||
{
|
||||
_subFile.WriteByte((byte)(i / 256));
|
||||
_subFile.WriteByte((byte)(i % 256));
|
||||
}
|
||||
|
||||
private byte[] GetImageBuffer()
|
||||
{
|
||||
var buffer = new byte[];
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void WriteParagraph(Paragraph p, Bitmap bmp)
|
||||
{
|
||||
// timestamp: 00:00:33:900, filepos: 000000000
|
||||
_idx.AppendLine(string.Format("timestamp: {0:00}:{1:00}:{2:00}:{3:000}, filepos: {4}", p.StartTime.Hours, p.StartTime.Minutes, p.StartTime.Seconds, p.StartTime.Milliseconds, _subFile.Position.ToString("X").PadLeft(9, '0')));
|
||||
|
||||
_idx.AppendLine(string.Format("timestamp: {0:00}:{1:00}:{2:00}:{3:000}, filepos: {4}", p.StartTime.Hours, p.StartTime.Minutes, p.StartTime.Seconds, p.StartTime.Milliseconds, _subFile.Position.ToString("X").PadLeft(9, '0')));
|
||||
|
||||
// write binary vobsub file (duration + image)
|
||||
long start = _subFile.Position;
|
||||
_subFile.Write(Mpeg2PackHeaderBuffer, 0, Mpeg2PackHeaderBuffer.Length);
|
||||
|
||||
NikseBitmap nbmp = new NikseBitmap(bmp);
|
||||
nbmp.ConverToFourColors(Color.Transparent, Color.White, Color.FromArgb(200, 0, 0, 0), Color.FromArgb(200, 25, 25, 25));
|
||||
|
||||
var outBmp = nbmp.GetBitmap();
|
||||
outBmp.Save(@"D:\download\-_-" + p.Number.ToString() + ".bmp");
|
||||
bmp.Save(@"D:\download\-__" + p.Number.ToString() + ".bmp");
|
||||
outBmp.Dispose();
|
||||
|
||||
var twoPartBuffer = nbmp.RunLengthEncodeForDvd(Color.Transparent, Color.White, Color.FromArgb(200, 0, 0, 0), Color.FromArgb(200, 25, 25, 25));
|
||||
var nbmp = new NikseBitmap(bmp);
|
||||
nbmp.ConverToFourColors(_background, _pattern, _emphasis1, _emphasis2);
|
||||
var twoPartBuffer = nbmp.RunLengthEncodeForDvd(_background, _pattern, _emphasis1, _emphasis2);
|
||||
|
||||
// PES size
|
||||
int length = Mpeg2PackHeaderBuffer.Length + PacketizedElementaryStreamHeaderBufferFirst.Length + 10 + twoPartBuffer.Length;
|
||||
|
||||
//block_size = 0x800 - header_size;
|
||||
//long j = (header_size - 20) + block_size;
|
||||
//SubHeader[18] = (byte)(j / 0x100);
|
||||
//SubHeader[19] = (byte)(j % 0x100);
|
||||
int length = Mpeg2PackHeaderBuffer.Length + PacketizedElementaryStreamHeaderBufferFirst.Length + twoPartBuffer.Length + 31;
|
||||
|
||||
PacketizedElementaryStreamHeaderBufferFirst[4] = (byte)(length / 256);
|
||||
PacketizedElementaryStreamHeaderBufferFirst[5] = (byte)(length % 256);
|
||||
|
||||
_subFile.Write(PacketizedElementaryStreamHeaderBufferFirst, 0, PacketizedElementaryStreamHeaderBufferFirst.Length);
|
||||
|
||||
// PTS (timestamp)
|
||||
FillPTS(p.StartTime);
|
||||
_subFile.Write(PresentationTimeStampBuffer, 0, PresentationTimeStampBuffer.Length);
|
||||
|
||||
_subFile.WriteByte(0x32); //sub-stream number
|
||||
_subFile.WriteByte(0x1e); // ??
|
||||
_subFile.WriteByte(0x60); // ??
|
||||
_subFile.WriteByte(0x3a); // ??
|
||||
|
||||
_subFile.WriteByte((byte)_languageStreamId); //sub-stream number, 32=english
|
||||
|
||||
// sup picture datasize
|
||||
WriteEndianWord(twoPartBuffer.Length + 42);
|
||||
|
||||
// first display control sequence table address
|
||||
int startDisplayControlSequenceTableAddress = twoPartBuffer.Length + 4;
|
||||
WriteEndianWord(startDisplayControlSequenceTableAddress);
|
||||
|
||||
if (twoPartBuffer.Length < 0x800 - (_subFile.Position - start))
|
||||
{
|
||||
// Write image
|
||||
int imageTopFieldDataAddress = (int) (4);
|
||||
_subFile.Write(twoPartBuffer.Buffer1, 0, twoPartBuffer.Buffer1.Length);
|
||||
int imageBottomFieldDataAddress = 4 + twoPartBuffer.Buffer1.Length;
|
||||
_subFile.Write(twoPartBuffer.Buffer2, 0, twoPartBuffer.Buffer2.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show("Too long for payload!!!");
|
||||
}
|
||||
|
||||
// HeaderDataLength = buffer[index + 8];
|
||||
// Write zero delay
|
||||
_subFile.WriteByte(0);
|
||||
_subFile.WriteByte(0);
|
||||
|
||||
// language id
|
||||
// int id = buffer[9 + HeaderDataLength];
|
||||
// if (id >= 0x20 && id <= 0x40) // x3f 0r x40 ?
|
||||
// SubPictureStreamId = id;
|
||||
// next display control sequence table address (use current is last)
|
||||
WriteEndianWord(startDisplayControlSequenceTableAddress+24); // start of display control sequence table address
|
||||
|
||||
// Control command 1 = ForcedStartDisplay
|
||||
_subFile.WriteByte(1);
|
||||
|
||||
// Control command 3 = SetColor
|
||||
WriteColors(_subFile); // 3 bytes
|
||||
|
||||
// Control command 4 = SetContrast
|
||||
WriteContrast(_subFile); // 3 bytes
|
||||
|
||||
// Control command 5 = SetDisplayArea
|
||||
WriteDisplayArea(_subFile, nbmp); // 7 bytes
|
||||
|
||||
// Control command 6 = SetPixelDataAddress
|
||||
WritePixelDataAddress(_subFile, imageTopFieldDataAddress, imageBottomFieldDataAddress); // 5 bytes
|
||||
|
||||
// Control command exit
|
||||
_subFile.WriteByte(255); // 1 bytes
|
||||
|
||||
// Control Sequence Table
|
||||
// Write delay - subtitle duration
|
||||
WriteEndianWord((int)((Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0 - 1023) >> 10))); //
|
||||
|
||||
// next display control sequence table address (use current is last)
|
||||
WriteEndianWord(startDisplayControlSequenceTableAddress+24); // start of display control sequence table address
|
||||
|
||||
// Control command 2 = StopDisplay
|
||||
_subFile.WriteByte(2);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// System.Windows.Forms.MessageBox.Show("Too long for payload!!!");
|
||||
//}
|
||||
|
||||
|
||||
for (long i = _subFile.Position - start; i < 0x800; i++) // 2048 packet size - pad with 0xff
|
||||
_subFile.WriteByte(0xff);
|
||||
}
|
||||
|
||||
private void WritePixelDataAddress(FileStream _subFile, int imageTopFieldDataAddress, int imageBottomFieldDataAddress)
|
||||
{
|
||||
_subFile.WriteByte(6);
|
||||
WriteEndianWord(imageTopFieldDataAddress);
|
||||
WriteEndianWord(imageBottomFieldDataAddress);
|
||||
}
|
||||
|
||||
private void WriteDisplayArea(FileStream _subFile, NikseBitmap nbmp)
|
||||
{
|
||||
_subFile.WriteByte(5);
|
||||
|
||||
// Write 6 bytes of area - starting X, ending X, starting Y, ending Y, each 12 bits
|
||||
ushort startX = (ushort) ((_screenWidth - nbmp.Width) / 2);
|
||||
ushort endX = (ushort)(startX + nbmp.Width-1);
|
||||
ushort startY = (ushort)(_screenHeight - nbmp.Height - _bottomMargin);
|
||||
ushort endY = (ushort)(startY + nbmp.Height-1);
|
||||
|
||||
WriteEndianWord((ushort)(startX << 4 | endX >> 8)); // 16 - 12 start x + 4 end x
|
||||
WriteEndianWord((ushort)(endX << 8 | startY >> 4)); // 16 - 8 endx + 8 starty
|
||||
WriteEndianWord((ushort)(startY << 12 | endY)); // 16 - 4 start y + 12 end y
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directly provides the four contrast (alpha blend) values to associate with the four pixel values. One nibble per pixel value for a total of 2 bytes. 0x0 = transparent, 0xF = opaque
|
||||
/// </summary>
|
||||
/// <param name="_subFile"></param>
|
||||
private void WriteContrast(FileStream _subFile)
|
||||
{
|
||||
_subFile.WriteByte(4);
|
||||
_subFile.WriteByte((byte)((_emphasis2.A << 4) | _emphasis1.A)); // emphasis2 + emphasis1
|
||||
_subFile.WriteByte((byte)((_pattern.A << 4) | _background.A)); // pattern + background
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// provides four indices into the CLUT for the current PGC to associate with the four pixel values. One nibble per pixel value for a total of 2 bytes.
|
||||
/// </summary>
|
||||
private void WriteColors(FileStream _subFile)
|
||||
{
|
||||
// Index to palette
|
||||
byte emphasis2 = 3;
|
||||
byte emphasis1 = 2;
|
||||
byte pattern = 1;
|
||||
byte background = 0;
|
||||
|
||||
_subFile.WriteByte(3);
|
||||
_subFile.WriteByte((byte)((emphasis2 << 4) | emphasis1)); // emphasis2 + emphasis1
|
||||
_subFile.WriteByte((byte)((pattern << 4) | background)); // pattern + background
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the 5 PTS bytes to buffer
|
||||
/// </summary>
|
||||
private void FillPTS(TimeCode timeCode)
|
||||
{
|
||||
string pre = "0011"; // 0011 or 0010 ?
|
||||
// pre = "0010";
|
||||
|
||||
long newPts = (long)(timeCode.TotalMilliseconds); // TODO: Calculation from milliseconds
|
||||
string bString = Convert.ToString(newPts, 2).PadLeft(33, '0');
|
||||
|
||||
string fiveBytesString = pre + bString.Substring(0, 3) + "1" + bString.Substring(3, 15) + "1" + bString.Substring(18, 15) + "1";
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
byte b = Convert.ToByte(fiveBytesString.Substring((i * 8), 8), 2);
|
||||
@ -164,7 +268,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
|
||||
private StringBuilder CreateIdxHeader()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(@"# VobSub index file, v7 (do not modify this line!)
|
||||
#
|
||||
# To repair desyncronization, you can insert gaps this way:
|
||||
@ -187,7 +291,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
|
||||
# Settings
|
||||
|
||||
# Original frame size
|
||||
size: 720x480
|
||||
size: " + _screenWidth + "x" + _screenHeight + @"
|
||||
|
||||
# Origin, relative to the upper-left corner, can be overloaded by aligment
|
||||
org: 0, 0
|
||||
@ -215,7 +319,7 @@ time offset: 0
|
||||
forced subs: OFF
|
||||
|
||||
# The original palette of the DVD
|
||||
palette: 000000, ffffff, 000000, 191919, 828282, 828282, 828282, ffffff, 828282, bababa, 828282, 828282, 828282, 828282, 828282, 828282
|
||||
palette: 00000000, " + ToHexColor(_pattern) + ", " + ToHexColor(_emphasis1) + ", " + ToHexColor(_emphasis2) + @", 828282, 828282, 828282, ffffff, 828282, bababa, 828282, 828282, 828282, 828282, 828282, 828282
|
||||
|
||||
# Custom colors (transp idxs and the four colors)
|
||||
custom colors: OFF, tridx: 0000, colors: 000000, 000000, 000000, 000000
|
||||
@ -230,5 +334,10 @@ id: en, index: 0
|
||||
return sb;
|
||||
}
|
||||
|
||||
}
|
||||
private string ToHexColor(Color c)
|
||||
{
|
||||
return (c.A.ToString("X2") + c.R.ToString("X2") + c.G.ToString("X2") + c.B.ToString("X2")).ToLower();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user