Added Bluray sup import (thx to open source project bdsup2sub) + ocr

git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@152 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
niksedk 2010-11-16 16:16:57 +00:00
parent 5bc07de545
commit 4c1e5129ae
29 changed files with 3114 additions and 1126 deletions

View File

@ -73,6 +73,7 @@
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripMenuItemImportDvdSubtitles = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemSubIdx = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemImportBluRaySup = new System.Windows.Forms.ToolStripMenuItem();
this.matroskaImportStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemManualAnsi = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItemImportText = new System.Windows.Forms.ToolStripMenuItem();
@ -656,6 +657,7 @@
this.toolStripSeparator1,
this.toolStripMenuItemImportDvdSubtitles,
this.toolStripMenuItemSubIdx,
this.toolStripMenuItemImportBluRaySup,
this.matroskaImportStripMenuItem,
this.toolStripMenuItemManualAnsi,
this.toolStripMenuItemImportText,
@ -742,6 +744,13 @@
this.toolStripMenuItemSubIdx.Text = "Import/OCR VobSub (sub/idx) subtitle...";
this.toolStripMenuItemSubIdx.Click += new System.EventHandler(this.ToolStripMenuItemSubIdxClick1);
//
// toolStripMenuItemImportBluRaySup
//
this.toolStripMenuItemImportBluRaySup.Name = "toolStripMenuItemImportBluRaySup";
this.toolStripMenuItemImportBluRaySup.Size = new System.Drawing.Size(334, 22);
this.toolStripMenuItemImportBluRaySup.Text = "Import/OCR BluRay sup file...";
this.toolStripMenuItemImportBluRaySup.Click += new System.EventHandler(this.toolStripMenuItemImportBluRaySup_Click);
//
// matroskaImportStripMenuItem
//
this.matroskaImportStripMenuItem.Name = "matroskaImportStripMenuItem";
@ -3137,6 +3146,7 @@
private System.Windows.Forms.TrackBar trackBarWaveFormPosition;
private System.Windows.Forms.Label labelVideoInfo;
private System.Windows.Forms.ToolStripMenuItem showhideWaveFormToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemImportBluRaySup;
}
}

View File

@ -14,6 +14,7 @@ using Nikse.SubtitleEdit.Logic.Enums;
using Nikse.SubtitleEdit.Logic.SubtitleFormats;
using Nikse.SubtitleEdit.Logic.VideoPlayers;
using Nikse.SubtitleEdit.Logic.VobSub;
using Nikse.SubtitleEdit.Logic.BluRaySup;
namespace Nikse.SubtitleEdit.Forms
{
@ -139,6 +140,8 @@ namespace Nikse.SubtitleEdit.Forms
labelVideoInfo.Text = string.Empty;
Text = Title;
timeUpDownStartTime.TimeCode = new TimeCode(0, 0, 0, 0);
checkBoxAutoRepeatOn.Checked = Configuration.Settings.General.AutoRepeatOn;
checkBoxAutoContinue.Checked = Configuration.Settings.General.AutoContinueOn;
SetFormatToSubRip();
@ -450,6 +453,10 @@ namespace Nikse.SubtitleEdit.Forms
toolStripMenuItemCompare.Text = _language.Menu.File.Compare;
toolStripMenuItemImportDvdSubtitles.Text = _language.Menu.File.ImportOcrFromDvd;
toolStripMenuItemSubIdx.Text = _language.Menu.File.ImportOcrVobSubSubtitle;
//toolStripMenuItemImportBluRaySup.Visible = false; //TODO: add blu ray sup import/ocr
toolStripMenuItemImportBluRaySup.Text = _language.Menu.File.ImportBluRaySupFile;
matroskaImportStripMenuItem.Text = _language.Menu.File.ImportSubtitleFromMatroskaFile;
toolStripMenuItemManualAnsi.Text = _language.Menu.File.ImportSubtitleWithManualChosenEncoding;
toolStripMenuItemImportText.Text = _language.Menu.File.ImportText;
@ -844,7 +851,8 @@ namespace Nikse.SubtitleEdit.Forms
return;
}
MakeHistoryForUndo(string.Format(_language.BeforeLoadOf, Path.GetFileName(fileName)));
if (_subtitle.HistoryItems.Count > 0 || _subtitle.Paragraphs.Count > 0)
MakeHistoryForUndo(string.Format(_language.BeforeLoadOf, Path.GetFileName(fileName)));
SubtitleFormat format = _subtitle.LoadSubtitle(fileName, out encoding, encoding);
@ -3454,6 +3462,9 @@ namespace Nikse.SubtitleEdit.Forms
//TODO: save in adjust all lines ...Configuration.Settings.General.DefaultAdjustMilliseconds = (int)timeUpDownAdjust.TimeCode.TotalMilliseconds;
Configuration.Settings.General.AutoRepeatOn = checkBoxAutoRepeatOn.Checked;
Configuration.Settings.General.AutoContinueOn = checkBoxAutoContinue.Checked;
Configuration.Settings.Save();
}
}
@ -4078,6 +4089,7 @@ namespace Nikse.SubtitleEdit.Forms
_fileName = Path.ChangeExtension(vobSubOcr.FileName, ".srt");
Text = Title + " - " + _fileName;
_converted = true;
Configuration.Settings.Save();
}
@ -4169,7 +4181,12 @@ namespace Nikse.SubtitleEdit.Forms
private void Main_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Right && e.Modifiers == Keys.Control)
if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Z)
{
ShowHistoryforUndoToolStripMenuItemClick(null, null);
e.SuppressKeyPress = true;
}
else if (e.KeyCode == Keys.Right && e.Modifiers == Keys.Control)
{
if (!textBoxListViewText.Focused)
{
@ -4282,6 +4299,13 @@ namespace Nikse.SubtitleEdit.Forms
e.SuppressKeyPress = true;
}
}
else if (e.Modifiers == Keys.None && e.KeyCode == Keys.F6)
{
if (mediaPlayer.VideoPlayer != null)
{
GotoSubPositionAndPause();
}
}
else if (e.Modifiers == Keys.None && e.KeyCode == Keys.F7)
{
if (mediaPlayer.VideoPlayer != null)
@ -4324,6 +4348,7 @@ namespace Nikse.SubtitleEdit.Forms
}
else if (e.Modifiers == Keys.None && e.KeyCode == Keys.F12)
{
StopAutoDuration();
buttonSetEnd_Click(null, null);
e.SuppressKeyPress = true;
}
@ -4347,6 +4372,7 @@ namespace Nikse.SubtitleEdit.Forms
}
else if (e.Modifiers == Keys.None && e.KeyCode == Keys.F12)
{
StopAutoDuration();
buttonSetEnd_Click(null, null);
e.SuppressKeyPress = true;
}
@ -6291,5 +6317,58 @@ namespace Nikse.SubtitleEdit.Forms
}
}
private void toolStripMenuItemImportBluRaySup_Click(object sender, EventArgs e)
{
if (ContinueNewOrExit())
{
openFileDialog1.Title = _language.OpenBluRaySupFile;
openFileDialog1.FileName = string.Empty;
openFileDialog1.Filter = _language.BluRaySupFiles + "|*.sup";
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
{
ImportAndOcrBluRaySup(openFileDialog1.FileName);
}
}
}
private void ImportAndOcrBluRaySup(string fileName)
{
StringBuilder log = new StringBuilder();
var subtitles = BluRaySupParser.ParseBluRaySup(fileName, log);
if (subtitles.Count > 0)
{
var vobSubOcr = new VobSubOcr();
vobSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr);
vobSubOcr.FileName = Path.GetFileName(fileName);
if (vobSubOcr.ShowDialog(this) == DialogResult.OK)
{
MakeHistoryForUndo(_language.BeforeImportingBluRaySupFile);
_subtitle.Paragraphs.Clear();
SetCurrentFormat(new SubRip().FriendlyName);
_subtitle.WasLoadedWithFrameNumbers = false;
_subtitle.CalculateFrameNumbersFromTimeCodes(CurrentFrameRate);
foreach (Paragraph p in vobSubOcr.SubtitleFromOcr.Paragraphs)
{
_subtitle.Paragraphs.Add(p);
}
ShowSource();
SubtitleListview1.Fill(_subtitle, _subtitleAlternate);
_change = true;
_subtitleListViewIndex = -1;
SubtitleListview1.FirstVisibleIndex = -1;
SubtitleListview1.SelectIndexAndEnsureVisible(0);
_fileName = Path.ChangeExtension(vobSubOcr.FileName, ".srt");
Text = Title + " - " + _fileName;
_converted = true;
Configuration.Settings.Save();
}
}
}
}
}

View File

@ -291,47 +291,47 @@
<data name="toolStripButtonReplace.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
RK5CYII=
</value>
</data>

View File

@ -63,7 +63,7 @@
// buttonAbort
//
this.buttonAbort.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonAbort.Location = new System.Drawing.Point(512, 404);
this.buttonAbort.Location = new System.Drawing.Point(623, 442);
this.buttonAbort.Name = "buttonAbort";
this.buttonAbort.Size = new System.Drawing.Size(85, 21);
this.buttonAbort.TabIndex = 24;
@ -86,9 +86,9 @@
this.groupBoxSuggestions.Controls.Add(this.buttonUseSuggestionAlways);
this.groupBoxSuggestions.Controls.Add(this.buttonUseSuggestion);
this.groupBoxSuggestions.Controls.Add(this.listBoxSuggestions);
this.groupBoxSuggestions.Location = new System.Drawing.Point(320, 211);
this.groupBoxSuggestions.Location = new System.Drawing.Point(320, 249);
this.groupBoxSuggestions.Name = "groupBoxSuggestions";
this.groupBoxSuggestions.Size = new System.Drawing.Size(277, 187);
this.groupBoxSuggestions.Size = new System.Drawing.Size(388, 187);
this.groupBoxSuggestions.TabIndex = 32;
this.groupBoxSuggestions.TabStop = false;
this.groupBoxSuggestions.Text = "Suggestions";
@ -96,7 +96,7 @@
// buttonUseSuggestionAlways
//
this.buttonUseSuggestionAlways.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.buttonUseSuggestionAlways.Location = new System.Drawing.Point(180, 16);
this.buttonUseSuggestionAlways.Location = new System.Drawing.Point(291, 16);
this.buttonUseSuggestionAlways.Name = "buttonUseSuggestionAlways";
this.buttonUseSuggestionAlways.Size = new System.Drawing.Size(87, 21);
this.buttonUseSuggestionAlways.TabIndex = 33;
@ -107,7 +107,7 @@
// buttonUseSuggestion
//
this.buttonUseSuggestion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.buttonUseSuggestion.Location = new System.Drawing.Point(95, 16);
this.buttonUseSuggestion.Location = new System.Drawing.Point(206, 16);
this.buttonUseSuggestion.Name = "buttonUseSuggestion";
this.buttonUseSuggestion.Size = new System.Drawing.Size(79, 21);
this.buttonUseSuggestion.TabIndex = 32;
@ -122,7 +122,7 @@
this.listBoxSuggestions.FormattingEnabled = true;
this.listBoxSuggestions.Location = new System.Drawing.Point(6, 39);
this.listBoxSuggestions.Name = "listBoxSuggestions";
this.listBoxSuggestions.Size = new System.Drawing.Size(261, 134);
this.listBoxSuggestions.Size = new System.Drawing.Size(372, 134);
this.listBoxSuggestions.TabIndex = 30;
//
// GroupBoxEditWord
@ -135,7 +135,7 @@
this.GroupBoxEditWord.Controls.Add(this.textBoxWord);
this.GroupBoxEditWord.Controls.Add(this.buttonSkipOnce);
this.GroupBoxEditWord.Controls.Add(this.buttonAddToNames);
this.GroupBoxEditWord.Location = new System.Drawing.Point(12, 211);
this.GroupBoxEditWord.Location = new System.Drawing.Point(12, 249);
this.GroupBoxEditWord.Name = "GroupBoxEditWord";
this.GroupBoxEditWord.Size = new System.Drawing.Size(302, 187);
this.GroupBoxEditWord.TabIndex = 33;
@ -217,7 +217,7 @@
this.groupBoxEditWholeText.Controls.Add(this.buttonSkipText);
this.groupBoxEditWholeText.Controls.Add(this.buttonChangeWholeText);
this.groupBoxEditWholeText.Controls.Add(this.textBoxWholeText);
this.groupBoxEditWholeText.Location = new System.Drawing.Point(12, 210);
this.groupBoxEditWholeText.Location = new System.Drawing.Point(12, 248);
this.groupBoxEditWholeText.Name = "groupBoxEditWholeText";
this.groupBoxEditWholeText.Size = new System.Drawing.Size(302, 188);
this.groupBoxEditWholeText.TabIndex = 37;
@ -261,7 +261,7 @@
this.groupBoxTextAsImage.Controls.Add(this.pictureBoxText);
this.groupBoxTextAsImage.Location = new System.Drawing.Point(12, 12);
this.groupBoxTextAsImage.Name = "groupBoxTextAsImage";
this.groupBoxTextAsImage.Size = new System.Drawing.Size(585, 114);
this.groupBoxTextAsImage.Size = new System.Drawing.Size(696, 152);
this.groupBoxTextAsImage.TabIndex = 34;
this.groupBoxTextAsImage.TabStop = false;
this.groupBoxTextAsImage.Text = "Image text";
@ -273,7 +273,7 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.pictureBoxText.Location = new System.Drawing.Point(6, 18);
this.pictureBoxText.Name = "pictureBoxText";
this.pictureBoxText.Size = new System.Drawing.Size(573, 89);
this.pictureBoxText.Size = new System.Drawing.Size(684, 127);
this.pictureBoxText.TabIndex = 32;
this.pictureBoxText.TabStop = false;
//
@ -284,9 +284,9 @@
this.groupBoxText.Controls.Add(this.richTextBoxParagraph);
this.groupBoxText.Controls.Add(this.buttonEditWholeText);
this.groupBoxText.Controls.Add(this.buttonEditWord);
this.groupBoxText.Location = new System.Drawing.Point(12, 132);
this.groupBoxText.Location = new System.Drawing.Point(12, 170);
this.groupBoxText.Name = "groupBoxText";
this.groupBoxText.Size = new System.Drawing.Size(585, 72);
this.groupBoxText.Size = new System.Drawing.Size(696, 72);
this.groupBoxText.TabIndex = 38;
this.groupBoxText.TabStop = false;
this.groupBoxText.Text = "Text";
@ -326,7 +326,7 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(609, 435);
this.ClientSize = new System.Drawing.Size(720, 473);
this.Controls.Add(this.groupBoxText);
this.Controls.Add(this.groupBoxTextAsImage);
this.Controls.Add(this.buttonAbort);

