Skip to content

Commit 28dfce3

Browse files
committed
Add OCR support (including text, bar codes and QR codes) on the "Image" tab for Windows 10, 11
1 parent 8e8b07a commit 28dfce3

File tree

13 files changed

+623
-125
lines changed

13 files changed

+623
-125
lines changed

Build/Build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<WindowTextExtractorDestFileWin64 Include="$(ApplicationPath)\WindowTextExtractor64.exe" />
2020
<WindowTextExtractorSourceConfgiFile Include="$(WindowTextExtractorProjectPath)\bin\x86\Release\WindowTextExtractor.exe.config" />
2121
<WindowTextExtractorDestConfgiFile Include="$(ApplicationPath)\WindowTextExtractor.exe.config" />
22-
<WindowTextExtractorSourceLibFiles Include="$(WindowTextExtractorProjectPath)\bin\x86\Release\Libs\*.dll" />
22+
<WindowTextExtractorSourceLibFiles Include="$(WindowTextExtractorProjectPath)\bin\x86\Release\*.dll" />
2323
<WindowTextExtractorDestLibFiles Include="$(ApplicationPath)\" />
2424
</ItemGroup>
2525

WindowTextExtractor/App.config

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<?xml version="1.0" encoding="utf-8" ?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<configuration>
33
<startup useLegacyV2RuntimeActivationPolicy="true">
4-
<supportedRuntime version="v4.0" />
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
55
</startup>
6-
</configuration>
6+
</configuration>

WindowTextExtractor/Extensions/StringExtensions.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23

34
namespace WindowTextExtractor.Extensions
45
{
@@ -13,5 +14,78 @@ public static string TrimEnd(this string text, string value, StringComparison co
1314
}
1415
return result;
1516
}
17+
18+
public static string TryFixEveryWordLetterNumberErrors(this string text)
19+
{
20+
var listOfWords = text.Split(' ');
21+
var fixedWords = new List<string>();
22+
23+
foreach (var word in listOfWords)
24+
{
25+
var newWord = word.TryFixNumberLetterErrors();
26+
fixedWords.Add(newWord);
27+
}
28+
29+
return string.Join(" ", fixedWords.ToArray())
30+
.Replace("\t ", "\t")
31+
.Replace("\r ", "\r")
32+
.Replace("\n ", "\n")
33+
.Trim();
34+
}
35+
36+
public static string TryFixNumberLetterErrors(this string text)
37+
{
38+
if (text.Length < 5)
39+
{
40+
return text;
41+
}
42+
43+
var totalNumbers = 0;
44+
var totalLetters = 0;
45+
46+
foreach (char charFromString in text)
47+
{
48+
if (char.IsNumber(charFromString))
49+
{
50+
totalNumbers++;
51+
}
52+
53+
if (char.IsLetter(charFromString))
54+
{
55+
totalLetters++;
56+
}
57+
}
58+
59+
var fractionNumber = totalNumbers / (float)text.Length;
60+
var letterNumber = totalLetters / (float)text.Length;
61+
62+
if (fractionNumber > 0.6)
63+
{
64+
text = text.TryFixToNumbers();
65+
}
66+
else if (letterNumber > 0.6)
67+
{
68+
text = text.TryFixToLetters();
69+
}
70+
71+
return text;
72+
}
73+
74+
public static string TryFixToNumbers(this string text) => text
75+
.Replace('o', '0')
76+
.Replace('O', '0')
77+
.Replace('Q', '0')
78+
.Replace('c', '0')
79+
.Replace('C', '0')
80+
.Replace('i', '1')
81+
.Replace('I', '1')
82+
.Replace('l', '1')
83+
.Replace('g', '9');
84+
85+
public static string TryFixToLetters(this string text) => text
86+
.Replace('0', 'o')
87+
.Replace('4', 'h')
88+
.Replace('9', 'g')
89+
.Replace('1', 'l');
1690
}
1791
}

WindowTextExtractor/Forms/MainForm.Designer.cs

Lines changed: 140 additions & 95 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

WindowTextExtractor/Forms/MainForm.cs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Text;
1313
using System.Linq;
1414
using System.Xml.Linq;
15+
using Windows.Media.Ocr;
1516
using WindowTextExtractor.Extensions;
1617
using WindowTextExtractor.Utils;
1718
using WindowTextExtractor.Diagnostics;
@@ -115,6 +116,14 @@ protected override void OnLoad(EventArgs e)
115116
font.Dispose();
116117
}
117118

