TesseractOcrMauiからIronOCRへの移行|IronOCR
このガイドでは、TesseractOcrMauiからIronOCRへの完全な移行手順を解説し、各ステップごとに実際の"移行前"と"移行後"のコード例を掲載しています。本ガイドは、MAUIプラットフォームの制約から脱却することをすでに決定しており、モバイルアプリ、サーバーサイドAPI、バックグラウンドワーカー、クラウド関数で同一に動作するIronOCRライブラリへの体系的な移行パスを必要としている開発者を対象としています。 比較記事を事前に読む必要はありません。
TesseractOcrMauiからの移行理由
TesseractOcrMauiは、ある現実的な課題を解決するために開発されました。既存 for .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レンダリングライブラリを追加し、ページごとの画像抽出を実装し、デバイスのキャッシュ内の一時ファイルを管理し、各呼び出し後にそれらをクリーンアップする必要があります。 たった1回のOCR呼び出しを実行するまでに、100行以上のインフラストラクチャコードが必要であり、しかもMAUI上でのみ動作します。
実世界の画像に対する組み込みの前処理機能はありません。モバイルカメラで撮影された画像には、回転、センサーノイズ、デバイスモデルごとのDPIの不一致などが生じます。 TesseractOcrMauiは、前処理を一切行わずに画像をTesseractエンジンに直接渡します。 より高い精度を必要とするチームは、SkiaSharpまたはImageSharpを追加し、手動で傾き補正やノイズ除去アルゴリズムを実装し、一時ファイルの管理機能を記述し、iOSおよびAndroidの各デバイスバリエーションでこれらすべてをテストする必要があります。 多くの人がこれを飛ばします。 その結果、実際のモバイル画面のキャプチャにおける精度は低下します。
本番環境での依存関係における単一開発者によるメンテナンスのリスク。TesseractOcrMauiは1人の開発者によってメンテナンスされています。 これには運営会社が存在せず、SLA(サービスレベル契約)やセキュリティパッチの提供義務はなく、GitHubのイシュー以外にはエスカレーションの手段もありません。 金融、医療、法務といった規制産業における本番環境向けアプリケーションにおいて、ボランティアによって維持管理され、NuGetでの総ダウンロード数が約33,900件に過ぎないライブラリは、許容できる依存関係とは言えません。
基本的な問題
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 ClassIronOCR 対 TesseractOcrMaui:機能比較
以下の表は、この移行を検討しているチームに関連する機能の違いをまとめたものです。
| フィーチャー | TesseractOcrMaui | IronOCR |
|---|---|---|
| .NET MAUI(iOS) | はい | はい (IronOcr.iOS) |
| .NET MAUI(アンドロイド) | はい | はい (IronOcr.Android) |
| .NET MAUI(Windows) | はい | はい |
| ASP.NET Core | なし | はい |
| Azure Functions | なし | はい |
| AWSラムダ | なし | はい |
| Docker / Linuxコンテナ | なし | はい |
| コンソールアプリケーション | なし | はい |
| WPF / WinForms | なし | はい |
| 共有.NETクラスライブラリ | なし | はい |
| PDF入力(ネイティブ) | なし | はい |
| パスワードで保護されたPDFファイルの入力 | なし | はい |
| ストリーム入力 | なし | はい |
| バイト配列入力 | なし | はい |
| 複数ページTIFF入力 | なし | はい |
| 検索可能なPDF出力 | なし | はい |
| hOCRエクスポート | なし | はい |
| 自動傾き補正 | なし | はい |
| 自動ノイズ除去 | なし | はい |
| コントラスト強調 | なし | はい |
| 二値化 | なし | はい |
| 地域ベースのOCR | なし | はい |
| OCR中のバーコード読み取り | なし | はい |
| 単語レベルの座標 | なし | はい |
| 多言語同時通訳 | なし | はい |
| 対応言語 | 手動でバンドルされたトレーニングデータ | NuGetパッケージ経由で125以上 |
| スレッドセーフティ | マニュアル | 内蔵 |
| 商用サポート | なし(個人開発者) | はい(Iron Software) |
| ライセンス | アパッチ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 Class MauiProgram
Public Shared 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 Class
' なし constructor injection needed — IronTesseract instantiates directly
Public Class InvoicePageViewModel
Public Function ScanInvoice(imagePath As String) As String
Dim ocr = New IronTesseract()
Using input As New OcrInput()
input.LoadImage(imagePath)
Return ocr.Read(input).Text
End Using
End Function
End ClassAddTesseractOcr()を削除すると、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 Namespace1つのクラスライブラリ、1つのテストセット、1つの精度プロファイル。MAUIアプリはProcessDocument(photoPath)を呼び出し、ASP.NET Core APIはProcessDocumentFromBytes(uploadedBytes)を呼び出し、Azure FunctionはProcessDocumentFromStream(blobStream)を呼び出します。– すべて同じ実装によりサポートされています。 ストリーム入力ガイドと画像入力ガイドにはすべてのOcrInput読み込みバリアントが記載されています。
ASP.NET Coreでのサーバーサイド OCR の有効化
TesseractOcrMauiは、ASP.NET Coreプロジェクトから参照することはできません。 ドキュメントのアップロードエンドポイントを追加するチームは、全く別のライブラリを利用せざるを得なくなります。 IronOCRは、ライセンスキー以外の設定変更を必要とせずに、ASP.NET Core上で動作します。
TesseractOcrMauiのアプローチ:
// ASP.NET Core Web API — TesseractOcrMaui CANNOT 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 Core Web API — TesseractOcrMaui CANNOT 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 — IronOCR works 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 — IronOCR works 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 = 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 = New List(Of Object)()
' Thread-safe: create one IronTesseract per thread
Await Task.Run(Async Function()
Await Parallel.ForEachAsync(files, Async Function(file, ct)
Dim ocr = 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 {Key .file = file.FileName, Key .text = result.Text})
End SyncLock
End Using
End Using
End Function)
End Function)
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 reference TesseractOcrMaui at 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およびトップレベルの信頼度スコアのみを公開します。 フォームフィールドの検証、ドキュメントの解析、またはハイライトオーバーレイなどに必要な、個々のWORDとその境界ボックスを抽出することはできません。 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 As New Dictionary(Of String, String)()
Dim lines = If(result.RecognizedText?.Split(vbLf), 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()
End If
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 ClassWORD座標を使用することで、既知のフォームテンプレートとの照合、人間によるレビューのための信頼度に基づくフラグ付け、およびドキュメントビューアUIでのハイライト表示が可能になります。 構造化結果ガイドは、文字レベルのアクセスを含むOcrResultオブジェクトモデル全体を文書化しています。信頼度スコアガイドでは、単語単位の信頼度フィルタリングパターンを扱います。
ネイティブ非同期処理と進行状況の追跡
TesseractOcrMauiは非同期API (RecognizeTextAsync) を公開しますが、MAUIアプリケーションコンテキスト内のみです。 長時間実行されるバッチジョブは、バックグラウンドサービス、Azure Function、またはワーカープロセスで実行する必要があります。TesseractOcrMauiは、これらいずれに対してもターゲット設定できません。 IronOCRは、あらゆるホスト型サービスで動作するネイティブな非同期サポートを提供します。
TesseractOcrMauiのアプローチ:
// Background processing is impossible with TesseractOcrMaui.
// IHostedService runs in a server context — TesseractOcrMaui has 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 reference TesseractOcrMaui will fail to compile:
// error: Package TesseractOcrMaui does 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 reference TesseractOcrMaui will fail to compile:
' error: Package TesseractOcrMaui does 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>()と登録され、Windows Service、Linux systemdユニット、Dockerコンテナ、またはAzure Container Appを含む任意 for .NET 8ホストで実行されます。非同期OCRガイドは非同期パターンをカバーし、検索可能PDFガイドはSaveAsSearchablePdf出力オプションを文書化しています。
TesseractOcrMaui API から 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(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パッケージ |
net8.0-androidターゲットのみ | net8.0 + IronOcr.Androidパッケージ |
一般的な移行の問題と解決策
課題 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: パッケージ削除後にトレーニングデータファイルが消失する
TesseractOcrMaui: <MauiAsset>宣言をすべて削除する必要があります。 これらを残したままにすると、ビルド警告が発生し、未使用のファイルによってアプリバンドルのサイズが肥大化します。
ソリューション: 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>
# Install IronOCR language pack (if non-English language was needed)
dotnet add package IronOcr.Languages.French
dotnet add package IronOcr.Languages.German
IronOCRの言語パッケージはビルド時に解決され、手動でのファイル管理を必要とせずにバンドルされます。 多言語ガイドでは、利用可能なすべてのパッケージと、同時多言語設定について解説しています。
課題 3: InitAsync は RecognizeTextAsync の実行前に必ず呼び出す必要があります
TesseractOcrMaui: RecognizeTextAsync呼び出しの前でなければなりません。 チームはしばしば_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例外セマンティクスを使用します。 success-flag のチェックを 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 because TesseractOcrMaui has 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サポートを実装したチームは、PDFページを画像に変換してRecognizeTextAsyncに渡すために、PDFium、PdfPig、またはクラウドレンダラーを含む2番目のライブラリを追加しました。 IronOCRへの移行後、その2つ目のライブラリおよびそのページレンダリング用コードはすべて削除できます。
ソリューション: 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 reference TesseractOcrMaui namespaces
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ファイルを削除します.csprojファイルからすべて削除しますbuilder.Services.AddTesseractOcr()を削除しますusing IronOcr;に置き換えます- すべてのサービスおよびビュー・モデルクラスから
ITesseractコンストラクタパラメータを削除します - 必要に応じて
ocr.Language = OcrLanguage.English;に置き換えます(デフォルトは英語です) ocr.Read(input)に置き換えますresult.Textに置き換えますif (!result.Success)チェックをtry/catchブロックと置き換えます- TesseractOcrMauiをサポートするために追加されたPDFレンダリングライブラリがある場合、それを削除し、ページ抽出コードを
input.LoadPdf()に置き換えます。 - オンリーMAUIターゲットフレームワークを持つクラスライブラリのOCRロジックを
netstandard2.1に変更します
移行後
- iOSおよびAndroidの両プラットフォームにおいて、デバイスのカメラで撮影したJPEG画像からOCRがテキストを生成できることを確認する
- サーバサイドAPIエンドポイントで
byte[]経由で読み込んだ同じ画像からOCRがテキストを生成することを確認します。 - MAUI プロジェクトとASP.NET Coreプロジェクトの両方から参照された場合、共有クラスライブラリが同様にコンパイルされ、実行されることを確認してください
- PDF入力が、一時ファイルを作成することなくエンドツーエンドで機能することをテストする
SaveAsSearchablePdf出力がPDFビューアでインデックス化可能であることを確認します。page.Words[i].Confidenceに信頼度スコアが存在することを確認します。- MAUIアプリが、traineddataファイルが見つからないという例外が発生することなく、エラーのない起動ログを出力することを確認してください
- MAUIアプリバンドルのリリースビルドに
Resources/Raw/tessdata/フォルダが存在しないことを確認します。 - 10件以上のドキュメントを使用して並列バッチジョブを実行し、スレッドセーフ性を確認してください
_isInitialized状態変数が残っていないことを確認します。
IronOCRへの移行の主なメリット
製品全体にわたる1つのコードベース。 移行後、ソリューションのすべてのプロジェクト(MAUIモバイルアプリ、ASP.NET Core API、Azure Function、バックグラウンドワーカー)は、同じ共有ライブラリから同じDocumentOcrServiceクラスを呼び出します。 言語設定、前処理設定、および精度調整は、すべて一か所で行われます。 新しいドキュメントタイプに新しい前処理フィルターが必要になった場合、変更は一度行えば、すべての場所で反映されます。
書き換え不要のサーバーサイド展開。IronOCRは、Linuxコンテナ、Windows Server、Azure App Service、AWS Lambda、およびその他 for .NET 8ランタイム環境へ、変更を加えることなくデプロイできます。 モバイルカメラキャプチャを処理する同じIronTesseractインスタンスがサーバーサイドのPDFアップロードを処理します。 Azure 導入ガイドおよび AWS 導入ガイドには、プラットフォーム固有の設定手順が記載されています。
2番目のライブラリなしでのPDF処理。 input.LoadPdf()によるネイティブなPDF入力は、TesseractOcrMauiのアーキテクチャが要求したPDFレンダリングライブラリ、ページごとの画像抽出ループ、一時ファイル管理、およびクリーンアップコードを排します。 スキャンされたPDF契約、請求書、身分証明書は1行でロードされます。テキストを抽出する同じOCRパスでresult.SaveAsSearchablePdf()を使用して検索可能なPDFを作成することができ、それをTesseractOcrMauiではどのレベルでも提供できません。
実際のモバイル画像を処理する前処理。 input.Sharpen()は、Tesseractエンジンがデータを処理する前に補正された画像訂正を適用するシングルメソッド呼び出しです。 前処理なしで低照度のモバイル撮影画像に対し、40~60%の精度で妥協していたチームでも、3段階のフィルタリングパイプラインを追加することで、一般的に85~90%以上の精度を達成しています。SkiaSharpもImageSharpも不要で、アルゴリズムの実装も必要ありません。 画像品質補正ガイドでは、利用可能なすべてのフィルターと、それぞれの適用タイミングについて解説しています。
明確なエスカレーション手順を備えた商用サポート。Iron Softwareは、すべてのIronOCRライセンス階層に対してメールサポートを提供し、ProfessionalおよびEnterpriseレベルでは優先的な電話およびチャットサポートを提供します。 特定のAndroid APIレベルにおいて、プラットフォームのアップデートによってネイティブライブラリの解決が機能しなくなる場合(TesseractOcrMauiのGitHubイシューキューでボランティアが対応しているような不具合)、対応義務を負う実際のエンジニアリングチームが存在します。 永続ライセンスはLiteティアで$999から始まります; ライセンスページには、すべてのプランと、各プランに含まれるサポートレベルが記載されています。
アプリサイズの肥大化を招くことなく、NuGet経由で125以上の言語に対応。TesseractOcrMauiは、トレーニング済みデータファイルをMAUIアプリ内にバンドルしています。各言語ごとに、アプリのダウンロードサイズが10~50 MB増加します。IronOCRの言語パックはNuGet経由でインストールされ、サーバーサイドビルド、または明示的に参照されているプラットフォームビルドにのみ含まれます。 モバイルアプリのバンドルは軽量に保たれています; サーバーサイドビルドでは、全言語セットが利用可能です。 新しい言語を追加するのは1つのdotnet add packageコマンドで、プロジェクトファイルの変更やファイル管理は不要です。 言語カタログには、利用可能な125以上のパックすべてが掲載されています。