View File

@ -82,6 +82,11 @@ namespace Nikse.SubtitleEdit.Forms
List<VobSubMergedPack> _vobSubMergedPackist;
List<Color> _palette;
// BluRay sup
List<Logic.BluRaySup.BluRaySupPicture> _bluRaySubtitlesOriginal;
List<Logic.BluRaySup.BluRaySupPicture> _bluRaySubtitles;
Nikse.SubtitleEdit.Logic.BluRaySup.BluRaySupPalette _defaultPaletteInfo;
// Tesseract OCR
//tessnet2.Tesseract _tesseractOcrEngine;
// object _tesseractOcrEngine;
@ -220,6 +225,40 @@ namespace Nikse.SubtitleEdit.Forms
checkBoxCustomFourColors.Checked = true;
}
internal void Initialize(List<Logic.BluRaySup.BluRaySupPicture> subtitles, VobSubOcrSettings vobSubOcrSettings)
{
buttonOK.Enabled = false;
buttonCancel.Enabled = false;
buttonStartOcr.Enabled = false;
buttonStop.Enabled = false;
buttonNewCharacterDatabase.Enabled = false;
buttonEditCharacterDatabase.Enabled = false;
labelStatus.Text = string.Empty;
progressBar1.Visible = false;
progressBar1.Maximum = 100;
progressBar1.Value = 0;
numericUpDownPixelsIsSpace.Value = 11; // vobSubOcrSettings.XOrMorePixelsMakesSpace;
_vobSubOcrSettings = vobSubOcrSettings;
InitializeModi();
InitializeTesseract();
LoadImageCompareCharacterDatabaseList();
if (Configuration.Settings.VobSubOcr.LastOcrMethod == "BitmapCompare" && comboBoxOcrMethod.Items.Count > 1)
comboBoxOcrMethod.SelectedIndex = 1;
else if (Configuration.Settings.VobSubOcr.LastOcrMethod == "MODI" && comboBoxOcrMethod.Items.Count > 2)
comboBoxOcrMethod.SelectedIndex = 2;
else
comboBoxOcrMethod.SelectedIndex = 0;
_bluRaySubtitlesOriginal = subtitles;
groupBoxImagePalette.Visible = false;
Text = Configuration.Settings.Language.VobSubOcr.TitleBluRay;
}
private void LoadImageCompareCharacterDatabaseList()
{
@ -324,6 +363,45 @@ namespace Nikse.SubtitleEdit.Forms
return true;
}
private void LoadBluRaySup()
{
_subtitle = new Subtitle();
_bluRaySubtitles = new List<Logic.BluRaySup.BluRaySupPicture>();
int max = _bluRaySubtitlesOriginal.Count;
for (int i = 0; i < max; i++)
{
var x = _bluRaySubtitlesOriginal[i];
if ((checkBoxShowOnlyForced.Checked && x.IsForced) ||
checkBoxShowOnlyForced.Checked == false)
{
_bluRaySubtitles.Add(x);
Paragraph p = new Paragraph();
p.StartTime = new TimeCode(TimeSpan.FromMilliseconds((x.StartTime + 45) / 90.0));
p.EndTime = new TimeCode(TimeSpan.FromMilliseconds((x.EndTime + 45) / 90.0));
_subtitle.Paragraphs.Add(p);
}
}
_subtitle.Renumber(1);
FixShortDisplayTimes(_subtitle);
subtitleListView1.Fill(_subtitle);
subtitleListView1.SelectIndexAndEnsureVisible(0);
numericUpDownStartNumber.Maximum = max;
if (numericUpDownStartNumber.Maximum > 0 && numericUpDownStartNumber.Minimum <= 1)
numericUpDownStartNumber.Value = 1;
buttonOK.Enabled = true;
buttonCancel.Enabled = true;
buttonStartOcr.Enabled = true;
buttonStop.Enabled = false;
buttonNewCharacterDatabase.Enabled = true;
buttonEditCharacterDatabase.Enabled = true;
buttonStartOcr.Focus();
}
private void LoadVobRip()
{
_subtitle = new Subtitle();
@ -385,7 +463,21 @@ namespace Nikse.SubtitleEdit.Forms
private Bitmap GetSubtitleBitmap(int index)
{
if (checkBoxCustomFourColors.Checked)
if (_bluRaySubtitlesOriginal != null)
{
if (_bluRaySubtitles[index].Palettes.Count == 0 && _defaultPaletteInfo == null)
{
for (int i = 0; i < _bluRaySubtitlesOriginal.Count; i++)
{
if (_bluRaySubtitlesOriginal[i].Palettes.Count > 0)
{
_defaultPaletteInfo = _bluRaySubtitlesOriginal[i].DecodePalette(null);
}
}
}
return _bluRaySubtitles[index].DecodeImage(_defaultPaletteInfo);
}
else if (checkBoxCustomFourColors.Checked)
{
Color pattern = pictureBoxPattern.BackColor;
Color emphasis1 = pictureBoxEmphasis1.BackColor;
@ -405,22 +497,36 @@ namespace Nikse.SubtitleEdit.Forms
private long GetSubtitleStartTimeMilliseconds(int index)
{
return (long)_vobSubMergedPackist[index].StartTime.TotalMilliseconds;
if (_bluRaySubtitlesOriginal != null)
return (_bluRaySubtitles[index].StartTime + 45) / 90;
else
return (long)_vobSubMergedPackist[index].StartTime.TotalMilliseconds;
}
private long GetSubtitleEndTimeMilliseconds(int index)
{
return (long)_vobSubMergedPackist[index].EndTime.TotalMilliseconds;
if (_bluRaySubtitlesOriginal != null)
return (_bluRaySubtitles[index].EndTime + 45) / 90;
else
return (long)_vobSubMergedPackist[index].EndTime.TotalMilliseconds;
}
private int GetSubtitleCount()
{
if (_bluRaySubtitlesOriginal != null)
return _bluRaySubtitles.Count;
else
return _vobSubMergedPackist.Count;
}
private void ShowSubtitleImage(int index)
{
int numberOfImages = _vobSubMergedPackist.Count;
int numberOfImages = GetSubtitleCount();
if (index < numberOfImages)
{
groupBoxSubtitleImage.Text = string.Format(Configuration.Settings.Language.VobSubOcr.SubtitleImageXofY, index + 1, numberOfImages);
pictureBoxSubtitleImage.Image = GetSubtitleBitmap(index); // SubtitleCreator.SUP.GetBitmap(index);
pictureBoxSubtitleImage.Image = GetSubtitleBitmap(index);
pictureBoxSubtitleImage.Refresh();
}
else
@ -476,7 +582,10 @@ namespace Nikse.SubtitleEdit.Forms
if (smallestIndex >= 0)
{
double differencePercentage = smallestDifference * 100.0 / (target.Width * target.Height);
if (differencePercentage < _vobSubOcrSettings.AllowDifferenceInPercent) // should be around 1.0...
double maxDiff= _vobSubOcrSettings.AllowDifferenceInPercent; // should be around 1.0 for vob/sub...
if (_bluRaySubtitlesOriginal != null)
maxDiff = 14; // let bluray sup have a 14% diff
if (differencePercentage < maxDiff) //_vobSubOcrSettings.AllowDifferenceInPercent) // should be around 1.0...
{
XmlNode node = _compareDoc.DocumentElement.SelectSingleNode("FileName[.='" + _compareBitmaps[smallestIndex].Name + "']");
if (node != null)
@ -789,28 +898,46 @@ namespace Nikse.SubtitleEdit.Forms
private void FormVobSubOcr_Shown(object sender, EventArgs e)
{
_vobSubMergedPackistOriginal = new List<VobSubMergedPack>();
bool hasIdxTimeCodes = false;
bool hasForcedSubtitles = false;
foreach (var x in _vobSubMergedPackist)
if (_bluRaySubtitlesOriginal != null)
{
_vobSubMergedPackistOriginal.Add(x);
if (x.IdxLine != null)
hasIdxTimeCodes = true;
if (x.SubPicture.Forced)
hasForcedSubtitles = true;
LoadBluRaySup();
bool hasForcedSubtitles = false;
foreach (var x in _bluRaySubtitlesOriginal)
{
if (x.IsForced)
{
hasForcedSubtitles = true;
break;
}
}
checkBoxShowOnlyForced.Enabled = hasForcedSubtitles;
checkBoxUseTimeCodesFromIdx.Visible = false;
}
else
{
_vobSubMergedPackistOriginal = new List<VobSubMergedPack>();
bool hasIdxTimeCodes = false;
bool hasForcedSubtitles = false;
foreach (var x in _vobSubMergedPackist)
{
_vobSubMergedPackistOriginal.Add(x);
if (x.IdxLine != null)
hasIdxTimeCodes = true;
if (x.SubPicture.Forced)
hasForcedSubtitles = true;
}
checkBoxUseTimeCodesFromIdx.CheckedChanged -= checkBoxUseTimeCodesFromIdx_CheckedChanged;
checkBoxUseTimeCodesFromIdx.Visible = hasIdxTimeCodes;
checkBoxUseTimeCodesFromIdx.Checked = hasIdxTimeCodes;
checkBoxUseTimeCodesFromIdx.CheckedChanged += checkBoxUseTimeCodesFromIdx_CheckedChanged;
checkBoxShowOnlyForced.Enabled = hasForcedSubtitles;
LoadVobRip();
}
checkBoxUseTimeCodesFromIdx.CheckedChanged -= checkBoxUseTimeCodesFromIdx_CheckedChanged;
checkBoxUseTimeCodesFromIdx.Visible = hasIdxTimeCodes;
checkBoxUseTimeCodesFromIdx.Checked = hasIdxTimeCodes;
checkBoxUseTimeCodesFromIdx.CheckedChanged += checkBoxUseTimeCodesFromIdx_CheckedChanged;
checkBoxShowOnlyForced.Enabled = hasForcedSubtitles;
LoadVobRip();
}
private void ButtonOkClick(object sender, EventArgs e)
{
if (Configuration.Settings.VobSubOcr.XOrMorePixelsMakesSpace != (int)numericUpDownPixelsIsSpace.Value)
if (Configuration.Settings.VobSubOcr.XOrMorePixelsMakesSpace != (int)numericUpDownPixelsIsSpace.Value && _bluRaySubtitlesOriginal == null)
{
Configuration.Settings.VobSubOcr.XOrMorePixelsMakesSpace = (int)numericUpDownPixelsIsSpace.Value;
Configuration.Settings.Save();
@ -843,7 +970,7 @@ namespace Nikse.SubtitleEdit.Forms
_abort = false;
int max = _vobSubMergedPackist.Count;
int max = GetSubtitleCount();
progressBar1.Maximum = max;
progressBar1.Value = 0;
@ -1093,6 +1220,8 @@ namespace Nikse.SubtitleEdit.Forms
subtitleListView1.SetBackgroundColor(index, Color.Orange);
else if (wordsNotFound == 1)
subtitleListView1.SetBackgroundColor(index, Color.Yellow);
else if (line.Trim().Length == 0)
subtitleListView1.SetBackgroundColor(index, Color.Orange);
else
subtitleListView1.SetBackgroundColor(index, Color.Green);
}
@ -1107,6 +1236,8 @@ namespace Nikse.SubtitleEdit.Forms
subtitleListView1.SetBackgroundColor(index, Color.Orange);
else if (badWords > 0)
subtitleListView1.SetBackgroundColor(index, Color.Yellow);
else if (line.Trim().Length == 0)
subtitleListView1.SetBackgroundColor(index, Color.Orange);
else
subtitleListView1.SetBackgroundColor(index, Color.Green);
}
@ -1598,7 +1729,10 @@ namespace Nikse.SubtitleEdit.Forms
{
Subtitle oldSubtitle = new Subtitle(_subtitle);
subtitleListView1.BeginUpdate();
LoadVobRip();
if (_bluRaySubtitlesOriginal != null)
LoadBluRaySup();
else
LoadVobRip();
for (int i = 0; i < _subtitle.Paragraphs.Count; i++)
{
Paragraph current = _subtitle.Paragraphs[i];
@ -1634,5 +1768,6 @@ namespace Nikse.SubtitleEdit.Forms
subtitleListView1.EndUpdate();
}
}
}

View File

@ -0,0 +1,468 @@
/*
* Copyright 2009 Volker Oth (0xdeadbeef)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
*/
namespace Nikse.SubtitleEdit.Logic.BluRaySup
{
public class BluRaySupPalette
{
/** Number of palette entries */
private int size;
/** Byte buffer for RED info */
private byte[] r;
/** Byte buffer for GREEN info */
private byte[] g;
/** Byte buffer for BLUE info */
private byte[] b;
/** Byte buffer for alpha info */
private byte[] a;
/** Byte buffer for Y (luminance) info */
private byte[] y;
/** Byte buffer for Cb (chrominance blue) info */
private byte[] cb;
/** Byte buffer for Cr (chrominance red) info */
private byte[] cr;
/** Use BT.601 color model instead of BT.709 */
private bool useBT601;
/**
* Convert YCBCr color info to RGB
* @param y 8 bit luminance
* @param cb 8 bit chrominance blue
* @param cr 8 bit chrominance red
* @return Integer array with red, blue, green component (in this order)
*/
static int[] YCbCr2Rgb(int y, int cb, int cr, bool useBt601)
{
int[] rgb = new int[3];
double y1, r, g, b;
y -= 16;
cb -= 128;
cr -= 128;
y1 = y * 1.164383562;
if (useBt601)
{
/* BT.601 for YCbCr 16..235 -> RGB 0..255 (PC) */
r = y1 + cr * 1.596026317;
g = y1 - cr * 0.8129674985 - cb * 0.3917615979;
b = y1 + cb * 2.017232218;
}
else
{
/* BT.709 for YCbCr 16..235 -> RGB 0..255 (PC) */
r = y1 + cr * 1.792741071;
g = y1 - cr * 0.5329093286 - cb * 0.2132486143;
b = y1 + cb * 2.112401786;
}
rgb[0] = (int)(r + 0.5);
rgb[1] = (int)(g + 0.5);
rgb[2] = (int)(b + 0.5);
for (int i = 0; i < 3; i++)
{
if (rgb[i] < 0)
rgb[i] = 0;
else if (rgb[i] > 255)
rgb[i] = 255;
}
return rgb;
}
/**
* Convert RGB color info to YCBCr
* @param r 8 bit red component
* @param g 8 bit green component
* @param b 8 bit blue component
* @return Integer array with luminance (Y), chrominance blue (Cb), chrominance red (Cr) (in this order)
*/
static int[] Rgb2YCbCr(int r, int g, int b, bool useBt601)
{
int[] yCbCr = new int[3];
double y, cb, cr;
if (useBt601)
{
/* BT.601 for RGB 0..255 (PC) -> YCbCr 16..235 */
y = r * 0.299 * 219 / 255 + g * 0.587 * 219 / 255 + b * 0.114 * 219 / 255;
cb = -r * 0.168736 * 224 / 255 - g * 0.331264 * 224 / 255 + b * 0.5 * 224 / 255;
cr = r * 0.5 * 224 / 255 - g * 0.418688 * 224 / 255 - b * 0.081312 * 224 / 255;
}
else
{
/* BT.709 for RGB 0..255 (PC) -> YCbCr 16..235 */
y = r * 0.2126 * 219 / 255 + g * 0.7152 * 219 / 255 + b * 0.0722 * 219 / 255;
cb = -r * 0.2126 / 1.8556 * 224 / 255 - g * 0.7152 / 1.8556 * 224 / 255 + b * 0.5 * 224 / 255;
cr = r * 0.5 * 224 / 255 - g * 0.7152 / 1.5748 * 224 / 255 - b * 0.0722 / 1.5748 * 224 / 255;
}
yCbCr[0] = 16 + (int)(y + 0.5);
yCbCr[1] = 128 + (int)(cb + 0.5);
yCbCr[2] = 128 + (int)(cr + 0.5);
for (int i = 0; i < 3; i++)
{
if (yCbCr[i] < 16)
yCbCr[i] = 16;
else
{
if (i == 0)
{
if (yCbCr[i] > 235)
yCbCr[i] = 235;
}
else
{
if (yCbCr[i] > 240)
yCbCr[i] = 240;
}
}
}
return yCbCr;
}
/**
* Ctor - initializes palette with transparent black (RGBA: 0x00000000)
* @param palSize Number of palette entries
* @param use601 Use BT.601 instead of BT.709
*/
public BluRaySupPalette(int palSize, bool use601)
{
size = palSize;
useBT601 = use601;
r = new byte[size];
g = new byte[size];
b = new byte[size];
a = new byte[size];
y = new byte[size];
cb = new byte[size];
cr = new byte[size];
// set at least all alpha values to invisible
int[] yCbCr = Rgb2YCbCr(0, 0, 0, useBT601);
for (int i = 0; i < palSize; i++)
{
a[i] = 0;
r[i] = 0;
g[i] = 0;
b[i] = 0;
y[i] = (byte)yCbCr[0];
cb[i] = (byte)yCbCr[1];
cr[i] = (byte)yCbCr[2];
}
}
/**
* Ctor - initializes palette with transparent black (RGBA: 0x00000000)
* @param palSize Number of palette entries
*/
public BluRaySupPalette(int palSize)
: this(palSize, false)
{
}
/**
* Ctor - construct palette from red, green blue and alpha buffers
* @param red Byte buffer containing the red components
* @param green Byte buffer containing the green components
* @param blue Byte buffer containing the blue components
* @param alpha Byte buffer containing the alpha components
* @param use601 Use BT.601 instead of BT.709
*/
public BluRaySupPalette(byte[] red, byte[] green, byte[] blue, byte[] alpha, bool use601)
{
size = red.Length;
useBT601 = use601;
r = new byte[size];
g = new byte[size];
b = new byte[size];
a = new byte[size];
y = new byte[size];
cb = new byte[size];
cr = new byte[size];
int[] yCbCr;
for (int i = 0; i < size; i++)
{
a[i] = alpha[i];
r[i] = red[i];
g[i] = green[i];
b[i] = blue[i];
yCbCr = Rgb2YCbCr(r[i] & 0xff, g[i] & 0xff, b[i] & 0xff, useBT601);
y[i] = (byte)yCbCr[0];
cb[i] = (byte)yCbCr[1];
cr[i] = (byte)yCbCr[2];
}
}
/**
* Ctor - construct palette from red, green blue and alpha buffers
* @param red Byte buffer containing the red components
* @param green Byte buffer containing the green components
* @param blue Byte buffer containing the blue components
* @param alpha Byte buffer containing the alpha components
*/
public BluRaySupPalette(byte[] red, byte[] green, byte[] blue, byte[] alpha)
: this(red, green, blue, alpha, false)
{
}
/**
* Ctor - construct new (independent) palette from existing one
* @param p Palette to copy values from
*/
public BluRaySupPalette(BluRaySupPalette p)
{
size = p.GetSize();
useBT601 = p.UsesBt601();
r = new byte[size];
g = new byte[size];
b = new byte[size];
a = new byte[size];
y = new byte[size];
cb = new byte[size];
cr = new byte[size];
for (int i = 0; i < size; i++)
{
a[i] = p.a[i];
r[i] = p.r[i];
g[i] = p.g[i];
b[i] = p.b[i];
y[i] = p.y[i];
cb[i] = p.cb[i];
cr[i] = p.cr[i];
}
}
/**
* Set palette index "index" to color "c" in ARGB format
* @param index Palette index
* @param c Color in ARGB format
*/
public void SetArgb(int index, int c)
{
int a1 = (c >> 24) & 0xff;
int r1 = (c >> 16) & 0xff;
int g1 = (c >> 8) & 0xff;
int b1 = c & 0xff;
SetRgb(index, r1, g1, b1);
SetAlpha(index, a1);
}
/**
* Return palette entry at index as Integer in ARGB format
* @param index Palette index
* @return Palette entry at index as Integer in ARGB format
*/
public int GetArgb(int index)
{
return ((a[index] & 0xff) << 24) | ((r[index] & 0xff) << 16) | ((g[index] & 0xff) << 8) | (b[index] & 0xff);
}
/**
* Set palette entry (RGB mode)
* @param index Palette index
* @param red 8bit red component
* @param green 8bit green component
* @param blue 8bit blue component
*/
public void SetRgb(int index, int red, int green, int blue)
{
r[index] = (byte)red;
g[index] = (byte)green;
b[index] = (byte)blue;
// create yCbCr
int[] yCbCr = Rgb2YCbCr(red, green, blue, useBT601);
y[index] = (byte)yCbCr[0];
cb[index] = (byte)yCbCr[1];
cr[index] = (byte)yCbCr[2];
}
/**
* Set palette entry (YCbCr mode)
* @param index Palette index
* @param yn 8bit Y component
* @param cbn 8bit Cb component
* @param crn 8bit Cr component
*/
public void SetYCbCr(int index, int yn, int cbn, int crn)
{
y[index] = (byte)yn;
cb[index] = (byte)cbn;
cr[index] = (byte)crn;
// create RGB
int[] rgb = YCbCr2Rgb(yn, cbn, crn, useBT601);
r[index] = (byte)rgb[0];
g[index] = (byte)rgb[1];
b[index] = (byte)rgb[2];
}
/**
* Set alpha channel
* @param index Palette index
* @param alpha 8bit alpha channel value
*/
public void SetAlpha(int index, int alpha)
{
a[index] = (byte)alpha;
}
/**
* Get alpha channel
* @param index Palette index
* @return 8bit alpha channel value
*/
public int GetAlpha(int index)
{
return a[index] & 0xff;
}
/**
* Return byte array of alpha channel components
* @return Byte array of alpha channel components (don't modify!)
*/
public byte[] GetAlpha()
{
return a;
}
/**
* Get Integer array containing 8bit red, green, blue components (in this order)
* @param index Palette index
* @return Integer array containing 8bit red, green, blue components (in this order)
*/
public int[] GetRgb(int index)
{
int[] rgb = new int[3];
rgb[0] = r[index] & 0xff;
rgb[1] = g[index] & 0xff;
rgb[2] = b[index] & 0xff;
return rgb;
}
/**
* Get Integer array containing 8bit Y, Cb, Cr components (in this order)
* @param index Palette index
* @return Integer array containing 8bit Y, Cb, Cr components (in this order)
*/
public int[] GetYCbCr(int index)
{
int[] yCbCr = new int[3];
yCbCr[0] = y[index] & 0xff;
yCbCr[1] = cb[index] & 0xff;
yCbCr[2] = cr[index] & 0xff;
return yCbCr;
}
/**
* Return byte array of red components
* @return Byte array of red components (don't modify!)
*/
public byte[] GetR()
{
return r;
}
/**
* Return byte array of green components
* @return Byte array of green components (don't modify!)
*/
public byte[] GetG()
{
return g;
}
/**
* Return byte array of blue components
* @return Byte array of blue components (don't modify!)
*/
public byte[] GetB()
{
return b;
}
/**
* Return byte array of Y components
* @return Byte array of Y components (don't modify!)
*/
public byte[] GetY()
{
return y;
}
/**
* Return byte array of Cb components
* @return Byte array of Cb components (don't modify!)
*/
public byte[] GetCb()
{
return cb;
}
/**
* Return byte array of Cr components
* @return Byte array of Cr components (don't modify!)
*/
public byte[] GetCr()
{
return cr;
}
/**
* Get size of palette (number of entries)
* @return Size of palette (number of entries)
*/
public int GetSize()
{
return size;
}
/**
* Return index of most transparent palette entry or the index of the first completely transparent color
* @return Index of most transparent palette entry or the index of the first completely transparent color
*/
public int GetTransparentIndex()
{
// find (most) transparent index in palette
int transpIdx = 0;
int minAlpha = 0x100;
for (int i = 0; i < size; i++)
{
if ((a[i] & 0xff) < minAlpha)
{
minAlpha = a[i] & 0xff;
transpIdx = i;
if (minAlpha == 0)
break;
}
}
return transpIdx;
}
/**
* Get: use of BT.601 color model instead of BT.709
* @return True if BT.601 is used
*/
public bool UsesBt601()
{
return useBT601;
}
}
}

View File

@ -0,0 +1,660 @@
/*
* Copyright 2009 Volker Oth (0xdeadbeef)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Nikse.SubtitleEdit.Logic.BluRaySup
{
public static class BluRaySupParser
{
private class SupSegment
{
/// <summary>
/// Type of segment
/// </summary>
public int Type;
/// <summary>
/// segment size in bytes
/// </summary>
public int Size;
/// <summary>
/// segment PTS time stamp
/// </summary>
public long PtsTimestamp;
/// <summary>
/// segment DTS time stamp
/// </summary>
public long DtsTimestamp;
}
/** PGS composition state */
private enum CompositionState
{
/** normal: doesn't have to be complete */
Normal,
/** acquisition point */
AcquPoint,
/** epoch start - clears the screen */
EpochStart,
/** epoch continue */
EpochContinue,
/** unknown value */
Invalid
}
private static byte[] packetHeader =
{
0x50, 0x47, // 0: "PG"
0x00, 0x00, 0x00, 0x00, // 2: PTS - presentation time stamp
0x00, 0x00, 0x00, 0x00, // 6: DTS - decoding time stamp
0x00, // 10: segment_type
0x00, 0x00, // 11: segment_length (bytes following till next PG)
};
private static byte[] headerPCSStart =
{
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
0x00, 0x00, // 5: composition_number (increased by start and end header)
(byte)0x80, // 7: composition_state (0x80: epoch start)
0x00, // 8: palette_update_flag (0x80), 7bit reserved
0x00, // 9: palette_id_ref (0..7)
0x01, // 10: number_of_composition_objects (0..2)
0x00, 0x00, // 11: 16bit object_id_ref
0x00, // 13: window_id_ref (0..1)
0x00, // 14: object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
0x00, 0x00, 0x00, 0x00 // 15: composition_object_horizontal_position, composition_object_vertical_position
};
private static byte[] headerPCSEnd =
{
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
0x00, 0x00, // 5: composition_number (increased by start and end header)
0x00, // 7: composition_state (0x00: normal)
0x00, // 8: palette_update_flag (0x80), 7bit reserved
0x00, // 9: palette_id_ref (0..7)
0x00, // 10: number_of_composition_objects (0..2)
};
private static byte[] headerODSFirst =
{
0x00, 0x00, // 0: object_id
0x00, // 2: object_version_number
(byte)0xC0, // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
0x00, 0x00, 0x00, // 4: object_data_length - full RLE buffer length (including 4 bytes size info)
0x00, 0x00, 0x00, 0x00, // 7: object_width, object_height
};
private static byte[] headerODSNext =
{
0x00, 0x00, // 0: object_id
0x00, // 2: object_version_number
(byte)0x40, // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
};
private static byte[] headerWDS =
{
0x01, // 0 : number of windows (currently assumed 1, 0..2 is legal)
0x00, // 1 : window id (0..1)
0x00, 0x00, 0x00, 0x00, // 2 : x-ofs, y-ofs
0x00, 0x00, 0x00, 0x00 // 6 : width, height
};
/// <summary>
/// Parses a BluRay sup file
/// </summary>
/// <param name="fileName">BluRay sup file name</param>
/// <param name="log">Parsing info is logged here</param>
/// <returns>List of BluRaySupPictures</returns>
public static List<BluRaySupPicture> ParseBluRaySup(string fileName, StringBuilder log)
{
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return ParseBluRaySup(fs, log);
}
}
/// <summary>
/// Can be used with e.g. MemoryStream or FileStream
/// </summary>
/// <param name="ms">memory stream containing sup data</param>
/// <param name="log">Text parser log</param>
public static List<BluRaySupPicture> ParseBluRaySup(Stream ms, StringBuilder log)
{
SupSegment segment;
BluRaySupPicture pic = null;
BluRaySupPicture picLast = null;
BluRaySupPicture picTmp = null;
List<BluRaySupPicture> subPictures = new List<BluRaySupPicture>();
int odsCtr = 0;
int pdsCtr = 0;
int odsCtrOld = 0;
int pdsCtrOld = 0;
int compNum = -1;
int compNumOld = -1;
int compCount = 0;
long ptsPcs = 0;
bool paletteUpdate = false;
CompositionState cs = CompositionState.Invalid;
ms.Position = 0;
long position = 0;
int i = 0;
const int headerSize = 13;
byte[] buffer;
while (position < ms.Length)
{
string[] so = new string[1]; // hack to return string
ms.Seek(position, SeekOrigin.Begin);
buffer = new byte[headerSize];
ms.Read(buffer, 0, buffer.Length);
segment = ReadSegment(buffer, log);
position += headerSize;
buffer = new byte[segment.Size];
ms.Read(buffer, 0, buffer.Length);
log.Append(i + ": ");
switch (segment.Type)
{
case 0x14: // Palette
log.AppendLine(string.Format("0x14 - Palette - PDS offset={0} size={1}", position, segment.Size));
if (compNum != compNumOld)
{
if (pic != null)
{
so[0] = null;
int ps = ParsePds(buffer, segment, pic, so);
if (ps >= 0)
{
log.AppendLine(", " + so[0]);
if (ps > 0) // don't count empty palettes
pdsCtr++;
}
else
{
log.AppendLine();
log.AppendLine(so[0]);
}
}
else
{
log.AppendLine();
log.AppendLine("missing PTS start -> ignored");
}
}
else
{
log.AppendLine(", comp # unchanged -> ignored");
}
break;
case 0x15: // Image bitmap data
log.AppendLine(string.Format("0x15 - bitmap data - ODS offset={0} size={1}", position, segment.Size));
if (compNum != compNumOld)
{
if (!paletteUpdate)
{
if (pic != null)
{
so[0] = null;
if (ParseOds(buffer, segment, pic, so))
odsCtr++;
if (so[0] != null)
log.Append(", " + so[0]);
log.AppendLine(", img size: " + pic.Width + "*" + pic.Height);
}
else
{
log.AppendLine();
log.AppendLine("missing PTS start -> ignored");
}
}
else
{
log.AppendLine();
log.AppendLine("palette update only -> ignored");
}
}
else
{
log.AppendLine(", comp # unchanged -> ignored");
}
break;
case 0x16:
log.AppendLine(string.Format("0x16 - Time codes, offset={0} size={1}", position, segment.Size));
compNum = BigEndianInt16(buffer, 5);
cs = GetCompositionState(buffer[7]);
paletteUpdate = buffer[8] == 0x80;
ptsPcs = segment.PtsTimestamp;
if (segment.Size >= 0x13)
compCount = 1; // could be also 2, but we'll ignore this for the moment
else
compCount = 0;
if (cs == CompositionState.Invalid)
{
log.AppendLine("Illegal composition state at offset " + position);
}
else if (cs == CompositionState.EpochStart)
{
//new frame
if (subPictures.Count > 0 && (odsCtr == 0 || pdsCtr == 0))
{
log.AppendLine("missing PDS/ODS: last epoch is discarded");
subPictures.RemoveAt(subPictures.Count - 1);
compNumOld = compNum - 1;
if (subPictures.Count > 0)
picLast = subPictures[subPictures.Count - 1];
else
picLast = null;
}
else
picLast = pic;
pic = new BluRaySupPicture();
subPictures.Add(pic); // add to list
pic.StartTime = segment.PtsTimestamp;
log.AppendLine("#> " + (subPictures.Count) + " (" + ToolBox.PtsToTimeString(pic.StartTime) + ")");
so[0] = null;
ParsePcs(segment, pic, so, buffer);
// fix end time stamp of previous pic if still missing
if (picLast != null && picLast.EndTime == 0)
picLast.EndTime = pic.StartTime;
if (so[0] != null)
log.AppendLine(", " + so[0]);
else
log.AppendLine();
log.Append(Environment.NewLine + "PTS start: " + ToolBox.PtsToTimeString(pic.StartTime));
log.AppendLine(", screen size: " + pic.Width + "*" + pic.Height);
odsCtr = 0;
pdsCtr = 0;
odsCtrOld = 0;
pdsCtrOld = 0;
picTmp = null;
}
else
{
if (pic == null)
{
log.AppendLine(" Missing start of epoch at offset " + position);
break;
}
log.Append("PCS ofs:" + ToolBox.ToHex(buffer, 0, 8) + ", ");
switch (cs)
{
case CompositionState.EpochContinue:
log.AppendLine(" CONT, ");
break;
case CompositionState.AcquPoint:
log.AppendLine(" ACQU, ");
break;
case CompositionState.Normal:
log.AppendLine(" NORM, ");
break;
}
log.AppendLine("size: " + segment.Size + ", comp#: " + compNum + ", forced: " + pic.IsForced);
if (compNum != compNumOld)
{
so[0] = null;
// store state to be able to revert to it
picTmp = new BluRaySupPicture(pic); // deep copy
picTmp.EndTime = ptsPcs;
// create new pic
ParsePcs(segment, pic, so, buffer);
}
if (so[0] != null)
log.AppendLine(", " + so[0]);
log.AppendLine(", pal update: " + paletteUpdate);
log.AppendLine("PTS: " + ToolBox.PtsToTimeString(segment.PtsTimestamp));
}
break;
case 0x17:
log.AppendLine(string.Format("0x17 - WDS offset={0} size={1}", position, segment.Size));
int x = BigEndianInt16(buffer, 2);
int y = BigEndianInt16(buffer, 4);
int width = BigEndianInt16(buffer, 6);
int height = BigEndianInt16(buffer, 8);
log.AppendLine(string.Format("width:{0}, height:{1}", width, height));
break;
case 0x80:
log.AppendLine(string.Format("0x18 - END offset={0} size={1}", position, segment.Size));
// decide whether to store this last composition section as caption or merge it
if (cs == CompositionState.EpochStart)
{
if (compCount > 0 && odsCtr > odsCtrOld && compNum != compNumOld && IsPictureMergable(picLast, pic))
{
// the last start epoch did not contain any (new) content
// and should be merged to the previous frame
subPictures.RemoveAt(subPictures.Count - 1);
pic = picLast;
if (subPictures.Count > 0)
picLast = subPictures[subPictures.Count - 1];
else
picLast = null;
log.AppendLine("#< caption merged");
}
}
else
{
long startTime = 0;
if (pic != null)
{
startTime = pic.StartTime; // store
pic.StartTime = ptsPcs; // set for testing merge
}
if (compCount > 0 && odsCtr > odsCtrOld && compNum != compNumOld && !IsPictureMergable(picTmp, pic))
{
// last PCS should be stored as separate caption
if (odsCtr - odsCtrOld > 1 || pdsCtr - pdsCtrOld > 1)
log.AppendLine("multiple PDS/ODS definitions: result may be erratic");
// replace pic with picTmp (deepCopy created before new PCS)
subPictures[subPictures.Count - 1] = picTmp; // replace in list
picLast = picTmp;
subPictures.Add(pic); // add to list
log.AppendLine("#< " + (subPictures.Count) + " (" + ToolBox.PtsToTimeString(pic.StartTime) + ")");
odsCtrOld = odsCtr;
}
else
{
if (pic != null)
{
// merge with previous pic
pic.StartTime = startTime; // restore
pic.EndTime = ptsPcs;
// for the unlikely case that forced flag changed during one captions
if (picTmp != null && picTmp.IsForced)
pic.IsForced = true;
if (pdsCtr > pdsCtrOld || paletteUpdate)
log.AppendLine("palette animation: result may be erratic\n");
}
else
log.AppendLine("end without at least one epoch start");
}
}
pdsCtrOld = pdsCtr;
compNumOld = compNum;
break;
default:
log.AppendLine(string.Format("0x?? - END offset={0} UNKOWN SEGMENT TYPE={1}", position, segment.Type));
break;
}
log.AppendLine();
position += segment.Size;
i++;
}
return subPictures;
}
/// <summary>
/// Checks if two SubPicture object can be merged because the time gap between them is rather small
/// and the embedded objects seem to be identical
/// </summary>
/// <param name="a">first SubPicture object (earlier)</param>
/// <param name="b">2nd SubPicture object (later)</param>
/// <returns>return true if the SubPictures can be merged</returns>
private static bool IsPictureMergable(BluRaySupPicture a, BluRaySupPicture b)
{
bool eq = false;
if (a != null && b != null)
{
if (a.EndTime == 0 || b.StartTime - a.EndTime < Core.GetMergePtSdiff())
{
ImageObject ao = a.ObjectIdImage;
ImageObject bo = b.ObjectIdImage;
if (ao != null && bo != null)
if (ao.BufferSize == bo.BufferSize && ao.Width == bo.Width && ao.Height == bo.Height)
eq = true;
}
}
return eq;
}
/// <summary>
/// Parse an PCS packet which contains width/height info
/// </summary>
/// <param name="segment">object containing info about the current segment</param>
/// <param name="pic">SubPicture object containing info about the current caption</param>
/// <param name="msg">reference to message string</param>
/// <param name="buffer">Raw data buffer, starting right after segment</param>
private static void ParsePcs(SupSegment segment, BluRaySupPicture pic, string[] msg, byte[] buffer)
{
if (segment.Size >= 4)
{
pic.Width = BigEndianInt16(buffer, 0); // video_width
pic.Height = BigEndianInt16(buffer, 2); // video_height
int type = buffer[4]; // hi nibble: frame_rate, lo nibble: reserved
int num = BigEndianInt16(buffer, 5); // composition_number
// skipped:
// 8bit composition_state: 0x00: normal, 0x40: acquisition point
// 0x80: epoch start, 0xC0: epoch continue, 6bit reserved
// 8bit palette_update_flag (0x80), 7bit reserved
int palId = buffer[9]; // 8bit palette_id_ref
int coNum = buffer[10]; // 8bit number_of_composition_objects (0..2)
if (coNum > 0)
{
// composition_object:
int objId = BigEndianInt16(buffer, 11); // 16bit object_id_ref
msg[0] = "palID: " + palId + ", objID: " + objId;
if (pic.ImageObjects == null)
pic.ImageObjects = new List<ImageObject>();
ImageObject imgObj;
if (objId >= pic.ImageObjects.Count)
{
imgObj = new ImageObject();
pic.ImageObjects.Add(imgObj);
}
else
imgObj = pic.GetImageObject(objId);
imgObj.PaletteId = palId;
pic.ObjectId = objId;
// skipped: 8bit window_id_ref
if (segment.Size >= 0x13)
{
pic.FramesPerSecondType = type;
// object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
int forcedCropped = buffer[14];
pic.CompositionNumber = num;
pic.IsForced = ((forcedCropped & 0x40) == 0x40);
imgObj.XOffset = BigEndianInt16(buffer, 15); // composition_object_horizontal_position
imgObj.YOffset = BigEndianInt16(buffer, 17); // composition_object_vertical_position
// if (object_cropped_flag==1)
// 16bit object_cropping_horizontal_position
// 16bit object_cropping_vertical_position
// 16bit object_cropping_width
// object_cropping_height
}
}
}
}
/// <summary>
/// parse an ODS packet which contain the image data
/// </summary>
/// <param name="buffer">raw byte date, starting right after segment</param>
/// <param name="segment">object containing info about the current segment</param>
/// <param name="pic">SubPicture object containing info about the current caption</param>
/// <param name="msg">reference to message string</param>
/// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns>
private static bool ParseOds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg)
{
ImageObjectFragment info;
int objId = BigEndianInt16(buffer, 0); // 16bit object_id
int objVer = buffer[2]; // 16bit object_id nikse - index 2 or 1???
int objSeq = buffer[3]; // 8bit first_in_sequence (0x80),
// last_in_sequence (0x40), 6bits reserved
bool first = (objSeq & 0x80) == 0x80;
bool last = (objSeq & 0x40) == 0x40;
if (pic.ImageObjects == null)
pic.ImageObjects = new List<ImageObject>();
ImageObject imgObj;
if (objId >= pic.ImageObjects.Count)
{
imgObj = new ImageObject();
pic.ImageObjects.Add(imgObj);
}
else
imgObj = pic.GetImageObject(objId);
if (imgObj.Fragments == null || first)
{ // 8bit object_version_number
// skipped:
// 24bit object_data_length - full RLE buffer length (including 4 bytes size info)
int width = BigEndianInt16(buffer, 7); // object_width
int height = BigEndianInt16(buffer, 9); // object_height
if (width <= pic.Width && height <= pic.Height)
{
imgObj.Fragments = new List<ImageObjectFragment>();
info = new ImageObjectFragment();
info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes)
info.ImageBuffer = new byte[info.ImagePacketSize];
Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize);
imgObj.Fragments.Add(info);
imgObj.BufferSize = info.ImagePacketSize;
imgObj.Height = height;
imgObj.Width = width;
msg[0] = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") +
((first && last) ? "/" : "") + (last ? "" + "last" : "");
return true;
}
System.Diagnostics.Debug.Print("Invalid image size - ignored");
return false;
}
// object_data_fragment
// skipped:
// 16bit object_id
// 8bit object_version_number
// 8bit first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
info = new ImageObjectFragment();
info.ImagePacketSize = segment.Size - 4;
info.ImageBuffer = new byte[info.ImagePacketSize];
Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize);
imgObj.Fragments.Add(info);
imgObj.BufferSize += info.ImagePacketSize; // total size (may contain several packets)
msg[0] = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : "");
return false;
}
private static CompositionState GetCompositionState(byte type)
{
switch (type)
{
case 0x00:
return CompositionState.Normal;
case 0x40:
return CompositionState.AcquPoint;
case 0x80:
return CompositionState.EpochStart;
case 0xC0:
return CompositionState.EpochContinue;
default:
return CompositionState.Invalid;
}
}
private static int BigEndianInt16(byte[] buffer, int index)
{
return (buffer[index + 1]) + (buffer[index + 0] << 8);
}
private static uint BigEndianInt32(byte[] buffer, int index)
{
return (uint)((buffer[index + 3]) + (buffer[index + 2] << 8) + (buffer[index + 1] << 0x10) + (buffer[index + 0] << 0x18));
}
private static SupSegment ReadSegment(byte[] buffer, StringBuilder log)
{
SupSegment segment = new SupSegment();
if (buffer[0] == 0x50 && buffer[1] == 0x47) // 80 + 71 - P G
{
segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS
segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS
segment.Type = buffer[10];
segment.Size = BigEndianInt16(buffer, 11);
}
else
{
log.AppendLine("Unable to read segment - PG missing!");
}
return segment;
}
/// <summary>
/// parse an PDS packet which contain palette info
/// </summary>
/// <param name="buffer">Buffer of raw byte data, starting right after segment</param>
/// <param name="segment">object containing info about the current segment</param>
/// <param name="pic">SubPicture object containing info about the current caption</param>
/// <param name="msg">reference to message string</param>
/// <returns>number of valid palette entries (-1 for fault)</returns>
private static int ParsePds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg)
{
int paletteId = buffer[0]; // 8bit palette ID (0..7)
// 8bit palette version number (incremented for each palette change)
int paletteUpdate = buffer[1];
if (pic.Palettes == null)
{
pic.Palettes = new List<List<PaletteInfo>>();
for (int i = 0; i < 8; i++)
pic.Palettes.Add(new List<PaletteInfo>());
}
if (paletteId > 7)
{
msg[0] = "Illegal palette id at offset " + ToolBox.ToHex(buffer, 0, 8);
return -1;
}
List<PaletteInfo> al = pic.Palettes[paletteId];
if (al == null)
al = new List<PaletteInfo>();
PaletteInfo p = new PaletteInfo();
p.PaletteSize = (segment.Size - 2) / 5;
p.PaletteBuffer = new byte[p.PaletteSize * 5];
Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object
al.Add(p);
msg[0] = "ID: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries";
return p.PaletteSize;
}
}
}

