從TesseractOcrMaui遷移到IronOCR
本指南完整地介紹了從TesseractOcrMaui遷移到IronOCR的過程,並為每一步提供了實用的前後程式碼範例。此指南面向已決定超越MAUI平台限制,並需要將程式庫系統化地應用於移動應用程式、伺服器端API、背景工作者和雲功能的開發者。 不需要閱讀比較文章。
為什麼要從TesseractOcrMaui遷移
TesseractOcrMaui的誕生是為了解決一個現實問題:現有的.NET Tesseract封裝無法自行解決行動平台的互操作性。 對於沒有伺服器佔用的純MAUI原型,它填補了這個空白。當產品超越這一狹隘範疇後,問題就會浮現。
僅限MAUI的目標框架阻止程式碼共享。 TesseractOcrMaui提供的目標僅限於net8.0-windows,這都是MAUI平台的標誌。 該程式包不包含netstandard2.1,也沒有與伺服器相容的目標。 從類別程式庫、ASP.NET Core專案或Azure Function來引用將會產生編譯錯誤。 沒有替代方案:該套件從架構上無法在MAUI主機以外運行。每次在非MAUI上下文中出現OCR需求時,都必須引入並平行維護第二個程式庫。
強制性的MAUI依賴注入耦合。 ITesseract連線到MAUI服務提供者。 沒有工廠方法、沒有靜態入口點,也沒有在DI圖以外的構造函式。 這意味著OCR邏輯無法提取到可移植的類別程式庫中——每個在其構造函式中取用ITesseract的類別都被鎖定於MAUI應用程式主機之中。
任何層級皆無PDF輸入。 PDF文件是掃描合同、發票和身分文件最常見的格式。 TesseractOcrMaui對任何PDF輸入都會丟擲NotSupportedException。 處理PDF需要新增單獨的PDF渲染程式庫,編寫逐頁畫面提取,管理裝置快取中的臨時文件,並在每次呼叫後進行清理。 那是在執行單個OCR呼叫前的100多行基礎設施程式碼——而它仍然僅能在MAUI中運行。
對現實圖像沒有內建預處理。行動攝影頭產生的圖像帶有旋轉、感應器噪點,以及在不同裝置型號之間不一致的DPI。 TesseractOcrMaui會將圖像直接傳遞給Tesseract引擎,並未進行任何預處理。 需要更高準確度的團隊必須自行新增SkiaSharp或ImageSharp,手動實施傾斜校正和降噪演算法,編寫臨時文件管理,並在各iOS和Android裝置變體中進行測試。 大多數人選擇略過它。 作為結果,真實行動裝置捕獲的準確度因此受到影響。
單開發者維護的生產依賴風險。 TesseractOcrMaui由一位開發者維護。 它背後沒有公司,沒有服務等級協議,沒有安全修補承諾,GitHub問題之外亦無升級途徑。 對於受監管行業中的生產應用——金融、健康醫療、法律——一個志願者維護的程式庫,總共僅約33,900個NuGet下載,不是一個可接受的依賴。
根本問題
TesseractOcrMaui僅在MAUI專案中編譯。 當其他專案型別需要OCR時,架構立即崩潰:
// TesseractOcrMaui: wired to MAUI host — cannot escape to a shared library
// This code compiles only inside a .NET MAUI application
public class OcrService
{
private readonly ITesseract _tesseract; // resolved from MAUI DI — no other source exists
public OcrService(ITesseract tesseract) { _tesseract = tesseract; }
public async Task<string> ReadAsync(string imagePath)
{
await _tesseract.InitAsync("eng"); // traineddata must be bundled as MauiAsset
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
// Cannot reference this class from ASP.NET Core, Azure Functions, or Docker
}Public Class OcrService
Private ReadOnly _tesseract As ITesseract ' resolved from MAUI DI — no other source exists
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract
End Sub
Public Async Function ReadAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng") ' traineddata must be bundled as MauiAsset
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.Success, result.RecognizedText, String.Empty)
End Function
' Cannot reference this class from ASP.NET Core, Azure Functions, or Docker
End Class// IronOCR: plain instantiable class — compiles in any .NET project type
public class OcrService
{
private readonly IronTesseract _ocr = new IronTesseract(); // no DI, no MAUI host
public string Read(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
}
// Place this in a netstandard2.1 library — reference from MAUI, API, and Functions together
}Public Class OcrService
Private ReadOnly _ocr As New IronTesseract() ' no DI, no MAUI host
Public Function Read(imagePath As String) As String
Using input As New OcrInput()
input.LoadImage(imagePath)
Return _ocr.Read(input).Text
End Using
End Function
' Place this in a netstandard2.1 library — reference from MAUI, API, and Functions together
End Class##IronOCRvs TesseractOcrMaui: 功能比較
下表涵蓋了對評估此遷移的團隊相關的能力差異。
| 功能 | TesseractOcrMaui | IronOCR |
|---|---|---|
| .NET MAUI(iOS) | 是 | 是 (IronOcr.iOS) |
| .NET MAUI(Android) | 是 | 是 (IronOcr.Android) |
| .NET MAUI(Windows) | 是 | 是 |
| ASP.NET Core | 不是 | 是 |
| Azure 功能 | 不是 | 是 |
| AWS Lambda | 不是 | 是 |
| Docker / Linux容器 | 不是 | 是 |
| 控制台應用程式 | 不是 | 是 |
| WPF / WinForms | 不是 | 是 |
| 共享 .NET 類別庫 | 不是 | 是 |
| PDF輸入(本機) | 不是 | 是 |
| 密碼保護PDF輸入 | 不是 | 是 |
| 流輸入 | 不是 | 是 |
| 字節陣列輸入 | 不是 | 是 |
| 多頁TIFF輸入 | 不是 | 是 |
| 可搜尋的 PDF 輸出 | 不是 | 是 |
| hOCR匯出 | 不是 | 是 |
| 自動去偏 | 不是 | 是 |
| 自動降噪 | 不是 | 是 |
| 對比增強 | 不是 | 是 |
| 二值化 | 不是 | 是 |
| 基於區域的OCR | 不是 | 是 |
| OCR期間的條碼讀取 | 不是 | 是 |
| 字詞級別坐標 | 不是 | 是 |
| 同時多語言支持 | 不是 | 是 |
| 支持的語言 | 手動打包的traineddata | 125+ 透過NuGet包 |
| 執行緒安全性 | 手動 | 內建 |
| 商業支持 | 無(單開發者) | 是(Iron Software) |
| 授權 | Apache 2.0(免費) | 自$999永久 |
| NuGet 下載次數 | ~33,900 | 超過 530 萬 |
快速開始:從TesseractOcrMaui遷移到IronOCR
步驟1:替換NuGet包
從MAUI項目中移除TesseractOcrMaui:
dotnet remove package TesseractOcrMaui
安裝IronOCR。 對於MAUI項目,除了核心套件之外,還需新增與平台相關的套件:
對於伺服器端項目(ASP.NET Core,Azure Functions,控制臺):
IronOCR NuGet包頁面列出了所有可用平台包。
步驟2:更新命名空間
將TesseractOcrMaui命名空間替換為IronOCR命名空間:
// Before (TesseractOcrMaui)
using TesseractOcrMaui;
using TesseractOcrMaui.Results;
using Microsoft.Maui.Storage;
// After (IronOCR)
using IronOcr;' Before (TesseractOcrMaui)
Imports TesseractOcrMaui
Imports TesseractOcrMaui.Results
Imports Microsoft.Maui.Storage
' After (IronOCR)
Imports IronOcr步驟3:初始化許可證
在應用程式啟動時新增授權初始化。在MAUI應用中放置於MauiProgram.cs中; 在ASP.NET Core中放置於Program.cs中:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"程式碼遷移範例
替換MAUI依賴注冊
TesseractOcrMaui需要通過MAUI服務提供者註冊OCR引擎。 移除該註冊是第一個架構步驟,因為這將為所有後續OCR程式碼鎖定在MAUI主機之上。
TesseractOcrMaui方法:
// MauiProgram.cs — OCR engine registered here; nowhere else resolves it
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Binds OCR to MAUI DI — no standalone path exists after this
builder.Services.AddTesseractOcr();
return builder.Build();
}
}
// Any class that needs OCR must receive ITesseract from the MAUI container
public class InvoicePageViewModel
{
private readonly ITesseract _tesseract;
public InvoicePageViewModel(ITesseract tesseract)
{
_tesseract = tesseract; // fails to construct outside MAUI host
}
public async Task<string> ScanInvoiceAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.RecognizedText ?? string.Empty;
}
}' MauiProgram.vb — OCR engine registered here; nowhere else resolves it
Public Module MauiProgram
Public Function CreateMauiApp() As MauiApp
Dim builder = MauiApp.CreateBuilder()
builder.UseMauiApp(Of App)()
' Binds OCR to MAUI DI — no standalone path exists after this
builder.Services.AddTesseractOcr()
Return builder.Build()
End Function
End Module
' Any class that needs OCR must receive ITesseract from the MAUI container
Public Class InvoicePageViewModel
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract ' fails to construct outside MAUI host
End Sub
Public Async Function ScanInvoiceAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng")
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.RecognizedText, String.Empty)
End Function
End ClassIronOCR方法:
// MauiProgram.cs — license only; no DI registration needed
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// One-line initialization — works for all project types
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
return builder.Build();
}
}
//不是constructor injection needed — IronTesseract instantiates directly
public class InvoicePageViewModel
{
public string ScanInvoice(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
return ocr.Read(input).Text;
}
}' MauiProgram.vb — license only; no DI registration needed
Public Module MauiProgram
Public Function CreateMauiApp() As MauiApp
Dim builder = MauiApp.CreateBuilder()
builder.UseMauiApp(Of App)()
' One-line initialization — works for all project types
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Return builder.Build()
End Function
End Module
'不是constructor injection needed — IronTesseract instantiates directly
Public Class InvoicePageViewModel
Public Function ScanInvoice(imagePath As String) As String
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
Return ocr.Read(input).Text
End Using
End Function
End Class移除AddTesseractOcr()將消除MAUI DI的耦合。 IronTesseract類別有一個公共無參數構造函式,並不攜帶平台依賴——它可以在任何地方實例化。 參閱IronTesseract設置指南以瞭解初始化選項,包括引擎模式和語言配置。
將OCR邏輯移動到共享類別程式庫
使用TesseractOcrMaui,跨專案型別共享OCR邏輯在結構上是不可能的。 使用IronOCR,遷移路徑很簡單:將服務提取到net8.0類別程式庫,並從解決方案中的每個專案中引用它。
TesseractOcrMaui方法:
// This service CANNOT be extracted to a shared library.
// It compiles only in a project that references TesseractOcrMaui,
// which only has MAUI platform targets.
//
// Result: every non-MAUI project must use a different OCR library,
// duplicating language config, error handling, and accuracy tuning.
public class DocumentOcrService
{
private readonly ITesseract _tesseract; // MAUI DI only
public DocumentOcrService(ITesseract tesseract)
{
_tesseract = tesseract;
}
public async Task<string> ProcessDocumentAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
// Server team writes their own version using a different library
// Two codebases, two accuracy profiles, two maintenance tracks
}Public Class DocumentOcrService
Private ReadOnly _tesseract As ITesseract ' MAUI DI only
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract
End Sub
Public Async Function ProcessDocumentAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng")
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.Success, result.RecognizedText, String.Empty)
End Function
' Server team writes their own version using a different library
' Two codebases, two accuracy profiles, two maintenance tracks
End ClassIronOCR方法:
// Place this in: MyCompany.OcrCore (net8.0 or netstandard2.1 class library)
// Reference from: MyCompany.MauiApp, MyCompany.Api, MyCompany.BatchWorker
using IronOcr;
namespace MyCompany.OcrCore
{
public class DocumentOcrService
{
private readonly IronTesseract _ocr;
public DocumentOcrService()
{
_ocr = new IronTesseract();
}
public string ProcessDocument(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew();
input.DeNoise();
return _ocr.Read(input).Text;
}
public string ProcessDocumentFromBytes(byte[] imageData)
{
using var input = new OcrInput();
input.LoadImage(imageData);
input.Deskew();
input.DeNoise();
return _ocr.Read(input).Text;
}
public string ProcessDocumentFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
return _ocr.Read(input).Text;
}
}
}Imports IronOcr
Namespace MyCompany.OcrCore
Public Class DocumentOcrService
Private ReadOnly _ocr As IronTesseract
Public Sub New()
_ocr = New IronTesseract()
End Sub
Public Function ProcessDocument(imagePath As String) As String
Using input As New OcrInput()
input.LoadImage(imagePath)
input.Deskew()
input.DeNoise()
Return _ocr.Read(input).Text
End Using
End Function
Public Function ProcessDocumentFromBytes(imageData As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageData)
input.Deskew()
input.DeNoise()
Return _ocr.Read(input).Text
End Using
End Function
Public Function ProcessDocumentFromStream(imageStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(imageStream)
Return _ocr.Read(input).Text
End Using
End Function
End Class
End Namespace一個類別程式庫,一套測試,一個準確度設定。MAUI應用程式呼叫ProcessDocument(photoPath),ASP.NET Core API呼叫ProcessDocumentFromBytes(uploadedBytes),而Azure Function呼叫ProcessDocumentFromStream(blobStream)——所有這些都依賴於相同的實現。 流輸入指南和影像輸入指南記錄了所有OcrInput載入變體。
在ASP.NET Core啟用伺服器端OCR
無法從ASP.NET Core專案引用TesseractOcrMaui。 新增文件上傳端點的團隊不得不完全切換到其他程式庫。 IronOCR在ASP.NET Core中運行不需要在授權金鑰之外進行任何設定更改。
TesseractOcrMaui方法:
//ASP.NET CoreWeb API —TesseractOcrMauiCANNOT be used here.
// The package has no net8.0 or netstandard target.
// Referencing it produces: "The given project does not support targeting net8.0-ios/android/windows."
//
// Team is forced to add a second OCR library — Tesseract charlesw wrapper,
// a cloud API, or another solution — creating a split codebase.
[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
// Cannot inject ITesseract here — no MAUI host, no MAUI DI container
// Must use a completely different OCR library for server-side processing
}'ASP.NET CoreWeb API —TesseractOcrMauiCANNOT be used here.
' The package has no net8.0 or netstandard target.
' Referencing it produces: "The given project does not support targeting net8.0-ios/android/windows."
'
' Team is forced to add a second OCR library — Tesseract charlesw wrapper,
' a cloud API, or another solution — creating a split codebase.
<ApiController>
<Route("api/[controller]")>
Public Class DocumentsController
Inherits ControllerBase
' Cannot inject ITesseract here — no MAUI host, no MAUI DI container
' Must use a completely different OCR library for server-side processing
End ClassIronOCR方法:
//ASP.NET Core—IronOCRworks without modification
using IronOcr;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
[HttpPost("extract-text")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file uploaded.");
var ocr = new IronTesseract();
using var input = new OcrInput();
// Load directly from the upload stream — no temp files
using var stream = file.OpenReadStream();
if (file.ContentType == "application/pdf")
input.LoadPdf(stream);
else
input.LoadImage(stream);
input.Deskew();
input.DeNoise();
var result = ocr.Read(input);
return Ok(new
{
text = result.Text,
confidence = result.Confidence,
pageCount = result.Pages.Count()
});
}
[HttpPost("extract-text-batch")]
public async Task<IActionResult> ExtractTextBatch(List<IFormFile> files)
{
var results = new List<object>();
// Thread-safe: create one IronTesseract per thread
await Parallel.ForEachAsync(files, async (file, ct) =>
{
var ocr = new IronTesseract();
using var input = new OcrInput();
using var stream = file.OpenReadStream();
input.LoadImage(stream);
var result = ocr.Read(input);
lock (results)
{
results.Add(new { file = file.FileName, text = result.Text });
}
});
return Ok(results);
}
}'ASP.NET Core—IronOCRworks without modification
Imports IronOcr
Imports Microsoft.AspNetCore.Mvc
<ApiController>
<Route("api/[controller]")>
Public Class DocumentsController
Inherits ControllerBase
<HttpPost("extract-text")>
Public Async Function ExtractText(file As IFormFile) As Task(Of IActionResult)
If file Is Nothing OrElse file.Length = 0 Then
Return BadRequest("No file uploaded.")
End If
Dim ocr As New IronTesseract()
Using input As New OcrInput()
' Load directly from the upload stream — no temp files
Using stream = file.OpenReadStream()
If file.ContentType = "application/pdf" Then
input.LoadPdf(stream)
Else
input.LoadImage(stream)
End If
input.Deskew()
input.DeNoise()
Dim result = ocr.Read(input)
Return Ok(New With {
.text = result.Text,
.confidence = result.Confidence,
.pageCount = result.Pages.Count()
})
End Using
End Using
End Function
<HttpPost("extract-text-batch")>
Public Async Function ExtractTextBatch(files As List(Of IFormFile)) As Task(Of IActionResult)
Dim results As New List(Of Object)()
' Thread-safe: create one IronTesseract per thread
Await Task.Run(Sub()
Parallel.ForEach(files, Sub(file)
Dim ocr As New IronTesseract()
Using input As New OcrInput()
Using stream = file.OpenReadStream()
input.LoadImage(stream)
Dim result = ocr.Read(input)
SyncLock results
results.Add(New With {.file = file.FileName, .text = result.Text})
End SyncLock
End Using
End Using
End Sub)
End Sub)
Return Ok(results)
End Function
End Class相同的程式碼不變地部署到IIS、Kestrel或Linux Docker容器。 ASP.NET OCR指南涵蓋了中介軟體配置,Docker部署指南記錄了Linux容器的設置。
消除平台特定的處理器程式碼
TesseractOcrMaui的僅限MAUI目標架構迫使開發者在尋求將OCR整合到多目標解決方案時編寫平台條件程式碼。 IronOCR去除了對平台條件的需求,因為無論目標為何,同一程式包都能正確解析。
TesseractOcrMaui方法:
// Attempting to share OCR logic across MAUI and non-MAUI targets
// requires platform-conditional compilation — a maintenance hazard
#if ANDROID || IOS || WINDOWS
// Only compile this block in MAUI targets
// Non-MAUI targets cannot referenceTesseractOcrMauiat all
using TesseractOcrMaui;
public class PlatformOcrHandler
{
private readonly ITesseract _tesseract;
public PlatformOcrHandler(ITesseract tesseract)
{
_tesseract = tesseract;
}
public async Task<string> ProcessAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var r = await _tesseract.RecognizeTextAsync(imagePath);
return r.RecognizedText ?? string.Empty;
}
}
#else
// Server targets need a completely different implementation
public class PlatformOcrHandler
{
public string ProcessAsync(string imagePath)
{
// Duplicate logic using a different library
throw new PlatformNotSupportedException("Use server OCR library here");
}
}
#endif#If ANDROID Or IOS Or WINDOWS Then
' Only compile this block in MAUI targets
' Non-MAUI targets cannot reference TesseractOcrMaui at all
Imports TesseractOcrMaui
Public Class PlatformOcrHandler
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract
End Sub
Public Async Function ProcessAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng")
Dim r = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(r.RecognizedText, String.Empty)
End Function
End Class
#Else
' Server targets need a completely different implementation
Public Class PlatformOcrHandler
Public Function ProcessAsync(imagePath As String) As String
' Duplicate logic using a different library
Throw New PlatformNotSupportedException("Use server OCR library here")
End Function
End Class
#End IfIronOCR方法:
// One implementation — no conditional compilation, no duplicate logic
using IronOcr;
public class PlatformOcrHandler
{
// This class compiles identically for:
// net8.0-android, net8.0-ios, net8.0-windows (MAUI targets)
// net8.0 (server targets)
// netstandard2.1 (shared library targets)
public string Process(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew();
return ocr.Read(input).Text;
}
}
// Multi-target .csproj — no conditional package references needed
// <TargetFrameworks>net8.0;net8.0-android;net8.0-ios</TargetFrameworks>
// IronOcr resolves correctly for all three targets from one package referenceImports IronOcr
Public Class PlatformOcrHandler
' This class compiles identically for:
' net8.0-android, net8.0-ios, net8.0-windows (MAUI targets)
' net8.0 (server targets)
' netstandard2.1 (shared library targets)
Public Function Process(imagePath As String) As String
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
input.Deskew()
Return ocr.Read(input).Text
End Using
End Function
End Class
' Multi-target .vbproj — no conditional package references needed
' <TargetFrameworks>net8.0;net8.0-android;net8.0-ios</TargetFrameworks>
' IronOcr resolves correctly for all three targets from one package referenceOCR處理程式碼中的平台條件表明了架構上的分裂,隨著時間的推移會變得複雜。每次語言配置更改,每次預處理調整,每次信心水平調整都必須在兩個分支中應用。 IronOCR使這種分裂變得不必要。 .NET OCR程式庫概述詳細介紹了多目標專案結構。
帶有詞座標的結構化資料提取
TesseractOcrMaui僅公開result.RecognizedText和頂層信心水平。 提取帶有其邊界框的個別單詞——進行表單字段驗證、文件解析或者高亮覆蓋所需——是不可行的。 IronOCR公開一個完整的文件物件模型:頁面、段落、行、單詞和字元,每個都帶有像素座標。
TesseractOcrMaui方法:
// TesseractOcrMaui: flat text string only — no structure, no coordinates
public class TesseractMauiFormParser
{
private readonly ITesseract _tesseract;
public TesseractMauiFormParser(ITesseract tesseract)
{
_tesseract = tesseract;
}
public async Task<Dictionary<string, string>> ParseFormAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
// result.RecognizedText is one flat string — no field positions
// Parsing requires fragile line-splitting and regex heuristics
var fields = new Dictionary<string, string>();
var lines = result.RecognizedText?.Split('\n') ?? Array.Empty<string>();
foreach (var line in lines)
{
// Hope the layout stays consistent enough to parse
var parts = line.Split(':');
if (parts.Length == 2)
fields[parts[0].Trim()] = parts[1].Trim();
}
return fields;
//不是way to validate against expected field positions
//不是confidence per word — only document-level confidence
}
}Public Class TesseractMauiFormParser
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract
End Sub
Public Async Function ParseFormAsync(imagePath As String) As Task(Of Dictionary(Of String, String))
Await _tesseract.InitAsync("eng")
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
' result.RecognizedText is one flat string — no field positions
' Parsing requires fragile line-splitting and regex heuristics
Dim fields = New Dictionary(Of String, String)()
Dim lines = If(result.RecognizedText?.Split(ControlChars.Lf), Array.Empty(Of String)())
For Each line In lines
' Hope the layout stays consistent enough to parse
Dim parts = line.Split(":"c)
If parts.Length = 2 Then fields(parts(0).Trim()) = parts(1).Trim()
Next
Return fields
'不是way to validate against expected field positions
'不是confidence per word — only document-level confidence
End Function
End ClassIronOCR方法:
// IronOCR: full document structure with bounding boxes per word
using IronOcr;
public class IronOcrFormParser
{
public List<WordLocation> ExtractWordsWithPositions(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = ocr.Read(input);
var wordLocations = new List<WordLocation>();
foreach (var page in result.Pages)
{
foreach (var word in page.Words)
{
wordLocations.Add(new WordLocation
{
Text = word.Text,
Confidence = word.Confidence,
X = word.X,
Y = word.Y,
Width = word.Width,
Height = word.Height
});
}
}
return wordLocations;
}
public FormData ParseStructuredForm(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew();
var result = ocr.Read(input);
var form = new FormData();
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
// Use Y coordinate to identify form regions
if (paragraph.Y < 200)
form.HeaderText += paragraph.Text + " ";
else if (paragraph.Y > 800)
form.FooterText += paragraph.Text + " ";
else
form.BodyLines.Add(paragraph.Text);
}
}
form.OverallConfidence = result.Confidence;
return form;
}
}
public class WordLocation
{
public string Text { get; set; }
public float Confidence { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public class FormData
{
public string HeaderText { get; set; } = string.Empty;
public string FooterText { get; set; } = string.Empty;
public List<string> BodyLines { get; set; } = new();
public float OverallConfidence { get; set; }
}Imports IronOcr
Public Class IronOcrFormParser
Public Function ExtractWordsWithPositions(imagePath As String) As List(Of WordLocation)
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
Dim result = ocr.Read(input)
Dim wordLocations = New List(Of WordLocation)()
For Each page In result.Pages
For Each word In page.Words
wordLocations.Add(New WordLocation With {
.Text = word.Text,
.Confidence = word.Confidence,
.X = word.X,
.Y = word.Y,
.Width = word.Width,
.Height = word.Height
})
Next
Next
Return wordLocations
End Using
End Function
Public Function ParseStructuredForm(imagePath As String) As FormData
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
input.Deskew()
Dim result = ocr.Read(input)
Dim form = New FormData()
For Each page In result.Pages
For Each paragraph In page.Paragraphs
' Use Y coordinate to identify form regions
If paragraph.Y < 200 Then
form.HeaderText &= paragraph.Text & " "
ElseIf paragraph.Y > 800 Then
form.FooterText &= paragraph.Text & " "
Else
form.BodyLines.Add(paragraph.Text)
End If
Next
Next
form.OverallConfidence = result.Confidence
Return form
End Using
End Function
End Class
Public Class WordLocation
Public Property Text As String
Public Property Confidence As Single
Public Property X As Integer
Public Property Y As Integer
Public Property Width As Integer
Public Property Height As Integer
End Class
Public Class FormData
Public Property HeaderText As String = String.Empty
Public Property FooterText As String = String.Empty
Public Property BodyLines As List(Of String) = New List(Of String)()
Public Property OverallConfidence As Single
End Class單詞座標使得基於已知表單模板的驗證、基於信心的標記以供人工審查,以及在文件查看器UI中的高亮覆蓋成為可能。 結構化結果指南記錄了完整的OcrResult物件模型,包含字元級別的存取,而信心水準指南涵蓋了每個單詞的信心水準篩選模式。
使用原生異步和進度追蹤進行背景處理
TesseractOcrMaui公開了一個異步API(RecognizeTextAsync),但僅在MAUI應用上下文中適用。 長時間運行的批次任務必須在背景服務、Azure Function或工作者進程中運行——這些都不是TesseractOcrMaui能夠目標的。 IronOCR提供了在任何受託服務中運行的原生異步支持。
TesseractOcrMaui方法:
// Background processing is impossible with TesseractOcrMaui.
// IHostedService runs in a server context —TesseractOcrMauihas no server target.
// The MAUI async API exists, but there is nowhere to run it outside the MAUI app host.
public class DocumentBatchWorker : BackgroundService
{
// ITesseract cannot be injected here — no MAUI DI in a hosted service
// Attempting to referenceTesseractOcrMauiwill fail to compile:
// error: PackageTesseractOcrMauidoes not support target net8.0
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
throw new PlatformNotSupportedException(
"TesseractOcrMaui has no server target. Use a different OCR library.");
}
}Public Class DocumentBatchWorker
Inherits BackgroundService
' ITesseract cannot be injected here — no MAUI DI in a hosted service
' Attempting to referenceTesseractOcrMauiwill fail to compile:
' error: PackageTesseractOcrMauidoes not support target net8.0
Protected Overrides Function ExecuteAsync(stoppingToken As CancellationToken) As Task
Throw New PlatformNotSupportedException(
"TesseractOcrMaui has no server target. Use a different OCR library.")
End Function
End ClassIronOCR方法:
// IronOCR: hosted service background batch processor
using IronOcr;
using Microsoft.Extensions.Hosting;
public class DocumentBatchWorker : BackgroundService
{
private readonly ILogger<DocumentBatchWorker> _logger;
private readonly string _inputFolder;
private readonly string _outputFolder;
public DocumentBatchWorker(ILogger<DocumentBatchWorker> logger, IConfiguration config)
{
_logger = logger;
_inputFolder = config["Ocr:InputFolder"];
_outputFolder = config["Ocr:OutputFolder"];
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var pendingFiles = Directory.GetFiles(_inputFolder, "*.pdf")
.Concat(Directory.GetFiles(_inputFolder, "*.jpg"))
.ToList();
if (pendingFiles.Count > 0)
{
_logger.LogInformation("Processing {Count} documents.", pendingFiles.Count);
// Thread-safe parallel processing — one IronTesseract per thread
await Parallel.ForEachAsync(pendingFiles,
new ParallelOptions { MaxDegreeOfParallelism = 4, CancellationToken = stoppingToken },
async (filePath, ct) =>
{
await ProcessDocumentAsync(filePath, ct);
});
}
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
}
private async Task ProcessDocumentAsync(string filePath, CancellationToken ct)
{
try
{
var ocr = new IronTesseract();
using var input = new OcrInput();
if (Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
input.LoadPdf(filePath);
else
input.LoadImage(filePath);
input.Deskew();
input.DeNoise();
var result = await Task.Run(() => ocr.Read(input), ct);
// Produce searchable PDF from the same OCR pass
var outputPath = Path.Combine(_outputFolder,
Path.GetFileNameWithoutExtension(filePath) + "_searchable.pdf");
result.SaveAsSearchablePdf(outputPath);
File.Delete(filePath); // move from input queue
_logger.LogInformation("Processed {File}: {Confidence:F1}% confidence.", filePath, result.Confidence);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to process {File}.", filePath);
}
}
}' IronOCR: hosted service background batch processor
Imports IronOcr
Imports Microsoft.Extensions.Hosting
Public Class DocumentBatchWorker
Inherits BackgroundService
Private ReadOnly _logger As ILogger(Of DocumentBatchWorker)
Private ReadOnly _inputFolder As String
Private ReadOnly _outputFolder As String
Public Sub New(logger As ILogger(Of DocumentBatchWorker), config As IConfiguration)
_logger = logger
_inputFolder = config("Ocr:InputFolder")
_outputFolder = config("Ocr:OutputFolder")
End Sub
Protected Overrides Async Function ExecuteAsync(stoppingToken As CancellationToken) As Task
While Not stoppingToken.IsCancellationRequested
Dim pendingFiles = Directory.GetFiles(_inputFolder, "*.pdf").Concat(Directory.GetFiles(_inputFolder, "*.jpg")).ToList()
If pendingFiles.Count > 0 Then
_logger.LogInformation("Processing {Count} documents.", pendingFiles.Count)
' Thread-safe parallel processing — one IronTesseract per thread
Await Parallel.ForEachAsync(pendingFiles, New ParallelOptions With {.MaxDegreeOfParallelism = 4, .CancellationToken = stoppingToken}, Async Function(filePath, ct) As Task
Await ProcessDocumentAsync(filePath, ct)
End Function)
End If
Await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken)
End While
End Function
Private Async Function ProcessDocumentAsync(filePath As String, ct As CancellationToken) As Task
Try
Dim ocr = New IronTesseract()
Using input = New OcrInput()
If Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase) Then
input.LoadPdf(filePath)
Else
input.LoadImage(filePath)
End If
input.Deskew()
input.DeNoise()
Dim result = Await Task.Run(Function() ocr.Read(input), ct)
' Produce searchable PDF from the same OCR pass
Dim outputPath = Path.Combine(_outputFolder, Path.GetFileNameWithoutExtension(filePath) & "_searchable.pdf")
result.SaveAsSearchablePdf(outputPath)
File.Delete(filePath) ' move from input queue
_logger.LogInformation("Processed {File}: {Confidence:F1}% confidence.", filePath, result.Confidence)
End Using
Catch ex As Exception
_logger.LogError(ex, "Failed to process {File}.", filePath)
End Try
End Function
End Class該工作者在builder.Services.AddHostedService<DocumentBatchWorker>()註冊,並在任何.NET 8主機中運行——Windows服務,Linux systemd單元,Docker容器或Azure容器應用。異步OCR指南涵蓋了異步模式,可搜尋PDF指南記錄了SaveAsSearchablePdf輸出選項。
##TesseractOcrMauiAPI到IronOCR的映射參考
| TesseractOcrMaui | IronOCR 等效 |
|---|---|
dotnet add package TesseractOcrMaui | dotnet add package IronOcr |
builder.Services.AddTesseractOcr() | 完全移除——無需註冊 |
ITesseract(注入) | new IronTesseract()(直接實例化) |
_tesseract.InitAsync("eng") | ocr.Language = OcrLanguage.English;(或忽略以使用預設英語) |
_tesseract.RecognizeTextAsync(imagePath) | ocr.Read(input) |
result.RecognizedText | result.Text |
result.Success | 基於異常; 無布林標誌 |
result.Status | catch (Exception ex)訊息 |
result.Confidence | result.Confidence(也適用於每個單詞) |
TesseractOcrMaui.Results.RecognitionResult | IronOcr.OcrResult |
<MauiAsset> traineddata套件 | dotnet add package IronOcr.Languages.French |
Resources/Raw/tessdata/eng.traineddata | 移除——語言資料在NuGet包內 |
FileSystem.OpenAppPackageFileAsync()(對於traineddata) | 移除——不需要 |
| 無PDF支持 | input.LoadPdf(path) 或 input.LoadPdf(stream) |
| 無前處理 | input.Deskew(), input.DeNoise(), input.Binarize(), input.Contrast() |
| 無可搜尋PDF輸出 | result.SaveAsSearchablePdf(outputPath) |
| 無單詞座標 | result.Pages[0].Words[i].X, .Y, .Width, .Height |
| 無每單字信巡 | result.Pages[0].Words[i].Confidence |
net8.0-ios 目標唯一 | net8.0 + IronOcr.iOS package |
net8.0-android目標唯一 | net8.0 + IronOcr.Android package |
常見的遷移問題与解決方案
問題1:無法移除AddTesseractOcr而不影響依賴類別
TesseractOcrMaui:每個執行OCR的類別通過構造函式注入接收ITesseract。 移除AddTesseractOcr()即刻使這些構造函式崩潰並產生DI解析例外。
解決方案:移除構造函式參數,並用直接IronTesseract實例化替換。 如果專案使用DI容器並希望保持可注入模式,請人工註冊IronTesseract:
// Option A: Direct instantiation (recommended for most cases)
public class ScanPageViewModel
{
public string ScanDocument(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
return ocr.Read(input).Text;
}
}
// Option B: Register IronTesseract in DI if your architecture requires it
// In MauiProgram.cs or Program.cs:
builder.Services.AddSingleton<IronTesseract>();
// Then inject normally:
public class ScanPageViewModel
{
private readonly IronTesseract _ocr;
public ScanPageViewModel(IronTesseract ocr) { _ocr = ocr; }
public string ScanDocument(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
}
}' Option A: Direct instantiation (recommended for most cases)
Public Class ScanPageViewModel
Public Function ScanDocument(ByVal imagePath As String) As String
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
Return ocr.Read(input).Text
End Using
End Function
End Class
' Option B: Register IronTesseract in DI if your architecture requires it
' In MauiProgram.vb or Program.vb:
builder.Services.AddSingleton(Of IronTesseract)()
' Then inject normally:
Public Class ScanPageViewModel
Private ReadOnly _ocr As IronTesseract
Public Sub New(ByVal ocr As IronTesseract)
_ocr = ocr
End Sub
Public Function ScanDocument(ByVal imagePath As String) As String
Using input = New OcrInput()
input.LoadImage(imagePath)
Return _ocr.Read(input).Text
End Using
End Function
End Class問題2:包移除後缺少traineddata文件
TesseractOcrMaui: .csproj中都需要被移除。 留著它們會導致構建警告,並使應用程式捆綁無用的文件。
解決方案:刪除tessdata文件夾,移除<MauiAsset>條目,並解除安裝任何手動下載的語言。 安裝等價的IronOCR語言包替代:
# Delete traineddata assets
rm -rf Resources/Raw/tessdata
# Remove from .csproj (delete the MauiAsset ItemGroup):
# <ItemGroup>
# <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />
# </ItemGroup>
# InstallIronOCRlanguage pack (if non-English language was needed)
dotnet add package IronOcr.Languages.French
dotnet add package IronOcr.Languages.German
來自IronOCR的語言包在編譯時解析,並且捆綁而無需進行任何手動文件管理。 多語言指南記錄了所有可用包和同時配置多語言。
問題3:每次RecognizeTextAsync前必須呼叫InitAsync
TesseractOcrMaui:每次ITesseract.InitAsync(language)。 團隊通常會加入_isInitialized護旗、雙檢鎖定或信號量來避免重復初始化。 所有這些程式碼在遷移後都變為死程式碼。
解決方案:IronTesseract無初始化步驟。語言在實例上設置一次。 移除所有_isInitialized旗幟,和所有初始化保障邏輯:
// Before: initialization guard required before every OCR call
private bool _isInitialized = false;
private readonly SemaphoreSlim _initLock = new SemaphoreSlim(1, 1);
public async Task<string> GetTextAsync(string imagePath)
{
await _initLock.WaitAsync();
try
{
if (!_isInitialized)
{
await _tesseract.InitAsync("eng");
_isInitialized = true;
}
}
finally { _initLock.Release(); }
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.RecognizedText ?? string.Empty;
}
// After: no initialization, no guard, no semaphore
public string GetText(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
return ocr.Read(input).Text;
}' Before: initialization guard required before every OCR call
Private _isInitialized As Boolean = False
Private ReadOnly _initLock As New SemaphoreSlim(1, 1)
Public Async Function GetTextAsync(imagePath As String) As Task(Of String)
Await _initLock.WaitAsync()
Try
If Not _isInitialized Then
Await _tesseract.InitAsync("eng")
_isInitialized = True
End If
Finally
_initLock.Release()
End Try
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.RecognizedText, String.Empty)
End Function
' After: no initialization, no guard, no semaphore
Public Function GetText(imagePath As String) As String
Dim ocr As New IronTesseract()
Using input As New OcrInput()
input.LoadImage(imagePath)
Return ocr.Read(input).Text
End Using
End Function問題4: result.Success檢查模式必須替換
TesseractOcrMaui:Status字串。 檢查result.Status以獲取錯誤資訊的程式碼需要重寫。
解決方案: IronOCR使用標準的.NET異常語義。 用try/catch替代成功旗標檢查。 在成功時,.Text總是有內容(若無發現文字則為空字串):
// Before: success-flag pattern
var result = await _tesseract.RecognizeTextAsync(imagePath);
if (!result.Success)
{
logger.LogError("OCR failed: {Status}", result.Status);
return string.Empty;
}
return result.RecognizedText ?? string.Empty;
// After: exception pattern
try
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = ocr.Read(input);
return result.Text; // empty string if no text found — never null
}
catch (Exception ex)
{
logger.LogError(ex, "OCR failed for {Path}.", imagePath);
return string.Empty;
}Try
Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadImage(imagePath)
Dim result = ocr.Read(input)
Return result.Text ' empty string if no text found — never null
End Using
Catch ex As Exception
logger.LogError(ex, "OCR failed for {Path}.", imagePath)
Return String.Empty
End Try問題5:共享程式庫專案中的僅限MAUI目標框架
TesseractOcrMaui:引用TesseractOcrMaui的類別程式庫自動繼承其平台限制。 該程式庫的net8.0-windows),這使得它無法被伺服器專案引用。
解決方案:將類別程式庫目標更改為IronOcr。 該程式庫現可從任何消費專案中正確解析:
<!-- Before: locked to MAUI target becauseTesseractOcrMauihas no net8.0 target -->
<TargetFramework>net8.0-android</TargetFramework>
<PackageReference Include="TesseractOcrMaui" Version="*" />
<!-- After: universal target — referenced from MAUI, API, worker, and Functions -->
<TargetFramework>net8.0</TargetFramework>
<PackageReference Include="IronOcr" Version="*" />
問題6:PDF處理需要移除第二個程式庫
TesseractOcrMaui:實現PDF支持的團隊新增了第二個程式庫(PDFium, PdfPig或雲渲染器)以將PDF頁面轉為影像然後傳遞給RecognizeTextAsync。 遷移到IronOCR後,該第二個程式庫及所有頁面渲染程式碼可以刪除。
解決方案:移除PDF渲染程式庫,並用input.LoadPdf()替換整個頁面提取流程:
// Before: PDF library + manual temp file management (50+ lines)
using var pdfDoc = PdfDocument.Open(pdfPath);
var results = new List<string>();
foreach (var page in pdfDoc.GetPages())
{
var tempImagePath = Path.Combine(FileSystem.CacheDirectory, $"page_{page.Number}.png");
RenderPageToImage(page, tempImagePath, dpi: 300);
await _tesseract.InitAsync("eng");
var r = await _tesseract.RecognizeTextAsync(tempImagePath);
results.Add(r.RecognizedText ?? string.Empty);
File.Delete(tempImagePath);
}
return string.Join("\n", results);
// After: native PDF support — 5 lines
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
return result.Text;Dim ocr = New IronTesseract()
Using input = New OcrInput()
input.LoadPdf(pdfPath)
Dim result = ocr.Read(input)
Return result.Text
End UsingPDF輸入指南涵蓋了頁面範圍選擇、受密碼保護的PDF和以流為基的載入。
TesseractOcrMaui遷移清單
遷移前
在更改任何程式碼之前,核查程式碼庫以盤點所有TesseractOcrMaui使用情況:
# Find all files that referenceTesseractOcrMauinamespaces
grep -r "TesseractOcrMaui" --include="*.cs" .
# Find all ITesseract injection points
grep -r "ITesseract" --include="*.cs" .
# Find all AddTesseractOcr registrations
grep -r "AddTesseractOcr" --include="*.cs" .
# Find all InitAsync calls
grep -r "InitAsync" --include="*.cs" .
# Find all RecognizeTextAsync calls
grep -r "RecognizeTextAsync" --include="*.cs" .
# Find traineddata asset declarations in project files
grep -r "tessdata" --include="*.csproj" .
# Find MauiAsset traineddata declarations
grep -r "MauiAsset" --include="*.csproj" .
# Identify projects with MAUI-only target frameworks that hold OCR logic
grep -r "net8.0-android\|net8.0-ios\|net8.0-windows" --include="*.csproj" .
記錄每個在構造函式中使用ITesseract的類別——這些構造函式將改變。 記錄每個為traineddata聲明<MauiAsset>的專案文件——這些聲明將被刪除。 確定是否存在PDF渲染程式庫以及其是否僅用於OCR預處理。
程式碼遷移
- 在每個引用它的專案中運行
dotnet remove package TesseractOcrMaui - 在每個將執行OCR的專案中運行
dotnet add package IronOcr - 在針對Android的MAUI專案中運行
dotnet add package IronOcr.Android - 在針對iOS的MAUI專案中運行
dotnet add package IronOcr.iOS - 針對先前捆綁為traineddata的任何非英語語言運行
dotnet add package IronOcr.Languages.* - 在每個入口點專案的應用啟動時新增
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; - 刪除
.traineddata文件從MAUI專案中 - 從
<MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />行 - 從所有
builder.Services.AddTesseractOcr() - 用
using TesseractOcrMaui.Results; - 從所有服務和視圖-模型類別中移除
ITesseract構造函式參數 - 如果需要(預設為英語),將
ocr.Language = OcrLanguage.English; - 使用
ocr.Read(input) - 將
result.Text - 用try/catch塊替換
if (!result.Success)檢查 - 如果僅是為了支持TesseractOcrMaui而新增PDF渲染程式庫,請移除它並用
input.LoadPdf()替換頁面提取程式碼。 - 更改任何包含OCR邏輯的類別程式庫中的僅限MAUI目標框架為
netstandard2.1
遷移後
- 驗證在iOS和Android目標上,從裝置攝像頭捕獲的JPEG圖像中是否產出文字
- 驗證載入於伺服器端API端點的相同影像透過
byte[]輸出文字 - 確認共享類別程式庫在被MAUI和ASP.NET Core專案引用時能夠編譯並相同地運行
- 測試PDF輸入是否端到端工作且不建立任何臨時文件
- 驗證
SaveAsSearchablePdf輸出是否在PDF檢視器中可被索引 - 確認
page.Words[i].Confidence上存在信心水準 - 測試MAUI應用啟動畫面日誌中無錯誤並且無找不到traineddata文件的例外
- 驗證在發布版本的MAUI應用捆綁中
Resources/Raw/tessdata/文件夾是否缺失 - 運行一個包含10個或更多文件的平行批次作業以確認執行緒安全性
- 確認
_isInitialized狀態變數
遷移至IronOCR的主要好處
一個程式碼庫支持整個產品。 遷移後,解決方案中的每個專案——MAUI移動應用、ASP.NET Core API、Azure Function、背景工作者——都調用同一個來自共享類別程式庫的DocumentOcrService類別。 語言配置、預處理設置和準確性優化在一個地方完成。 當新型別文件需要新的預處理過濾器時,該更改只要做一次就能在所有地方生效。
無需重寫的伺服器端部署。 IronOCR可以部署到Linux容器、Windows伺服器、Azure App Service、AWS Lambda及其他任何.NET 8運行時目標而無需進行修改。 同樣的IronTesseract實例可以處理行動攝像頭捕獲的影像和伺服器端的PDF上傳。 Azure部署指南和AWS部署指南記錄平台特定的配置步驟。
無需第二個程式庫進行PDF處理。透過input.LoadPdf()的原生PDF輸入消除了PDF渲染程式庫、逐頁影像提取迴圈、臨時文件管理以及TesseractOcrMaui架構所需的清理程式碼。 掃描的PDF合同、發票和身分文件能夠在一行程式碼中載入。能提取文字的相同OCR行程能夠產生具有result.SaveAsSearchablePdf()的可搜尋PDF——TesseractOcrMaui無法在任何級別提供這項功能。
能夠處理實際行動影像的預處理。 input.Sharpen()是單一方法呼叫,能在Tesseract引擎檢視資料之前應用校準的影像校正。 那些在沒有預處理的低光線行動捕獲中接受了40–60%準確度的團隊通常在新增三濾波器管線後看到85–90%+。不需要SkiaSharp,不需要ImageSharp,不需要演算法實施。 影像質量校正指南記錄了每個可用的過濾器以及何時應用。
商業支援,具備明確的升級路徑。 Iron Software為所有IronOCR授權層級提供電子郵件支援,為Professional和Enterprise層級提供電話和聊天優先支援。 當平台更新在特定Android API級別上導致本機程式庫分辨失敗——這種型別的故障在TesseractOcrMaui的GitHub問題隊列中是在志願者時間處理——實際上有一個具響應義務的工程團隊。 永續性授權從$999的Lite層級開始; 授權頁面列出了所有層級及其所含支援等級。
透過NuGet支持125+種語言,不讓應用包膨脹。 TesseractOcrMaui在MAUI應用內捆綁traineddata文件——每種語言會使應用下載大小增加10–50 MB。IronOCR語言包透過NuGet安裝,僅在伺服器端構建中使用,或在其被顯式引用的平台構建中使用。 移動應用包保持精簡; 伺服器端構建能夠獲得完整語言集合。 新增新語言是單次dotnet add package指令,無需對專案文件進行變更或文件管理。 完整的語言目錄列出了所有125+可用包。
[[i:(PDFium、PdfPig和Tesseract是其各自所有者的註冊商標。 本網站與Chromium項目、Google或UglyToad無關聯、贊助或認可。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊用途,並反映撰寫時獲得的公開資訊。)]]
