
從 Charlesw Tesseract 遷移到 IronOCR
本指南指導.NET開發人員從charlesw/tesseract NuGet包(Tesseract)遷移到IronOCR。 遷移主要針對一個特定問題:charlesw封裝器強加的原生二進制部署模型以及該模型迫使開發人員編寫的平台條件程式碼。曾經在CI中徘徊於DllNotFoundException、在Linux上與Leptonica程式庫路徑角力、或編寫與OCR無關的OS檢測塊的團隊會發現,此指南顯示了切換後消失的確切內容。
為什麼從Charlesw Tesseract遷移
存檔的charlesw/tesseract包給新專案帶來麻煩不是因為API不好,而是因為它所要求的部署模型是圍繞不再成立的假設設計的,而這些假設不適合現代.NET基礎設施。 以下是驅動遷移決策的因素:
每個平台的原生二進制部署。 Tesseract NuGet包隨平台特定的原生二進制作為:tesseract50.dll適用於Windows x64,對於x86有單獨的構建,libtesseract.so適用於Linux x64。這些二進制文件必須在執行時正確放置以使P/Invoke調用成功。 在開發人員工作站上,SDK會自動複製它們。 在Docker容器、ARM64構建代理或具有非標準應用程式根目錄的Azure App Service中,它們不會自動複製。 每個新的部署物件都會變成一個除錯會話。
Leptonica作為隱藏的依賴。 Tesseract的圖像載入是由Leptonica庫處理的,它與Tesseract二進制作為自己的原生DLL集分發。 在Windows上,leptonica-1.82.0.dll必須存在於輸出目錄中。 在Linux上,Leptonica共享庫必須捆綁或作為系統包安裝。 沒有Pix.LoadFromFile()處失敗,會出現無助於除錯的原生異常,並且修復它需要知道哪個系統包能解決依賴問題。
應用程式邏輯中的平台條件程式碼。 僅憑原生二進制載入和tessdata路徑解析的結合,迫使開發人員編寫RuntimeInformation.IsOSPlatform()檢查、容器上下文的環境變數檢測和按目標而異的路徑生成邏輯。 這些程式碼都不是OCR邏輯。 這是純粹因為包的二進制管理不完整而存在的部署箝制。
沒有補救路徑的存檔包。 自2021年以來,儲存庫已被存檔。當Linux主機上的系統包更新更改Leptonica ABI,或新.NET運行時更改原生二進制載入行為時,沒有版本可以更新。 唯一的選擇是fork原生構建管道或更換庫。
Tesseract 4.1.1 引擎凍結。 該包封裝了Tesseract 4.1.1。Tesseract 5重新編寫的LSTM模型在劣化文件上提供了顯著更高的精度。 該升級無法透過charlesw包獲得——需要更換庫。
缺乏標準模式的信心處理。 charlesw封裝器將iter.GetConfidence(PageIteratorLevel.Word)。 沒有標準的過濾API; 每個團隊都以不同的方式實施他們自己的門檻邏輯。
根本問題
charlesw封裝器需要在OCR運行之前配置平台特定的原生二進制:
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();' charlesw Tesseract: OS detection required just to find native DLLs
' DllNotFoundException on any platform where binaries do not resolve
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib")
End If
Dim engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath) ' Requires leptonica native DLL
Using page = engine.Process(img)
Return page.GetText()
End Using
End Using' charlesw Tesseract: OS detection required just to find native DLLs
' DllNotFoundException on any platform where binaries do not resolve
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib")
End If
Dim engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath) ' Requires leptonica native DLL
Using page = engine.Process(img)
Return page.GetText()
End Using
End UsingIronOCR沒有原生二進制配置:
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).TextIronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text##IronOCRvs Charlesw Tesseract:功能比較
下表涵蓋與評估此遷移相關的功能:
| 功能 | Charlesw Tesseract | IronOCR |
|---|---|---|
| 維護狀態 | 存檔(自2021年起無更新) | 積極維護 |
| Tesseract引擎版本 | 4.1.1(凍結) | 5(目前,已優化) |
| 授權 | Apache 2.0(免費) | 商業($999–$2,999 永久) |
| NuGet安裝 | Tesseract | IronOcr |
| 原生二進制管理 | 每個平台的DLL部署需要手動進行 | 捆綁,不需設定 |
| Leptonica依賴 | 需要leptonica-1.82.0.dll / libleptonica-dev | 不適用(內部處理) |
| Tessdata管理 | 手動下載和.csproj複製條目 | NuGet語言包 |
| 平台條件程式碼 | 多目標部署需要 | 不需要 |
| Docker部署 | 需要明確的tessdata COPY + Leptonica apt-get | 僅標準.NET容器要求 |
| ARM64支援 | 存檔後未確認 | 捆綁,已驗證 |
| 圖像輸入格式 | TIFF、PNG、BMP、JPG(透過Leptonica) | JPG、PNG、BMP、TIFF、GIF等 |
| 多頁TIFF | 手動框架迭代 | input.LoadImageFrames() |
| 本地PDF輸入 | 不(需要次要庫) | 是 |
| 可搜尋的PDF輸出 | 不是 | 是(result.SaveAsSearchablePdf()) |
| 內嵌預處理 | None | Deskew、去噪、對比度、二值化、銳化、縮放、膨脹、侵蝕、反轉 |
| 信心過濾API | 手動迭代器與GetConfidence() | result.Confidence, word.Confidence |
| 結構化結果 | 迭代器模式(ResultIterator) | 直接集合(頁、段落、行、詞) |
| 條碼識別 | 不是 | 是(在OCR處理期間) |
| 基於區域的OCR | 不是 | 是(CropRectangle) |
| 執行緒安全 | 呼叫者責任 | 內建 |
| 超過125種語言包 | 手動tessdata下載 | dotnet add package IronOcr.Languages.* |
| 跨平台.NET | 是(.NET Standard 2.0) | 是(.NET Framework 4.6.2+、.NET 5/6/7/8/9) |
| 安全補丁節奏 | 無(存檔) | 定期發佈 |
快速啟動:Charlesw Tesseract到IronOCR的遷移
步驟1:替換NuGet包
移除charlesw Tesseract包:
dotnet remove package Tesseract
從NuGet安裝IronOCR:
步驟2:更新命名空間
// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;' Before (charlesw Tesseract)
Imports Tesseract
' After (IronOCR)
Imports IronOcr' Before (charlesw Tesseract)
Imports Tesseract
' After (IronOCR)
Imports IronOcr步驟3:初始化許可證
在應用程式啟動時新增此調用一次,在任何OCR操作運行之前:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"免費試用授權在IronOCR授權頁面可獲得。 試用去除了輸出水印,並啟用了完整API存取。
程式碼遷移範例
移除原生二進制路徑配置
charlesw/tesseract專案中最常見的初始化模式是一個構建tessdata路徑並配置每個環境的原生庫載入的工廠或助手類。 這段程式碼純粹是由於封裝器的部署模型存在。
Charlesw Tesseract 方法:
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());Public NotInheritable Class OcrEngineFactory
Private Sub New()
End Sub
Private Shared Function GetTessDataPath() As String
' Different path per environment — all wrong until explicitly configured
If Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") = "true" Then
Return "/app/tessdata" ' Docker
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Return Path.Combine(AppContext.BaseDirectory, "tessdata") ' Linux bare metal
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.OSX) Then
Return "/usr/local/share/tessdata" ' macOS Homebrew install
End If
Return ".\tessdata" ' Windows dev machine
End Function
Public Shared Function Create(Optional language As String = "eng") As TesseractEngine
' If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
' If tessdata folder is missing: TesseractException at engine construction
Return New TesseractEngine(GetTessDataPath(), language, EngineMode.Default)
End Function
End Class
' Call site
Using engine = OcrEngineFactory.Create()
Using img = Pix.LoadFromFile("invoice.jpg")
Using page = engine.Process(img)
Console.WriteLine(page.GetText())
End Using
End Using
End UsingPublic NotInheritable Class OcrEngineFactory
Private Sub New()
End Sub
Private Shared Function GetTessDataPath() As String
' Different path per environment — all wrong until explicitly configured
If Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") = "true" Then
Return "/app/tessdata" ' Docker
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Return Path.Combine(AppContext.BaseDirectory, "tessdata") ' Linux bare metal
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.OSX) Then
Return "/usr/local/share/tessdata" ' macOS Homebrew install
End If
Return ".\tessdata" ' Windows dev machine
End Function
Public Shared Function Create(Optional language As String = "eng") As TesseractEngine
' If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
' If tessdata folder is missing: TesseractException at engine construction
Return New TesseractEngine(GetTessDataPath(), language, EngineMode.Default)
End Function
End Class
' Call site
Using engine = OcrEngineFactory.Create()
Using img = Pix.LoadFromFile("invoice.jpg")
Using page = engine.Process(img)
Console.WriteLine(page.GetText())
End Using
End Using
End UsingIronOCR方法:
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("invoice.jpg")
Console.WriteLine(result.Text)IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("invoice.jpg")
Console.WriteLine(result.Text)整個OcrEngineFactory類被刪除。 平台條件的路徑邏輯、DOTNET_RUNNING_IN_CONTAINER檢查和Leptonica DLL依賴都隨之消失。 每個環境——開發人員工作站、CI代理、Docker容器、雲VM——都運行相同的兩行程式碼。 IronTesseract安裝指南涵蓋了當預設設定需要調整時的配置選項,但對於大多數部署來說不需要這些調整。
Leptonica圖像轉換替換
charlesw封裝器使用Leptonica的Pix型別作為其圖像表示。 任何在OCR之前操作圖像的程式碼都必須透過Pix進行轉換,這需要Leptonica原生DLL載入和操作。 使用OcrInput替換此模式完全消除了Leptonica依賴。
Charlesw Tesseract 方法:
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
//不是direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
//不是direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}Public Function ProcessInMemoryImage(bitmap As Bitmap) As String
'不是direct Bitmap → Pix conversion; must write to temp file
Dim tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png")
Try
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using pix = Pix.LoadFromFile(tempPath) ' Leptonica file I/O
Using page = engine.Process(pix)
Return page.GetText()
End Using
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
End FunctionPublic Function ProcessInMemoryImage(bitmap As Bitmap) As String
'不是direct Bitmap → Pix conversion; must write to temp file
Dim tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png")
Try
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using pix = Pix.LoadFromFile(tempPath) ' Leptonica file I/O
Using page = engine.Process(pix)
Return page.GetText()
End Using
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
End FunctionIronOCR方法:
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}' OcrInput accepts byte arrays and streams — no temp file, no Leptonica
Public Function ProcessInMemoryImage(imageBytes As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageBytes) ' Direct byte array loading
Dim result = (New IronTesseract()).Read(input)
Return result.Text
End Using
End Function
' Or from a stream — same pattern
Public Function ProcessFromStream(imageStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(imageStream)
Dim result = (New IronTesseract()).Read(input)
Return result.Text
End Using
End Function' OcrInput accepts byte arrays and streams — no temp file, no Leptonica
Public Function ProcessInMemoryImage(imageBytes As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageBytes) ' Direct byte array loading
Dim result = (New IronTesseract()).Read(input)
Return result.Text
End Using
End Function
' Or from a stream — same pattern
Public Function ProcessFromStream(imageStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(imageStream)
Dim result = (New IronTesseract()).Read(input)
Return result.Text
End Using
End Function臨時文件的往返消失。 沒有文件寫入磁碟,沒有調用Leptonica DLL進行轉換,也沒有finally塊需要清理。圖像輸入指南和流輸入指南記錄了所有支持的輸入來源,包括從URL和記憶體映射文件載入。
信心門檻過濾
charlesw封裝器在兩個層次上暴露信心:iter.GetConfidence(PageIteratorLevel.Word)對個別字詞。 從輸出中過濾低置信度的單詞需要手動管理迭代器迴圈。 IronOCR直接在結果物件中暴露信心,將門檻邏輯轉化為LINQ表達式。
Charlesw Tesseract 方法:
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Single = 0.8F) As List(Of String)
Dim highConfidenceWords As New List(Of String)()
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath)
Using page = engine.Process(img)
' Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}")
Using iter = page.GetIterator()
iter.Begin()
Do
If iter.IsAtBeginningOf(PageIteratorLevel.Word) Then
Dim wordText = iter.GetText(PageIteratorLevel.Word)?.Trim()
Dim wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100.0F ' Returns 0-100
If Not String.IsNullOrEmpty(wordText) And wordConf >= minConfidence Then
highConfidenceWords.Add(wordText)
End If
End If
Loop While iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word)
End Using
End Using
End Using
End Using
Return highConfidenceWords
End FunctionPublic Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Single = 0.8F) As List(Of String)
Dim highConfidenceWords As New List(Of String)()
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath)
Using page = engine.Process(img)
' Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}")
Using iter = page.GetIterator()
iter.Begin()
Do
If iter.IsAtBeginningOf(PageIteratorLevel.Word) Then
Dim wordText = iter.GetText(PageIteratorLevel.Word)?.Trim()
Dim wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100.0F ' Returns 0-100
If Not String.IsNullOrEmpty(wordText) And wordConf >= minConfidence Then
highConfidenceWords.Add(wordText)
End If
End If
Loop While iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word)
End Using
End Using
End Using
End Using
Return highConfidenceWords
End FunctionIronOCR方法:
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Double = 80.0) As List(Of String)
Dim result = New IronTesseract().Read(imagePath)
Console.WriteLine($"Page confidence: {result.Confidence}%")
Return result.Pages _
.SelectMany(Function(p) p.Lines) _
.SelectMany(Function(l) l.Words) _
.Where(Function(w) w.Confidence >= minConfidence AndAlso Not String.IsNullOrWhiteSpace(w.Text)) _
.Select(Function(w) w.Text) _
.ToList()
End FunctionPublic Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Double = 80.0) As List(Of String)
Dim result = New IronTesseract().Read(imagePath)
Console.WriteLine($"Page confidence: {result.Confidence}%")
Return result.Pages _
.SelectMany(Function(p) p.Lines) _
.SelectMany(Function(l) l.Words) _
.Where(Function(w) w.Confidence >= minConfidence AndAlso Not String.IsNullOrWhiteSpace(w.Text)) _
.Select(Function(w) w.Text) _
.ToList()
End Function迭代器狀態機消失。 IronOCR的信心值始終在0到100範圍內,不需要除以100。 信心分數指南涵蓋了每個單詞、每行和每頁的信心存取模式。 閱讀結果指南展示了如何導航完整的結構化結果層級。
多頁TIFF批處理
在文件掃描工作流中,多幀TIFF文件很常見。 charlesw封裝器沒有內建的多幀TIFF支持; 每個幀必須在處理前手動提取。 IronOCR原生處理多幀TIFF,只需一次載入調用。
Charlesw Tesseract 方法:
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}Public Function ProcessMultiFrameTiff(tiffPath As String) As String
Dim fullText = New StringBuilder()
Using tiffImage = Image.FromFile(tiffPath)
Dim frameCount = tiffImage.GetFrameCount(FrameDimension.Page)
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
For i As Integer = 0 To frameCount - 1
tiffImage.SelectActiveFrame(FrameDimension.Page, i)
' Must save each frame as a temp file for Pix to load
Dim tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png")
Try
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using pix = Pix.LoadFromFile(tempPath)
Using page = engine.Process(pix)
fullText.AppendLine(page.GetText())
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
Next
End Using
End Using
Return fullText.ToString()
End FunctionPublic Function ProcessMultiFrameTiff(tiffPath As String) As String
Dim fullText = New StringBuilder()
Using tiffImage = Image.FromFile(tiffPath)
Dim frameCount = tiffImage.GetFrameCount(FrameDimension.Page)
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
For i As Integer = 0 To frameCount - 1
tiffImage.SelectActiveFrame(FrameDimension.Page, i)
' Must save each frame as a temp file for Pix to load
Dim tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png")
Try
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using pix = Pix.LoadFromFile(tempPath)
Using page = engine.Process(pix)
fullText.AppendLine(page.GetText())
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
Next
End Using
End Using
Return fullText.ToString()
End FunctionIronOCR方法:
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}Public Function ProcessMultiFrameTiff(ByVal tiffPath As String) As String
Using input = New OcrInput()
input.LoadImageFrames(tiffPath) ' All frames loaded in one call
Dim result = (New IronTesseract()).Read(input)
' Pages maps directly to TIFF frames
For Each page In result.Pages
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words")
Next
Return result.Text
End Using
End FunctionPublic Function ProcessMultiFrameTiff(ByVal tiffPath As String) As String
Using input = New OcrInput()
input.LoadImageFrames(tiffPath) ' All frames loaded in one call
Dim result = (New IronTesseract()).Read(input)
' Pages maps directly to TIFF frames
For Each page In result.Pages
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words")
Next
Return result.Text
End Using
End Function臨時文件提取迴圈和每幀處理鏈消失。 透過FrameDimension.Page檢測幀數消失。 IronOCR將TIFF幀映射到OcrResult.Pages,因此每幀文字存取不需要額外的迭代邏輯。 TIFF/GIF輸入指南涵蓋了幀選擇和部分TIFF處理的其他選項。
可搜尋PDF生成
charlesw封裝器僅生成文字輸出。 將掃描文件轉換為可搜尋的PDF——文件管理系統的一個常見要求——需要一個次要的PDF庫(IronPDF、PDFSharp或類似庫)將提取的文字覆蓋在原始圖像頁上。 IronOCR透過一個方法調用生成可搜尋的PDF,無需次級庫。
Charlesw Tesseract 方法:
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
' Step 1: Extract text from image
Dim extractedText As String
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath)
Using page = engine.Process(img)
extractedText = page.GetText()
End Using
End Using
End Using
' Step 2: Build a PDF with the image as background and text overlay
' Requires a separate PDF library (not shown — 50-100+ additional lines)
' The text layer must be positioned to match the original image layout
' Word-level coordinates from the iterator are needed for accurate alignment
Throw New NotImplementedException("Searchable PDF generation requires a separate PDF library. " & "Add PdfSharp, IronPDF, or similar, then implement text layer overlay.")
End SubPublic Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
' Step 1: Extract text from image
Dim extractedText As String
Using engine = New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img = Pix.LoadFromFile(imagePath)
Using page = engine.Process(img)
extractedText = page.GetText()
End Using
End Using
End Using
' Step 2: Build a PDF with the image as background and text overlay
' Requires a separate PDF library (not shown — 50-100+ additional lines)
' The text layer must be positioned to match the original image layout
' Word-level coordinates from the iterator are needed for accurate alignment
Throw New NotImplementedException("Searchable PDF generation requires a separate PDF library. " & "Add PdfSharp, IronPDF, or similar, then implement text layer overlay.")
End SubIronOCR方法:
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
//不是secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
//不是secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(imagePath)
result.SaveAsSearchablePdf(outputPdfPath)
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}")
End Sub
Public Sub MakePdfSearchable(scannedPdfPath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(scannedPdfPath)
result.SaveAsSearchablePdf(outputPdfPath)
End SubPublic Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(imagePath)
result.SaveAsSearchablePdf(outputPdfPath)
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}")
End Sub
Public Sub MakePdfSearchable(scannedPdfPath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(scannedPdfPath)
result.SaveAsSearchablePdf(outputPdfPath)
End SubSaveAsSearchablePdf()將OCR文字嵌入為對齊到識別字詞的隱藏層,使文件變得全文字可搜尋,並且不改變其外觀。 可搜尋PDF操作指南涵蓋頁面範圍選擇和壓縮選項。 可用的工作範例在可搜尋PDF範例頁面上有提供。
##Charlesw TesseractAPI 到IronOCR映射參考
| Charlesw Tesseract | IronOCR 等效 |
|---|---|
new TesseractEngine(tessDataPath, "eng", EngineMode.Default) | new IronTesseract() |
Pix.LoadFromFile(imagePath) | input.LoadImage(imagePath) |
Pix.LoadFromMemory(bytes) | input.LoadImage(imageBytes) |
engine.Process(pix) | ocr.Read(input) |
page.GetText() | result.Text |
page.GetMeanConfidence() | result.Confidence(0–100範圍) |
page.GetIterator() | result.Words(直接集合) |
iter.GetText(PageIteratorLevel.Word) | word.Text |
iter.GetConfidence(PageIteratorLevel.Word) | word.Confidence |
iter.TryGetBoundingBox(PageIteratorLevel.Word, out var b) | word.X, word.Y, word.Width, word.Height |
iter.GetText(PageIteratorLevel.Para) | paragraph.Text |
iter.IsAtBeginningOf(PageIteratorLevel.Block) | page.Paragraphs(直接迭代) |
EngineMode.Default | 自動(Tesseract 5 LSTM預設) |
EngineMode.TesseractOnly | ocr.Configuration.PageSegmentationMode |
手動tessdata .traineddata文件 | dotnet add package IronOcr.Languages.French |
TessDataPath常數 + .csproj複製條目 | 不適用──捆綁 |
Pix.LoadFromFile()透過Leptonica DLL | input.LoadImage() ——無需原生DLL |
平台GetTessDataPath()方法 | 不適用——淘汰 |
leptonica-1.82.0.dll / libleptonica-dev | 不適用——無Leptonica依賴 |
| 手動臨時文件框架提取供TIFF使用 | input.LoadImageFrames(tiffPath) |
| 無可搜尋PDF輸出 | result.SaveAsSearchablePdf(outputPath) |
new TesseractEngine()每執行緒 | 一個IronTesseract——執行緒安全 |
常見的遷移問題与解決方案
問題1:Leptonica 或 Tesseract 二進制未找到的DllNotFoundException
Charlesw Tesseract: System.DllNotFoundException: Unable to load DLL 'leptonica-1.82.0': The specified module could not be found. 當Leptonica原生DLL不在預期位置時會觸發此異常。 在全新Docker容器、CI代理或NuGet包的runtimes/目錄未正確複製的任何環境中很常見。
解決方案: 移除Tesseract包。 安裝IronOcr。 IronOCR將所有原生二進制捆綁在內部,不會P/Invoke到系統Leptonica。 由於沒有外部Leptonica依賴,因此不會發生例外狀況:
無需apt-get install libleptonica-dev。 原生DLL的<CopyToOutputDirectory>條目同樣不需要。
問題2:部署後tessdata路徑錯誤
Charlesw Tesseract: Tesseract.TesseractException: Failed to initialise tesseract engine. 當TessDataPath在運行時無法解析時觸發。它在編譯時沒有報錯,僅在運行時失敗,失敗路徑取決於部署環境。
解決方案: IronOCR中不存在tessdata路徑概念。 刪除常量、刪除.csproj中的XML,並刪除構建它的工廠方法。 語言資料作為NuGet包分發:
# Replace this manual tessdata file management:
# tessdata/eng.traineddata (15 MB, manually downloaded)
# tessdata/fra.traineddata (15 MB, manually downloaded)
# .csproj <CopyToOutputDirectory> entry
# With NuGet packages:
dotnet add package IronOcr.Languages.French
多語言指南顯示如何在新增語言包後配置多語言識別。
問題3:基礎映像更新時容器構建崩潰
Charlesw Tesseract: Dockerfile包含apt-get install -y libleptonica-dev以滿足Leptonica的原生依賴。 當基本映像從Debian Bullseye移動到Bookworm,或在分發過程中更改Leptonica包名稱時,構建會因apt錯誤而崩潰。 修復它需要知道在新分發上使用哪個包名。
解決方案:完全移除Leptonica apt-get行。 Linux上的IronOCR僅需標準libgdiplus包,此任何使用System.Drawing的.NET應用程式已經需要:
# Before: Leptonica explicit install — breaks on base image updates
RUN apt-get update && apt-get install -y libleptonica-dev
# After: standard .NET Linux requirement only
RUN apt-get update && apt-get install -y libgdiplus
Docker部署指南提供經測試的Dockerfile模板適用於常見的基本映像。 不需要特定於charlesw的基礎設施程式碼。
問題4:迭代器模式在空白或空格頁上失效
Charlesw Tesseract: NullReferenceException。
解決方案: IronOCR結果集合從不為null。 空白頁面返回空集合。 檢查文字內容而非空值引用:
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}' Before: null checks required at every iterator level
Dim wordText As String = iter.GetText(PageIteratorLevel.Word)
If wordText IsNot Nothing AndAlso wordText.Trim().Length > 0 Then
results.Add(wordText.Trim())
End If
' After: collection is safe to enumerate; check content as needed
For Each word In result.Pages.SelectMany(Function(p) p.Lines).SelectMany(Function(l) l.Words)
If Not String.IsNullOrWhiteSpace(word.Text) Then
results.Add(word.Text)
End If
Next' Before: null checks required at every iterator level
Dim wordText As String = iter.GetText(PageIteratorLevel.Word)
If wordText IsNot Nothing AndAlso wordText.Trim().Length > 0 Then
results.Add(wordText.Trim())
End If
' After: collection is safe to enumerate; check content as needed
For Each word In result.Pages.SelectMany(Function(p) p.Lines).SelectMany(Function(l) l.Words)
If Not String.IsNullOrWhiteSpace(word.Text) Then
results.Add(word.Text)
End If
Next問題5:負載下的執行緒安全違規
Charlesw Tesseract: TesseractEngine不支持執行緒安全。 在ASP.NET應用程式中共享一個實例給並發請求會導致存取違規或結果損壞。 標準修正是在每個執行緒建立一個引擎,但這不是從API可以明顯看出的,當錯誤發生時,錯誤消息是難以理解的原生異常。
解決方案: IronTesseract支持執行緒安全。 一個實例可以服務並發請求,或為最大吞吐量,每個執行緒建立一個Parallel.ForEach——這兩種模式的工作不需要修改:
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});Dim results As New System.Collections.Concurrent.ConcurrentBag(Of String)()
Parallel.ForEach(imageFiles, Sub(imagePath)
Dim ocr = New IronTesseract()
Dim result = ocr.Read(imagePath)
results.Add(result.Text)
End Sub)Dim results As New System.Collections.Concurrent.ConcurrentBag(Of String)()
Parallel.ForEach(imageFiles, Sub(imagePath)
Dim ocr = New IronTesseract()
Dim result = ocr.Read(imagePath)
results.Add(result.Text)
End Sub)async OCR指南涵蓋ASP.NET Core控制器的异步模式,執行緒阻塞不被接受。
問題6:運行時缺少ARM64二進制
Charlesw Tesseract:在AWS Graviton(Linux ARM64)或Apple Silicon CI代理上,存檔包可能不提供ARM64原生二進制。 故障是BadImageFormatException在引擎建立時——一個包無法支持的平台上的運行時錯誤。
解決方案: IronOCR提供經驗證的ARM64二進制適用於Linux和macOS。 部署到ARM64無需程式碼更改。 Linux部署指南和macOS部署指南確認了支持的運行時標識符。
Charlesw Tesseract遷移清單
遷移前
審計程式碼庫以識別所有將改變的模式:
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .
# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .
# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .
# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .
# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .
# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .
# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .
# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
註釋項目所針對的部署環境(Docker、Linux、ARM64、Azure、AWS)——這些是charlesw/tesseract需要最多配置而IronOCR消除這種配置的環境。
程式碼遷移
1.運行dotnet remove package Tesseract解除安裝charlesw包裝器
2.運行dotnet add package IronOcr安裝IronOCR
3.在應用程式啟動時新增IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
4.用using Tesseract;語句
5.刪除tessdata路徑常量及任何每環境建立路徑的方法
6.刪除為選擇tessdata路徑而寫的所有RuntimeInformation.IsOSPlatform()塊
7.從所有<CopyToOutputDirectory>條目
8.從源控管或部署工件儲存中刪除tessdata .traineddata文件
9.對每個先前部署作為dotnet add package IronOcr.Languages.*
10.用TesseractEngine + Pix.LoadFromFile() + engine.Process()鏈
11.將所有input.LoadImage()
12.將所有result.Text
13.用result.Pages上的直接集合存取替換基於迭代器的單詞/行提取
14.用LINQ在iter.GetConfidence()門檻邏輯
15.從 Dockerfile 和部署腳本中移除 libleptonica-dev / leptonica-1.82.0.dll
遷移後
完成程式碼更新後檢查以下內容:
- OCR在Windows上運行成功,沒有任何原生DLL錯誤
- OCR在Docker Linux容器中運行成功,除
apt-get變更 - 如果部署矩陣中包含該平台,OCR在ARM64上產生文字輸出
- 多頁TIFF文件不只在第一幀返回文字,而是在所有幀上返回文字
- 信任過濾返回與之前迭代器實現相同邏輯集的高信任度單詞
- 安裝語言NuGet包後,語言特定文件(法語、德語等)正確識別
- 並行OCR操作無異常或損壞輸出完成
- 以前僅返回文字的實現現在產生可搜尋PDF輸出
- CI/CD管道構建時沒有任何tessdata下載步驟或Leptonica安裝命令 對同一圖像組進行驗證,做為過去實現的煙霧測試
遷移至IronOCR的主要好處
自包裝部署模型。 遷移後,OCR依賴由一個NuGet包引用完全描述。 源控制中無tessdata文件,無CopyToOutputDirectory條目,無原生DLL部署步驟,無Leptonica系統包。 以前需要多步工件管理的CI/CD管道簡化為dotnet publish。 為支持charlesw包裝器而積累的與部署相關的程式碼永久消失。
平台可移植性無需條件邏輯。 相同的應用程式二進制作為可在Windows x64、Linux x64、Linux ARM64、macOS x64和macOS ARM64上運行,無需修改。 無論是AWS Graviton、Apple Silicon CI還是樹莓派,增加ARM64部署目標的團隊都不再編寫新的平台檢測程式碼。 Linux部署指南和AWS部署指南確認了經測試的配置。
Tesseract 5在內建前處理的準確性。從Tesseract 4.1.1到Tesseract 5的躍升提高了在劣化文件上的識別。 IronOCR在引擎升級之上增加了自動預處理,在引擎處理每個圖片前應用Deskew、去噪、對比度正規化和二值化。 以前需要自定義預處理管道才能達到可接受準確度門檻的文件現在不需要額外程式碼即可達到這些門檻。 圖像質量校正指南記錄了需要超過預設值調整的情況時的明確預處理選項。
直接結果導航替換了迭代器樣板。 charlesw迭代器模式——GetIterator(), Begin(), Next(), IsAtBeginningOf(), 全程空值檢查——被簡單集合取代。 詞、行、段落和頁為結果物件上的屬性。 基於信心的過濾是一個LINQ表達式。 提取詞彙資料的程式碼以前需要15–30行迭代器管理; IronOCR等價只需2–3行。 OCR結果功能頁匯總了完整的結構化輸出模型。
無需次級庫即可生成可搜尋PDF輸出。result.SaveAsSearchablePdf()產生一個帶有對齊到識別字詞的文字層的PDF,不需要次級PDF庫。 接受可搜尋PDF的文件管理系統不再需要單獨的PDF生成步驟。提供提取文字的相同結果物件還寫入可搜尋文件,將文件處理管道保持在單一庫依賴。
積極維護和安全補丁覆蓋。 IronOCR接收定期更新,跟踪Tesseract 5模型的改進、.NET運行環境相容性驗證以及基礎C++引擎的安全補丁覆蓋。依賴不再承擔存檔包的風險,合規審查不會為缺少的安全補丁路徑生成發現。 隨著.NET 10自2026年普遍可用,IronOCR文件中心將反映當前相容性,無需變通或分支。
相關文章