View File

@ -0,0 +1,403 @@
/*
* Copyright 2009 Volker Oth (0xdeadbeef)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
*/
using System;
using System.Collections.Generic;
using System.Drawing;
namespace Nikse.SubtitleEdit.Logic.BluRaySup
{
public class BluRaySupPicture
{
/// <summary>
/// screen width
/// </summary>
public int Width { get; set; }
/// <summary>
/// screen height
/// </summary>
public int Height { get; set; }
/// <summary>
/// start time in milliseconds
/// </summary>
public long StartTime { get; set; }
/// <summary>
/// end time in milliseconds
/// </summary>
public long EndTime { get; set; }
/// <summary>
/// if true, this is a forced subtitle
/// </summary>
public bool IsForced { get; set; }
/// <summary>
/// composition number - increased at start and end PCS
/// </summary>
public int CompositionNumber { get; set; }
/// <summary>
/// objectID used in decoded object
/// </summary>
public int ObjectId { get; set; }
/// <summary>
/// list of ODS packets containing image info
/// </summary>
public List<ImageObject> ImageObjects;
/// <summary>
/// width of subtitle window (might be larger than image)
/// </summary>
public int WindowWidth { get; set; }
/// <summary>
/// height of subtitle window (might be larger than image)
/// </summary>
public int WindowHeight { get; set; }
/// <summary>
/// upper left corner of subtitle window x
/// </summary>
public int WindowXOffset { get; set; }
/// <summary>
/// upper left corner of subtitle window y
/// </summary>
public int WindowYOffset { get; set; }
/// <summary>
/// FPS type (e.g. 0x10 = 24p)
/// </summary>
public int FramesPerSecondType { get; set; }
/** list of (list of) palette info - there are up to 8 palettes per epoch, each can be updated several times */
public List<List<PaletteInfo>> Palettes;
public BluRaySupPicture(BluRaySupPicture subPicture)
{
Width = subPicture.Width;
Height = subPicture.Height;
StartTime = subPicture.StartTime;
EndTime = subPicture.EndTime;
IsForced = subPicture.IsForced;
CompositionNumber = subPicture.CompositionNumber;
ObjectId = subPicture.ObjectId;
ImageObjects = new List<ImageObject>();
foreach (ImageObject io in subPicture.ImageObjects)
ImageObjects.Add(io);
WindowWidth = subPicture.WindowWidth;
WindowHeight = subPicture.WindowHeight;
WindowXOffset = subPicture.WindowXOffset;
WindowYOffset = subPicture.WindowYOffset;
FramesPerSecondType = subPicture.FramesPerSecondType;
Palettes = new List<List<PaletteInfo>>();
foreach (List<PaletteInfo> palette in subPicture.Palettes)
{
List<PaletteInfo> p = new List<PaletteInfo>();
foreach (PaletteInfo pi in palette)
{
p.Add(new PaletteInfo(pi));
}
Palettes.Add(p);
}
}
public BluRaySupPicture()
{
}
public ImageObject GetImageObject(int index)
{
return ImageObjects[index];
}
internal ImageObject ObjectIdImage
{
get
{
return ImageObjects[ObjectId];
}
}
/// <summary>
/// decode palette from the input stream
/// </summary>
/// <param name="pic">SubPicture object containing info about the current caption</param>
/// <returns>Palette object</returns>
public BluRaySupPalette DecodePalette(BluRaySupPalette defaultPalette)
{
BluRaySupPicture pic = this;
bool fadeOut = false;
if (pic.Palettes.Count == 0 || pic.ObjectIdImage.PaletteId >= pic.Palettes.Count)
{
System.Diagnostics.Debug.Print("Palette not found in objectID=" + pic.ObjectId + " PaletteId=" + pic.ObjectIdImage.PaletteId + "!");
if (defaultPalette == null)
return new BluRaySupPalette(256, Core.UsesBt601());
else
return new BluRaySupPalette(defaultPalette);
}
List<PaletteInfo> pl = pic.Palettes[pic.ObjectIdImage.PaletteId];
BluRaySupPalette palette = new BluRaySupPalette(256, Core.UsesBt601());
// by definition, index 0xff is always completely transparent
// also all entries must be fully transparent after initialization
for (int j = 0; j < pl.Count; j++)
{
PaletteInfo p = pl[j];
int index = 0;
for (int i = 0; i < p.PaletteSize; i++)
{
// each palette entry consists of 5 bytes
int palIndex = p.PaletteBuffer[index];
int y = p.PaletteBuffer[++index];
int cr, cb;
if (Core.GetSwapCrCb())
{
cb = p.PaletteBuffer[++index];
cr = p.PaletteBuffer[++index];
}
else
{
cr = p.PaletteBuffer[++index];
cb = p.PaletteBuffer[++index];
}
int alpha = p.PaletteBuffer[++index];
int alphaOld = palette.GetAlpha(palIndex);
// avoid fading out
if (alpha >= alphaOld)
{
if (alpha < Core.GetAlphaCrop())
{// to not mess with scaling algorithms, make transparent color black
y = 16;
cr = 128;
cb = 128;
}
palette.SetAlpha(palIndex, alpha);
}
else fadeOut = true;
palette.SetYCbCr(palIndex, y, cb, cr);
index++;
}
}
if (fadeOut)
System.Diagnostics.Debug.Print("fade out detected -> patched palette\n");
return palette;
}
/// <summary>
/// Decode caption from the input stream
/// </summary>
/// <param name="pic">SubPicture object containing info about the caption</param>
/// <param name="transIdx">index of the transparent color</param>
/// <returns>bitmap of the decoded caption</returns>
public Bitmap DecodeImage(BluRaySupPalette defaultPalette)
{
int w = ObjectIdImage.Width;
int h = ObjectIdImage.Height;
if (w > Width || h > Height)
throw new Exception("Subpicture too large: " + w + "x" + h);
//Bitmap bm = new Bitmap(w, h);
FastBitmap bm = new FastBitmap(new Bitmap(w, h));
bm.LockImage();
BluRaySupPalette pal = DecodePalette(defaultPalette);
int index = 0;
int ofs = 0;
int xpos = 0;
// just for multi-packet support, copy all of the image data in one common buffer
byte[] buf = new byte[ObjectIdImage.BufferSize];
foreach (ImageObjectFragment fragment in ObjectIdImage.Fragments)
{
Buffer.BlockCopy(fragment.ImageBuffer, 0, buf, index, fragment.ImagePacketSize);
index += fragment.ImagePacketSize;
}
index = 0;
do
{
int b = buf[index++] & 0xff;
if (b == 0)
{
b = buf[index++] & 0xff;
if (b == 0)
{
// next line
ofs = (ofs / w) * w;
if (xpos < w)
ofs += w;
xpos = 0;
}
else
{
int size;
if ((b & 0xC0) == 0x40)
{
// 00 4x xx -> xxx zeroes
size = ((b - 0x40) << 8) + (buf[index++] & 0xff);
for (int i = 0; i < size; i++)
PutPixel(bm, ofs++, 0, pal);
xpos += size;
}
else if ((b & 0xC0) == 0x80)
{
// 00 8x yy -> x times value y
size = (b - 0x80);
b = buf[index++] & 0xff;
for (int i = 0; i < size; i++)
PutPixel(bm, ofs++, b, pal);
xpos += size;
}
else if ((b & 0xC0) != 0)
{
// 00 cx yy zz -> xyy times value z
size = ((b - 0xC0) << 8) + (buf[index++] & 0xff);
b = buf[index++] & 0xff;
for (int i = 0; i < size; i++)
PutPixel(bm, ofs++, b, pal);
xpos += size;
}
else
{
// 00 xx -> xx times 0
for (int i = 0; i < b; i++)
PutPixel(bm, ofs++, 0, pal);
xpos += b;
}
}
}
else
{
PutPixel(bm, ofs++, b, pal);
xpos++;
}
} while (index < buf.Length);
bm.UnlockImage();
return bm.GetBitmap();
}
private static void PutPixel(FastBitmap bmp, int index, int color, BluRaySupPalette palette)
{
int x = index % bmp.Width;
int y = index / bmp.Width;
if (color > 0 && x < bmp.Width && y < bmp.Height)
bmp.SetPixel(x, y, Color.FromArgb(palette.GetArgb(color)));
}
}
public class ImageObject
{
/// <summary>
/// list of ODS packets containing image info
/// </summary>
public List<ImageObjectFragment> Fragments;
/// <summary>
/// palette identifier
/// </summary>
public int PaletteId { get; set; }
/// <summary>
/// overall size of RLE buffer (might be spread over several packages)
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// with of subtitle image
/// </summary>
public int Width { get; set; }
/// <summary>
/// height of subtitle image
/// </summary>
public int Height { get; set; }
/// <summary>
/// upper left corner of subtitle x
/// </summary>
public int XOffset { get; set; }
/// <summary>
/// upper left corner of subtitle y
/// </summary>
public int YOffset { get; set; }
}
/// <summary>
/// contains offset and size of one fragment containing (parts of the) RLE buffer
/// </summary>
public class ImageObjectFragment
{
/// <summary>
/// size of this part of the RLE buffer
/// </summary>
public int ImagePacketSize { get; set; }
/// <summary>
/// Buffer for raw image data fragment
/// </summary>
public byte[] ImageBuffer { get; set; }
}
/// <summary>
/// contains offset and size of one update of a palette
/// </summary>
public class PaletteInfo
{
/// <summary>
/// number of palette entries
/// </summary>
public int PaletteSize { get; set; }
/// <summary>
/// raw palette data
/// </summary>
public byte[] PaletteBuffer { get; set; }
public PaletteInfo()
{
}
public PaletteInfo(PaletteInfo paletteInfo)
{
PaletteSize = paletteInfo.PaletteSize;
PaletteBuffer = new byte[paletteInfo.PaletteBuffer.Length];
Buffer.BlockCopy(paletteInfo.PaletteBuffer, 0, PaletteBuffer, 0, PaletteBuffer.Length);
}
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2009 Volker Oth (0xdeadbeef)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
*/
namespace Nikse.SubtitleEdit.Logic.BluRaySup
{
public static class Core
{
/** Use BT.601 color model instead of BT.709 */
private const bool UseBt601 = false;
/** Flag that defines whether to swap Cr/Cb components when loading a SUP */
private const bool SwapCrCb = false;
/** Alpha threshold for cropping */
private const int AlphaCrop = 14;
/** Two equal captions are merged of they are closer than 200ms (0.2*90000 = 18000) */
private const int MergePtSdiff = 18000;
/** Frames per seconds for 24p (23.976) */
public static double Fps24P = 24000.0 / 1001;
/** Frames per seconds for wrong 24P (23.975) */
public static double Fps23975 = 23.975;
/** Frames per seconds for 24Hz (24.0) */
public static double Fps24Hz = 24.0;
/** Frames per seconds for PAL progressive (25.0) */
public static double FpsPal = 25.0;
/** Frames per seconds for NTSC progressive (29.97) */
public static double FpsNtsc = 30000.0 / 1001;
/** Frames per seconds for PAL interlaced (50.0) */
public static double FpsPalI = 50.0;
/** Frames per seconds for NTSC interlaced (59.94) */
public static double FpsNtscI = 60000.0 / 1001;
/**
* Get maximum time difference for merging captions.
* @return Maximum time difference for merging captions
*/
public static int GetMergePtSdiff()
{
return MergePtSdiff;
}
/**
* Get: use of BT.601 color model instead of BT.709.
* @return True if BT.601 is used
*/
public static bool UsesBt601()
{
return UseBt601;
}
/**
* Get flag that defines whether to swap Cr/Cb components when loading a SUP.
* @return True: swap cr/cb
*/
public static bool GetSwapCrCb()
{
return SwapCrCb;
}
/**
* Get alpha threshold for cropping.
* @return Alpha threshold for cropping
*/
public static int GetAlphaCrop()
{
return AlphaCrop;
}
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2009 Volker Oth (0xdeadbeef)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
*/
using System.Text;
namespace Nikse.SubtitleEdit.Logic.BluRaySup
{
public static class ToolBox
{
/// <summary>
/// Convert bytes to a C-style hex string with leading zeroes
/// </summary>
public static string ToHex(byte[] buffer, int index, int digits)
{
var sb = new StringBuilder();
for (int i = index; i < index + digits; i++)
{
string s = string.Format("{0:X}", buffer[i]);
if (s.Length < 2)
sb.Append("0");
sb.Append(s);
}
return "0x" + sb;
}
/// <summary>
/// Convert a long integer to a C-style hex string with leading zeroes
/// </summary>
public static string ToHex(int number, int index, int digits)
{
string s = string.Format("{0:X}", number);
if (s.Length < digits)
s.PadLeft(digits, '0');
return "0x" + s;
}
/// <summary>
/// Convert an integer to a string with leading zeroes
/// </summary>
/// <param name="i">Integer value to convert</param>
/// <param name="digits">Number of digits to display - note that a 32bit number can have only 10 digits</param>
/// <returns>String version of integer with trailing zeroes</returns>
public static string ZeroTrim(int i, int digits)
{
string s = i.ToString();
return s.PadLeft(digits, '0');
}
/**
* Convert time in milliseconds to array containing hours, minutes, seconds and milliseconds
* @param ms Time in milliseconds
* @return Array containing hours, minutes, seconds and milliseconds (in this order)
*/
public static int[] MillisecondsToTime(long ms)
{
int[] time = new int[4];
// time[0] = hours
time[0] = (int)(ms / (60 * 60 * 1000));
ms -= time[0] * 60 * 60 * 1000;
// time[1] = minutes
time[1] = (int)(ms / (60 * 1000));
ms -= time[1] * 60 * 1000;
// time[2] = seconds
time[2] = (int)(ms / 1000);
ms -= time[2] * 1000;
time[3] = (int)ms;
return time;
}
/**
* Convert time in 90kHz ticks to string hh:mm:ss.ms
* @param pts Time in 90kHz resolution
* @return String in format hh:mm:ss:ms
*/
public static string PtsToTimeString(long pts)
{
int[] time = MillisecondsToTime((pts + 45) / 90);
return ZeroTrim(time[0], 2) + ":" + ZeroTrim(time[1], 2) + ":" + ZeroTrim(time[2], 2) + "." + ZeroTrim(time[3], 3);
}
}
}

View File

@ -8,6 +8,13 @@ namespace Nikse.SubtitleEdit.Logic
{
public static bool IsColorClose(Color a, Color b, int tolerance)
{
if (a.A < 120 && b.A < 120)
return true; // transparent
if (a.A > 250 && a.R > 90 && a.G > 90 && a.B > 90 &&
b.A > 250 && b.R > 90 && b.G > 90 && b.B > 90)
return true; // dark, non transparent
int diff = (a.R + a.G + a.B) - (b.R + b.G + b.B);
return diff < tolerance && diff > -tolerance;
}
@ -131,7 +138,9 @@ namespace Nikse.SubtitleEdit.Logic
for (int y = 1; y < bmp1.Height; y++)
{
if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
{
different++;
}
}
}
return different;

View File

@ -45,12 +45,10 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
#Subtitle text begin";
const string Footer = @"#Subtitle text end
#Subtitle text attribute begin
#/R:1,856 /FP:8 /FS:24
#/R:1,{0} /FP:8 /FS:24
#Subtitle text attribute end";
StringBuilder sb = new StringBuilder();
sb.AppendLine(Header);
int index = 0;
@ -63,7 +61,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
sb.AppendLine(Utilities.RemoveHtmlTags(p.Text));
index++;
}
sb.AppendLine(Footer);
sb.AppendLine(string.Format(Footer, subtitle.Paragraphs.Count));
return sb.ToString();
}

View File

@ -372,6 +372,7 @@
<Compare>Sammenlign...</Compare>
<ImportOcrFromDvd>Import/OCR undertekster fra VOB/IFO (dvd) ...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Importer/OCR VobSub (sub/idx) undertekst...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Importer/OCR BluRay sup fil...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Importer undertekster fra Matroska fil...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Importer undertekst med manuel valgt tegnsæt...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Importer tekst...</ImportText>
@ -672,7 +673,10 @@ Fortsæt?</SubtitleAppendPrompt>
<InvalidVobSubHeader>Header ikke gyldig VobSub fil: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Åbn VobSub (sub/idx) undertekst...</OpenVobSubFile>
<VobSubFiles>VobSub undertekst filer</VobSubFiles>
<BeforeImportingVobSubFile>Før import af VobSub undertekster</BeforeImportingVobSubFile>
<OpenBluRaySupFile>Åbn BluRay sup fil...</OpenBluRaySupFile>
<BluRaySupFiles>BluRay sup filer</BluRaySupFiles>
<BeforeImportingVobSubFile>Før import af VobSub undertekst</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Før import af BluRay sup undertekst</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Før vis udvalgte linjer tidligere/senere</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Vis tidligere/senere udført på udvalgte linjer</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Dobbelt ord via regex {0}</DoubleWordsViaRegEx>
@ -973,7 +977,8 @@ Fortsæt?</SubtitleAppendPrompt>
<Image>Billede</Image>
</VobSubEditCharacters>
<VobSubOcr>
<Title>Importer/OCR VobSub (sub/idx) undertekster</Title>
<Title>Importer/OCR VobSub (sub/idx) undertekst</Title>
<TitleBluRay>Importer/OCR BluRay (.sup) undertekst</TitleBluRay>
<OcrMethod>OCR-metoden</OcrMethod>
<OcrViaModi>OCR via Microsoft Office Document Imaging (MODI). Kræver MS Office</OcrViaModi>
<OcrViaTesseract>OCR via Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -371,6 +371,7 @@ de inicio del próximo texto</Note>
<Compare>&amp;Comparar...</Compare>
<ImportOcrFromDvd>Importar/OCR subtítulo desde vob/ifo (dvd) ...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Importar/subtítuloOCR VobSub (sub/idx)...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Importar/subtítuloOCR BluRay (.sup)...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Importar subtítulo desde archivo Matroska...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Importar subtítulo de modo manual eligiendo codificador...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Importar texto...</ImportText>
@ -671,7 +672,10 @@ Continuar?</SubtitleAppendPrompt>
<InvalidVobSubHeader>Encabezado de archivoVobSub inválido: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Abrir subtítulo VobSub (sub/idx)...</OpenVobSubFile>
<VobSubFiles>Subtítulos de archivos VobSub</VobSubFiles>
<OpenBluRaySupFile>Abrir subtítulo BluRay (.sup)...</OpenBluRaySupFile>
<BluRaySupFiles>Subtítulos de archivos BluRay</BluRaySupFiles>
<BeforeImportingVobSubFile>Antes de importar subtítulos VobSub</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Antes de importar subtítulos BluRay</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Antes de mostrar las líneas seleccionadas antes/después
</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Mostrar el antes/después realizado sobre las líneas seleccionadas</ShowSelectedLinesEarlierLaterPerformed>
@ -975,6 +979,7 @@ Continuar?</SubtitleAppendPrompt>
</VobSubEditCharacters>
<VobSubOcr>
<Title>Importar/subtítuloOCR VobSub (sub/idx)</Title>
<TitleBluRay>Importar/subtítuloOCR BluRay (.sup)</TitleBluRay>
<OcrMethod>método OCR</OcrMethod>
<OcrViaModi>OCR vía Microsoft Office Document Imaging (MODI). MS Office requerido</OcrViaModi>
<OcrViaTesseract>OCR a traves de Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -370,6 +370,7 @@ Email : mailto:nikse.dk@gmail.com</AboutText1>
<Compare>&amp;Comparer...</Compare>
<ImportOcrFromDvd>Import/sous-titres OCR de VOB/IFO (DVD) ...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Import/OCR VobSub (sub/idx) sous-titres...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Import/OCR BluRay (.sup) sous-titres...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Sous-titres d'importation de fichier Matroska...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Sous-titres d'importation avec le codage choisi manuel...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Importer texte...</ImportText>
@ -667,7 +668,10 @@ Poursuivre?</SubtitleAppendPrompt>
<InvalidVobSubHeader>En-tête non valide fichier VobSub : {0}</InvalidVobSubHeader>
<OpenVobSubFile>Ouvrir sous-titres VobSub (sub/idx)...</OpenVobSubFile>
<VobSubFiles>Fichiers sous-titres VobSub</VobSubFiles>
<OpenBluRaySupFile>Ouvrir sous-titres BluRay (.sup)...</OpenBluRaySupFile>
<BluRaySupFiles>Fichiers sous-titres BluRay</BluRaySupFiles>
<BeforeImportingVobSubFile>Avant d'importer des sous-titres VobSub</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Avant d'importer des sous-titres BluRay</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Avant de montrer les lignes précédentes/suivantes sélectionnées</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Montrer précédent/suivant effectué sur les lignes sélectionnées </ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Double mots via regex {0}</DoubleWordsViaRegEx>
@ -970,6 +974,7 @@ Poursuivre?</SubtitleAppendPrompt>
</VobSubEditCharacters>
<VobSubOcr>
<Title>Import/OCR VobSub (sub/idx) sous-titres</Title>
<TitleBluRay>Import/OCR BluRay (.sup) sous-titres</TitleBluRay>
<OcrMethod>Méthode OCR</OcrMethod>
<OcrViaModi>OCR par Microsoft Office Document Imaging (MODI). Nécessite MS Office</OcrViaModi>
<OcrViaTesseract>OCR par Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -371,6 +371,7 @@ Email: mailto:nikse.dk@gmail.com</AboutText1>
<Compare>Po&amp;równaj...</Compare>
<ImportOcrFromDvd>Importuj/OCR napisy z VOB/IFO (DVD)...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Importuj/OCR napisy z VobSub (sub/idx)...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Importuj/OCR napisy z BluRay (.sup)...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Importuj napisy z pliku Matroska...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Importuj napisy z ręcznym wyborem kodowania...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Importuj tekst...</ImportText>
@ -671,7 +672,10 @@ Kontynuować?</SubtitleAppendPrompt>
<InvalidVobSubHeader>Błędny nagłówek pliku VobSub: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Otwórz napisy VobSub (sub/idx)...</OpenVobSubFile>
<VobSubFiles>Pliki napisów VobSub</VobSubFiles>
<OpenBluRaySupFile>Otwórz napisy BluRay (.sup)...</OpenBluRaySupFile>
<BluRaySupFiles>Pliki napisów BluRay (.sup)</BluRaySupFiles>
<BeforeImportingVobSubFile>Przed importowaniem napisów VobSub</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Przed importowaniem napisów BluRay (.sup)</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Przed wybraniem wcześniejszego/późniejszego ukazywania się linii</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Wykonanie na wybranych liniach wcześniejszego/późniejszego ukazywania się</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Podwójne wyrazy via regex {0}</DoubleWordsViaRegEx>
@ -973,6 +977,7 @@ Kontynuować?</SubtitleAppendPrompt>
</VobSubEditCharacters>
<VobSubOcr>
<Title>Import/OCR napisów VobSub (sub/idx)</Title>
<TitleBluRay>Import/OCR napisów BluRay (.sup)</TitleBluRay>
<OcrMethod>Metody OCR</OcrMethod>
<OcrViaModi>OCR za pomocą MS MODI. Wymagany MS Office</OcrViaModi>
<OcrViaTesseract>OCR przy użyciu Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -368,6 +368,7 @@ E-mail: nikse.dk @gmail.com</AboutText1>
<Compare>&amp;Compara...</Compare>
<ImportOcrFromDvd>Import/subtitrarea OCR din vob/IFO (DVD) ...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Import/OCR VobSub (sub/idx) subtitrarea...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Import/OCR BluRay (,sup) subtitrarea...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Import subtitrare din fisier Matroska...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Import subtitrare cu alegerea manuala a codarii...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Import text simplu...</ImportText>
@ -668,7 +669,10 @@ E-mail: nikse.dk @gmail.com</AboutText1>
<InvalidVobSubHeader>Antetul nu este valabil pentru fisier VobSubr: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Deschide subtitrare VobSub (sub/idx)...</OpenVobSubFile>
<VobSubFiles>Fisier subtitrare VobSub</VobSubFiles>
<OpenBluRaySupFile>Deschide subtitrare BluRay (.sup)...</OpenBluRaySupFile>
<BluRaySupFiles>Fisier subtitrare BluRay</BluRaySupFiles>
<BeforeImportingVobSubFile>Inainte de a importa subtitrare VobSub</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Inainte de a importa subtitrare BluRay (.sup)</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Inainte de a arata liniile selectate mai devreme/tarziu</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Arata mai devreme/tarziu efectuate pe liniile selectate</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Cuvinte dublate via regex {0}</DoubleWordsViaRegEx>
@ -970,6 +974,7 @@ E-mail: nikse.dk @gmail.com</AboutText1>
</VobSubEditCharacters>
<VobSubOcr>
<Title>Import subtitrare /OCR VobSub (sub/idx)</Title>
<TitleBluRay>Import subtitrare /OCR BluRay (.sup)</TitleBluRay>
<OcrMethod>OCR metoda</OcrMethod>
<OcrViaModi>OCR, prin intermediul Microsoft Office Document Imaging (MODI). Necesita MS Office</OcrViaModi>
<OcrViaTesseract>OCR prin Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Language Name="Српски">
<General>
<Title>Subtitle Edit</Title>
@ -370,6 +370,7 @@ C# изворни кôд се налази на интернет страниц
<Compare>&amp;Упореди...</Compare>
<ImportOcrFromDvd>Увези/препознај знакове титла из VOB/IFO датотеке (ДВД)...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Увези/препознај знакове VobSub титла...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Увези/препознај знакове BluRay титла...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Увези титл из матрошка датотеке...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Увези титл с ручно изабраним кодним распоредом...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Увези чист текст...</ImportText>
@ -599,8 +600,7 @@ C# изворни кôд се налази на интернет страниц
<SubtitleAppendPromptTitle>Качење титла</SubtitleAppendPromptTitle>
<OpenSubtitleToAppend>Отвори титл за качење...</OpenSubtitleToAppend>
<AppendViaVisualSyncTitle>Визуелна синхронизација — качење другог дела титла</AppendViaVisualSyncTitle>
<AppendSynchronizedSubtitlePrompt>
</AppendSynchronizedSubtitlePrompt>
<AppendSynchronizedSubtitlePrompt>Додај овај синхронизовани титлове?</AppendSynchronizedSubtitlePrompt>
<BeforeAppend>Пре качења</BeforeAppend>
<SubtitleAppendedX>Прикачено титлова: {0}</SubtitleAppendedX>
<SubtitleNotAppended>Титл није прикачен!</SubtitleNotAppended>
@ -671,7 +671,10 @@ C# изворни кôд се налази на интернет страниц
<InvalidVobSubHeader>Заглавље није исправна VobSub датотека: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Отварање VobSub титла...</OpenVobSubFile>
<VobSubFiles>VobSub титлови</VobSubFiles>
<OpenBluRaySupFile>Отварање BluRay (.sup) титла...</OpenBluRaySupFile>
<BluRaySupFiles>BluRay титлови</BluRaySupFiles>
<BeforeImportingVobSubFile>Пре увоза VobSub титла</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Пре увоза BluRay титла</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Пре приказивања изабране линије раније/касније</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Прикажи изабране линије раније или касније</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Дупле речи путем регекса {0}</DoubleWordsViaRegEx>
@ -694,10 +697,8 @@ C# изворни кôд се налази на интернет страниц
<XMinimumDisplayTimeBetweenParagraphsChanged>Измењено броја линија с минималним временом приказа између пасуса: {0}</XMinimumDisplayTimeBetweenParagraphsChanged>
<BeforeImportText>Пре увоза чистог текста</BeforeImportText>
<TextImported>Текст је увезен</TextImported>
<BeforePointSynchronization>
</BeforePointSynchronization>
<PointSynchronizationDone>
</PointSynchronizationDone>
<BeforePointSynchronization>Пре тачка синхронизације</BeforePointSynchronization>
<PointSynchronizationDone>Тачка синхронизације урадити</PointSynchronizationDone>
<BeforeTimeCodeImport>Пре увоза временских одредница</BeforeTimeCodeImport>
<TimeCodeImportedFromXY>Временске одреднице су увезене из {0}: {1}</TimeCodeImportedFromXY>
<BeforeInsertSubtitleAtVideoPosition>Пре постављања титла у положај видео записа</BeforeInsertSubtitleAtVideoPosition>
@ -975,6 +976,7 @@ C# изворни кôд се налази на интернет страниц
</VobSubEditCharacters>
<VobSubOcr>
<Title>Увожење/препознавање знакова VobSub титла</Title>
<TitleBluRay>Увожење/препознавање знакова BluRay титла</TitleBluRay>
<OcrMethod>Метода препознавања знакова</OcrMethod>
<OcrViaModi>Препознавање знакова путем Microsoft Office Document Imaging (MODI). Захтева MS Office</OcrViaModi>
<OcrViaTesseract>Препознавање знакова путем хиперкоцке</OcrViaTesseract>

Binary file not shown.

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Language Name="Srpski">
<General>
<Title>Subtitle Edit</Title>
@ -370,6 +370,7 @@ E-pošta: mailto:nikse.dk@gmail.com</AboutText1>
<Compare>&amp;Uporedi...</Compare>
<ImportOcrFromDvd>Uvezi/prepoznaj znakove titla iz VOB/IFO datoteke (DVD)...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Uvezi/prepoznaj znakove VobSub titla...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Uvezi/prepoznaj znakove BluRay (.sup) titla...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Uvezi titl iz matroška datoteke...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Uvezi titl s ručno izabranim kodnim rasporedom...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Uvezi čist tekst...</ImportText>
@ -599,8 +600,7 @@ koji bi trebalo da je već sinhronizovan s video zapisom.
<SubtitleAppendPromptTitle>Kačenje titla</SubtitleAppendPromptTitle>
<OpenSubtitleToAppend>Otvori titl za kačenje...</OpenSubtitleToAppend>
<AppendViaVisualSyncTitle>Vizuelna sinhronizacija — kačenje drugog dela titla</AppendViaVisualSyncTitle>
<AppendSynchronizedSubtitlePrompt>
</AppendSynchronizedSubtitlePrompt>
<AppendSynchronizedSubtitlePrompt>Додај овај синхронизовани титлове?</AppendSynchronizedSubtitlePrompt>
<BeforeAppend>Pre kačenja</BeforeAppend>
<SubtitleAppendedX>Prikačeno titlova: {0}</SubtitleAppendedX>
<SubtitleNotAppended>Titl nije prikačen!</SubtitleNotAppended>
@ -671,7 +671,10 @@ koji bi trebalo da je već sinhronizovan s video zapisom.
<InvalidVobSubHeader>Zaglavlje nije ispravna VobSub datoteka: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Otvaranje VobSub titla...</OpenVobSubFile>
<VobSubFiles>VobSub titlovi</VobSubFiles>
<OpenBluRaySupFile>Otvaranje BluRay titla...</OpenBluRaySupFile>
<BluRaySupFiles>BluRay (.sup) titlovi</BluRaySupFiles>
<BeforeImportingVobSubFile>Pre uvoza VobSub titla</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Pre uvoza BluRay titla</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Pre prikazivanja izabrane linije ranije/kasnije</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Prikaži izabrane linije ranije ili kasnije</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Duple reči putem regeksa {0}</DoubleWordsViaRegEx>
@ -694,10 +697,8 @@ koji bi trebalo da je već sinhronizovan s video zapisom.
<XMinimumDisplayTimeBetweenParagraphsChanged>Izmenjeno broja linija s minimalnim vremenom prikaza između pasusa: {0}</XMinimumDisplayTimeBetweenParagraphsChanged>
<BeforeImportText>Pre uvoza čistog teksta</BeforeImportText>
<TextImported>Tekst je uvezen</TextImported>
<BeforePointSynchronization>
</BeforePointSynchronization>
<PointSynchronizationDone>
</PointSynchronizationDone>
<BeforePointSynchronization>Пре тачка синхронизације</BeforePointSynchronization>
<PointSynchronizationDone>Тачка синхронизације урадити</PointSynchronizationDone>
<BeforeTimeCodeImport>Pre uvoza vremenskih odrednica</BeforeTimeCodeImport>
<TimeCodeImportedFromXY>Vremenske odrednice su uvezene iz {0}: {1}</TimeCodeImportedFromXY>
<BeforeInsertSubtitleAtVideoPosition>Pre postavljanja titla u položaj video zapisa</BeforeInsertSubtitleAtVideoPosition>
@ -975,6 +976,7 @@ koji bi trebalo da je već sinhronizovan s video zapisom.
</VobSubEditCharacters>
<VobSubOcr>
<Title>Uvoženje/prepoznavanje znakova VobSub titla</Title>
<TitleBluRay>Uvoženje/prepoznavanje znakova BluRay titla</TitleBluRay>
<OcrMethod>Metoda prepoznavanja znakova</OcrMethod>
<OcrViaModi>Prepoznavanje znakova putem Microsoft Office Document Imaging (MODI). Zahteva MS Office</OcrViaModi>
<OcrViaTesseract>Prepoznavanje znakova putem hiperkocke</OcrViaTesseract>

Binary file not shown.

View File

@ -371,6 +371,7 @@
<Compare>&amp;Jämför...</Compare>
<ImportOcrFromDvd>Importera/OCR textning från VOB/IFO (DVD) ...</ImportOcrFromDvd>
<ImportOcrVobSubSubtitle>Importera/OCR VobSub (sub/idx) undertext...</ImportOcrVobSubSubtitle>
<ImportBluRaySupFile>Importera/OCR BluRay (.sup) undertext...</ImportBluRaySupFile>
<ImportSubtitleFromMatroskaFile>Importera undertext från Matroska fil...</ImportSubtitleFromMatroskaFile>
<ImportSubtitleWithManualChosenEncoding>Importera undertext med manuell valda kodningen...</ImportSubtitleWithManualChosenEncoding>
<ImportText>Importera enbart text...</ImportText>
@ -671,7 +672,10 @@
<InvalidVobSubHeader>Rubrik inte giltigt VobSub fil: {0}</InvalidVobSubHeader>
<OpenVobSubFile>Öppna VobSub (sub/idx) undertext...</OpenVobSubFile>
<VobSubFiles>VobSub undertext filer</VobSubFiles>
<OpenBluRaySupFile>Öppna BluRay (.sup) undertext...</OpenBluRaySupFile>
<BluRaySupFiles>BluRay undertext filer</BluRaySupFiles>
<BeforeImportingVobSubFile>Innan du importerar VobSub undertext</BeforeImportingVobSubFile>
<BeforeImportingBluRaySupFile>Innan du importerar BluRay undertext</BeforeImportingBluRaySupFile>
<BeforeShowSelectedLinesEarlierLater>Före visa valda rader tidigare/senare</BeforeShowSelectedLinesEarlierLater>
<ShowSelectedLinesEarlierLaterPerformed>Visa tidigare/senare utförs på utvalda rader</ShowSelectedLinesEarlierLaterPerformed>
<DoubleWordsViaRegEx>Dubbel ord via regex {0}</DoubleWordsViaRegEx>
@ -973,6 +977,7 @@
</VobSubEditCharacters>
<VobSubOcr>
<Title>Import/OCR VobSub (sub/idx) undertext</Title>
<TitleBluRay>Import/OCR BluRay (.sup) undertext</TitleBluRay>
<OcrMethod>OCR-metod</OcrMethod>
<OcrViaModi>OCR via Microsoft Office Document Imaging (MODI). Kräver MS Office</OcrViaModi>
<OcrViaTesseract>OCR via Tesseract</OcrViaTesseract>

Binary file not shown.

View File

@ -369,6 +369,11 @@
<Compile Include="Forms\VobSubOcrNewFolder.Designer.cs">
<DependentUpon>VobSubOcrNewFolder.cs</DependentUpon>
</Compile>
<Compile Include="Logic\BluRaySup\BluRaySupPalette.cs" />
<Compile Include="Logic\BluRaySup\BluRaySupParser.cs" />
<Compile Include="Logic\BluRaySup\BluRaySupPicture.cs" />
<Compile Include="Logic\BluRaySup\Core.cs" />
<Compile Include="Logic\BluRaySup\ToolBox.cs" />
<Compile Include="Logic\DetectEncoding\EncodingTools.cs" />
<Compile Include="Logic\DetectEncoding\Multilang\CMLangConvertCharset.cs" />
<Compile Include="Logic\DetectEncoding\Multilang\CMLangConvertCharsetClass.cs" />
@ -436,6 +441,8 @@
<Compile Include="Logic\SubtitleFormats\Ebu.cs" />
<Compile Include="Logic\SubtitleFormats\SonyDVDArchitect.cs" />
<Compile Include="Logic\SubtitleFormats\Spruce.cs" />
<Compile Include="Logic\SubtitleFormats\SubtitleEditorProject.cs" />
<Compile Include="Logic\SubtitleFormats\UleadSubtitleFormat.cs" />
<Compile Include="Logic\SubtitleFormats\UnknownSubtitle5.cs" />
<Compile Include="Logic\SubtitleFormats\OpenDvt.cs" />
<Compile Include="Logic\SubtitleFormats\YouTubeSbv.cs" />
@ -670,7 +677,7 @@
<SubType>Designer</SubType>
</None>
<EmbeddedResource Include="Resources\da-DK.xml.zip" />
<None Include="Resources\es-ES.xml.zip" />
<EmbeddedResource Include="Resources\es-ES.xml.zip" />
<EmbeddedResource Include="Resources\pl-PL.xml.zip" />
<EmbeddedResource Include="Resources\ro-RO.xml.zip" />
<EmbeddedResource Include="Resources\sr-Cyrl-CS.xml.zip" />