/// <summary> /// Initializes a new instance of the <see cref="ImageSplitterItem"/> class. /// </summary> /// <param name="x"> /// The x. /// </param> /// <param name="y"> /// The y. /// </param> /// <param name="bitmap"> /// The bitmap. /// </param> public ImageSplitterItem(int x, int y, NikseBitmap bitmap) { this.X = x; this.Y = y; this.NikseBitmap = bitmap; this.SpecialCharacter = null; }
private byte[] GetSubImageBuffer(RunLengthTwoParts twoPartBuffer, NikseBitmap nbmp, Paragraph p, ContentAlignment alignment) { var ms = new MemoryStream(); // sup picture datasize WriteEndianWord(twoPartBuffer.Length + 34, ms); // first display control sequence table address int startDisplayControlSequenceTableAddress = twoPartBuffer.Length + 4; WriteEndianWord(startDisplayControlSequenceTableAddress, ms); // Write image const int imageTopFieldDataAddress = 4; ms.Write(twoPartBuffer.Buffer1, 0, twoPartBuffer.Buffer1.Length); int imageBottomFieldDataAddress = 4 + twoPartBuffer.Buffer1.Length; ms.Write(twoPartBuffer.Buffer2, 0, twoPartBuffer.Buffer2.Length); // Write zero delay ms.WriteByte(0); ms.WriteByte(0); // next display control sequence table address (use current is last) WriteEndianWord(startDisplayControlSequenceTableAddress + 24, ms); // start of display control sequence table address // Control command start if (p.Forced) ms.WriteByte(0); // ForcedStartDisplay==0 else ms.WriteByte(1); // StartDisplay==1 // Control command 3 = SetColor WriteColors(ms); // 3 bytes // Control command 4 = SetContrast WriteContrast(ms); // 3 bytes // Control command 5 = SetDisplayArea WriteDisplayArea(ms, nbmp, alignment); // 7 bytes // Control command 6 = SetPixelDataAddress WritePixelDataAddress(ms, imageTopFieldDataAddress, imageBottomFieldDataAddress); // 5 bytes // Control command exit ms.WriteByte(255); // 1 byte // Control Sequence Table // Write delay - subtitle duration WriteEndianWord(Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0 - 1023) >> 10, ms); // next display control sequence table address (use current is last) WriteEndianWord(startDisplayControlSequenceTableAddress + 24, ms); // start of display control sequence table address // Control command 2 = StopDisplay ms.WriteByte(2); // extra byte - for compatability with gpac/MP4BOX ms.WriteByte(255); // 1 byte return ms.ToArray(); }
public ImageSplitterItem(int x, int y, NikseBitmap bitmap) { X = x; Y = y; NikseBitmap = bitmap; SpecialCharacter = null; }
public BinaryOcrBitmap(NikseBitmap nbmp, bool italic, int expandCount, string text) { InitializeViaNikseBmp(nbmp); Italic = italic; ExpandCount = expandCount; Text = text; }
public BinaryOcrBitmap(NikseBitmap nbmp, bool italic, int expandCount, string text, int x, int y) { this.InitializeViaNikseBmp(nbmp); this.Italic = italic; this.ExpandCount = expandCount; this.Text = text; this.X = x; this.Y = y; }
public static NikseBitmap CropTopAndBottom(NikseBitmap bmp, out int topCropping, int maxDifferentPixelsOnLine) { int startTop = 0; int maxTop = bmp.Height - 2; if (maxTop > bmp.Height) maxTop = bmp.Height; for (int y = 0; y < maxTop; y++) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (!allTransparent) break; startTop++; } if (startTop > 9) startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with '). topCropping = startTop; for (int y = bmp.Height - 1; y > 3; y--) { int difference = 0; bool allTransparent = true; for (int x = 1; x < bmp.Width - 1; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { difference++; if (difference >= maxDifferentPixelsOnLine) { allTransparent = false; break; } } } if (allTransparent == false) return bmp.CopyRectangle(new Rectangle(0, startTop, bmp.Width - 1, y - startTop + 1)); } return bmp; }
internal void Initialize(Bitmap vobSubImage, ImageSplitterItem character, Point position, bool italicChecked, bool showShrink) { listBoxLinesForeground.Items.Clear(); listBoxlinesBackground.Items.Clear(); NikseBitmap nbmp = new NikseBitmap(vobSubImage); nbmp.ReplaceTransparentWith(Color.Black); vobSubImage = nbmp.GetBitmap(); radioButtonHot.Checked = true; ShrinkSelection = false; ExpandSelection = false; textBoxCharacters.Text = string.Empty; _nocrChar = new NOcrChar(); _nocrChar.MarginTop = character.Y - character.ParentY; _imageWidth = character.NikseBitmap.Width; _imageHeight = character.NikseBitmap.Height; _drawLineOn = false; _warningNoNotForegroundLinesShown = false; buttonShrinkSelection.Visible = showShrink; if (position.X != -1 && position.Y != -1) { StartPosition = FormStartPosition.Manual; Left = position.X; Top = position.Y; } pictureBoxSubtitleImage.Image = vobSubImage; pictureBoxCharacter.Image = character.NikseBitmap.GetBitmap(); Bitmap org = (Bitmap)vobSubImage.Clone(); Bitmap bm = new Bitmap(org.Width, org.Height); Graphics g = Graphics.FromImage(bm); g.DrawImage(org, 0, 0, org.Width, org.Height); g.DrawRectangle(Pens.Red, character.X, character.Y, character.NikseBitmap.Width, character.NikseBitmap.Height - 1); g.Dispose(); pictureBoxSubtitleImage.Image = bm; pictureBoxCharacter.Top = labelCharacters.Top + 16; SizePictureBox(); checkBoxItalic.Checked = italicChecked; _history = new List<NOcrChar>(); _historyIndex = -1; _nocrChar.Width = _imageWidth; _nocrChar.Height = _imageHeight; GenerateLineSegments(150, false, _nocrChar, new NikseBitmap(pictureBoxCharacter.Image as Bitmap)); ShowOcrPoints(); pictureBoxCharacter.Invalidate(); }
internal void Initialize(Bitmap bitmap, int pixelsIsSpace, bool rightToLeft, NOcrDb nOcrDb, VobSubOcr vobSubOcr) { _bitmap = bitmap; var nbmp = new NikseBitmap(bitmap); nbmp.ReplaceNonWhiteWithTransparent(); bitmap = nbmp.GetBitmap(); _bitmap2 = bitmap; _nocrChars = nOcrDb.OcrCharacters; _matchList = new List<VobSubOcr.CompareMatch>(); _vobSubOcr = vobSubOcr; const int minLineHeight = 6; _imageList = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmp, pixelsIsSpace, rightToLeft, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); // _imageList = NikseBitmapImageSplitter.SplitBitmapToLetters(nbmp, pixelsIsSpace, rightToLeft, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; while (index < _imageList.Count) { ImageSplitterItem item = _imageList[index]; if (item.NikseBitmap == null) { listBoxInspectItems.Items.Add(item.SpecialCharacter); _matchList.Add(null); } else { nbmp = item.NikseBitmap; nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); //get nocr matches var match = vobSubOcr.GetNOcrCompareMatchNew(item, nbmp, nOcrDb, false, false); if (match == null) { listBoxInspectItems.Items.Add("?"); _matchList.Add(null); } else { listBoxInspectItems.Items.Add(match.Text); _matchList.Add(match); } } index++; } }
public static NikseBitmap CropTopAndBottom(NikseBitmap bmp, out int topCropping) { int startTop = 0; int maxTop = bmp.Height - 2; if (maxTop > bmp.Height) maxTop = bmp.Height; for (int y = 0; y < maxTop; y++) { bool allTransparent = true; for (int x = 0; x < bmp.Width; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { allTransparent = false; break; } } if (!allTransparent) break; startTop++; } //if (startTop > 9) //startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with '). topCropping = startTop; int h = bmp.Height; bool bottomCroppingDone = false; for (int y = bmp.Height - 1; y > 3; y--) { for (int x = 0; x < bmp.Width; x++) { int a = bmp.GetAlpha(x, y); if (a != 0) { bottomCroppingDone = true; break; } } h = y; if (bottomCroppingDone) break; } if (h - startTop + 1 <= 0) return new NikseBitmap(0, 0); return bmp.CopyRectangle(new Rectangle(0, startTop, bmp.Width, h - startTop + 1)); }
private string SaveCompareItem(NikseBitmap newTarget, string text, bool isItalic, int expandCount) { string path = Configuration.VobSubCompareFolder + comboBoxCharacterDatabase.SelectedItem + Path.DirectorySeparatorChar; string databaseName = path + "Images.db"; FileStream f; long pos; if (!File.Exists(databaseName)) { if (!Directory.Exists(Configuration.OcrFolder)) { Directory.CreateDirectory(Configuration.OcrFolder); } using (f = new FileStream(databaseName, FileMode.Create)) { pos = f.Position; new ManagedBitmap(newTarget).AppendToStream(f); } } else { using (f = new FileStream(databaseName, FileMode.Append)) { pos = f.Position; new ManagedBitmap(newTarget).AppendToStream(f); } } string name = pos.ToString(CultureInfo.InvariantCulture); if (_compareDoc == null) { _compareDoc = new XmlDocument(); _compareDoc.LoadXml("<OcrBitmaps></OcrBitmaps>"); } if (_compareBitmaps == null) _compareBitmaps = new List<CompareItem>(); _compareBitmaps.Add(new CompareItem(new ManagedBitmap(newTarget), name, isItalic, expandCount, text)); XmlElement element = _compareDoc.CreateElement("Item"); XmlAttribute attribute = _compareDoc.CreateAttribute("Text"); attribute.InnerText = text; element.Attributes.Append(attribute); if (expandCount > 0) { XmlAttribute expandSelection = _compareDoc.CreateAttribute("Expand"); expandSelection.InnerText = expandCount.ToString(CultureInfo.InvariantCulture); element.Attributes.Append(expandSelection); } if (isItalic) { XmlAttribute italic = _compareDoc.CreateAttribute("Italic"); italic.InnerText = "true"; element.Attributes.Append(italic); } element.InnerText = pos.ToString(CultureInfo.InvariantCulture); _compareDoc.DocumentElement.AppendChild(element); _compareDoc.Save(path + "Images.xml"); return name; }
private string OcrViaNOCR(Bitmap bitmap, int listViewIndex) { if (_ocrFixEngine == null) comboBoxDictionaries_SelectedIndexChanged(null, null); string line = string.Empty; if (_nocrThreadResults != null) line = _nocrThreadResults[listViewIndex]; if (string.IsNullOrEmpty(line)) { var nbmpInput = new NikseBitmap(bitmap); var matches = new List<CompareMatch>(); int minLineHeight = _binOcrLastLowercaseHeight - 3; if (minLineHeight < 5) minLineHeight = _nocrLastLowercaseHeight - 3; if (minLineHeight < 5) minLineHeight = 5; List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmpInput, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); foreach (ImageSplitterItem item in list) { if (item.NikseBitmap != null) { item.NikseBitmap.ReplaceTransparentWith(Color.Black); } } int index = 0; bool expandSelection = false; bool shrinkSelection = false; var expandSelectionList = new List<ImageSplitterItem>(); while (index < list.Count) { ImageSplitterItem item = list[index]; if (expandSelection || shrinkSelection) { expandSelection = false; if (shrinkSelection && index > 0) { shrinkSelection = false; } else if (index + 1 < list.Count && list[index + 1].NikseBitmap != null) // only allow expand to EndOfLine or space { index++; expandSelectionList.Add(list[index]); } item = GetExpandedSelection(nbmpInput, expandSelectionList, checkBoxRightToLeft.Checked); if (item.NikseBitmap != null) { item.NikseBitmap.ReplaceTransparentWith(Color.Black); } _vobSubOcrNOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, expandSelectionList.Count > 1); DialogResult result = _vobSubOcrNOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrNOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrNOcrCharacter.ShrinkSelection) { shrinkSelection = true; index--; if (expandSelectionList.Count > 0) expandSelectionList.RemoveAt(expandSelectionList.Count - 1); } else if (result == DialogResult.OK && _vobSubOcrNOcrCharacter.ExpandSelection) { expandSelection = true; } else if (result == DialogResult.OK) { var c = _vobSubOcrNOcrCharacter.NOcrChar; if (expandSelectionList.Count > 1) c.ExpandCount = expandSelectionList.Count; _nOcrDb.Add(c); SaveNOcrWithCurrentLanguage(); string text = _vobSubOcrNOcrCharacter.NOcrChar.Text; //string name = SaveCompareItem(item.NikseBitmap, text, _vobSubOcrNOcrCharacter.IsItalic, expandSelectionList.Count); //var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrNOcrCharacter.IsItalic, listViewIndex); //_lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrNOcrCharacter.IsItalic, expandSelectionList.Count, null)); expandSelectionList = new List<ImageSplitterItem>(); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrNOcrCharacter.IsItalic; } else if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch match = GetNOcrCompareMatchNew(item, nbmpInput, _nOcrDb, checkBoxNOcrItalic.Checked, !checkBoxNOcrCorrect.Checked); if (match == null) { _vobSubOcrNOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, false); DialogResult result = _vobSubOcrNOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrNOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrNOcrCharacter.ExpandSelection) { expandSelectionList.Add(item); expandSelection = true; } else if (result == DialogResult.OK) { _nOcrDb.Add(_vobSubOcrNOcrCharacter.NOcrChar); SaveNOcrWithCurrentLanguage(); string text = _vobSubOcrNOcrCharacter.NOcrChar.Text; //string name = SaveCompareItem(item.NikseBitmap, text, _vobSubOcrNOcrCharacter.IsItalic, 0); //var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrNOcrCharacter.IsItalic, listViewIndex); //_lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrNOcrCharacter.IsItalic, 0, null)); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrNOcrCharacter.IsItalic; } else // found image match { matches.Add(new CompareMatch(match.Text, match.Italic, 0, null)); if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } if (_abort) return string.Empty; if (!expandSelection && !shrinkSelection) index++; if (shrinkSelection && expandSelectionList.Count < 2) { shrinkSelection = false; expandSelectionList = new List<ImageSplitterItem>(); } } line = GetStringWithItalicTags(matches); } line = FixNocrHardcodedStuff(line); //OCR fix engine string textWithOutFixes = line; if (_ocrFixEngine.IsDictionaryLoaded) { if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, listViewIndex, _lastLine, true, GetAutoGuessLevel()); int correctWords; int wordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(line, out correctWords); if (wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && string.IsNullOrWhiteSpace(textWithOutFixes.Replace("~", string.Empty))) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); line = _ocrFixEngine.FixUnknownWordsViaGuessOrPrompt(out wordsNotFound, line, listViewIndex, bitmap, checkBoxAutoFixCommonErrors.Checked, checkBoxPromptForUnknownWords.Checked, true, GetAutoGuessLevel()); } if (_ocrFixEngine.Abort) { ButtonStopClick(null, null); _ocrFixEngine.Abort = false; return string.Empty; } // Log used word guesses (via word replace list) foreach (string guess in _ocrFixEngine.AutoGuessesUsed) listBoxLogSuggestions.Items.Add(guess); _ocrFixEngine.AutoGuessesUsed.Clear(); // Log unkown words guess (found via spelling dictionaries) LogUnknownWords(); ColorLineByNumberOfUnknownWords(listViewIndex, wordsNotFound, line); } if (textWithOutFixes.Trim() != line.Trim()) { _tesseractOcrAutoFixes++; labelFixesMade.Text = string.Format(" - {0}", _tesseractOcrAutoFixes); LogOcrFix(listViewIndex, textWithOutFixes, line); } return line; }
public Bitmap GetSubtitleBitmap(int index) { Bitmap returnBmp = null; Color background; Color pattern; Color emphasis1; Color emphasis2; if (_mp4List != null) { if (index >= 0 && index < _mp4List.Count) { if (checkBoxCustomFourColors.Checked) { GetCustomColors(out background, out pattern, out emphasis1, out emphasis2); returnBmp = _mp4List[index].Picture.GetBitmap(null, background, pattern, emphasis1, emphasis2, true); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } else { returnBmp = _mp4List[index].Picture.GetBitmap(null, Color.Transparent, Color.Black, Color.White, Color.Black, false); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } } } else if (_spList != null) { if (index >= 0 && index < _spList.Count) { if (checkBoxCustomFourColors.Checked) { GetCustomColors(out background, out pattern, out emphasis1, out emphasis2); returnBmp = _spList[index].Picture.GetBitmap(null, background, pattern, emphasis1, emphasis2, true); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } else { returnBmp = _spList[index].Picture.GetBitmap(null, Color.Transparent, Color.Black, Color.White, Color.Black, false); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } } } else if (_bdnXmlSubtitle != null) { if (index >= 0 && index < _bdnXmlSubtitle.Paragraphs.Count) { var fileNames = _bdnXmlSubtitle.Paragraphs[index].Text.SplitToLines(); var bitmaps = new List<Bitmap>(); int maxWidth = 0; int totalHeight = 0; foreach (string fn in fileNames) { string fullFileName = Path.Combine(Path.GetDirectoryName(_bdnFileName), fn); if (!File.Exists(fullFileName)) { // fix AVISubDetector lines int idxOfIEquals = fn.IndexOf("i=", StringComparison.OrdinalIgnoreCase); if (idxOfIEquals >= 0) { int idxOfSpace = fn.IndexOf(' ', idxOfIEquals); if (idxOfSpace > 0) { fullFileName = Path.Combine(Path.GetDirectoryName(_bdnFileName), fn.Remove(0, idxOfSpace).Trim()); } } } if (File.Exists(fullFileName)) { try { var temp = new Bitmap(fullFileName); if (temp.Width > maxWidth) maxWidth = temp.Width; totalHeight += temp.Height; bitmaps.Add(temp); } catch { return null; } } } Bitmap b = null; if (bitmaps.Count > 1) { var merged = new Bitmap(maxWidth, totalHeight + 7 * bitmaps.Count); int y = 0; for (int k = 0; k < bitmaps.Count; k++) { Bitmap part = bitmaps[k]; if (checkBoxAutoTransparentBackground.Checked) part.MakeTransparent(); using (var g = Graphics.FromImage(merged)) g.DrawImage(part, 0, y); y += part.Height + 7; part.Dispose(); } b = merged; } else if (bitmaps.Count == 1) { b = bitmaps[0]; } if (b != null) { if (_isSon && checkBoxCustomFourColors.Checked) { GetCustomColors(out background, out pattern, out emphasis1, out emphasis2); FastBitmap fbmp = new FastBitmap(b); fbmp.LockImage(); for (int x = 0; x < fbmp.Width; x++) { for (int y = 0; y < fbmp.Height; y++) { Color c = fbmp.GetPixel(x, y); if (c.R == Color.Red.R && c.G == Color.Red.G && c.B == Color.Red.B) // normally anti-alias fbmp.SetPixel(x, y, emphasis2); else if (c.R == Color.Blue.R && c.G == Color.Blue.G && c.B == Color.Blue.B) // normally text? fbmp.SetPixel(x, y, pattern); else if (c.R == Color.White.R && c.G == Color.White.G && c.B == Color.White.B) // normally background fbmp.SetPixel(x, y, background); else if (c.R == Color.Black.R && c.G == Color.Black.G && c.B == Color.Black.B) // outline/border fbmp.SetPixel(x, y, emphasis1); else fbmp.SetPixel(x, y, c); } } fbmp.UnlockImage(); } if (checkBoxAutoTransparentBackground.Checked) b.MakeTransparent(); returnBmp = b; } } } else if (_xSubList != null) { if (index >= 0 && index < _xSubList.Count) { if (checkBoxCustomFourColors.Checked) { GetCustomColors(out background, out pattern, out emphasis1, out emphasis2); returnBmp = _xSubList[index].GetImage(background, pattern, emphasis1, emphasis2); } else { returnBmp = _xSubList[index].GetImage(); } } } else if (_dvbSubtitles != null) { if (index >= 0 && index < _dvbSubtitles.Count) { var dvbBmp = _dvbSubtitles[index].GetActiveImage(); var nDvbBmp = new NikseBitmap(dvbBmp); nDvbBmp.CropTopTransparent(2); nDvbBmp.CropTransparentSidesAndBottom(2, true); if (checkBoxTransportStreamGetColorAndSplit.Checked) _dvbSubColor = nDvbBmp.GetBrightestColorWhiteIsTransparent(); if (checkBoxAutoTransparentBackground.Checked) nDvbBmp.MakeBackgroundTransparent((int)numericUpDownAutoTransparentAlphaMax.Value); if (checkBoxTransportStreamGrayscale.Checked) nDvbBmp.GrayScale(); dvbBmp.Dispose(); returnBmp = nDvbBmp.GetBitmap(); } } else if (_dvbPesSubtitles != null) { if (index >= 0 && index < _dvbPesSubtitles.Count) { var dvbBmp = _dvbPesSubtitles[index].GetImageFull(); var nDvbBmp = new NikseBitmap(dvbBmp); nDvbBmp.CropTopTransparent(2); nDvbBmp.CropTransparentSidesAndBottom(2, true); if (checkBoxTransportStreamGetColorAndSplit.Checked) _dvbSubColor = nDvbBmp.GetBrightestColorWhiteIsTransparent(); if (checkBoxAutoTransparentBackground.Checked) nDvbBmp.MakeBackgroundTransparent((int)numericUpDownAutoTransparentAlphaMax.Value); if (checkBoxTransportStreamGrayscale.Checked) nDvbBmp.GrayScale(); dvbBmp.Dispose(); returnBmp = nDvbBmp.GetBitmap(); } } else if (_bluRaySubtitlesOriginal != null) { if (index >= 0 && index < _bluRaySubtitles.Count) { returnBmp = _bluRaySubtitles[index].GetBitmap(); } } else if (index >= 0 && index < _vobSubMergedPackist.Count) { if (checkBoxCustomFourColors.Checked) { GetCustomColors(out background, out pattern, out emphasis1, out emphasis2); returnBmp = _vobSubMergedPackist[index].SubPicture.GetBitmap(null, background, pattern, emphasis1, emphasis2, true); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } else { returnBmp = _vobSubMergedPackist[index].SubPicture.GetBitmap(_palette, Color.Transparent, Color.Black, Color.White, Color.Black, false); if (checkBoxAutoTransparentBackground.Checked) returnBmp.MakeTransparent(); } } if (returnBmp == null) return null; if ((_binaryOcrDb == null && _nOcrDb == null) || _fromMenuItem) return returnBmp; var n = new NikseBitmap(returnBmp); n.MakeTwoColor(280); returnBmp.Dispose(); return n.GetBitmap(); }
private double GetPixelDifPercentage(BinaryOcrBitmap expanded, BinaryOcrBitmap bobNext, NikseBitmap nbmpNext) { var difColoredPercentage = (Math.Abs(expanded.NumberOfColoredPixels - bobNext.NumberOfColoredPixels)) * 100.0 / (bobNext.Width * bobNext.Height); if (difColoredPercentage > 1 && expanded.Width < 3 || bobNext.Width < 3) return 100; int dif = int.MaxValue; if (expanded.Height == bobNext.Height && expanded.Width == bobNext.Width) { dif = NikseBitmapImageSplitter.IsBitmapsAlike(nbmpNext, expanded); } else if (expanded.Height == bobNext.Height && expanded.Width == bobNext.Width + 1) { dif = NikseBitmapImageSplitter.IsBitmapsAlike(nbmpNext, expanded); } else if (expanded.Height == bobNext.Height && expanded.Width == bobNext.Width - 1) { dif = NikseBitmapImageSplitter.IsBitmapsAlike(expanded, nbmpNext); } else if (expanded.Width == bobNext.Width && expanded.Height == bobNext.Height + 1) { dif = NikseBitmapImageSplitter.IsBitmapsAlike(nbmpNext, expanded); } else if (expanded.Width == bobNext.Width && expanded.Height == bobNext.Height - 1) { dif = NikseBitmapImageSplitter.IsBitmapsAlike(expanded, nbmpNext); } var percentage = dif * 100.0 / (bobNext.Width * bobNext.Height); return percentage; }
private static void NOcrThreadDoWork(object sender, DoWorkEventArgs e) { var p = (NOcrThreadParameter)e.Argument; e.Result = p; var nbmpInput = new NikseBitmap(p.Picture); nbmpInput.ReplaceNonWhiteWithTransparent(); var matches = new List<CompareMatch>(); int minLineHeight = p.NOcrLastLowercaseHeight; if (minLineHeight < 10) minLineHeight = 22; int maxLineHeight = p.NOcrLastUppercaseHeight; if (maxLineHeight < 10) minLineHeight = 80; List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(nbmpInput, p.NumberOfPixelsIsSpace, p.RightToLeft, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); foreach (ImageSplitterItem item in list) { if (item.NikseBitmap != null) { var nbmp = item.NikseBitmap; // nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); } } int index = 0; while (index < list.Count) { ImageSplitterItem item = list[index]; if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch match = GetNOcrCompareMatch(item, nbmpInput, p); if (match == null) { p.Result = string.Empty; return; } else // found image match { matches.Add(new CompareMatch(match.Text, match.Italic, 0, null)); if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } index++; } p.Result = GetStringWithItalicTags(matches); }
private static void FindBestMatchNew(ref int index, ref int smallestDifference, ref int smallestIndex, NikseBitmap target, BinaryOcrDb binOcrDb, BinaryOcrBitmap bob, double maxDiff) { var bobExactMatch = binOcrDb.FindExactMatch(bob); if (bobExactMatch >= 0) { index = bobExactMatch; smallestDifference = 0; smallestIndex = bobExactMatch; return; } if (maxDiff < 0.2 || target.Width < 3 || target.Height < 5) return; int numberOfForegroundColors = bob.NumberOfColoredPixels; const int minForeColorMatch = 90; index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width && compareItem.Height == target.Height) // precise math in size { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < 3) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif < 3) { break; // foreach ending } } } } index++; } if (smallestDifference > 1) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width && compareItem.Height == target.Height) // precise math in size { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < 40) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) { break; // foreach ending } } } } index++; } } if (target.Width > 16 && target.Height > 16 && smallestDifference > 2) // for other than very narrow letter (like 'i' and 'l' and 'I'), try more sizes { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width && compareItem.Height == target.Height - 1) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } if (smallestDifference > 2) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width && compareItem.Height == target.Height + 1) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 3) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width + 1 && compareItem.Height == target.Height + 1) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 5) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width - 1 && compareItem.Height == target.Height - 1) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 5) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width - 1 == target.Width && compareItem.Height == target.Height) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 11) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width - 2 && compareItem.Height == target.Height) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 14) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width - 3 && compareItem.Height == target.Height) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 14) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width == target.Width && compareItem.Height == target.Height - 3) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 14) { index = 0; foreach (var compareItem in binOcrDb.CompareImages) { if (compareItem.Width - 2 == target.Width && compareItem.Height == target.Height) { if (Math.Abs(compareItem.NumberOfColoredPixels - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } } if (smallestDifference == 0) { if (smallestIndex > 200) { var hit = binOcrDb.CompareImages[smallestIndex]; binOcrDb.CompareImages.RemoveAt(smallestIndex); binOcrDb.CompareImages.Insert(0, hit); smallestIndex = 0; index = 0; } } }
public BinaryOcrBitmap(NikseBitmap nbmp) { InitializeViaNikseBmp(nbmp); }
private Bitmap GenerateImageFromTextWithStyle(string text, bool bold, bool italic) { bool subtitleFontBold = bold; text = HtmlUtil.RemoveHtmlTags(text); Font font; try { var fontStyle = FontStyle.Regular; if (subtitleFontBold) { fontStyle = FontStyle.Bold; } font = new Font(_subtitleFontName, _subtitleFontSize, fontStyle); } catch (Exception exception) { MessageBox.Show(exception.Message); font = new Font(FontFamily.Families[0].Name, _subtitleFontSize); } var bmp = new Bitmap(400, 300); var g = Graphics.FromImage(bmp); SizeF textSize = g.MeasureString("Hj!", font); var lineHeight = (textSize.Height * 0.64f); textSize = g.MeasureString(HtmlUtil.RemoveHtmlTags(text), font); g.Dispose(); bmp.Dispose(); int sizeX = (int)(textSize.Width * 0.8) + 40; int sizeY = (int)(textSize.Height * 0.8) + 30; if (sizeX < 1) { sizeX = 1; } if (sizeY < 1) { sizeY = 1; } bmp = new Bitmap(sizeX, sizeY); g = Graphics.FromImage(bmp); g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; g.SmoothingMode = SmoothingMode.AntiAlias; g.CompositingQuality = CompositingQuality.HighQuality; var sf = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Near }; // draw the text to a path var path = new GraphicsPath(); // display italic var sb = new StringBuilder(); int i = 0; const float left = 5f; float top = 5; bool newLine = false; const float leftMargin = left; int newLinePathPoint = -1; Color c = _subtitleColor; int textLen = text.Length; while (i < textLen) { char ch = text[i]; if (ch == '\n' || ch == '\r') { TextDraw.DrawText(font, sf, path, sb, italic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); top += lineHeight; newLine = true; if (i + 1 < textLen && text[i + 1] == '\n' && text[i] == '\r') { i += 2; // CR+LF (Microsoft Windows) } else { i++; // LF (Unix and Unix-like systems ) } } else { sb.Append(ch); } i++; } if (sb.Length > 0) { TextDraw.DrawText(font, sf, path, sb, italic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); } sf.Dispose(); g.DrawPath(new Pen(_borderColor, BorderWidth), path); g.FillPath(new SolidBrush(c), path); g.Dispose(); var nbmp = new NikseBitmap(bmp); nbmp.CropTransparentSidesAndBottom(2, true); return(nbmp.GetBitmap()); }
protected override void GeneratePreviewReal() { if (_backgroundImage == null) { const int rectangleSize = 9; _backgroundImage = TextDesigner.MakeBackgroundImage(pictureBoxPreview.Width, pictureBoxPreview.Height, rectangleSize, _backgroundImageDark); } var outlineWidth = (float)numericUpDownOutline.Value; var shadowWidth = (float)numericUpDownShadowWidth.Value; var outlineColor = _isSubStationAlpha ? panelBackColor.BackColor : panelOutlineColor.BackColor; Font font; try { font = new Font(comboBoxFontName.Text, (float)numericUpDownFontSize.Value * 1.1f, checkBoxFontBold.Checked ? FontStyle.Bold : FontStyle.Regular); } catch { font = new Font(Font, FontStyle.Regular); } var measureBmp = TextDesigner.MakeTextBitmapAssa( Configuration.Settings.General.PreviewAssaText, 0, 0, font, pictureBoxPreview.Width, pictureBoxPreview.Height, outlineWidth, shadowWidth, null, panelPrimaryColor.BackColor, outlineColor, panelBackColor.BackColor, radioButtonOpaqueBox.Checked); var nBmp = new NikseBitmap(measureBmp); var measuredWidth = nBmp.GetNonTransparentWidth(); var measuredHeight = nBmp.GetNonTransparentHeight(); float left; if (radioButtonTopLeft.Checked || radioButtonMiddleLeft.Checked || radioButtonBottomLeft.Checked) { left = (float)numericUpDownMarginLeft.Value; } else if (radioButtonTopRight.Checked || radioButtonMiddleRight.Checked || radioButtonBottomRight.Checked) { left = pictureBoxPreview.Width - (measuredWidth + (float)numericUpDownMarginRight.Value); } else { left = (pictureBoxPreview.Width - measuredWidth) / 2.0f; } float top; if (radioButtonTopLeft.Checked || radioButtonTopCenter.Checked || radioButtonTopRight.Checked) { top = (float)numericUpDownMarginVertical.Value; } else if (radioButtonMiddleLeft.Checked || radioButtonMiddleCenter.Checked || radioButtonMiddleRight.Checked) { top = (pictureBoxPreview.Height - measuredHeight) / 2.0f; } else { top = pictureBoxPreview.Height - measuredHeight - (int)numericUpDownMarginVertical.Value; } var designedText = TextDesigner.MakeTextBitmapAssa( Configuration.Settings.General.PreviewAssaText, (int)Math.Round(left), (int)Math.Round(top), font, pictureBoxPreview.Width, pictureBoxPreview.Height, outlineWidth, shadowWidth, _backgroundImage, panelPrimaryColor.BackColor, panelOutlineColor.BackColor, panelBackColor.BackColor, radioButtonOpaqueBox.Checked); pictureBoxPreview.Image?.Dispose(); pictureBoxPreview.Image = designedText; font.Dispose(); }
private Bitmap GenerateImageFromTextWithStyle(string text) { const bool subtitleFontBold = false; bool subtitleAlignLeft = comboBoxHAlign.SelectedIndex == 0; // remove styles for display text (except italic) text = Utilities.RemoveSsaTags(text); text = text.Replace("<b>", string.Empty); text = text.Replace("</b>", string.Empty); text = text.Replace("<B>", string.Empty); text = text.Replace("</B>", string.Empty); text = text.Replace("<u>", string.Empty); text = text.Replace("</u>", string.Empty); text = text.Replace("<U>", string.Empty); text = text.Replace("</U>", string.Empty); Font font; try { font = new Font(_subtitleFontName, _subtitleFontSize, FontStyle.Regular); } catch (Exception exception) { MessageBox.Show(exception.Message); font = new Font(FontFamily.Families[0].Name, _subtitleFontSize); } var bmp = new Bitmap(400, 200); var g = Graphics.FromImage(bmp); SizeF textSize = g.MeasureString("Hj!", font); var lineHeight = (textSize.Height * 0.64f); textSize = g.MeasureString(HtmlUtil.RemoveHtmlTags(text), font); g.Dispose(); bmp.Dispose(); int sizeX = (int)(textSize.Width * 0.8) + 40; int sizeY = (int)(textSize.Height * 0.8) + 30; if (sizeX < 1) { sizeX = 1; } if (sizeY < 1) { sizeY = 1; } bmp = new Bitmap(sizeX, sizeY); g = Graphics.FromImage(bmp); var lefts = new List <float>(); foreach (var line in HtmlUtil.RemoveOpenCloseTags(text, HtmlUtil.TagItalic, HtmlUtil.TagFont).SplitToLines()) { if (subtitleAlignLeft) { lefts.Add(5); } else { lefts.Add((float)(bmp.Width - g.MeasureString(line, font).Width * 0.8 + 15) / 2); } } g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; g.SmoothingMode = SmoothingMode.AntiAlias; g.CompositingQuality = CompositingQuality.HighQuality; var sf = new StringFormat(); sf.Alignment = StringAlignment.Near; sf.LineAlignment = StringAlignment.Near;// draw the text to a path var path = new GraphicsPath(); // display italic var sb = new StringBuilder(); int i = 0; bool isItalic = false; float left = 5; if (lefts.Count > 0) { left = lefts[0]; } float top = 5; bool newLine = false; int lineNumber = 0; float leftMargin = left; int newLinePathPoint = -1; Color c = _subtitleColor; var colorStack = new Stack <Color>(); var lastText = new StringBuilder(); while (i < text.Length) { if (text.Substring(i).StartsWith("<font ", StringComparison.OrdinalIgnoreCase)) { float addLeft = 0; int oldPathPointIndex = path.PointCount; if (oldPathPointIndex < 0) { oldPathPointIndex = 0; } if (sb.Length > 0) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); } if (path.PointCount > 0) { PointF[] list = (PointF[])path.PathPoints.Clone(); // avoid using very slow path.PathPoints indexer!!! for (int k = oldPathPointIndex; k < list.Length; k++) { if (list[k].X > addLeft) { addLeft = list[k].X; } } } if (addLeft == 0) { addLeft = left + 2; } left = addLeft; if (_borderWidth > 0) { g.DrawPath(new Pen(_borderColor, _borderWidth), path); } g.FillPath(new SolidBrush(c), path); path.Reset(); path = new GraphicsPath(); sb.Clear(); int endIndex = text.Substring(i).IndexOf('>'); if (endIndex < 0) { i += 9999; } else { string fontContent = text.Substring(i, endIndex); if (fontContent.Contains(" color=")) { var arr = fontContent.Substring(fontContent.IndexOf(" color=", StringComparison.Ordinal) + 7).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (arr.Length > 0) { string fontColor = arr[0].Trim('\'').Trim('"').Trim('\''); try { colorStack.Push(c); // save old color if (fontColor.StartsWith("rgb(")) { arr = fontColor.Remove(0, 4).TrimEnd(')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); c = Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2])); } else { c = ColorTranslator.FromHtml(fontColor); } } catch { c = _subtitleColor; } } } i += endIndex; } } else if (text.Substring(i).StartsWith("</font>", StringComparison.OrdinalIgnoreCase)) { if (text.Substring(i).ToLower().Replace("</font>", string.Empty).Length > 0) { if (lastText.EndsWith(' ') && !sb.StartsWith(' ')) { string t = sb.ToString(); sb.Clear(); sb.Append(' '); sb.Append(t); } float addLeft = 0; int oldPathPointIndex = path.PointCount - 1; if (oldPathPointIndex < 0) { oldPathPointIndex = 0; } if (sb.Length > 0) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); } if (path.PointCount > 0) { PointF[] list = (PointF[])path.PathPoints.Clone(); // avoid using very slow path.PathPoints indexer!!! for (int k = oldPathPointIndex; k < list.Length; k++) { if (list[k].X > addLeft) { addLeft = list[k].X; } } } if (addLeft == 0) { addLeft = left + 2; } left = addLeft; if (_borderWidth > 0) { g.DrawPath(new Pen(_borderColor, _borderWidth), path); } g.FillPath(new SolidBrush(c), path); path.Reset(); sb.Clear(); if (colorStack.Count > 0) { c = colorStack.Pop(); } } i += 6; } else if (text.Substring(i).StartsWith("<i>", StringComparison.OrdinalIgnoreCase)) { if (sb.Length > 0) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); } isItalic = true; i += 2; } else if (text.Substring(i).StartsWith("</i>", StringComparison.OrdinalIgnoreCase) && isItalic) { if (lastText.EndsWith(' ') && !sb.StartsWith(' ')) { string t = sb.ToString(); sb.Clear(); sb.Append(' '); sb.Append(t); } TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); isItalic = false; i += 3; } else if (text.Substring(i).StartsWith(Environment.NewLine, StringComparison.Ordinal)) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); top += lineHeight; newLine = true; i += Environment.NewLine.Length - 1; lineNumber++; if (lineNumber < lefts.Count) { leftMargin = lefts[lineNumber]; left = leftMargin; } } else { sb.Append(text[i]); } i++; } if (sb.Length > 0) { TextDraw.DrawText(font, sf, path, sb, isItalic, subtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); } sf.Dispose(); if (_borderWidth > 0) { g.DrawPath(new Pen(_borderColor, _borderWidth), path); } g.FillPath(new SolidBrush(c), path); g.Dispose(); var nbmp = new NikseBitmap(bmp); nbmp.CropTransparentSidesAndBottom(2, true); return(nbmp.GetBitmap()); }
public NOcrChar GetMatch(NikseBitmap bitmap, int topMargin, bool deepSeek, bool italic, double italicAngle) { // only very very accurate matches foreach (var oc in OcrCharacters) { if (bitmap.Width == oc.Width && bitmap.Height == oc.Height && Math.Abs(oc.MarginTop - topMargin) < 5) { if (IsMatch(bitmap, oc, 0)) { return(oc); } } } // only very accurate matches double widthPercent = bitmap.Height * 100.0 / bitmap.Width; foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 15 && Math.Abs(bitmap.Width - oc.Width) < 5 && Math.Abs(bitmap.Height - oc.Height) < 5 && Math.Abs(oc.MarginTop - topMargin) < 5) { if (IsMatch(bitmap, oc, 0)) { return(oc); } } } foreach (var oc in OcrCharacters) { if (Math.Abs(bitmap.Width - oc.Width) < 8 && Math.Abs(bitmap.Height - oc.Height) < 8 && Math.Abs(oc.MarginTop - topMargin) < 8) { if (IsMatch(bitmap, oc, 1)) { return(oc); } } } foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 20 && Math.Abs(oc.MarginTop - topMargin) < 15) { if (IsMatch(bitmap, oc, 2)) { return(oc); } } } foreach (var oc in OcrCharacters) { if (!oc.IsSensitive && Math.Abs(widthPercent - oc.WidthPercent) < 20 && Math.Abs(oc.MarginTop - topMargin) < 15 && oc.LinesForeground.Count + oc.LinesBackground.Count > 40) { if (IsMatch(bitmap, oc, 20)) { return(oc); } } } foreach (var oc in OcrCharacters) { if (oc.IsSensitive && Math.Abs(widthPercent - oc.WidthPercent) < 30 && Math.Abs(oc.MarginTop - topMargin) < 15 && oc.LinesForeground.Count + oc.LinesBackground.Count > 40) { if (IsMatch(bitmap, oc, 10)) { return(oc); } } } if (italic) { foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 60 && Math.Abs(oc.MarginTop - topMargin) < 17 && oc.LinesForeground.Count + oc.LinesBackground.Count > 50) { var italicOc = MakeItalicNOcrChar(oc, 0, italicAngle); if (IsMatch(bitmap, italicOc, 25)) { return(italicOc); } } } } if (deepSeek) { foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 60 && Math.Abs(oc.MarginTop - topMargin) < 17 && oc.LinesForeground.Count + oc.LinesBackground.Count > 50) { if (IsMatch(bitmap, oc, 25)) { return(oc); } } } } return(null); }
public static bool ConvertFromTsToBdnXml(string fileName, string outputFolder, bool overwrite, StreamWriter stdOutWriter, CommandLineConverter.BatchConvertProgress progressCallback, Point? resolution) { var programMapTableParser = new ProgramMapTableParser(); programMapTableParser.Parse(fileName); // get languages from PMT if possible var tsParser = new TransportStreamParser(); tsParser.Parse(fileName, (position, total) => { var percent = (int)Math.Round(position * 100.0 / total); stdOutWriter?.Write("\rParsing transport stream: {0}%", percent); progressCallback?.Invoke($"{percent}%"); }); stdOutWriter?.Write("\r".PadRight(32, ' ')); stdOutWriter?.Write("\r"); var overrideScreenSize = Configuration.Settings.Tools.BatchConvertTsOverrideScreenSize && Configuration.Settings.Tools.BatchConvertTsScreenHeight > 0 && Configuration.Settings.Tools.BatchConvertTsScreenWidth > 0 || resolution.HasValue; using (var form = new ExportPngXml()) { if (tsParser.SubtitlePacketIds.Count == 0) { stdOutWriter?.WriteLine("No subtitles found"); progressCallback?.Invoke("No subtitles found"); return false; } foreach (int pid in tsParser.SubtitlePacketIds) { var language = TsToBluRaySup.GetFileNameEnding(programMapTableParser, pid); var nameNoExt = Utilities.GetFileNameWithoutExtension(fileName) + "." + language; var folder = Path.Combine(outputFolder, nameNoExt); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } var outputFileName = CommandLineConverter.FormatOutputFileNameForBatchConvert(nameNoExt + Path.GetExtension(fileName), ".xml", folder, overwrite); stdOutWriter?.WriteLine($"Saving PID {pid} to {outputFileName}..."); progressCallback?.Invoke($"Save PID {pid}"); var sub = tsParser.GetDvbSubtitles(pid); var subtitle = new Subtitle(); foreach (var p in sub) { subtitle.Paragraphs.Add(new Paragraph(string.Empty, p.StartMilliseconds, p.EndMilliseconds)); } var res = TsToBluRaySup.GetSubtitleScreenSize(sub, overrideScreenSize, resolution); var videoInfo = new VideoInfo { Success = true, Width = res.X, Height = res.Y }; form.Initialize(subtitle, new SubRip(), BatchConvert.BdnXmlSubtitle, fileName, videoInfo, fileName); var sb = new StringBuilder(); var imagesSavedCount = 0; for (int index = 0; index < sub.Count; index++) { var p = sub[index]; var pos = p.GetPosition(); var bmp = sub[index].GetBitmap(); var tsWidth = bmp.Width; var tsHeight = bmp.Height; var nBmp = new NikseBitmap(bmp); pos.Top += nBmp.CropTopTransparent(0); pos.Left += nBmp.CropSidesAndBottom(0, Color.FromArgb(0, 0, 0, 0), true); bmp.Dispose(); bmp = nBmp.GetBitmap(); var mp = form.MakeMakeBitmapParameter(index, videoInfo.Width, videoInfo.Height); if (overrideScreenSize) { var widthFactor = (double)videoInfo.Width / tsWidth; var heightFactor = (double)videoInfo.Height / tsHeight; var resizeBmp = ResizeBitmap(bmp, (int)Math.Round(bmp.Width * widthFactor), (int)Math.Round(bmp.Height * heightFactor)); bmp.Dispose(); bmp = resizeBmp; pos.Left = (int)Math.Round(pos.Left * widthFactor); pos.Top = (int)Math.Round(pos.Top * heightFactor); progressCallback?.Invoke($"Save PID {pid}: {(index + 1) * 100 / sub.Count}%"); } mp.Bitmap = bmp; mp.P = new Paragraph(string.Empty, p.StartMilliseconds, p.EndMilliseconds); mp.ScreenWidth = videoInfo.Width; mp.ScreenHeight = videoInfo.Height; int bottomMarginInPixels; if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition || Configuration.Settings.Tools.BatchConvertTsOverrideYPosition) { if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition && Configuration.Settings.Tools.BatchConvertTsOverrideYPosition) { var x = (int)Math.Round(videoInfo.Width / 2.0 - mp.Bitmap.Width / 2.0); if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase)) { x = Configuration.Settings.Tools.BatchConvertTsOverrideHMargin; } else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase)) { x = videoInfo.Width - Configuration.Settings.Tools.BatchConvertTsOverrideHMargin - mp.Bitmap.Width; } var y = videoInfo.Height - Configuration.Settings.Tools.BatchConvertTsOverrideBottomMargin - mp.Bitmap.Height; mp.OverridePosition = new Point(x, y); } else if (Configuration.Settings.Tools.BatchConvertTsOverrideXPosition) { var x = (int)Math.Round(videoInfo.Width / 2.0 - mp.Bitmap.Width / 2.0); if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("left", StringComparison.OrdinalIgnoreCase)) { x = Configuration.Settings.Tools.BatchConvertTsOverrideHMargin; } else if (Configuration.Settings.Tools.BatchConvertTsOverrideHAlign.Equals("right", StringComparison.OrdinalIgnoreCase)) { x = videoInfo.Width - Configuration.Settings.Tools.BatchConvertTsOverrideHMargin - mp.Bitmap.Width; } mp.OverridePosition = new Point(x, pos.Top); } else { var y = videoInfo.Height - Configuration.Settings.Tools.BatchConvertTsOverrideBottomMargin - mp.Bitmap.Height; mp.OverridePosition = new Point(pos.Left, y); } bottomMarginInPixels = Configuration.Settings.Tools.BatchConvertTsScreenHeight - pos.Top - mp.Bitmap.Height; } else { mp.OverridePosition = new Point(pos.Left, pos.Top); // use original position bottomMarginInPixels = Configuration.Settings.Tools.BatchConvertTsScreenHeight - pos.Top - mp.Bitmap.Height; } imagesSavedCount = form.WriteBdnXmlParagraph(videoInfo.Width, sb, bottomMarginInPixels, videoInfo.Height, imagesSavedCount, mp, index, Path.GetDirectoryName(outputFileName)); } form.WriteBdnXmlFile(imagesSavedCount, sb, outputFileName); } } return true; }
public Bitmap ToOldBitmap() { if (ExpandedList != null && ExpandedList.Count > 0) { int minX = X; int minY = Y; int maxX = X + Width; int maxY = Y + Height; var list = new List <BinaryOcrBitmap>(); list.Add(this); foreach (BinaryOcrBitmap bob in ExpandedList) { if (bob.X < minX) { minX = bob.X; } if (bob.Y < minY) { minY = bob.Y; } if (bob.X + bob.Width > maxX) { maxX = bob.X + bob.Width; } if (bob.Y + bob.Height > maxY) { maxY = bob.Y + bob.Height; } list.Add(bob); } var nbmp = new BinaryOcrBitmap(maxX - minX, maxY - minY); foreach (BinaryOcrBitmap bob in list) { for (int y = 0; y < bob.Height; y++) { for (int x = 0; x < bob.Width; x++) { int c = bob.GetPixel(x, y); if (c > 0) { nbmp.SetPixel(bob.X - minX + x, bob.Y - minY + y, 1); } } } } return(nbmp.ToOldBitmap()); // Resursive } else { var nbmp = new NikseBitmap(Width, Height); for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { Color c = Color.Transparent; if (GetPixel(x, y) > 0) { c = Color.White; } nbmp.SetPixel(x, y, c); } } return(nbmp.GetBitmap()); } }
public string NocrFastCheck(Bitmap bitmap) { var nbmpInput = new NikseBitmap(bitmap); nbmpInput.ReplaceNonWhiteWithTransparent(); var matches = new List<CompareMatch>(); List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLetters(nbmpInput, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); foreach (ImageSplitterItem item in list) { if (item.NikseBitmap != null) { item.NikseBitmap.ReplaceTransparentWith(Color.Black); } } int index = 0; while (index < list.Count) { ImageSplitterItem item = list[index]; if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch match = null; var nbmp = item.NikseBitmap; int topMargin = item.Y - item.ParentY; foreach (NOcrChar oc in _nOcrDb.OcrCharacters) { if (Math.Abs(oc.Width - nbmp.Width) < 3 && Math.Abs(oc.Height - nbmp.Height) < 4 && Math.Abs(oc.MarginTop - topMargin) < 4) { // only very accurate matches bool ok = true; var index2 = 0; while (index2 < oc.LinesForeground.Count && ok) { NOcrPoint op = oc.LinesForeground[index2]; foreach (Point point in op.ScaledGetPoints(oc, nbmp.Width, nbmp.Height)) { if (point.X >= 0 && point.Y >= 0 && point.X < nbmp.Width && point.Y < nbmp.Height) { Color c = nbmp.GetPixel(point.X, point.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { } else { Point p = new Point(point.X - 1, point.Y); if (p.X < 0) p.X = 1; c = nbmp.GetPixel(p.X, p.Y); if (nbmp.Width > 20 && c.A > 150 && c.R + c.G + c.B > NocrMinColor) { } else { ok = false; break; } } } } index2++; } index2 = 0; while (index2 < oc.LinesBackground.Count && ok) { NOcrPoint op = oc.LinesBackground[index2]; foreach (Point point in op.ScaledGetPoints(oc, nbmp.Width, nbmp.Height)) { if (point.X >= 0 && point.Y >= 0 && point.X < nbmp.Width && point.Y < nbmp.Height) { Color c = nbmp.GetPixel(point.X, point.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { Point p = new Point(point.X, point.Y); if (oc.Width > 19 && point.X > 0) p.X = p.X - 1; c = nbmp.GetPixel(p.X, p.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { ok = false; break; } } } } index2++; } if (ok) match = new CompareMatch(oc.Text, oc.Italic, 0, null); } } if (match == null) { matches.Add(new CompareMatch("*", false, 0, null)); } else // found image match { matches.Add(new CompareMatch(match.Text, match.Italic, 0, null)); if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } index++; } return GetStringWithItalicTags(matches); }
private string Tesseract3DoOcrViaExe(Bitmap bmp, string language, string psmMode) { // change yellow color to white - easier for Tesseract var nbmp = new NikseBitmap(bmp); nbmp.ReplaceYellowWithWhite(); // optimized replace string tempTiffFileName = Path.GetTempPath() + Guid.NewGuid() + ".png"; string tempTextFileName; using (var b = nbmp.GetBitmap()) { b.Save(tempTiffFileName, System.Drawing.Imaging.ImageFormat.Png); tempTextFileName = Path.GetTempPath() + Guid.NewGuid(); } using (var process = new Process()) { process.StartInfo = new ProcessStartInfo(Configuration.TesseractFolder + "tesseract.exe"); process.StartInfo.UseShellExecute = true; process.StartInfo.Arguments = "\"" + tempTiffFileName + "\" \"" + tempTextFileName + "\" -l " + language; if (checkBoxTesseractMusicOn.Checked) process.StartInfo.Arguments += "+music"; if (!string.IsNullOrEmpty(psmMode)) process.StartInfo.Arguments += " " + psmMode.Trim(); process.StartInfo.Arguments += " hocr"; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; if (Configuration.IsRunningOnLinux() || Configuration.IsRunningOnMac()) { process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = "tesseract"; } else { process.StartInfo.WorkingDirectory = (Configuration.TesseractFolder); } try { process.Start(); } catch { if (Configuration.IsRunningOnLinux() || Configuration.IsRunningOnMac()) { MessageBox.Show("Unable to start 'Tesseract' - make sure tesseract-ocr 3.x is installed!"); } else { MessageBox.Show("Unable to start 'Tesseract' (" + Configuration.TesseractFolder + "tesseract.exe) - make sure tesseract-ocr 3.x is installed!"); } throw; } process.WaitForExit(5000); } string result = string.Empty; string outputFileName = tempTextFileName + ".html"; if (!File.Exists(outputFileName)) outputFileName = tempTextFileName + ".hocr"; try { if (File.Exists(outputFileName)) { result = File.ReadAllText(outputFileName); result = ParseHocr(result); File.Delete(outputFileName); } File.Delete(tempTiffFileName); } catch { } return result; }
public NOcrChar GetMatchExpanded(NikseBitmap nikseBitmap, ImageSplitterItem targetItem, int listIndex, List <ImageSplitterItem> list) { int w = targetItem.NikseBitmap.Width; for (var i = 0; i < OcrCharactersExpanded.Count; i++) { var oc = OcrCharactersExpanded[i]; if (oc.ExpandCount > 1 && oc.Width > w && targetItem.X + oc.Width < nikseBitmap.Width) { bool ok = true; var index = 0; while (index < oc.LinesForeground.Count && ok) { var op = oc.LinesForeground[index]; foreach (var point in op.GetPoints()) { var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y - oc.MarginTop); if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height) { var a = nikseBitmap.GetAlpha(p.X, p.Y); if (a <= 150) { ok = false; break; } } else if (p.X >= 0 && p.Y >= 0) { ok = false; break; } } index++; } index = 0; while (index < oc.LinesBackground.Count && ok) { var op = oc.LinesBackground[index]; foreach (var point in op.GetPoints()) { var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y - oc.MarginTop); if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height) { var a = nikseBitmap.GetAlpha(p.X, p.Y); if (a > 150) { ok = false; break; } } else if (p.X >= 0 && p.Y >= 0) { ok = false; break; } } index++; } if (ok) { var size = GetTotalSize(listIndex, list, oc.ExpandCount); if (Math.Abs(size.X - oc.Width) < 3 && Math.Abs(size.Y - oc.Height) < 3) { return(oc); } } } } for (var i = 0; i < OcrCharactersExpanded.Count; i++) { var oc = OcrCharactersExpanded[i]; if (oc.ExpandCount > 1 && oc.Width > w && targetItem.X + oc.Width < nikseBitmap.Width) { bool ok = true; var index = 0; while (index < oc.LinesForeground.Count && ok) { var op = oc.LinesForeground[index]; foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1)) { var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y - oc.MarginTop); if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height) { var a = nikseBitmap.GetAlpha(p.X, p.Y); if (a <= 150) { ok = false; break; } } else if (p.X >= 0 && p.Y >= 0) { ok = false; break; } } index++; } index = 0; while (index < oc.LinesBackground.Count && ok) { var op = oc.LinesBackground[index]; foreach (var point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1)) { var p = new Point(point.X + targetItem.X, point.Y + targetItem.Y - oc.MarginTop); if (p.X >= 0 && p.Y >= 0 && p.X < nikseBitmap.Width && p.Y < nikseBitmap.Height) { var a = nikseBitmap.GetAlpha(p.X, p.Y); if (a > 150) { ok = false; break; } } else if (p.X >= 0 && p.Y >= 0) { ok = false; break; } } index++; } if (ok) { var size = GetTotalSize(listIndex, list, oc.ExpandCount); var widthPercent = size.Y * 100.0 / size.X; if (Math.Abs(widthPercent - oc.WidthPercent) < 15 && Math.Abs(size.X - oc.Width) < 25 && Math.Abs(size.Y - oc.Height) < 20) { return(oc); } } } } return(null); }
private static void FindBestMatch(ref int index, ref int smallestDifference, ref int smallestIndex, NikseBitmap target, List<CompareItem> compareBitmaps) { int numberOfForegroundColors = CalculateNumberOfForegroundColors(target); const int minForeColorMatch = 90; index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width && compareItem.Bitmap.Height == target.Height) // precise math in size { if (compareItem.NumberOfForegroundColors < 1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 3) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif < 3) { break; // foreach ending } } } } index++; } if (smallestDifference > 1) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width && compareItem.Bitmap.Height == target.Height) // precise math in size { if (compareItem.NumberOfForegroundColors < 1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < 40) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) { break; // foreach ending } } } } index++; } } if (target.Width > 5 && smallestDifference > 2) // for other than very narrow letter (like 'i' and 'l' and 'I'), try more sizes { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width && compareItem.Bitmap.Height == target.Height - 1) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } if (smallestDifference > 2) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width && compareItem.Bitmap.Height == target.Height + 1) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 3) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width + 1 && compareItem.Bitmap.Height == target.Height + 1) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 5) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width - 1 && compareItem.Bitmap.Height == target.Height) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 5) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width - 1 && compareItem.Bitmap.Height == target.Height - 1) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 5) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width - 1 == target.Width && compareItem.Bitmap.Height == target.Height) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 10) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width - 2 && compareItem.Bitmap.Height == target.Height) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 12) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width - 3 && compareItem.Bitmap.Height == target.Height) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9 && target.Width > 12) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width == target.Width && compareItem.Bitmap.Height == target.Height - 3) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, target); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } if (smallestDifference > 9) { index = 0; foreach (CompareItem compareItem in compareBitmaps) { if (compareItem.Bitmap.Width - 2 == target.Width && compareItem.Bitmap.Height == target.Height) { if (compareItem.NumberOfForegroundColors == -1) compareItem.NumberOfForegroundColors = CalculateNumberOfForegroundColors(compareItem.Bitmap); if (Math.Abs(compareItem.NumberOfForegroundColors - numberOfForegroundColors) < minForeColorMatch) { int dif = NikseBitmapImageSplitter.IsBitmapsAlike(target, compareItem.Bitmap); if (dif < smallestDifference) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } } } if (smallestDifference == 0) { if (smallestIndex > 200) { CompareItem hit = compareBitmaps[smallestIndex]; compareBitmaps.RemoveAt(smallestIndex); compareBitmaps.Insert(0, hit); smallestIndex = 0; index = 0; } } }
public static void GenerateLineSegments(int numberOfLines, bool veryPrecise, NOcrChar nOcrChar, NikseBitmap nbmp) { const int giveUpCount = 10000; var r = new Random(); int count = 0; int hits = 0; bool tempVeryPrecise = veryPrecise; while (hits < numberOfLines && count < giveUpCount) { var start = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); var end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); if (hits < 5 && count < 100) // a few large lines { for (int k = 0; k < 500; k++) { if (Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y) > nOcrChar.Height / 2) { break; } else { end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); } } } else // and a lot of small lines { for (int k = 0; k < 500; k++) { if (Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y) < 5) { break; } else { end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); } } } var op = new NOcrPoint(start, end); bool ok = true; foreach (NOcrPoint existingOp in nOcrChar.LinesForeground) { if (existingOp.Start.X == op.Start.X && existingOp.Start.Y == op.Start.Y && existingOp.End.X == op.End.X && existingOp.End.Y == op.End.Y) { ok = false; } } if (ok && IsMatchPointForeGround(op, !tempVeryPrecise, nbmp, nOcrChar)) { nOcrChar.LinesForeground.Add(op); //AddHistoryItem(nOcrChar); hits++; } count++; if (count > giveUpCount - 100 && !tempVeryPrecise) { tempVeryPrecise = true; } } count = 0; hits = 0; tempVeryPrecise = veryPrecise; while (hits < numberOfLines && count < giveUpCount) { var start = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); var end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); if (hits < 5 && count < 100) // a few large lines { for (int k = 0; k < 500; k++) { if (Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y) > nOcrChar.Height / 2) { break; } else { end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); } } } else // and a lot of small lines { for (int k = 0; k < 500; k++) { if (Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y) < 5) { break; } else { end = new Point(r.Next(nOcrChar.Width), r.Next(nOcrChar.Height)); } } } var op = new NOcrPoint(start, end); bool ok = true; foreach (NOcrPoint existingOp in nOcrChar.LinesBackground) { if (existingOp.Start.X == op.Start.X && existingOp.Start.Y == op.Start.Y && existingOp.End.X == op.End.X && existingOp.End.Y == op.End.Y) { ok = false; } } if (ok && IsMatchPointBackGround(op, !tempVeryPrecise, nbmp, nOcrChar)) { nOcrChar.LinesBackground.Add(op); //AddHistoryItem(nOcrChar); hits++; } count++; if (count > giveUpCount - 100 && !tempVeryPrecise) { tempVeryPrecise = true; } } }
private static NOcrChar NOcrFindExpandedMatch(NikseBitmap nbmp, ImageSplitterItem targetItem, List<NOcrChar> nOcrChars) { int w = targetItem.NikseBitmap.Width; foreach (NOcrChar oc in nOcrChars) { if (oc.ExpandCount > 1 && oc.Width > w && targetItem.X + oc.Width < nbmp.Width) { bool ok = true; var index = 0; while (index < oc.LinesForeground.Count && ok) { NOcrPoint op = oc.LinesForeground[index]; foreach (Point point in op.GetPoints()) { Point p = new Point(point.X + targetItem.X, point.Y + targetItem.Y); if (p.X >= 0 && p.Y >= 0 && p.X < nbmp.Width && p.Y < nbmp.Height) { Color c = nbmp.GetPixel(p.X, p.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { } else { ok = false; break; } } } index++; } index = 0; while (index < oc.LinesBackground.Count && ok) { NOcrPoint op = oc.LinesBackground[index]; foreach (Point point in op.GetPoints()) { Point p = new Point(point.X + targetItem.X, point.Y + targetItem.Y); if (p.X >= 0 && p.Y >= 0 && p.X < nbmp.Width && p.Y < nbmp.Height) { Color c = nbmp.GetPixel(p.X, p.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { ok = false; break; } } } index++; } if (ok) return oc; ok = true; index = 0; while (index < oc.LinesForeground.Count && ok) { NOcrPoint op = oc.LinesForeground[index]; foreach (Point point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1)) { Point p = new Point(point.X + targetItem.X, point.Y + targetItem.Y); if (p.X >= 0 && p.Y >= 0 && p.X < nbmp.Width && p.Y < nbmp.Height) { Color c = nbmp.GetPixel(p.X, p.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { } else { ok = false; break; } } } index++; } index = 0; while (index < oc.LinesBackground.Count && ok) { NOcrPoint op = oc.LinesBackground[index]; foreach (Point point in op.ScaledGetPoints(oc, oc.Width, oc.Height - 1)) { Point p = new Point(point.X + targetItem.X, point.Y + targetItem.Y); if (p.X >= 0 && p.Y >= 0 && p.X < nbmp.Width && p.Y < nbmp.Height) { Color c = nbmp.GetPixel(p.X, p.Y); if (c.A > 150 && c.R + c.G + c.B > NocrMinColor) { ok = false; break; } } } index++; } if (ok) return oc; } } return null; }
private static bool IsMatchPointForeGround(NOcrPoint op, bool loose, NikseBitmap nbmp, NOcrChar nOcrChar) { if (Math.Abs(op.Start.X - op.End.X) < 2 && Math.Abs(op.End.Y - op.Start.Y) < 2) { return(false); } foreach (Point point in op.ScaledGetPoints(nOcrChar, nbmp.Width, nbmp.Height)) { if (point.X >= 0 && point.Y >= 0 && point.X < nbmp.Width && point.Y < nbmp.Height) { Color c = nbmp.GetPixel(point.X, point.Y); if (c.A > 150 && c.R + 100 + c.G + c.B > VobSubOcr.NocrMinColor) { } else { return(false); } if (loose) { if (nbmp.Width > 10 && point.X + 1 < nbmp.Width) { c = nbmp.GetPixel(point.X + 1, point.Y); if (c.A > 150 && c.R + 100 + c.G + c.B > VobSubOcr.NocrMinColor) { } else { return(false); } } if (nbmp.Width > 10 && point.X >= 1) { c = nbmp.GetPixel(point.X - 1, point.Y); if (c.A > 150 && c.R + 100 + c.G + c.B > VobSubOcr.NocrMinColor) { } else { return(false); } } if (nbmp.Height > 10 && point.Y + 1 < nbmp.Height) { c = nbmp.GetPixel(point.X, point.Y + 1); if (c.A > 150 && c.R + 100 + c.G + c.B > VobSubOcr.NocrMinColor) { } else { return(false); } } if (nbmp.Height > 10 && point.Y >= 1) { c = nbmp.GetPixel(point.X, point.Y - 1); if (c.A > 150 && c.R + 100 + c.G + c.B > VobSubOcr.NocrMinColor) { } else { return(false); } } } } } return(true); }
private CompareMatch GetCompareMatch(ImageSplitterItem targetItem, NikseBitmap parentBitmap, out CompareMatch secondBestGuess, List<ImageSplitterItem> list, int listIndex) { secondBestGuess = null; int index = 0; int smallestDifference = 10000; int smallestIndex = -1; NikseBitmap target = targetItem.NikseBitmap; if (_compareBitmaps == null) { return null; } foreach (CompareItem compareItem in _compareBitmaps) { // check for expand match! if (compareItem.ExpandCount > 0 && compareItem.Bitmap.Width > target.Width && parentBitmap.Width >= compareItem.Bitmap.Width + targetItem.X) // && parentBitmap.Height >= compareItem.Bitmap.Height + targetItem.Y) //NIXE-debug-test- what not correct? { int minY = targetItem.Y; for (int j = 1; j < compareItem.ExpandCount; j++) { if (list != null && list.Count > listIndex + j && list[listIndex + j].Y < minY) minY = list[listIndex + j].Y; } if (parentBitmap.Height >= compareItem.Bitmap.Height + minY) { var cutBitmap = parentBitmap.CopyRectangle(new Rectangle(targetItem.X, minY, compareItem.Bitmap.Width, compareItem.Bitmap.Height)); int dif = NikseBitmapImageSplitter.IsBitmapsAlike(compareItem.Bitmap, cutBitmap); if (dif < smallestDifference && (Math.Abs(target.Height - compareItem.Bitmap.Height) <= 5 || compareItem.Text != "\"")) { smallestDifference = dif; smallestIndex = index; if (dif == 0) break; // foreach ending } } } index++; } // Search images with minor location changes FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, target, _compareBitmaps); if (smallestDifference * 100.0 / (target.Width * target.Height) > _vobSubOcrSettings.AllowDifferenceInPercent && target.Width < 70) { if (smallestDifference > 2 && target.Width > 25) { var cutBitmap = target.CopyRectangle(new Rectangle(4, 0, target.Width - 4, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap, _compareBitmaps); } if (smallestDifference > 2 && target.Width > 12) { var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap, _compareBitmaps); } if (smallestDifference > 2 && target.Width > 12) { var cutBitmap = target.CopyRectangle(new Rectangle(0, 0, target.Width - 2, target.Height)); FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap, _compareBitmaps); } if (smallestDifference > 2 && target.Width > 12) { var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop = 0; var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop, 2); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2, _compareBitmaps); } if (smallestDifference > 2 && target.Width > 15) { var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop = 0; var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2, _compareBitmaps); } if (smallestDifference > 2 && target.Width > 15) { var cutBitmap = target.CopyRectangle(new Rectangle(1, 0, target.Width - 2, target.Height)); int topCrop; var cutBitmap2 = NikseBitmapImageSplitter.CropTopAndBottom(cutBitmap, out topCrop); if (cutBitmap2.Height != target.Height) FindBestMatch(ref index, ref smallestDifference, ref smallestIndex, cutBitmap2, _compareBitmaps); } } if (smallestIndex >= 0) { double differencePercentage = smallestDifference * 100.0 / (target.Width * target.Height); double maxDiff = (double)numericUpDownMaxErrorPct.Value; if (differencePercentage <= maxDiff) { var hit = _compareBitmaps[smallestIndex]; return new CompareMatch(hit.Text, hit.Italic, hit.ExpandCount, hit.Name); } var guess = _compareBitmaps[smallestIndex]; secondBestGuess = new CompareMatch(guess.Text, guess.Italic, guess.ExpandCount, guess.Name); } return null; }
private byte[] GetSubImageBuffer(RunLengthTwoParts twoPartBuffer, NikseBitmap nbmp, Paragraph p, ContentAlignment alignment, Point?overridePosition) { var ms = new MemoryStream(); // sup picture datasize WriteEndianWord(twoPartBuffer.Length + 34, ms); // first display control sequence table address int startDisplayControlSequenceTableAddress = twoPartBuffer.Length + 4; WriteEndianWord(startDisplayControlSequenceTableAddress, ms); // Write image const int imageTopFieldDataAddress = 4; ms.Write(twoPartBuffer.Buffer1, 0, twoPartBuffer.Buffer1.Length); int imageBottomFieldDataAddress = 4 + twoPartBuffer.Buffer1.Length; ms.Write(twoPartBuffer.Buffer2, 0, twoPartBuffer.Buffer2.Length); // Write zero delay ms.WriteByte(0); ms.WriteByte(0); // next display control sequence table address (use current is last) WriteEndianWord(startDisplayControlSequenceTableAddress + 24, ms); // start of display control sequence table address // Control command start ms.WriteByte(p.Forced ? (byte)0 : (byte)1); // Control command 3 = SetColor WriteColors(ms); // 3 bytes // Control command 4 = SetContrast WriteContrast(ms); // 3 bytes // Control command 5 = SetDisplayArea WriteDisplayArea(ms, nbmp, alignment, overridePosition); // 7 bytes // Control command 6 = SetPixelDataAddress WritePixelDataAddress(ms, imageTopFieldDataAddress, imageBottomFieldDataAddress); // 5 bytes // Control command exit ms.WriteByte(255); // 1 byte // Control Sequence Table // Write delay - subtitle duration WriteEndianWord(Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0) >> 10, ms); // WriteEndianWord(Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0 - 1023) >> 10, ms); // next display control sequence table address (use current is last) WriteEndianWord(startDisplayControlSequenceTableAddress + 24, ms); // start of display control sequence table address // Control command 2 = StopDisplay ms.WriteByte(2); // extra byte - for compatability with gpac/MP4BOX ms.WriteByte(255); // 1 byte return(ms.ToArray()); }
private void inspectImageCompareMatchesForCurrentImageToolStripMenuItem_Click(object sender, EventArgs e) { if (subtitleListView1.SelectedItems.Count != 1) return; if (_compareBitmaps == null) LoadImageCompareBitmaps(); Cursor = Cursors.WaitCursor; Bitmap bitmap = GetSubtitleBitmap(subtitleListView1.SelectedItems[0].Index); NikseBitmap parentBitmap = new NikseBitmap(bitmap); var matches = new List<CompareMatch>(); List<ImageSplitterItem> list; if (_binaryOcrDb == null) { list = NikseBitmapImageSplitter.SplitBitmapToLetters(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); } else { int minLineHeight = _binOcrLastLowercaseHeight - 3; if (minLineHeight < 5) minLineHeight = 5; list = NikseBitmapImageSplitter.SplitBitmapToLettersNew(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom, minLineHeight); } int index = 0; var imageSources = new List<Bitmap>(); while (index < list.Count) { ImageSplitterItem item = list[index]; if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); imageSources.Add(null); } else { CompareMatch bestGuess; CompareMatch match; if (_binaryOcrDb != null) match = GetCompareMatchNew(item, out bestGuess, list, index); else match = GetCompareMatch(item, parentBitmap, out bestGuess, list, index); if (match == null) { matches.Add(new CompareMatch(Configuration.Settings.Language.VobSubOcr.NoMatch, false, 0, null)); imageSources.Add(item.NikseBitmap.GetBitmap()); } else // found image match { if (match.ExpandCount > 0) { List<ImageSplitterItem> expandSelectionList = new List<ImageSplitterItem>(); for (int i = 0; i < match.ExpandCount; i++) { expandSelectionList.Add(list[index + i]); } item = GetExpandedSelectionNew(parentBitmap, expandSelectionList); matches.Add(new CompareMatch(match.Text, match.Italic, 0, match.Name, item)); imageSources.Add(item.NikseBitmap.GetBitmap()); } else { matches.Add(new CompareMatch(match.Text, match.Italic, 0, match.Name, item)); imageSources.Add(item.NikseBitmap.GetBitmap()); } if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } index++; } Cursor = Cursors.Default; using (var inspect = new VobSubOcrCharacterInspect()) { inspect.Initialize(comboBoxCharacterDatabase.SelectedItem.ToString(), matches, imageSources, _binaryOcrDb); if (inspect.ShowDialog(this) == DialogResult.OK) { Cursor = Cursors.WaitCursor; if (_binaryOcrDb != null) { _binaryOcrDb.Save(); Cursor = Cursors.Default; return; } _compareDoc = inspect.ImageCompareDocument; string path = Configuration.VobSubCompareFolder + comboBoxCharacterDatabase.SelectedItem + Path.DirectorySeparatorChar; _compareDoc.Save(path + "Images.xml"); LoadImageCompareBitmaps(); Cursor = Cursors.Default; } } if (_binaryOcrDb != null) _binaryOcrDb.LoadCompareImages(); Cursor = Cursors.Default; }
public void WriteParagraph(Paragraph p, Bitmap bmp, ContentAlignment alignment, Point?overridePosition = null) // inspired by code from SubtitleCreator { // timestamp: 00:00:33:900, filepos: 000000000 _idx.AppendLine($"timestamp: {p.StartTime.Hours:00}:{p.StartTime.Minutes:00}:{p.StartTime.Seconds:00}:{p.StartTime.Milliseconds:000}, filepos: {_subFile.Position.ToString("X").PadLeft(9, '0').ToLower()}"); var nbmp = new NikseBitmap(bmp); _emphasis2 = nbmp.ConverToFourColors(_background, _pattern, _emphasis1, _useInnerAntialiasing); var twoPartBuffer = nbmp.RunLengthEncodeForDvd(_background, _pattern, _emphasis1, _emphasis2); var imageBuffer = GetSubImageBuffer(twoPartBuffer, nbmp, p, alignment, overridePosition); int bufferIndex = 0; byte vobSubId = (byte)_languageStreamId; var mwsub = new MemWriter(200000); byte[] subHeader = new byte[30]; byte[] ts = new byte[4]; // Lended from "Son2VobSub" by Alain Vielle and Petr Vyskocil // And also from Sup2VobSub by Emmel subHeader[0] = 0x00; // MPEG 2 PACK HEADER subHeader[1] = 0x00; subHeader[2] = 0x01; subHeader[3] = 0xba; subHeader[4] = 0x44; subHeader[5] = 0x02; subHeader[6] = 0xc4; subHeader[7] = 0x82; subHeader[8] = 0x04; subHeader[9] = 0xa9; subHeader[10] = 0x01; subHeader[11] = 0x89; subHeader[12] = 0xc3; subHeader[13] = 0xf8; subHeader[14] = 0x00; // PES subHeader[15] = 0x00; subHeader[16] = 0x01; subHeader[17] = 0xbd; int packetSize = imageBuffer.Length; long toWrite = packetSize; // Image buffer + control sequence length bool header0 = true; while (toWrite > 0) { long headerSize; if (header0) { header0 = false; // This is only for first packet subHeader[20] = 0x81; // mark as original subHeader[21] = 0x80; // first packet: PTS subHeader[22] = 0x05; // PES header data length // PTS (90kHz): //-------------- subHeader[23] = (byte)((ts[3] & 0xc0) >> 5 | 0x21); subHeader[24] = (byte)((ts[3] & 0x3f) << 2 | (ts[2] & 0xc0) >> 6); subHeader[25] = (byte)((ts[2] & 0x3f) << 2 | (ts[1] & 0x80) >> 6 | 0x01); subHeader[26] = (byte)((ts[1] & 0x7f) << 1 | (ts[0] & 0x80) >> 7); subHeader[27] = (byte)((ts[0] & 0x7f) << 1 | 0x01); const string pre = "0010"; // 0011 or 0010 ? (KMPlayer will not understand 0011!!!) long newPts = (long)(p.StartTime.TotalSeconds * 90000.0); 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++) { subHeader[23 + i] = Convert.ToByte(fiveBytesString.Substring(i * 8, 8), 2); } subHeader[28] = vobSubId; headerSize = 29; } else { subHeader[20] = 0x81; // mark as original subHeader[21] = 0x00; // no PTS subHeader[22] = 0x00; // header data length subHeader[23] = vobSubId; headerSize = 24; } if ((toWrite + headerSize) <= 0x800) { // write whole image in one 0x800 part long j = (headerSize - 20) + toWrite; subHeader[18] = (byte)(j / 0x100); subHeader[19] = (byte)(j % 0x100); // First Write header for (int x = 0; x < headerSize; x++) { mwsub.WriteByte(subHeader[x]); } // Write Image Data for (int x = 0; x < toWrite; x++) { mwsub.WriteByte(imageBuffer[bufferIndex++]); } // Pad remaining space long paddingSize = 0x800 - headerSize - toWrite; for (int x = 0; x < paddingSize; x++) { mwsub.WriteByte(0xff); } toWrite = 0; } else { // write multiple parts long blockSize = 0x800 - headerSize; long j = (headerSize - 20) + blockSize; subHeader[18] = (byte)(j / 0x100); subHeader[19] = (byte)(j % 0x100); // First Write header for (int x = 0; x < headerSize; x++) { mwsub.WriteByte(subHeader[x]); } // Write Image Data for (int x = 0; x < blockSize; x++) { mwsub.WriteByte(imageBuffer[bufferIndex++]); } toWrite -= blockSize; } } // Write whole memory stream to file long endPosition = mwsub.GetPosition(); mwsub.GotoBegin(); _subFile.Write(mwsub.GetBuf(), 0, (int)endPosition); }
private void NOCRIntialize(Bitmap bitmap) { var nikseBitmap = new NikseBitmap(bitmap); List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLetters(nikseBitmap, (int)numericUpDownNumberOfPixelsIsSpaceNOCR.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); foreach (ImageSplitterItem item in list) { if (item.NikseBitmap != null) { var nbmp = item.NikseBitmap; nbmp.ReplaceNonWhiteWithTransparent(); item.Y += nbmp.CropTopTransparent(0); nbmp.CropTransparentSidesAndBottom(0, true); nbmp.ReplaceTransparentWith(Color.Black); GetNOcrCompareMatch(item, nikseBitmap, _nOcrDb, false, false); } } }
internal static ImageSplitterItem GetExpandedSelection(NikseBitmap bitmap, List<ImageSplitterItem> expandSelectionList, bool rightToLeft) { if (rightToLeft) { int minimumX = expandSelectionList[expandSelectionList.Count - 1].X - expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int maximumX = expandSelectionList[0].X; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; foreach (ImageSplitterItem item in expandSelectionList) { if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } var part = bitmap.CopyRectangle(new Rectangle(minimumX, minimumY, maximumX - minimumX, maximumY - minimumY)); return new ImageSplitterItem(minimumX, minimumY, part); } else { int minimumX = expandSelectionList[0].X; int maximumX = expandSelectionList[expandSelectionList.Count - 1].X + expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; foreach (ImageSplitterItem item in expandSelectionList) { if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } var part = bitmap.CopyRectangle(new Rectangle(minimumX, minimumY, maximumX - minimumX, maximumY - minimumY)); return new ImageSplitterItem(minimumX, minimumY, part); } }
private string OcrViaTesseract(Bitmap bitmap, int index) { if (bitmap == null) return string.Empty; if (_ocrFixEngine == null) comboBoxDictionaries_SelectedIndexChanged(null, null); const int badWords = 0; string textWithOutFixes; if (_tesseractAsyncStrings != null && !string.IsNullOrEmpty(_tesseractAsyncStrings[index])) { textWithOutFixes = _tesseractAsyncStrings[index]; } else { if (_tesseractAsyncIndex <= index) _tesseractAsyncIndex = index + 10; textWithOutFixes = Tesseract3DoOcrViaExe(bitmap, _languageId, "-psm 6"); // 6 = Assume a single uniform block of text. } if ((!textWithOutFixes.Contains(Environment.NewLine) || Utilities.CountTagInText(textWithOutFixes, '\n') > 2) && (textWithOutFixes.Length < 17 || bitmap.Height < 50)) { string psm = Tesseract3DoOcrViaExe(bitmap, _languageId, "-psm 7"); // 7 = Treat the image as a single text line. if (textWithOutFixes != psm) { if (string.IsNullOrWhiteSpace(textWithOutFixes)) { textWithOutFixes = psm; } else if (psm.Length > textWithOutFixes.Length) { if (!psm.Contains('9') && textWithOutFixes.Contains('9') || !psm.Contains('6') && textWithOutFixes.Contains('6') || !psm.Contains('5') && textWithOutFixes.Contains('5') || !psm.Contains('3') && textWithOutFixes.Contains('3') || !psm.Contains('1') && textWithOutFixes.Contains('1') || !psm.Contains('$') && textWithOutFixes.Contains('$') || !psm.Contains('•') && textWithOutFixes.Contains('•') || !psm.Contains('Y') && textWithOutFixes.Contains('Y') || !psm.Contains('\'') && textWithOutFixes.Contains('\'') || !psm.Contains('€') && textWithOutFixes.Contains('€')) { textWithOutFixes = psm; } else if (_ocrFixEngine != null && !psm.Contains('$') && !psm.Contains('•') && !psm.Contains('€')) { int correctWordsNoFixes; int wordsNotFoundNoFixes = _ocrFixEngine.CountUnknownWordsViaDictionary(textWithOutFixes, out correctWordsNoFixes); int correctWordsPsm7; int wordsNotFoundPsm7 = _ocrFixEngine.CountUnknownWordsViaDictionary(psm, out correctWordsPsm7); if (wordsNotFoundPsm7 <= wordsNotFoundNoFixes && correctWordsPsm7 > correctWordsNoFixes) { textWithOutFixes = psm; } } } else if (psm.Length == textWithOutFixes.Length && (!psm.Contains('0') && textWithOutFixes.Contains('0') || // these chars are often mistaken !psm.Contains('9') && textWithOutFixes.Contains('9') || !psm.Contains('8') && textWithOutFixes.Contains('8') || !psm.Contains('5') && textWithOutFixes.Contains('5') || !psm.Contains('3') && textWithOutFixes.Contains('3') || !psm.Contains('1') && textWithOutFixes.Contains('1') || !psm.Contains('$') && textWithOutFixes.Contains('$') || !psm.Contains('€') && textWithOutFixes.Contains('€') || !psm.Contains('•') && textWithOutFixes.Contains('•') || !psm.Contains('Y') && textWithOutFixes.Contains('Y') || !psm.Contains('\'') && textWithOutFixes.Contains('\'') || !psm.Contains('/') && textWithOutFixes.Contains('/') || !psm.Contains('(') && textWithOutFixes.Contains('(') || !psm.Contains(')') && textWithOutFixes.Contains(')') || !psm.Contains('_') && textWithOutFixes.Contains('_'))) { textWithOutFixes = psm; } else if (psm.Length == textWithOutFixes.Length && psm.EndsWith('.') && !textWithOutFixes.EndsWith('.')) { textWithOutFixes = psm; } } } if (!checkBoxTesseractItalicsOn.Checked) textWithOutFixes = HtmlUtil.RemoveOpenCloseTags(textWithOutFixes, HtmlUtil.TagItalic); // Sometimes Tesseract has problems with small fonts - it helps to make the image larger if (HtmlUtil.RemoveOpenCloseTags(textWithOutFixes, HtmlUtil.TagItalic).Replace("@", string.Empty).Replace("%", string.Empty).Replace("|", string.Empty).Trim().Length < 3 || Utilities.CountTagInText(textWithOutFixes, '\n') > 2) { string rs = TesseractResizeAndRetry(bitmap); textWithOutFixes = rs; if (!checkBoxTesseractItalicsOn.Checked) textWithOutFixes = HtmlUtil.RemoveOpenCloseTags(textWithOutFixes, HtmlUtil.TagItalic); } // fix italics textWithOutFixes = FixItalics(textWithOutFixes); int numberOfWords = textWithOutFixes.Split((" " + Environment.NewLine).ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Length; string line = textWithOutFixes.Trim(); if (_ocrFixEngine.IsDictionaryLoaded) { if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, index, _lastLine, true, GetAutoGuessLevel()); int correctWords; int wordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(line, out correctWords); int oldCorrectWords = correctWords; if (wordsNotFound > 0 || correctWords == 0) { List<string> oldUnkownWords = new List<string>(); oldUnkownWords.AddRange(_ocrFixEngine.UnknownWordsFound); _ocrFixEngine.UnknownWordsFound.Clear(); string newUnfixedText = TesseractResizeAndRetry(bitmap); string newText = _ocrFixEngine.FixOcrErrors(newUnfixedText, index, _lastLine, true, GetAutoGuessLevel()); int newWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(newText, out correctWords); if (wordsNotFound == 1 && newWordsNotFound == 1 && newUnfixedText.EndsWith("!!") && textWithOutFixes.EndsWith('u') && newText.Length > 1) { _ocrFixEngine.UnknownWordsFound.Clear(); newText = textWithOutFixes.Substring(0, textWithOutFixes.Length - 1) + "!!"; newWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(newText, out correctWords); } else if (correctWords >= oldCorrectWords && (!newText.Contains('9') || textWithOutFixes.Contains('9')) && (!newText.Replace("</i>", string.Empty).Contains('/') || textWithOutFixes.Replace("</i>", string.Empty).Contains('/')) && !string.IsNullOrWhiteSpace(newUnfixedText) && newWordsNotFound < wordsNotFound || (newWordsNotFound == wordsNotFound && newText.EndsWith('!') && textWithOutFixes.EndsWith('l'))) { wordsNotFound = newWordsNotFound; if (textWithOutFixes.Length > 3 && textWithOutFixes.EndsWith("...") && !newText.EndsWith('.') && !newText.EndsWith(',') && !newText.EndsWith('!') && !newText.EndsWith('?') && !newText.EndsWith("</i>")) newText = newText.TrimEnd() + "..."; else if (textWithOutFixes.Length > 0 && textWithOutFixes.EndsWith('.') && !newText.EndsWith('.') && !newText.EndsWith(',') && !newText.EndsWith('!') && !newText.EndsWith('?') && !newText.EndsWith("</i>")) newText = newText.TrimEnd() + "."; else if (textWithOutFixes.Length > 0 && textWithOutFixes.EndsWith('?') && !newText.EndsWith('.') && !newText.EndsWith(',') && !newText.EndsWith('!') && !newText.EndsWith('?') && !newText.EndsWith("</i>")) newText = newText.TrimEnd() + "?"; textWithOutFixes = newUnfixedText; line = FixItalics(newText); } else if (correctWords > oldCorrectWords + 1 || (correctWords > oldCorrectWords && !textWithOutFixes.Contains(' '))) { wordsNotFound = newWordsNotFound; textWithOutFixes = newUnfixedText; line = newText; } else { _ocrFixEngine.UnknownWordsFound.Clear(); _ocrFixEngine.UnknownWordsFound.AddRange(oldUnkownWords); } } if (wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && textWithOutFixes.Replace("~", string.Empty).Trim().Length < 2) { if (_bluRaySubtitles != null && !line.Contains("<i>")) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); // which is best - normal image or one color image? var nbmp = new NikseBitmap(bitmap); nbmp.MakeOneColor(Color.White); Bitmap oneColorBitmap = nbmp.GetBitmap(); string oneColorText = Tesseract3DoOcrViaExe(oneColorBitmap, _languageId, "-psm 6"); // 6 = Assume a single uniform block of text. oneColorBitmap.Dispose(); nbmp = null; if (oneColorText.Length > 1 && !oneColorText.Contains("CD") && (!oneColorText.Contains('0') || line.Contains('0')) && (!oneColorText.Contains('2') || line.Contains('2')) && (!oneColorText.Contains('3') || line.Contains('4')) && (!oneColorText.Contains('5') || line.Contains('5')) && (!oneColorText.Contains('9') || line.Contains('9')) && (!oneColorText.Contains('•') || line.Contains('•')) && (!oneColorText.Contains(')') || line.Contains(')')) && Utilities.CountTagInText(oneColorText, '(') < 2 && Utilities.CountTagInText(oneColorText, ')') < 2 && Utilities.GetNumberOfLines(oneColorText) < 4) { int modiCorrectWords; int modiWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(oneColorText, out modiCorrectWords); string modiTextOcrFixed = oneColorText; if (checkBoxAutoFixCommonErrors.Checked) modiTextOcrFixed = _ocrFixEngine.FixOcrErrors(oneColorText, index, _lastLine, false, GetAutoGuessLevel()); int modiOcrCorrectedCorrectWords; int modiOcrCorrectedWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(modiTextOcrFixed, out modiOcrCorrectedCorrectWords); if (modiOcrCorrectedWordsNotFound <= modiWordsNotFound) { oneColorText = modiTextOcrFixed; modiWordsNotFound = modiOcrCorrectedWordsNotFound; modiCorrectWords = modiOcrCorrectedCorrectWords; } if (modiWordsNotFound < wordsNotFound || (textWithOutFixes.Length == 1 && modiWordsNotFound == 0)) { line = FixItalics(oneColorText); // use one-color text wordsNotFound = modiWordsNotFound; correctWords = modiCorrectWords; if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, index, _lastLine, true, GetAutoGuessLevel()); } else if (wordsNotFound == modiWordsNotFound && oneColorText.EndsWith('!') && (line.EndsWith('l') || line.EndsWith('fl'))) { line = FixItalics(oneColorText); wordsNotFound = modiWordsNotFound; correctWords = modiCorrectWords; if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, index, _lastLine, true, GetAutoGuessLevel()); } } } } if (checkBoxTesseractItalicsOn.Checked) { if (line.Contains("<i>") || wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && textWithOutFixes.Replace("~", string.Empty).Trim().Length < 2) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); // which is best - normal image or de-italic'ed? We find out here var unItalicedBmp = UnItalic(bitmap, _unItalicFactor); string unItalicText = Tesseract3DoOcrViaExe(unItalicedBmp, _languageId, "-psm 6"); // 6 = Assume a single uniform block of text. unItalicedBmp.Dispose(); if (unItalicText.Length > 1) { int modiCorrectWords; int modiWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(unItalicText, out modiCorrectWords); string modiTextOcrFixed = unItalicText; if (checkBoxAutoFixCommonErrors.Checked) modiTextOcrFixed = _ocrFixEngine.FixOcrErrors(unItalicText, index, _lastLine, false, GetAutoGuessLevel()); int modiOcrCorrectedCorrectWords; int modiOcrCorrectedWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(modiTextOcrFixed, out modiOcrCorrectedCorrectWords); if (modiOcrCorrectedWordsNotFound <= modiWordsNotFound) { unItalicText = modiTextOcrFixed; modiWordsNotFound = modiOcrCorrectedWordsNotFound; modiCorrectWords = modiOcrCorrectedCorrectWords; } bool ok = modiWordsNotFound < wordsNotFound || (textWithOutFixes.Length == 1 && modiWordsNotFound == 0); if (!ok) ok = wordsNotFound == modiWordsNotFound && unItalicText.EndsWith('!') && (line.EndsWith('l') || line.EndsWith('fl')); if (!ok) ok = wordsNotFound == modiWordsNotFound && line.StartsWith("<i>") && line.EndsWith("</i>"); if (ok && Utilities.CountTagInText(unItalicText, '/') > Utilities.CountTagInText(line, '/') + 1) ok = false; if (ok && Utilities.CountTagInText(unItalicText, '\\') > Utilities.CountTagInText(line, '\\')) ok = false; if (ok && Utilities.CountTagInText(unItalicText, ')') > Utilities.CountTagInText(line, ')') + 1) ok = false; if (ok && Utilities.CountTagInText(unItalicText, '(') > Utilities.CountTagInText(line, '(') + 1) ok = false; if (ok && Utilities.CountTagInText(unItalicText, '$') > Utilities.CountTagInText(line, '$') + 1) ok = false; if (ok && Utilities.CountTagInText(unItalicText, '€') > Utilities.CountTagInText(line, '€') + 1) ok = false; if (ok && Utilities.CountTagInText(unItalicText, '•') > Utilities.CountTagInText(line, '•')) ok = false; if (ok) { wordsNotFound = modiWordsNotFound; correctWords = modiCorrectWords; line = HtmlUtil.RemoveOpenCloseTags(line, HtmlUtil.TagItalic).Trim(); if (line.Length > 7 && unItalicText.Length > 7 && unItalicText.StartsWith("I ") && line.StartsWith(unItalicText.Remove(0, 2).Substring(0, 4))) unItalicText = unItalicText.Remove(0, 2); if (checkBoxTesseractMusicOn.Checked) { if ((line.StartsWith("J' ") || line.StartsWith("J“ ") || line.StartsWith("J* ") || line.StartsWith("♪ ")) && unItalicText.Length > 3 && HtmlUtil.RemoveOpenCloseTags(unItalicText, HtmlUtil.TagItalic).Substring(1, 2) == "' ") { unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); } if ((line.StartsWith("J' ") || line.StartsWith("J“ ") || line.StartsWith("J* ") || line.StartsWith("♪ ")) && unItalicText.Length > 3 && HtmlUtil.RemoveOpenCloseTags(unItalicText, HtmlUtil.TagItalic)[1] == ' ') { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if ((line.StartsWith("J' ") || line.StartsWith("J“ ") || line.StartsWith("J* ") || line.StartsWith("♪ ")) && unItalicText.Length > 3 && HtmlUtil.RemoveOpenCloseTags(unItalicText, HtmlUtil.TagItalic)[2] == ' ') { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if (unItalicText.StartsWith("J'") && (line.StartsWith('♪') || textWithOutFixes.StartsWith('♪') || textWithOutFixes.StartsWith("<i>♪") || unItalicText.EndsWith('♪'))) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if ((line.StartsWith("J` ") || line.StartsWith("J“ ") || line.StartsWith("J' ") || line.StartsWith("J* ")) && unItalicText.StartsWith("S ")) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if ((line.StartsWith("J` ") || line.StartsWith("J“ ") || line.StartsWith("J' ") || line.StartsWith("J* ")) && unItalicText.StartsWith("<i>S</i> ")) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 8).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if (unItalicText.StartsWith(";'") && (line.StartsWith('♪') || textWithOutFixes.StartsWith('♪') || textWithOutFixes.StartsWith("<i>♪") || unItalicText.EndsWith('♪'))) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 2).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if (unItalicText.StartsWith(",{*") && (line.StartsWith('♪') || textWithOutFixes.StartsWith('♪') || textWithOutFixes.StartsWith("<i>♪") || unItalicText.EndsWith('♪'))) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = "♪ " + unItalicText.Remove(0, 3).TrimStart(); if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } if (unItalicText.EndsWith("J'") && (line.EndsWith('♪') || textWithOutFixes.EndsWith('♪') || textWithOutFixes.EndsWith("♪</i>") || unItalicText.StartsWith('♪'))) { bool ita = unItalicText.StartsWith("<i>") && unItalicText.EndsWith("</i>"); unItalicText = HtmlUtil.RemoveHtmlTags(unItalicText); unItalicText = unItalicText.Remove(unItalicText.Length - 3, 2).TrimEnd() + " ♪"; if (ita) unItalicText = "<i>" + unItalicText + "</i>"; } } if (unItalicText.StartsWith('[') && !line.StartsWith('[')) { unItalicText = unItalicText.Remove(0, 1); if (unItalicText.EndsWith(']')) unItalicText = unItalicText.TrimEnd(']'); } if (unItalicText.StartsWith('{') && !line.StartsWith('{')) { unItalicText = unItalicText.Remove(0, 1); if (unItalicText.EndsWith('}')) unItalicText = unItalicText.TrimEnd('}'); } if (unItalicText.EndsWith('}') && !line.EndsWith('}')) unItalicText = unItalicText.TrimEnd('}'); if (line.EndsWith("...") && unItalicText.EndsWith("”!")) unItalicText = unItalicText.TrimEnd('!').TrimEnd('”') + "."; if (line.EndsWith("...") && unItalicText.EndsWith("\"!")) unItalicText = unItalicText.TrimEnd('!').TrimEnd('"') + "."; if (line.EndsWith('.') && !unItalicText.EndsWith('.') && !unItalicText.EndsWith(".</i>")) { string post = string.Empty; if (unItalicText.EndsWith("</i>")) { post = "</i>"; unItalicText = unItalicText.Remove(unItalicText.Length - 4); } if (unItalicText.EndsWith('\'') && !line.EndsWith("'.")) unItalicText = unItalicText.TrimEnd('\''); unItalicText += "." + post; } if (unItalicText.EndsWith('.') && !unItalicText.EndsWith("...") && !unItalicText.EndsWith("...</i>") && line.EndsWith("...")) { string post = string.Empty; if (unItalicText.EndsWith("</i>")) { post = "</i>"; unItalicText = unItalicText.Remove(unItalicText.Length - 4); } unItalicText += ".." + post; } if (unItalicText.EndsWith("..") && !unItalicText.EndsWith("...") && !unItalicText.EndsWith("...</i>") && line.EndsWith("...")) { string post = string.Empty; if (unItalicText.EndsWith("</i>")) { post = "</i>"; unItalicText = unItalicText.Remove(unItalicText.Length - 4); } unItalicText += "." + post; } if (line.EndsWith('!') && !unItalicText.EndsWith('!') && !unItalicText.EndsWith("!</i>")) { if (unItalicText.EndsWith("!'")) { unItalicText = unItalicText.TrimEnd('\''); } else { if (unItalicText.EndsWith("l</i>") && _ocrFixEngine != null) { string w = unItalicText.Substring(0, unItalicText.Length - 4); int wIdx = w.Length - 1; while (wIdx >= 0 && !@" .,!?<>:;'-$@£()[]<>/""".Contains(w[wIdx])) { wIdx--; } if (wIdx + 1 < w.Length && unItalicText.Length > 5) { w = w.Substring(wIdx + 1); if (!_ocrFixEngine.DoSpell(w)) unItalicText = unItalicText.Remove(unItalicText.Length - 5, 1); } unItalicText = unItalicText.Insert(unItalicText.Length - 4, "!"); } else if (unItalicText.EndsWith('l') && _ocrFixEngine != null) { string w = unItalicText; int wIdx = w.Length - 1; while (wIdx >= 0 && !@" .,!?<>:;'-$@£()[]<>/""".Contains(w[wIdx])) { wIdx--; } if (wIdx + 1 < w.Length && unItalicText.Length > 5) { w = w.Substring(wIdx + 1); if (!_ocrFixEngine.DoSpell(w)) unItalicText = unItalicText.Remove(unItalicText.Length - 1, 1); } unItalicText += "!"; } else { unItalicText += "!"; } } } if (line.EndsWith('?') && !unItalicText.EndsWith('?') && !unItalicText.EndsWith("?</i>")) { if (unItalicText.EndsWith("?'")) unItalicText = unItalicText.TrimEnd('\''); else unItalicText += "?"; } line = HtmlUtil.RemoveOpenCloseTags(unItalicText, HtmlUtil.TagItalic); if (checkBoxAutoFixCommonErrors.Checked) { if (line.Contains("'.") && !textWithOutFixes.Contains("'.") && textWithOutFixes.Contains(':') && !line.EndsWith("'.") && Configuration.Settings.Tools.OcrFixUseHardcodedRules) { line = line.Replace("'.", ":"); } line = _ocrFixEngine.FixOcrErrors(line, index, _lastLine, true, GetAutoGuessLevel()); } line = "<i>" + line + "</i>"; } else { unItalicText = unItalicText.Replace("</i>", string.Empty); if (line.EndsWith("</i>", StringComparison.Ordinal) && unItalicText.EndsWith('.')) { line = line.Remove(line.Length - 4, 4); if (line.EndsWith('-')) line = line.TrimEnd('-') + "."; if (char.IsLetter(line[line.Length - 1])) line += "."; line += "</i>"; } } } } } if (checkBoxTesseractMusicOn.Checked) { if (line == "[J'J'J~]" || line == "[J'J'J']") line = "[ ♪ ♪ ♪ ]"; line = line.Replace(" J' ", " ♪ "); if (line.StartsWith("J'")) { line = "♪ " + line.Remove(0, 2).TrimStart(); } if (line.StartsWith("<i>J'")) { line = "<i>♪ " + line.Remove(0, 5).TrimStart(); } if (line.StartsWith("[J'")) { line = "[♪ " + line.Remove(0, 3).TrimStart(); } if (line.StartsWith("<i>[J'")) { line = "<i>[♪ " + line.Remove(0, 6).TrimStart(); } if (line.EndsWith("J'")) { line = line.Remove(line.Length - 2, 2).TrimEnd() + " ♪"; } if (line.EndsWith("J'</i>")) { line = line.Remove(line.Length - 6, 6).TrimEnd() + " ♪</i>"; } if (line.Contains(Environment.NewLine + "J'")) { line = line.Replace(Environment.NewLine + "J'", Environment.NewLine + "♪ "); line = line.Replace(" ", " "); } if (line.Contains("J'" + Environment.NewLine)) { line = line.Replace("J'" + Environment.NewLine, " ♪" + Environment.NewLine); line = line.Replace(" ", " "); } } if (wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && textWithOutFixes.Replace("~", string.Empty).Trim().Length < 2) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); if (_modiEnabled && checkBoxUseModiInTesseractForUnknownWords.Checked) { // which is best - modi or Tesseract - we find out here string modiText = CallModi(index); if (modiText.Length == 0) modiText = CallModi(index); // retry... strange MODI if (modiText.Length == 0) modiText = CallModi(index); // retry... strange MODI if (modiText.Length > 1 && !modiText.Contains("CD") && (!modiText.Contains('0') || line.Contains('0')) && (!modiText.Contains('2') || line.Contains('2')) && (!modiText.Contains('3') || line.Contains('4')) && (!modiText.Contains('5') || line.Contains('5')) && (!modiText.Contains('9') || line.Contains('9')) && (!modiText.Contains('•') || line.Contains('•')) && (!modiText.Contains(')') || line.Contains(')')) && Utilities.CountTagInText(modiText, '(') < 2 && Utilities.CountTagInText(modiText, ')') < 2 && Utilities.GetNumberOfLines(modiText) < 4) { int modiWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(modiText, out correctWords); //if (modiWordsNotFound > 0) { string modiTextOcrFixed = modiText; if (checkBoxAutoFixCommonErrors.Checked) modiTextOcrFixed = _ocrFixEngine.FixOcrErrors(modiText, index, _lastLine, false, GetAutoGuessLevel()); int modiOcrCorrectedWordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(modiTextOcrFixed, out correctWords); if (modiOcrCorrectedWordsNotFound <= modiWordsNotFound) modiText = modiTextOcrFixed; } if (modiWordsNotFound < wordsNotFound || (textWithOutFixes.Length == 1 && modiWordsNotFound == 0)) line = modiText; // use the modi OCR'ed text else if (wordsNotFound == modiWordsNotFound && modiText.EndsWith('!') && (line.EndsWith('l') || line.EndsWith('fl'))) line = modiText; } // take the best option - before OCR fixing, which we do again to save suggestions and prompt for user input line = _ocrFixEngine.FixUnknownWordsViaGuessOrPrompt(out wordsNotFound, line, index, bitmap, checkBoxAutoFixCommonErrors.Checked, checkBoxPromptForUnknownWords.Checked, true, GetAutoGuessLevel()); } else { // fix some error manually (modi not available) line = _ocrFixEngine.FixUnknownWordsViaGuessOrPrompt(out wordsNotFound, line, index, bitmap, checkBoxAutoFixCommonErrors.Checked, checkBoxPromptForUnknownWords.Checked, true, GetAutoGuessLevel()); } } if (_ocrFixEngine.Abort) { ButtonStopClick(null, null); _ocrFixEngine.Abort = false; return string.Empty; } //check Tesseract... find an other way to do this... //string tmp = HtmlUtil.RemoveHtmlTags(line).Trim(); //if (!tmp.TrimEnd().EndsWith("...")) //{ // tmp = tmp.TrimEnd('.').TrimEnd(); // if (tmp.Length > 2 && Utilities.LowercaseLetters.Contains(tmp[tmp.Length - 1])) // { // if (_nocrChars == null) // _nocrChars = LoadNOcrForTesseract("Nikse.SubtitleEdit.Resources.nOCR_TesseractHelper.xml.zip"); // string text = HtmlUtil.RemoveHtmlTags(NocrFastCheck(bitmap).TrimEnd()); // string post = string.Empty; // if (line.EndsWith("</i>")) // { // post = "</i>"; // line = line.Remove(line.Length - 4, 4).Trim(); // } // if (text.EndsWith('.')) // { // line = line.TrimEnd('.').Trim(); // while (text.EndsWith('.') || text.EndsWith(' ')) // { // line += text.Substring(text.Length - 1).Trim(); // text = text.Remove(text.Length - 1, 1); // } // } // else if (text.EndsWith('l') && text.EndsWith('!') && !text.EndsWith("l!")) // { // line = line.Remove(line.Length - 1, 1) + "!"; // } // line += post; // } //} // Log used word guesses (via word replace list) foreach (string guess in _ocrFixEngine.AutoGuessesUsed) listBoxLogSuggestions.Items.Add(guess); _ocrFixEngine.AutoGuessesUsed.Clear(); // Log unkown words guess (found via spelling dictionaries) LogUnknownWords(); ColorLineByNumberOfUnknownWords(index, wordsNotFound, line); } else { // no dictionary :( if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, index, _lastLine, true, GetAutoGuessLevel()); if (badWords >= numberOfWords) subtitleListView1.SetBackgroundColor(index, Color.Red); else if (badWords >= numberOfWords / 2) subtitleListView1.SetBackgroundColor(index, Color.Orange); else if (badWords > 0 || line.Contains('_') || HasSingleLetters(line)) subtitleListView1.SetBackgroundColor(index, Color.Yellow); else if (string.IsNullOrWhiteSpace(HtmlUtil.RemoveOpenCloseTags(line, HtmlUtil.TagItalic))) subtitleListView1.SetBackgroundColor(index, Color.Orange); else subtitleListView1.SetBackgroundColor(index, Color.LightGreen); } if (textWithOutFixes.Trim() != line.Trim()) { _tesseractOcrAutoFixes++; labelFixesMade.Text = string.Format(" - {0}", _tesseractOcrAutoFixes); LogOcrFix(index, textWithOutFixes, line); } if (_vobSubMergedPackist != null) bitmap.Dispose(); return line; }
/// <summary> /// Create the binary stream representation of one caption /// </summary> /// <param name="pic">SubPicture object containing caption info</param> /// <param name="bmp">Bitmap</param> /// <param name="fps">Frames per second</param> /// <param name="bottomMargin">Image bottom margin</param> /// <param name="leftOrRightMargin">Image left/right margin</param> /// <param name="alignment">Alignment of image</param> /// <returns>Byte buffer containing the binary stream representation of one caption</returns> public static byte[] CreateSupFrame(BluRaySupPicture pic, Bitmap bmp, double fps, int bottomMargin, int leftOrRightMargin, ContentAlignment alignment) { var bm = new NikseBitmap(bmp); var colorPalette = GetBitmapPalette(bm); var pal = new BluRaySupPalette(colorPalette.Count); int k = 0; foreach (var kvp in colorPalette) { pal.SetColor(k, kvp.Key); k++; } byte[] rleBuf = EncodeImage(bm, colorPalette); // for some obscure reason, a packet can be a maximum 0xfffc bytes // since 13 bytes are needed for the header("PG", PTS, DTS, ID, SIZE) // there are only 0xffef bytes available for the packet // since the first ODS packet needs an additional 11 bytes for info // and the following ODS packets need 4 additional bytes, the // first package can store only 0xffe4 RLE buffer bytes and the // following packets can store 0xffeb RLE buffer bytes int numAddPackets; if (rleBuf.Length <= 0xffe4) { numAddPackets = 0; // no additional packets needed; } else { numAddPackets = 1 + (rleBuf.Length - 0xffe4) / 0xffeb; } // a typical frame consists of 8 packets. It can be enlonged by additional // object frames int palSize = colorPalette.Count; var packetHeader = new byte[] { 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) }; var headerPcsStart = new byte[] { 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) 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 }; var headerPcsEnd = new byte[] { 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) }; var headerWds = new byte[] { 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 }; var headerOdsFirst = new byte[] { 0x00, 0x00, // 0: object_id 0x00, // 2: object_version_number 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 }; var headerOdsNext = new byte[] { 0x00, 0x00, // 0: object_id 0x00, // 2: object_version_number 0x40 // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved }; int size = packetHeader.Length * (8 + numAddPackets); size += headerPcsStart.Length + headerPcsEnd.Length; size += 2 * headerWds.Length + headerOdsFirst.Length; size += numAddPackets * headerOdsNext.Length; size += (2 + palSize * 5) /* PDS */; size += rleBuf.Length; switch (alignment) { case ContentAlignment.BottomLeft: pic.WindowXOffset = leftOrRightMargin; pic.WindowYOffset = pic.Height - (bm.Height + bottomMargin); break; case ContentAlignment.BottomRight: pic.WindowXOffset = pic.Width - bm.Width - bottomMargin; pic.WindowYOffset = pic.Height - (bm.Height + leftOrRightMargin); break; case ContentAlignment.MiddleCenter: pic.WindowXOffset = (pic.Width - bm.Width) / 2; pic.WindowYOffset = (pic.Height - bm.Height) / 2; break; case ContentAlignment.MiddleLeft: pic.WindowXOffset = leftOrRightMargin; pic.WindowYOffset = (pic.Height - bm.Height) / 2; break; case ContentAlignment.MiddleRight: pic.WindowXOffset = pic.Width - bm.Width - leftOrRightMargin; pic.WindowYOffset = (pic.Height - bm.Height) / 2; break; case ContentAlignment.TopCenter: pic.WindowXOffset = (pic.Width - bm.Width) / 2; pic.WindowYOffset = bottomMargin; break; case ContentAlignment.TopLeft: pic.WindowXOffset = leftOrRightMargin; pic.WindowYOffset = bottomMargin; break; case ContentAlignment.TopRight: pic.WindowXOffset = pic.Width - bm.Width - leftOrRightMargin; pic.WindowYOffset = bottomMargin; break; default: // ContentAlignment.BottomCenter: pic.WindowXOffset = (pic.Width - bm.Width) / 2; pic.WindowYOffset = pic.Height - (bm.Height + bottomMargin); break; } int yOfs = pic.WindowYOffset - Core.CropOfsY; if (yOfs < 0) { yOfs = 0; } else { int yMax = pic.Height - pic.WindowHeight - 2 * Core.CropOfsY; if (yOfs > yMax) { yOfs = yMax; } } int h = pic.Height - 2 * Core.CropOfsY; byte[] buf = new byte[size]; int index = 0; int fpsId = GetFpsId(fps); /* time (in 90kHz resolution) needed to initialize (clear) the screen buffer * based on the composition pixel rate of 256e6 bit/s - always rounded up */ int frameInitTime = (pic.Width * pic.Height * 9 + 3199) / 3200; // better use default height here /* time (in 90kHz resolution) needed to initialize (clear) the window area * based on the composition pixel rate of 256e6 bit/s - always rounded up * Note: no cropping etc. -> window size == image size */ int windowInitTime = (bm.Width * bm.Height * 9 + 3199) / 3200; /* time (in 90kHz resolution) needed to decode the image * based on the decoding pixel rate of 128e6 bit/s - always rounded up */ int imageDecodeTime = (bm.Width * bm.Height * 9 + 1599) / 1600; // write PCS start packetHeader[10] = 0x16; // ID int dts = pic.StartTimeForWrite - (frameInitTime + windowInitTime + imageDecodeTime); // int dts = pic.StartTimeForWrite - windowInitTime; ???? ToolBox.SetDWord(packetHeader, 2, pic.StartTimeForWrite); // PTS ToolBox.SetDWord(packetHeader, 6, dts); // DTS ToolBox.SetWord(packetHeader, 11, headerPcsStart.Length); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } ToolBox.SetWord(headerPcsStart, 0, pic.Width); ToolBox.SetWord(headerPcsStart, 2, h); // cropped height ToolBox.SetByte(headerPcsStart, 4, fpsId); ToolBox.SetWord(headerPcsStart, 5, pic.CompositionNumber); headerPcsStart[14] = (byte)(pic.IsForced ? 0x40 : 0); ToolBox.SetWord(headerPcsStart, 15, pic.WindowXOffset); ToolBox.SetWord(headerPcsStart, 17, yOfs); for (int i = 0; i < headerPcsStart.Length; i++) { buf[index++] = headerPcsStart[i]; } // write WDS packetHeader[10] = 0x17; // ID int timestamp = pic.StartTimeForWrite - windowInitTime; ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS (keep DTS) ToolBox.SetWord(packetHeader, 11, headerWds.Length); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } ToolBox.SetWord(headerWds, 2, pic.WindowXOffset); ToolBox.SetWord(headerWds, 4, yOfs); ToolBox.SetWord(headerWds, 6, bm.Width); ToolBox.SetWord(headerWds, 8, bm.Height); for (int i = 0; i < headerWds.Length; i++) { buf[index++] = headerWds[i]; } // write PDS packetHeader[10] = 0x14; // ID ToolBox.SetDWord(packetHeader, 2, dts); // PTS (=DTS of PCS/WDS) ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0) ToolBox.SetWord(packetHeader, 11, (2 + palSize * 5)); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } buf[index++] = 0; buf[index++] = 0; for (int i = 0; i < palSize; i++) { buf[index++] = (byte)i; // index buf[index++] = pal.GetY()[i]; // Y buf[index++] = pal.GetCr()[i]; // Cr buf[index++] = pal.GetCb()[i]; // Cb buf[index++] = pal.GetAlpha()[i]; // Alpha } // write first OBJ int bufSize = rleBuf.Length; int rleIndex = 0; if (bufSize > 0xffe4) { bufSize = 0xffe4; } packetHeader[10] = 0x15; // ID timestamp = dts + imageDecodeTime; ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS ToolBox.SetDWord(packetHeader, 6, dts); // DTS ToolBox.SetWord(packetHeader, 11, headerOdsFirst.Length + bufSize); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } int marker = (int)((numAddPackets == 0) ? 0xC0000000 : 0x80000000); ToolBox.SetDWord(headerOdsFirst, 3, marker | (rleBuf.Length + 4)); ToolBox.SetWord(headerOdsFirst, 7, bm.Width); ToolBox.SetWord(headerOdsFirst, 9, bm.Height); for (int i = 0; i < headerOdsFirst.Length; i++) { buf[index++] = headerOdsFirst[i]; } for (int i = 0; i < bufSize; i++) { buf[index++] = rleBuf[rleIndex++]; } // write additional OBJ packets bufSize = rleBuf.Length - bufSize; // remaining bytes to write for (int p = 0; p < numAddPackets; p++) { int psize = bufSize; if (psize > 0xffeb) { psize = 0xffeb; } packetHeader[10] = 0x15; // ID (keep DTS & PTS) ToolBox.SetWord(packetHeader, 11, headerOdsNext.Length + psize); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } for (int i = 0; i < headerOdsNext.Length; i++) { buf[index++] = headerOdsNext[i]; } for (int i = 0; i < psize; i++) { buf[index++] = rleBuf[rleIndex++]; } bufSize -= psize; } // write END packetHeader[10] = 0x80; // ID ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0) (keep PTS of ODS) ToolBox.SetWord(packetHeader, 11, 0); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } // write PCS end packetHeader[10] = 0x16; // ID ToolBox.SetDWord(packetHeader, 2, pic.EndTimeForWrite); // PTS dts = pic.EndTimeForWrite - 1; //dts = pic.StartTimeForWrite - 1; ToolBox.SetDWord(packetHeader, 6, dts); // DTS ToolBox.SetWord(packetHeader, 11, headerPcsEnd.Length); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } ToolBox.SetWord(headerPcsEnd, 0, pic.Width); ToolBox.SetWord(headerPcsEnd, 2, h); // cropped height ToolBox.SetByte(headerPcsEnd, 4, fpsId); ToolBox.SetWord(headerPcsEnd, 5, pic.CompositionNumber + 1); for (int i = 0; i < headerPcsEnd.Length; i++) { buf[index++] = headerPcsEnd[i]; } // write WDS packetHeader[10] = 0x17; // ID timestamp = pic.EndTimeForWrite - windowInitTime; ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS (keep DTS of PCS) ToolBox.SetWord(packetHeader, 11, headerWds.Length); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } ToolBox.SetWord(headerWds, 2, pic.WindowXOffset); ToolBox.SetWord(headerWds, 4, yOfs); ToolBox.SetWord(headerWds, 6, bm.Width); ToolBox.SetWord(headerWds, 8, bm.Height); for (int i = 0; i < headerWds.Length; i++) { buf[index++] = headerWds[i]; } // write END packetHeader[10] = 0x80; // ID ToolBox.SetDWord(packetHeader, 2, dts); // PTS (DTS of end PCS) ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0) ToolBox.SetWord(packetHeader, 11, 0); // size for (int i = 0; i < packetHeader.Length; i++) { buf[index++] = packetHeader[i]; } return(buf); }
/// <summary> /// Ocr via image compare /// </summary> private string SplitAndOcrBitmapNormal(Bitmap bitmap, int listViewIndex) { if (_ocrFixEngine == null) LoadOcrFixEngine(null, LanguageString); string threadText = null; if (_icThreadResults != null && !string.IsNullOrEmpty(_icThreadResults[listViewIndex])) threadText = _icThreadResults[listViewIndex]; string line = string.Empty; if (threadText == null) { var matches = new List<CompareMatch>(); var parentBitmap = new NikseBitmap(bitmap); List<ImageSplitterItem> list = NikseBitmapImageSplitter.SplitBitmapToLetters(parentBitmap, (int)numericUpDownPixelsIsSpace.Value, checkBoxRightToLeft.Checked, Configuration.Settings.VobSubOcr.TopToBottom); int index = 0; bool expandSelection = false; bool shrinkSelection = false; var expandSelectionList = new List<ImageSplitterItem>(); while (index < list.Count) { ImageSplitterItem item = list[index]; if (expandSelection || shrinkSelection) { expandSelection = false; if (shrinkSelection && index > 0) { shrinkSelection = false; } else if (index + 1 < list.Count && list[index + 1].NikseBitmap != null) // only allow expand to EndOfLine or space { index++; expandSelectionList.Add(list[index]); } item = GetExpandedSelection(parentBitmap, expandSelectionList, checkBoxRightToLeft.Checked); _vobSubOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, expandSelectionList.Count > 1, null, _lastAdditions, this); DialogResult result = _vobSubOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrCharacter.ShrinkSelection) { shrinkSelection = true; index--; if (expandSelectionList.Count > 0) expandSelectionList.RemoveAt(expandSelectionList.Count - 1); } else if (result == DialogResult.OK && _vobSubOcrCharacter.ExpandSelection) { expandSelection = true; } else if (result == DialogResult.OK) { string text = _vobSubOcrCharacter.ManualRecognizedCharacters; string name = SaveCompareItem(item.NikseBitmap, text, _vobSubOcrCharacter.IsItalic, expandSelectionList.Count); var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrCharacter.IsItalic, listViewIndex); _lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrCharacter.IsItalic, expandSelectionList.Count, null)); expandSelectionList = new List<ImageSplitterItem>(); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrCharacter.IsItalic; } else if (item.NikseBitmap == null) { matches.Add(new CompareMatch(item.SpecialCharacter, false, 0, null)); } else { CompareMatch bestGuess; CompareMatch match = GetCompareMatch(item, parentBitmap, out bestGuess, list, index); if (match == null) { _vobSubOcrCharacter.Initialize(bitmap, item, _manualOcrDialogPosition, _italicCheckedLast, false, bestGuess, _lastAdditions, this); DialogResult result = _vobSubOcrCharacter.ShowDialog(this); _manualOcrDialogPosition = _vobSubOcrCharacter.FormPosition; if (result == DialogResult.OK && _vobSubOcrCharacter.ExpandSelection) { expandSelectionList.Add(item); expandSelection = true; } else if (result == DialogResult.OK) { string text = _vobSubOcrCharacter.ManualRecognizedCharacters; string name = SaveCompareItem(item.NikseBitmap, text, _vobSubOcrCharacter.IsItalic, 0); var addition = new ImageCompareAddition(name, text, item.NikseBitmap, _vobSubOcrCharacter.IsItalic, listViewIndex); _lastAdditions.Add(addition); matches.Add(new CompareMatch(text, _vobSubOcrCharacter.IsItalic, 0, null)); } else if (result == DialogResult.Abort) { _abort = true; } else { matches.Add(new CompareMatch("*", false, 0, null)); } _italicCheckedLast = _vobSubOcrCharacter.IsItalic; } else // found image match { matches.Add(new CompareMatch(match.Text, match.Italic, 0, null)); if (match.ExpandCount > 0) index += match.ExpandCount - 1; } } if (_abort) return string.Empty; if (!expandSelection && !shrinkSelection) index++; if (shrinkSelection && expandSelectionList.Count < 2) { shrinkSelection = false; expandSelectionList = new List<ImageSplitterItem>(); } } line = GetStringWithItalicTags(matches); } else { line = threadText; } if (checkBoxAutoFixCommonErrors.Checked && _ocrFixEngine != null) line = _ocrFixEngine.FixOcrErrorsViaHardcodedRules(line, _lastLine, null); // TODO: Add abbreviations list if (checkBoxRightToLeft.Checked) line = ReverseNumberStrings(line); //OCR fix engine string textWithOutFixes = line; //OCR fix engine not loaded, when no dictionary is selected if (_ocrFixEngine != null && _ocrFixEngine.IsDictionaryLoaded) { if (checkBoxAutoFixCommonErrors.Checked) line = _ocrFixEngine.FixOcrErrors(line, listViewIndex, _lastLine, true, GetAutoGuessLevel()); int correctWords; int wordsNotFound = _ocrFixEngine.CountUnknownWordsViaDictionary(line, out correctWords); if (wordsNotFound > 0 || correctWords == 0 || textWithOutFixes != null && string.IsNullOrWhiteSpace(textWithOutFixes.Replace("~", string.Empty))) { _ocrFixEngine.AutoGuessesUsed.Clear(); _ocrFixEngine.UnknownWordsFound.Clear(); line = _ocrFixEngine.FixUnknownWordsViaGuessOrPrompt(out wordsNotFound, line, listViewIndex, bitmap, checkBoxAutoFixCommonErrors.Checked, checkBoxPromptForUnknownWords.Checked, true, GetAutoGuessLevel()); } if (_ocrFixEngine.Abort) { ButtonStopClick(null, null); _ocrFixEngine.Abort = false; return string.Empty; } // Log used word guesses (via word replace list) foreach (string guess in _ocrFixEngine.AutoGuessesUsed) listBoxLogSuggestions.Items.Add(guess); _ocrFixEngine.AutoGuessesUsed.Clear(); // Log unkown words guess (found via spelling dictionaries) LogUnknownWords(); ColorLineByNumberOfUnknownWords(listViewIndex, wordsNotFound, line); } if (textWithOutFixes.Trim() != line.Trim()) { _tesseractOcrAutoFixes++; labelFixesMade.Text = string.Format(" - {0}", _tesseractOcrAutoFixes); LogOcrFix(listViewIndex, textWithOutFixes, line); } return line; }
internal CompareMatch GetNOcrCompareMatchNew(ImageSplitterItem targetItem, NikseBitmap parentBitmap, NOcrDb nOcrDb, bool tryItalicScaling, bool deepSeek) { var expandedResult = NOcrFindExpandedMatch(parentBitmap, targetItem, nOcrDb.OcrCharactersExpanded); if (expandedResult != null) { return new CompareMatch(expandedResult.Text, expandedResult.Italic, expandedResult.ExpandCount, null, expandedResult); } bool italic; var result = NOcrFindBestMatchNew(targetItem, targetItem.Y - targetItem.ParentY, out italic, nOcrDb, tryItalicScaling, deepSeek); if (result == null) { if (checkBoxNOcrCorrect.Checked) return null; return new CompareMatch("*", false, 0, null); } // Fix uppercase/lowercase issues (not I/l) if (result.Text == "e") _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastLowercaseHeight == -1 && result.Text == "a") _nocrLastLowercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "E" || result.Text == "H" || result.Text == "R" || result.Text == "D" || result.Text == "T") _nocrLastUppercaseHeight = targetItem.NikseBitmap.Height; else if (_nocrLastUppercaseHeight == -1 && result.Text == "M") _nocrLastUppercaseHeight = targetItem.NikseBitmap.Height; if (result.Text == "V" || result.Text == "W" || result.Text == "U" || result.Text == "S" || result.Text == "Z" || result.Text == "O" || result.Text == "X" || result.Text == "Ø" || result.Text == "C") { if (_nocrLastLowercaseHeight > 3 && targetItem.NikseBitmap.Height - _nocrLastLowercaseHeight < 2) result.Text = result.Text.ToLower(); } else if (result.Text == "v" || result.Text == "w" || result.Text == "u" || result.Text == "s" || result.Text == "z" || result.Text == "o" || result.Text == "x" || result.Text == "ø" || result.Text == "c") { if (_nocrLastUppercaseHeight > 3 && _nocrLastUppercaseHeight - targetItem.NikseBitmap.Height < 2) result.Text = result.Text.ToUpper(); } if (italic) return new CompareMatch(result.Text, true, 0, null, result); else return new CompareMatch(result.Text, result.Italic, 0, null, result); }
private void SplitDvbForEachSubImage() { var list = new List<TransportStreamSubtitle>(); foreach (var dvbSub in _dvbSubtitles) { if (dvbSub.ActiveImageIndex == null) { var tempList = new List<TransportStreamSubtitle>(); for (int i = 0; i < dvbSub.Pes.ObjectDataList.Count; i++) { if (dvbSub.Pes.ObjectDataList[i].TopFieldDataBlockLength > 8) { tempList.Add(new TransportStreamSubtitle { Pes = dvbSub.Pes, ActiveImageIndex = i, StartMilliseconds = dvbSub.StartMilliseconds, EndMilliseconds = dvbSub.EndMilliseconds }); } } if (tempList.Count > 1) { var lastColor = Color.Transparent; bool allAlike = true; foreach (var item in tempList) { var dvbBmp = item.GetActiveImage(); var nDvbBmp = new NikseBitmap(dvbBmp); var color = nDvbBmp.GetBrightestColor(); if (lastColor != Color.Transparent && (Math.Abs(color.R - lastColor.R) > 10 || Math.Abs(color.G - lastColor.G) > 10 || Math.Abs(color.B - lastColor.B) > 10)) { allAlike = false; break; } lastColor = color; } if (allAlike) { tempList.Clear(); tempList.Add(dvbSub); } } list.AddRange(tempList); } else { list.Add(dvbSub); } } _dvbSubtitles = list; _tesseractAsyncStrings = null; ShowDvbSubs(); }
private static int CalculateNumberOfForegroundColors(NikseBitmap nikseBitmap) { int count = 0; for (int y = 0; y < nikseBitmap.Height; y++) { for (int x = 0; x < nikseBitmap.Width; x++) { Color c = nikseBitmap.GetPixel(x, y); if (c.A > 100 && c.R + c.G + c.B > 200) count++; } } return count; }
public ImageCompareAddition(string name, string text, NikseBitmap image, bool italic, int index) { Name = name; Text = text; Image = image; Text = text; Italic = italic; Index = index; }
public NOcrChar GetMatch(NikseBitmap bitmap, int topMargin, bool deepSeek, int maxWrongPixels) { // only very very accurate matches foreach (var oc in OcrCharacters) { if (bitmap.Width == oc.Width && bitmap.Height == oc.Height && Math.Abs(oc.MarginTop - topMargin) < 5) { if (IsMatch(bitmap, oc, 0)) { return(oc); } } } // only very accurate matches double widthPercent = bitmap.Height * 100.0 / bitmap.Width; foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 15 && Math.Abs(bitmap.Width - oc.Width) < 5 && Math.Abs(bitmap.Height - oc.Height) < 5 && Math.Abs(oc.MarginTop - topMargin) < 5) { if (IsMatch(bitmap, oc, 0)) { return(oc); } } } if (maxWrongPixels >= 1) { foreach (var oc in OcrCharacters) { if (Math.Abs(bitmap.Width - oc.Width) < 4 && Math.Abs(bitmap.Height - oc.Height) < 4 && Math.Abs(oc.MarginTop - topMargin) < 8) { if (IsMatch(bitmap, oc, 1)) { return(oc); } } } } if (maxWrongPixels >= 1) { foreach (var oc in OcrCharacters) { if (Math.Abs(bitmap.Width - oc.Width) < 8 && Math.Abs(bitmap.Height - oc.Height) < 8 && Math.Abs(oc.MarginTop - topMargin) < 8) { if (IsMatch(bitmap, oc, 1)) { return(oc); } } } } if (maxWrongPixels >= 2) { var errorsAllowed = Math.Min(3, maxWrongPixels); foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 20 && Math.Abs(oc.MarginTop - topMargin) < 15) { if (IsMatch(bitmap, oc, errorsAllowed)) { return(oc); } } } } if (maxWrongPixels >= 10) { var errorsAllowed = Math.Min(20, maxWrongPixels); foreach (var oc in OcrCharacters) { if (!oc.IsSensitive && Math.Abs(widthPercent - oc.WidthPercent) < 20 && Math.Abs(oc.MarginTop - topMargin) < 15 && oc.LinesForeground.Count + oc.LinesBackground.Count > 40) { if (IsMatch(bitmap, oc, errorsAllowed)) { return(oc); } } } } if (maxWrongPixels >= 10) { foreach (var oc in OcrCharacters) { if (oc.IsSensitive && Math.Abs(widthPercent - oc.WidthPercent) < 30 && Math.Abs(oc.MarginTop - topMargin) < 15 && oc.LinesForeground.Count + oc.LinesBackground.Count > 40) { if (IsMatch(bitmap, oc, 10)) { return(oc); } } } } if (deepSeek) { foreach (var oc in OcrCharacters) { if (Math.Abs(widthPercent - oc.WidthPercent) < 60 && Math.Abs(oc.MarginTop - topMargin) < 17 && oc.LinesForeground.Count + oc.LinesBackground.Count > 50) { if (IsMatch(bitmap, oc, maxWrongPixels)) { return(oc); } } } } return(null); }
internal static ImageSplitterItem GetExpandedSelectionNew(NikseBitmap bitmap, List<ImageSplitterItem> expandSelectionList) { int minimumX = expandSelectionList[0].X; int maximumX = expandSelectionList[expandSelectionList.Count - 1].X + expandSelectionList[expandSelectionList.Count - 1].NikseBitmap.Width; int minimumY = expandSelectionList[0].Y; int maximumY = expandSelectionList[0].Y + expandSelectionList[0].NikseBitmap.Height; var nbmp = new NikseBitmap(bitmap.Width, bitmap.Height); foreach (ImageSplitterItem item in expandSelectionList) { for (int y = 0; y < item.NikseBitmap.Height; y++) { for (int x = 0; x < item.NikseBitmap.Width; x++) { int a = item.NikseBitmap.GetAlpha(x, y); if (a > 100) nbmp.SetPixel(item.X + x, item.Y + y, Color.White); } } if (item.Y < minimumY) minimumY = item.Y; if (item.Y + item.NikseBitmap.Height > maximumY) maximumY = item.Y + item.NikseBitmap.Height; } nbmp.CropTransparentSidesAndBottom(0, true); int topCropping; nbmp = NikseBitmapImageSplitter.CropTopAndBottom(nbmp, out topCropping); return new ImageSplitterItem(minimumX, minimumY, nbmp); }
/// <summary> /// Create RLE buffer from bitmap /// </summary> /// <param name="bm">Bitmap to compress</param> /// <param name="palette">Palette used for bitmap encoding</param> /// <returns>RLE buffer</returns> private static byte[] EncodeImage(NikseBitmap bm, Dictionary <Color, int> palette) { var bytes = new List <Byte>(); for (int y = 0; y < bm.Height; y++) { var ofs = y * bm.Width; //eol = false; int x; int len; for (x = 0; x < bm.Width; x += len, ofs += len) { Color c = bm.GetPixel(x, y); byte color; if (palette.ContainsKey(c)) { color = (byte)palette[c]; } else { color = FindBestMatch(c, palette); } for (len = 1; x + len < bm.Width; len++) { if (bm.GetPixel(x + len, y) != c) { break; } } if (len <= 2 && color != 0) { // only a single occurrence -> add color bytes.Add(color); if (len == 2) { bytes.Add(color); } } else { if (len > 0x3fff) { len = 0x3fff; } bytes.Add(0); // rle id // commented out due to bug in SupRip /*if (color == 0 && x+len == bm.Width) * { * bytes.Add(0); * eol = true; * } * else */ if (color == 0 && len < 0x40) { // 00 xx -> xx times 0 bytes.Add((byte)len); } else if (color == 0) { // 00 4x xx -> xxx zeroes bytes.Add((byte)(0x40 | (len >> 8))); bytes.Add((byte)len); } else if (len < 0x40) { // 00 8x cc -> x times value cc bytes.Add((byte)(0x80 | len)); bytes.Add(color); } else { // 00 cx yy cc -> xyy times value cc bytes.Add((byte)(0xc0 | (len >> 8))); bytes.Add((byte)len); bytes.Add(color); } } } if (/*!eol &&*/ x == bm.Width) { bytes.Add(0); // rle id bytes.Add(0); } } int size = bytes.Count; byte[] retval = new byte[size]; for (int i = 0; i < size; i++) { retval[i] = bytes[i]; } return(retval); }