119+
try
120+
{
121+
BindLanguages();
122+
}
123+
catch
124+
{
125+
}
126+
118127
#if WIN32
119128
if (Environment.Is64BitOperatingSystem)
120129
{
@@ -433,7 +442,18 @@ private void btnRecord_Click(object sender, EventArgs e)
433442
_startRecordingTime = _isRecording ? DateTime.Now : (DateTime?)null;
434443
if (_isRecording)
435444
{
436-
_videoWriter.Open(_videoFileName, _image.Width, _image.Height, _fps, VideoCodec.Raw);
445+
try
446+
{
447+
_videoWriter.Open(_videoFileName, _image.Width, _image.Height, _fps, VideoCodec.Raw);
448+
}
449+
catch (Exception ex)
450+
{
451+
_startRecordingTime = null;
452+
_isRecording = false;
453+
_videoWriter.Close();
454+
MessageBox.Show($"Failed to start recording a video file. {ex.Message}", AssemblyUtils.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
455+
return;
456+
}
437457
}
438458
else
439459
{
@@ -446,13 +466,52 @@ private void btnRecord_Click(object sender, EventArgs e)
446466
button.Text = isRecording ? "Stop" : "Record";
447467
btnTarget.Enabled = !isRecording;
448468
btnShowHide.Enabled = !isRecording;
469+
btnGrab.Enabled = !isRecording;
449470
cmbRefresh.Enabled = !isRecording;
450471
cmbCaptureCursor.Enabled = !isRecording;
472+
cmbLanguages.Enabled = !isRecording;
451473
btnBrowseFile.Enabled = !isRecording;
452474
numericFps.Enabled = !isRecording;
453475
numericScale.Enabled = !isRecording;
454476
}
455477

478+
private void btnGrab_Click(object sender, EventArgs e)
479+
{
480+
lock (_lockObject)
481+
{
482+
if (!_isRecording)
483+
{
484+
var text = string.Empty;
485+
try
486+
{
487+
text = ImageUtils.ExtractTextAsync((Bitmap)_image.Clone(), cmbLanguages.SelectedValue as string).GetAwaiter().GetResult();
488+
var barcodes = ImageUtils.ExtractBarcodes((Bitmap)_image.Clone());
489+
if (!string.IsNullOrEmpty(barcodes))
490+
{
491+
text += Environment.NewLine + barcodes;
492+
}
493+
}
494+
catch (Exception ex)
495+
{
496+
MessageBox.Show($"Failed to recognize a text in the image. {ex.Message}", AssemblyUtils.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
497+
return;
498+
}
499+
500+
if (string.IsNullOrEmpty(text))
501+
{
502+
MessageBox.Show("Text is not found in the image.", AssemblyUtils.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
503+
}
504+
else
505+
{
506+
txtContent.Text = text;
507+
txtContent.ScrollTextToEnd();
508+
AddTextToList(text);
509+
tabContent.SelectedTab = tabpText;
510+
}
511+
}
512+
}
513+
}
514+
456515
private void btnBrowseFile_Click(object sender, EventArgs e)
457516
{
458517
var dialog = new SaveFileDialog
@@ -798,8 +857,11 @@ private void InitTimers(int fps)
798857
private void EnableImageTabControls()
799858
{
800859
btnRecord.Visible = _imageTab && btnShowHide.Visible;
860+
btnGrab.Visible = _imageTab && btnShowHide.Visible;
801861
lblRefresh.Visible = _imageTab && btnShowHide.Visible;
802862
cmbRefresh.Visible = _imageTab && btnShowHide.Visible;
863+
lblLanguages.Visible = _imageTab && btnShowHide.Visible;
864+
cmbLanguages.Visible = _imageTab && btnShowHide.Visible;
803865
lblCaptureCursor.Visible = _imageTab && btnShowHide.Visible;
804866
cmbCaptureCursor.Visible = _imageTab && btnShowHide.Visible;
805867
lblFps.Visible = _imageTab && btnShowHide.Visible;
@@ -917,6 +979,13 @@ private void AddTextToList(string text)
917979
gvTextList.FirstDisplayedScrollingRowIndex = index;
918980
}
919981

982+
private void BindLanguages()
983+
{
984+
cmbLanguages.DisplayMember = "Text";
985+
cmbLanguages.ValueMember = "Value";
986+
cmbLanguages.DataSource = OcrEngine.AvailableRecognizerLanguages.Select(x => new { Text = x.DisplayName, Value = x.LanguageTag }).ToList();
987+
}
988+
920989
private void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
921990
{
922991
var ex = e.ExceptionObject as Exception;
@@ -925,6 +994,6 @@ private void OnCurrentDomainUnhandledException(object sender, UnhandledException
925994
}
926995

927996
private void OnThreadException(object sender, ThreadExceptionEventArgs e) =>
928-
MessageBox.Show(e.Exception.ToString(), AssemblyUtils.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
997+
MessageBox.Show(e.Exception.Message, AssemblyUtils.AssemblyTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
929998
}
930999
}

WindowTextExtractor/Forms/MainForm.resx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,28 +150,28 @@
150150
<metadata name="toolTipForButton.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
151151
<value>339, 17</value>
152152
</metadata>
153-
<metadata name="clmnEnvironmentName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
153+
<metadata name="clmnName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
154154
<value>True</value>
155155
</metadata>
156-
<metadata name="clmnEnvironmentValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
156+
<metadata name="clmnValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
157157
<value>True</value>
158158
</metadata>
159-
<metadata name="clmnName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
159+
<metadata name="dataGridColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
160160
<value>True</value>
161161
</metadata>
162-
<metadata name="clmnValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
162+
<metadata name="dataGridColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
163163
<value>True</value>
164164
</metadata>
165-
<metadata name="clmnName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
165+
<metadata name="clmnEnvironmentName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
166166
<value>True</value>
167167
</metadata>
168-
<metadata name="clmnValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
168+
<metadata name="clmnEnvironmentValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
169169
<value>True</value>
170170
</metadata>
171-
<metadata name="dataGridColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
171+
<metadata name="clmnEnvironmentName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
172172
<value>True</value>
173173
</metadata>
174-
<metadata name="dataGridColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
174+
<metadata name="clmnEnvironmentValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
175175
<value>True</value>
176176
</metadata>
177177
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
1.35 MB
Binary file not shown.
157 KB
Binary file not shown.
5.1 MB
Binary file not shown.

WindowTextExtractor/Properties/Settings.Designer.cs

Lines changed: 9 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)