Tesseract.NET SDKからIronOCRへの移行|IronOCR
このガイドでは、.NET 開発者が Tesseract .NET SDK (Tesseract.Net.SDK、namespace Patagames.Ocr) から IronOCR への具体的な移行を案内します。 特に、.NET Framework時代の初期化パターン、レガシーなディスポーズの慣用表現、および同期処理のみのパイプラインを、現在.NET 8、Linuxコンテナ、および非同期ファーストのWebフレームワーク上で動作する環境へと移行させているチームを対象としています。 あなたの OCR サービスが net472 に対してコンパイルされ、<TargetFramework>net8.0</TargetFramework> を .csproj に追加したとき失敗するなら、このガイドはあなたのために書かれています。
Tesseract .NET SDK から移行する理由
Patagames SDKは、.NET Framework 4.5がデプロイメントのベースラインであり、Windows Serverが唯一のターゲットであった当時、真の価値を提供していました。 その状況は変化しました。 現在、多くの組織ではサービスのコンテナ化、LinuxランナーでのCI実行、および.NET 6、8、または9への標準化が進んでいます。Tesseract.NET SDKは、こうした動向に対応できていません。
.NET Framework 4.5 でのハード上限。 パッケージは net20 から net45 をターゲットにしています。 それは netstandard や net6.0 アセンブリを生成しません。 Tesseract.Net.SDK を含むプロジェクトファイルは <TargetFramework>net8.0</TargetFramework> を設定できません。 コードベースの残りの部分がスプリント内で完了するはず for .NETのアップグレードが、OCRレイヤーで無期限に停滞している。
**コンテナパスは指定されません。**この SDK は、Windows ネイティブバイナリへの Windows 専用 P/Invoke 呼び出しを提供します。 どの Linux ベースイメージでも — alpine:3.19 — アプリケーションは単一のドキュメントを処理する前に DllNotFoundException をスローします。 Windowsコンテナは代替手段として存在しますが、イメージサイズが大きく、別途ライセンス費用がかかり、デフォルトでLinuxノードプールを使用するほとんどのマネージドKubernetesサービスとは互換性がありません。
同期のみの API が ASP.NET Core パイプラインをブロックします。 OcrApi.GetTextFromImage() メソッドは同期です。 .NET Core では、リクエストスレッドでブロッキング型の同期操作を呼び出すと、負荷がかかった際のスループットが低下し、スレッドプールの枯渇リスクが生じます。 IronOCR は ReadAsync() を提供して非同期統合を可能にします。 パターンについては、非同期OCRガイドを参照してください。
リクエストごとのエンジン作成はメモリを消費します。 .NET Framework コードでは通常、メソッドコールやリクエストごとに OcrApi インスタンスを作成し、終了時に破棄します。 これは、.NET Frameworkのライフサイクル管理における慣用的な表現です。 それはまた高価です: 各 Init() で 40–100 MB の言語データがロードされます。 10件の同時リクエストにより、同じ言語モデルが10回読み込まれます。 IronOCR の IronTesseract はスレッドセーフです — アプリケーションライフタイム中に一つのインスタンスが存在し、全ての同時呼び出しに対応するために単一の言語モデルロードを使用します。
**レガシーな処理パターンはリスクを蓄積させます。**SDKを正しく使用するには、using (var api = OcrApi.Create()) { ... statement that predates using var 宣言。 C# 8.0 以前に書かれたコードベースには、try/finally 廃棄パターンや、バグの場合には廃棄が全く行われないものがよく含まれています。 これらのパターンは.NET Framework上でコンパイルおよび実行可能ですが、現代的なリファクタリングを妨げる技術的負債を抱えています。
非同期なし、DIなし、モダンスタートアップなし。 SDK は依存性注入の統合、ホストされたサービスライフタイム、または IOptions<t> 設定の概念を持っていません。 これを ASP.NET Core アプリケーションに組み込むには、手動でのサービス登録が必要であり、リクエストごとのインスタンス化を慎重に回避する必要があります。 IronOCRは、標準的なDIコンテナ内でシングルトンサービスとしてシームレスに統合されます。
基本的な問題
// Tesseract.NET SDK: .NET Framework 4.5 ceiling — will not compile on net8.0
// Every project referencing this package is locked below the upgrade line
using Patagames.Ocr; // Patagames.Ocr targets net45; no netstandard or net8 assembly
public class OcrService
{
public string ProcessDocument(string imagePath)
{
// Synchronous-only — blocks ASP.NET Core request threads
// なし DI support — must be instantiated manually each time
using (var api = OcrApi.Create()) // C# 1.0 using statement, 40-100MB load per call
{
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
// Project cannot target net6.0, net8.0, or any Linux container base image
}
}
// IronOCR: same logic, any runtime from net462 to net9.0, any platform
using IronOcr; // Single NuGet, supports .NET Framework 4.6.2+, .NET 5/6/7/8/9
// Register once as singleton — load language model once, share across all requests
// Call ReadAsync() in ASP.NET Core for non-blocking operation
var ocr = new IronTesseract();
var result = await ocr.ReadAsync("document.jpg"); // Async-first, no thread blocking
Console.WriteLine(result.Text);
IronOCR 対 Tesseract.NET SDK:機能比較
以下の表は、.NET へのモダナイゼーション移行に直接関連する機能を示しています。
| フィーチャー | Tesseract .NET SDK | IronOCR |
|---|---|---|
| .NET Framework 2.0~4.5 | はい | なし |
| .NET Framework 4.6.2~4.8 | なし | はい |
| .NET Core 2.x / 3.x | なし | はい |
| .NET 5 | なし | はい |
| .NET 6 | なし | はい |
| .NET 7 | なし | はい |
| .NET 8 | なし | はい |
| .NET 9 | なし | はい |
| Windows展開 | はい | はい |
| Linuxの展開 | なし | はい |
| macOSへの展開 | なし | はい |
| Docker Linux コンテナ | なし | はい |
| Azure App Service(Linux) | なし | はい |
| AWSラムダ | なし | はい |
非同期 API (ReadAsync) | なし | はい |
| スレッドセーフなシングルインスタンス | なし | はい |
| ASP.NET Core DI 統合 | マニュアル | シングルトンサービス |
| ネイティブPDF入力 | なし | はい |
| 組み込みの前処理 | なし | はい |
| 検索可能なPDF出力 | なし | はい |
| 構造化データ(WORD、行、段落) | なし | はい |
| 商用サポート/SLA | いいえ(個人開発者) | はい |
| 永続ライセンス価格 | ~$20–50(開発者1名) | $999 から |
クイックスタート:Tesseract.NET SDK から IronOCR への移行
ステップ 1: NuGet パッケージを置き換える
Tesseract.NET SDKを削除:
dotnet remove package Tesseract.Net.SDK
PdfiumViewerや類似のPDFレンダリングライブラリが、SDKにPDFページを供給する目的のみでインストールされていた場合は、それらも削除してください。IronOCRはPDFをネイティブで読み取ります:
dotnet remove package PdfiumViewer
NuGetからIronOCRをインストールしてください。
ステップ 2: 名前空間の更新
// Before (Tesseract.NET SDK)
using Patagames.Ocr;
using Patagames.Ocr.Enums;
// After (IronOCR)
using IronOcr;
ステップ 3: ライセンスの初期化
アプリケーションの起動時に一度ライセンスキーコールを追加します — Startup.cs、またはアプリケーションホストビルダー内で:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"ウォーターマークなしで評価できる無料トライアルライセンスが利用可能です。
コード移行の例
.NET Framework スタートアップ パターンから Modern Host Builder へ
.NET Framework アプリケーションは通常、OCR エンジンを静的コンストラクター、Application_Start イベント、または Global.asax ハンドラー内で初期化します。 これらは、ジェネリックホストモデルに基づいて構築された.NET 6以降のアプリケーションには存在しません。
Tesseract.NET SDK へのアプローチ:
// Global.asax.cs — .NET Framework MVC application
// OcrApi lifecycle managed manually; no DI container involved
public class MvcApplication : System.Web.HttpApplication
{
// Static field — one engine for the app lifetime
// But: NOT thread-safe; concurrent requests share a single OcrApi instance
private static OcrApi _globalApi;
protected void Application_Start()
{
// Initialize OCR engine on app startup
// Path to tessdata hardcoded for deployment environment
_globalApi = OcrApi.Create();
_globalApi.Init(Languages.English);
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
protected void Application_End()
{
// Must manually dispose on shutdown
_globalApi?.Dispose();
}
}
IronOCRのアプローチ:
// Program.cs —.NET 8ASP.NET Core application
// IronTesseractはスレッドセーフです。 register as singleton, inject where needed
var builder = WebApplication.CreateBuilder(args);
IronOcr.License.LicenseKey = builder.Configuration["IronOcr:LicenseKey"];
// Register as singleton — one instance, thread-safe, shared across all requests
builder.Services.AddSingleton<IronTesseract>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Global.asax パターンは完全に消え去ります。 IronTesseract は標準のシングルトンサービスとして登録され、コントローラーやサービスにコンストラクターを通じて注入されます。 言語モデルは初回使用時に一度読み込まれ、アプリケーションの稼働中はメモリ内に保持されます。IronTesseractのセットアップガイドでは、登録時の言語選択やエンジンモードを含む設定オプションについて解説しています。
レガシー処理パターンの近代化
.NET Framework 2.0 コードは using (var x = ...) { } ブロック文を使用します。 C# 8.0 により using var 宣言が導入され、廃棄が囲みブロックにスコープされます。 古いコードベースには try/finally 廃棄ガードも含まれており、using 文が全てのシナリオで信頼されていなかった時に書かれたものです。 これらのパターンはすべて、.NET Framework向けに記述されたコードを示しており、移行の際に最新化する必要があります。
Tesseract.NET SDK へのアプローチ:
// .NET Framework 4.x disposal patterns — three variants encountered in production
public class LegacyOcrProcessor
{
// Pattern 1: try/finally guard (pre-C# 2.0 style, still common in legacy code)
public string ProcessWithTryFinally(string imagePath)
{
OcrApi api = null;
try
{
api = OcrApi.Create();
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
finally
{
if (api != null)
api.Dispose(); // マニュアル null check required
}
}
// Pattern 2: nested using blocks — one for engine, one for image object
public string ProcessWithNestedUsing(string imagePath)
{
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var img = OcrImage.FromFile(imagePath))
{
api.SetImage(img);
return api.GetText();
} // img disposed here
} // api disposed here — nested indentation grows with each resource
}
// Pattern 3: missing disposal — memory leak, common in older service code
public string ProcessUnsafe(string imagePath)
{
var api = OcrApi.Create(); // WARNING: never disposed
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
}
IronOCRのアプローチ:
// Modern C# 8.0+ disposal — flat, readable, no nesting
public class ModernOcrProcessor
{
private readonly IronTesseract _ocr; // Injected singleton, never disposed per-request
public ModernOcrProcessor(IronTesseract ocr) => _ocr = ocr;
// Pattern 1: using var declaration — scoped to method, no nesting
public string ProcessDocument(string imagePath)
{
using var input = new OcrInput(); // OcrInput is the disposable resource, not the engine
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
} // input disposed here automatically — no nesting, no try/finally
// Pattern 2: multiple inputs in one scope — still flat
public string ProcessMultipleInputs(string imagePath, string pdfPath)
{
using var imageInput = new OcrInput();
imageInput.LoadImage(imagePath);
using var pdfInput = new OcrInput();
pdfInput.LoadPdf(pdfPath);
var imageText = _ocr.Read(imageInput).Text;
var pdfText = _ocr.Read(pdfInput).Text;
return $"{imageText}\n{pdfText}";
} // both inputs disposed here — zero nesting
}
OcrInput は IronOCR で唯一の廃棄可能なリソースです。 エンジン自体 (IronTesseract) はリクエストごとに廃棄されません — それはシングルトンです。 これにより OcrApi.Create() + api.Init() が強制したリクエストごとの 40–100 MB 言語モデルの再ロードが排除されます。 画像入力ガイド にはストリーム、バイト配列、および URL を含むすべての OcrInput のロード方法が説明されています。
ASP.NET Core コントローラー向け Async Integration
Tesseract.NET SDK には非同期 API はありません。 すべての呼び出しは同期式です。 .NET Core では、非同期コントローラーアクションから同期的なブロッキング操作を呼び出すと、負荷がかかった際にスレッドプールのリソース枯渇リスクが生じます。 一般的な回避策 — 同期呼び出しを Task.Run() でラップする — ブロッキング作業をスレッドプールスレッドにオフロードしますが、スレッドの消費を排除しません。 IronOCR の ReadAsync() は本物の非同期 I/O 統合を提供します。
Tesseract.NET SDK へのアプローチ:
// ASP.NET Core controller — forced workaround for synchronous OCR API
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Must copy upload to temp file — OcrApi does not accept streams directly
var tempPath = Path.GetTempFileName();
await using (var stream = System.IO.File.OpenWrite(tempPath))
await file.CopyToAsync(stream);
string text;
try
{
// Task.Run wraps synchronous call — still consumes a thread-pool thread
// Does NOT free the calling thread during OCR processing
text = await Task.Run(() =>
{
using (var api = OcrApi.Create()) // 40-100MB load per request
{
api.Init(Languages.English);
return api.GetTextFromImage(tempPath); // synchronous, blocking
}
});
}
finally
{
System.IO.File.Delete(tempPath); // マニュアル temp file cleanup
}
return Ok(new { text });
}
}
IronOCRのアプローチ:
// ASP.NET Core controller — genuine async OCR, no temp files, no thread blocking
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
private readonly IronTesseract _ocr; // Singleton injected via DI
public OcrController(IronTesseract ocr) => _ocr = ocr;
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Load stream directly — no temp file needed
using var input = new OcrInput();
input.LoadImage(file.OpenReadStream()); // Stream input, no disk write
// ReadAsync — genuinely non-blocking, integrates with ASP.NET Core pipeline
var result = await _ocr.ReadAsync(input);
return Ok(new
{
text = result.Text,
confidence = result.Confidence
});
}
}
一時ファイルの往復通信が終了します。 Task.Run ラッパーは消え去ります。 リクエストごとの OcrApi.Create() およびそれに続く 40–100 MB のロードは消え去ります。 非同期OCRのハウツーとストリーム入力ガイドでは、キャンセルトークンのサポートを含む、完全な非同期パイプラインについて解説しています。
マルチフレームTIFF処理
フェーズ1の比較記事では、基本的な画像およびPDF処理について取り上げました。 マルチフレーム TIFF は、文書アーカイブ、FAX システム、および医療画像処理パイプラインで一般的な、特有のシナリオです。 Tesseract .NET SDK は System.Drawing.Bitmap を使用して TIFF フレームを手動でイテレートし、各フレームを一時的な PNG ファイルに抽出し、テンポラリファイルに OCR を実行し、クリーンアップを行う必要があります。このパターンはメモリ不足エラーを避けるために大きな文書で明示的な GC 呼び出しを強制します。
Tesseract.NET SDK へのアプローチ:
// Multi-frame TIFF: manual frame extraction to temp files + forced GC
using System.Drawing;
using System.Drawing.Imaging;
using Patagames.Ocr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var pageTexts = new List<string>();
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var bitmap = new Bitmap(tiffPath))
{
var dimension = new FrameDimension(bitmap.FrameDimensionsList[0]);
int frameCount = bitmap.GetFrameCount(dimension);
for (int i = 0; i < frameCount; i++)
{
bitmap.SelectActiveFrame(dimension, i);
// Must write each frame to a temp file — no in-memory path
var tempPath = Path.GetTempFileName() + ".png";
bitmap.Save(tempPath, ImageFormat.Png);
try
{
pageTexts.Add(api.GetTextFromImage(tempPath));
}
finally
{
File.Delete(tempPath); // マニュアル cleanup on every frame
}
// Force GC every 10 frames — workaround for memory pressure
// Slows processing; indicates memory management is manual
if (i % 10 == 0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}
return pageTexts;
}
IronOCRのアプローチ:
// Multi-frame TIFF: one method call, no temp files, no manual GC
using IronOcr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // Loads all frames natively — no temp files
var result = ocr.Read(input);
// Pages map directly to TIFF frames
return result.Pages.Select(page => page.Text).ToList();
}
30行が8行に凝縮されました。 テンポラリファイルなし、Bitmap フレームイテレーションなし、GC.Collect() 呼び出しなし。 LoadImageFrames は中間ファイルを書きこまずに任意の大きさのマルチフレーム TIFF を処理します。 TIFFおよびGIFの入力ガイドでは、大規模なドキュメントに対するフレームの選択的読み込み(インデックス範囲指定)および進行状況コールバックについて解説しています。
Dockerコンテナのデプロイ準備
開発者の Windows マシン上で動作する Tesseract .NET SDK のコードは、ベースイメージが Linux の場合、Docker のビルドまたは実行ステップで失敗します。 この修正は Dockerfile の微調整ではありません。ネイティブバイナリは Windows 専用であり、Linux ではまったく読み込むことができません。 IronOCR の Linux サポートは、Dockerfile に apt-get の小さな追加を必要とするだけで、アプリケーションコードには何も変更を必要としません。
Tesseract.NET SDK へのアプローチ:
# Dockerfile attempt — fails at runtime on Linux base image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# This base image is Linux (Debian) by default
# Tesseract.Net.SDK's Windows native DLLs cannot load here
# Application throws DllNotFoundException on first OCR call
WORKDIR /app
COPY --from=build /app/publish .
# Even copying the Windows tessdata folder has no effect —
# the P/Invoke DLL cannot be loaded regardless of file placement
COPY tessdata/ ./tessdata/
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Runtime error: DllNotFoundException: Unable to load DLL 'libtesseract'
# なし fix available within Tesseract.Net.SDK — requires replacing the library
IronOCRのアプローチ:
# Dockerfile for IronOCR on Linux — add one apt-get line, nothing else changes
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Required system dependency for IronOCR on Debian/Ubuntu base images
RUN apt-get update && apt-get install -y libgdiplus \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# なし tessdata folder — language data is bundled with the IronOcr NuGet packages
# なし platform check code — IronOCR runs identically on Windows and Linux
ENTRYPOINT ["dotnet", "MyApp.dll"]
1 行の apt-get。tessdata フォルダーはありません。 アプリケーション内にプラットフォーム依存のコードは含まれていません。 開発者の Windows マシン上で動作するアプリケーションバイナリは、変更を加えることなく、この Linux コンテナ内でも動作します。 Docker デプロイメントガイド には、Alpine ベースのイメージ(apk を apt-get の代わりに使用)や、マルチステージビルドの最適化、ライセンスキー用の環境変数設定が説明されています。 Linux 導入ガイドでは、ベアメタル Linux および WSL2 のシナリオについて解説しています。
Tesseract .NET SDK API から IronOCR へのマッピングリファレンス
| Tesseract .NET SDK | IronOCR相当値 | ノート |
|---|---|---|
Install-Package Tesseract.Net.SDK | dotnet add package IronOcr | IronOCRは、.NET Framework 4.6.2 以降および .NET 5~9 を対象としています。 |
using Patagames.Ocr; | using IronOcr; | 単一のネームスペース |
using Patagames.Ocr.Enums; | (not needed) | Enums は IronOcr の namespace にあります |
OcrApi.Create() | new IronTesseract() | IronTesseractはスレッドセーフです。 シングルトンとして使用 |
api.Init(Languages.English) | ocr.Language = OcrLanguage.English | プロパティへの代入であり、メソッド呼び出しではありません |
| api.Init(言語.英語) | 言語.ドイツ語) | ocr.Language = OcrLanguage.English + OcrLanguage.German |
api.GetTextFromImage(path) | ocr.Read("path.jpg").Text | 直接またはOcrInput 経由 |
api.GetTextFromImage(path) (非同期) | await ocr.ReadAsync(input) | 本当の非同期 — Task.Run ラッパーが不要 |
OcrImage.FromFile(path) | input.LoadImage(path) | OcrInput は OcrImage を置き換えます |
OcrImage.FromBitmap(bitmap) | input.LoadImage(bitmap) | |
new MemoryStream(bytes) → OcrImage.FromBitmap | input.LoadImage(bytes) | バイト配列の直接サポート |
api.SetImage(img); api.GetText() | ocr.Read(input).Text | OcrInput はRead に渡されます |
api.GetMeanConfidence() | result.Confidence | パーセンテージを返します; also available per-word |
api.SetRectangle(x, y, w, h) | input.LoadImage(path, new CropRectangle(x, y, w, h)) | 地域ベースの OCR は CropRectangle 経由 |
api.SetVariable("tessedit_char_whitelist", x) | ocr.Configuration.WhiteListCharacters = x | |
api.SetVariable("tessedit_char_blacklist", x) | ocr.Configuration.BlackListCharacters = x | |
| ビットマップフレームの反復処理 + 一時ファイル | input.LoadImageFrames(tiffPath) | ネイティブのマルチフレーム TIFF サポート |
| (synchronous only) | result.SaveAsSearchablePdf("out.pdf") | Tesseract.NET SDKには同等の機能はありません |
| (no structured output) | result.Pages, result.Words, result.Lines | 単語レベルの座標と信頼度 |
GC.Collect() 回避策 | (not needed) | IronOCRは内部でメモリを管理します |
プラットフォームチェック: IsOSPlatform(Windows) | (remove entirely) | IronOCRはクロスプラットフォームです |
| Tessdataフォルダ管理 | (remove entirely) | NuGet パッケージに同梱されている言語 |
一般的な移行の問題と解決策
課題 1: プロジェクトのターゲットフレームワークの不一致
Tesseract.NET SDK: Tesseract.Net.SDK を取り除き IronOcr を追加後も、プロジェクトは古い要件から net45 または net472 をターゲットにしています。 IronOCR は net462 および以降をサポートしているため、net45 プロジェクトはパッケージがクリーンにリストアされる前にターゲットフレームワークを更新する必要があります。
解決策: IronOCR を追加する前に .csproj ファイル内の <TargetFramework> を更新します。 段階的な移行期間中に新旧両方のランタイムをサポートする必要がある場合は、マルチターゲティングを使用してください:
<!-- Single modern target (preferred) -->
<TargetFramework>net8.0</TargetFramework>
<!-- Multi-targeting during phased migration — supports both simultaneously -->
<TargetFrameworks>net462;net8.0</TargetFrameworks>
IronOCRは、各ターゲットに対して適切なアセンブリを自動的に特定します。 同じ dotnet add package IronOcr コマンドは両方に対して機能します。 .NET OCRライブラリのページには、サポートされているすべてのターゲットフレームワークが記載されています。
課題 2: 静的 OcrApi フィールドが DI シングルトンに置き換えられました
Tesseract.NET SDK: レガシーコードは単一の OcrApi インスタンスを静的フィールドとして登録します(Global.asax、静的サービスロケーター、またはシングルトンラッパークラスにおいて)。 このパターンが必要だったのは、OcrApi がスレッドセーフでなかったためです — スレッド間で一つのインスタンスを共有すると競合状態を引き起こすため、静的フィールドはロックで保護されるか、実際にはフィールド名にもかかわらずリクエストごとに再作成されていました。
解決策: IronTesseract を DI コンテナを通じて真のスレッドセーフシングルトンとして登録します。 ロックを削除し、静的フィールドを削除し、リクエストごとの再作成をすべて削除してください:
// Remove: private static OcrApi _instance; / private static readonly object _lock = new();
// Replace with DI registration in Program.cs
builder.Services.AddSingleton<IronTesseract>();
// In consuming classes — constructor injection
public class DocumentProcessor
{
private readonly IronTesseract _ocr;
public DocumentProcessor(IronTesseract ocr) => _ocr = ocr;
public async Task<string> ProcessAsync(string path)
{
using var input = new OcrInput();
input.LoadImage(path);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
課題 3: デプロイ後に Tessdata フォルダーが見つからない
Tesseract.NET SDK: IronOCRへの移行後も、チームによってはCI/CDパイプラインにtessdataのデプロイ手順を残したままにしている場合があります。 ビルドスクリプトおよびデプロイメントマニフェストで参照される tessdata/ フォルダーはもう存在しません — それは古い SDK の言語モデル管理の一部でした。 スクリプトは、存在しなくなったフォルダーをコピーまたは検証しようとすると失敗します。
解決策: デプロイスクリプトからすべての tessdata 参照、.csproj コピーターゲット、Docker COPY コマンド、および CI/CD パイプラインステップを削除します。 IronOCRの言語データは、NuGetパッケージに同梱されています。 dotnet restore を実行すると、言語データが利用可能になります。 これ以外の情報は不要です:
# Remove from CI/CD pipeline
# BEFORE (delete these lines):
# - cp -r tessdata/ $DEPLOY_PATH/tessdata/
# - test -f $DEPLOY_PATH/tessdata/eng.traineddata
# AFTER: nothing — language data is in the NuGet package restore output
dotnet restore # Downloads IronOcr and any IronOcr.Languages.* packages
dotnet publish # Includes language data automatically
多言語ガイドでは、オフラインまたはエアギャップ環境での展開向けに、特定の言語パックを NuGet パッケージとしてインストールする方法について解説しています。
問題 4: BadImageFormatException の 32/64 ビット不一致について
Tesseract.NET SDK: このSDKには、x86およびx64用のWindowsネイティブバイナリが別々に同梱されています。 AnyCPUをターゲットにしたプロジェクトは、プロセスアーキテクチャによっては誤ったバイナリに解決されることがあります。 エラーはランタイムに BadImageFormatException または DllNotFoundException として表面化し、プロセスアーキテクチャが出力フォルダー内のネイティブ DLL と一致しない場合に発生します。
解決策: IronOCR は各プラットフォームに対応する正しいネイティブバイナリをNuGetパッケージ内でバンドルし、パッケージレイアウトのruntimes/フォルダーを通じて自動的に正しいバイナリを解決します。 Platform ターゲット設定なし、アーキテクチャ条件付きコピーコマンドなし、x64 サブフォルダーを管理する必要なし:
<!-- Remove architecture-specific build configurations from .csproj -->
<!-- BEFORE: Conditional native DLL copy based on Platform target -->
<!--
<ItemGroup Condition="'$(Platform)' == 'x64'">
<Content Include="$(SolutionDir)libs\x64\*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
-->
<!-- AFTER: Nothing. IronOCR resolves the correct binary automatically. -->
課題 5: 構成文字列の移行
Tesseract.NET SDK: Tesseract エンジン変数は、Tesseract API リファレンスからの生の文字列キーを使用して api.SetVariable(string name, string value) 経由で設定されます(例:"tessedit_pageseg_mode")。 これらは型指定のない文字列であり、IDEの自動補完機能は利用できません。 タイプミスはサイレントエラーを引き起こします。つまり、変数が無視されるだけで、例外は発生しません。
解決策: IronOCR は ocr.Configuration 上で型付きプロパティとしてエンジンの構成を公開します。 タイプミスはコンパイル時のエラーになります:
// Before: untyped string variables, silent failures on typos
api.SetVariable("tessedit_char_whitelist", "0123456789");
api.SetVariable("tessedit_pageseg_mode", "7");
// After: typed properties, compile-time validation, IDE completion
ocr.Configuration.WhiteListCharacters = "0123456789";
ocr.Configuration.PageSegmentationMode = TesseractPageSegmentationMode.SingleLine;
IronTesseract API リファレンスには、すべての構成プロパティとその型、および許容される値が記載されています。
課題 6: 長時間実行されるバッチジョブの進捗報告
Tesseract.NET SDK: IProgress<t> を使用して進捗を報告するバッチ処理コードはジョブレベルで動作します(ファイルごとにカウンターを増加させる)しかし、単一のドキュメント内では報告できません — GetTextFromImage() 内にはコールバックメカニズムがありません。 500ページのドキュメントの場合、ドキュメント全体が完了するまで進捗バーは動かないままになります。
解決策: IronOCR は OcrInput 上の OcrProgress イベントを通じて組み込みの進捗追跡を提供します。 ページごとの進行状況が更新されるため、長文の複数ページにわたるドキュメントでも正確な進行状況バーを表示できます:
// IronOCR: page-level progress tracking for multi-page documents
using IronOcr;
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("large-archive.pdf");
// Subscribe to page-level progress events
input.OcrProgress += (sender, e) =>
{
Console.WriteLine($"Processing page {e.CurrentPage} of {e.TotalPages} " +
$"({e.ProgressPercent:F0}%)");
};
var result = ocr.Read(input);
Console.WriteLine($"Complete: {result.Pages.Count} pages extracted");
進捗追跡ガイドでは、ブラウザクライアントへのリアルタイム進捗プッシュを実現するための、.NET Core SignalRとの統合について解説しています。
Tesseract .NET SDK 移行チェックリスト
移行前
コードに手を加える前に、コードベース全体で Tesseract .NET SDK の使用状況をすべて確認してください:
# Find all files referencing Patagames namespace
grep -rl "Patagames" --include="*.cs" .
# Find all OcrApi instantiation points
grep -rn "OcrApi.Create" --include="*.cs" .
# Find tessdata references in project and build files
grep -rn "tessdata" --include="*.cs" --include="*.csproj" --include="*.yaml" --include="*.yml" .
# Find platform guard checks that can be removed after migration
grep -rn "IsOSPlatform.*Windows" --include="*.cs" .
# Find Task.Run wrappers around synchronous OCR calls
grep -rn "Task.Run" --include="*.cs" . | grep -i "ocr\|image\|text"
# Count distinct OcrApi.Create() call sites to estimate migration scope
grep -c "OcrApi.Create" $(find . -name "*.cs")
OcrApi.Create() 呼び出しサイトの件数を記録する — 各サイトはシングルトンとしての注入置き換えの候補です。 近代化のために try/finally 廃棄パターンをメモします。 Application_Start、または静的コンストラクタ初期化で Program.cs に移行するものを識別します。
コードの移行
- すべての
.csprojファイルで<TargetFramework>をnet8.0(またはターゲットのモダンランタイム)に更新します - 各プロジェクトで
dotnet remove package Tesseract.Net.SDKを実行します dotnet remove package PdfiumViewer(または同等の PDF レンダリングパッケージ)が存在する場合は実行します- 各プロジェクトで
dotnet add package IronOcrを実行します IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";をProgram.csもしくはホストビルダーに追加します- DI コンテナーで
IronTesseractをシングルトンとして登録します:services.AddSingleton<IronTesseract>() - すべての
using Patagames.Ocr;およびusing Patagames.Ocr.Enums;をusing IronOcr;で置換します OcrApi.Create()+api.Init(Languages.X)をコンストラクタに注入されたIronTesseractに置き換えますusing (var api = OcrApi.Create()) { ...を置き換えてくださいblocks withusing var input = new OcrInput()` 宣言api.GetTextFromImage(path)をocr.Read(input).Textまたはawait ocr.ReadAsync(input)に置き換えますTask.Run(() =>)を直接await ocr.ReadAsync(input)に置き換えますapi.GetMeanConfidence()をresult.Confidenceに置き換えます- ビットマップフレームイテレーションTIFFループを
input.LoadImageFrames(tiffPath)に置き換えます api.SetVariable("tessedit_char_whitelist", x)をocr.Configuration.WhiteListCharacters = xに置き換えます- プロジェクトから tessdata フォルダを削除し、tessdata へのすべてのデプロイメントスクリプトの参照を削除してください
移行後
- プロジェクトを
net8.0を対象にコンパイルし、ビルド出力にPatagamesの参照が残っていないことを確認してください。 - アプリケーションを Linux ホストまたは Linux Docker コンテナで実行し、
DllNotFoundExceptionがないことを確認します - 本番環境の文書から抽出した代表的なサンプル(10~20件)を用いて、OCRテキストの出力が移行前の出力と一致していることを確認する
- 複数ページの TIFF 処理をテストし、ページ数が元のフレーム数と一致することを確認する
ReadAsync()を使用して ASP.NET Core エンドポイントで負荷テストを実行し、スレッドプールメトリックがブロックなしであることを確認します- DI コンテナが
IronTesseractをシングルトンとして解決することを確認します(リクエスト間で同じインスタンス) - tessdataのコピー手順が削除されたため、CI/CDパイプラインがエラーなしで完了することを確認してください
- Linuxベースイメージ上でDockerイメージのビルドとコンテナの実行をテストする
- 複数ページのドキュメント(PDFまたはTIFF)において、進行状況イベントが正しく発火することを確認する
- 正常な文書に対して、信頼度スコアが想定範囲内にあることを確認してください
IronOCRへの移行の主なメリット
**.NETのアップグレードの障害は解消されました。**移行前は、.NET Framework 4.xから.NET 8へのサービス移行計画は、OCRレイヤーで頓挫していました。 移行後、OCRサービスは同じパッケージ参照から、.NET Framework 4.6.2、.NET 6、.NET 8、および.NET 9上でコンパイルおよび実行されます。 アップグレードパスは確保されています。 OCR専用に別個のレガシーランタイム環境を維持していたチームは、単一の最新ランタイム環境に統合することができます。
コンテナーデプロイメントは妥協なしで動作します。 Linux ベースイメージでの DllNotFoundException は排除されました。 開発者の Windows ワークステーションで動作する同じアプリケーションバイナリが Debian または Alpine コンテナ内で、Dockerfile に 1 行の apt-get ラインを追加するだけで実行されます。Kubernetes デプロイメント、Azure Container Apps、および Linux ノードプールの AWS ECS タスクはすべて、Windows コンテナライセンス、より大きなイメージサイズ、またはアーキテクチャ条件付きコードパスなしで動作します。 Docker 導入ガイドおよび Azure ガイドには、各ターゲット環境における正確な設定方法が記載されています。
非同期ファーストパイプラインはスレッドプールの圧力を排除します。 同期 OCR を非同期メソッドでラップする Task.Run の回避策は ReadAsync() に置き換えられます。 ASP.NET Coreのリクエストスレッドは、OCR処理中にブロックされるのではなく解放されます。 高同時実行環境下では、これは単にOCRエンドポイントだけでなく、アプリケーション全体においてリクエストのスループット向上とレイテンシの低減に直結します。
メモリ消費は同時性に比例して減少します。 以前は並行要求ごとに 1 つの OcrApi インスタンスを作成していたサービス — 各インスタンスが 40–100 MB の言語データをロード — は、今そのデータを単一の IronTesseract インスタンスに一度ロードします。 同時リクエスト数が10件の場合、単一の固定負荷と比較して400~1000 MBの差が生じます。 この削減効果はコンテナリソースのメトリクスに即座に反映され、ポッドのメモリ制限の縮小、ポッド密度の向上、およびクラウドインフラコストの削減を可能にします。
最新の C# パターンが .NET Framework の儀式を置き換えます。 try/finally 廃棄ガード、入れ子になった using ブロック、TIFF フレーム間の GC.Collect() 呼び出し — これらすべてが消え去ります。 using var input = new OcrInput() はすべてのリソース管理パターンです。 コードレビューは短めです。 OCRサービスへの新規開発者の導入にかかる時間が短縮されます。OcrResult APIリファレンスには、構造化データ、信頼度スコア、検索可能なPDF出力など、結果オブジェクトモデル全体が記載されており、従来のSDKにおける手動での結果処理パターンを置き換えます。
**商用サポートにより、個人開発者への依存から解放されます。**Tesseract.NET SDKは個人開発者によって運営されており、SLA(サービスレベル契約)や組織的な継続性の保証はありません。 IronOCRは、専用のサポートチャネル、文書化されたセキュリティ情報開示プロセス、および企業の調達要件を満たすライセンス条項を備えた商用企業であるIron Softwareによって開発されています。 IronOCR ライセンシングページ は、サポートティアと永久ライセンスモデル($999 から)をカバーしており、Patagames SDK の料金と、モダンに進化する .NET スタックでの Windows 専用インフラの隠れたコストの両方を置き換えます。
