フッターコンテンツにスキップ
ビデオ

Migrating from AWS Textract to IronOCR

このガイドは、OCRワークロードをKofax OmniPage Capture SDK(現在はTungsten Automationとして販売されています)からIronOCRに移行する.NET開発者向けです。 これは、SDKインストーラーへの依存関係の削除、エンジンライフサイクル手順の廃止、ゾーンベースの認識パターンの置き換え、エラー処理の近代化など、完全な移行パスを網羅しています。 比較記事を事前に読む必要はありません。

コファックス・オムニページ (Tungsten) から移行する理由

OmniPage Capture SDKは、 NuGet 、Docker、CI/CDパイプラインが登場する以前の時代に、Enterprise文書管理インフラストラクチャ向けに設計されました。 2005年には理にかなっていた建築上の選択のすべてが、2026年には摩擦を生む。

SDKインストーラーはNuGet環境には適していません。OmniPageコードを実行するすべての開発マシン、ビルドエージェント、および本番サーバーは、コンパイル前にTungsten SDKインストーラーを実行する必要があります。 復元する.csprojパッケージ参照はありません。 SDKのバージョンをアップグレードするには、すべてのシステムに対してインストーラーを再実行する必要があります。 新規開発者は、SDKライセンスを管理している担当者に連絡を取り、インストーラーへのアクセス権を取得するまで待たなければ、プロジェクトを実行することはできません。

ライセンスファイルは運用上の責任です。engine.Initialize()を呼び出すすべてのマシンで特定のパスに存在する必要があります。 新しいサーバーにデプロイしてそのファイルを忘れてしまうと、OCR呼び出しはすべてライセンス例外で失敗し、OCRエラーは発生しません。 フローティングライセンスとアプリケーションサーバーとライセンスサーバー間のネットワーク分割を使用すると、そのマシンが前日にライセンスを正常に検証したかどうかにかかわらず、接続が復元するまでInitialize()呼び出しはすべて失敗します。

エンジンのライフサイクル管理がエラーパスでリソースリークを引き起こします。OmniPageEngine.Shutdown()は、例外ハンドラ、早期リターン、タイムアウトを含むすべてのコードパスで呼び出される必要があります。さもなければ、フローティングライセンスシートは、ライセンスサーバーのチェックアウトタイムアウトが切れるまでロックされたままになります。 この制約に対抗的に対応するためには、エンジンのシャットダウンがスキップされないようにするためだけに存在するIDisposableパターンで統合ポイントをラップする必要があります。

ハードウェアフィンガープリンティングは最新の導入環境と競合します。OmniPageのアクティベーションはハードウェアに依存しています。 コンテナの再起動、VMの移行、クラウドの自動スケーリングはすべて、ハードウェアIDの変更を伴い、再アクティベーションの必要性を生じさせます。 オートスケーリングと互換性のないデプロイメントモデルは、クラウドインフラストラクチャと互換性のないデプロイメントモデルである。

ページ単位の料金は、規模が大きくなると予測不可能になります。新規顧客の獲得や未処理案件の一括提出など、文書処理量が急増すると、誰も予算に計上していなかった上限を超える超過料金が発生します。 IronOCRは、ライセンスの範囲内であれば永続的に無制限に利用できます。ページごとの課金、割り当て、超過料金は一切ありません。

調達プロセスにより出荷がブロックされます。OmniPage SDKは販売状況によってアクセスが制限されます。 評価版へのアクセス、価格設定、契約条件などについては、4~12週間かかる営業担当者とのやり取りが必要です。 製品納期が迫っている中でOCR機能を開発しているチームは、Enterpriseの調達サイクルを待つことはできない。 dotnet add package IronOcrは30秒で解決されます。 IronOCRのライセンスページを参照してください。$999 Liteから$2,999のEnterpriseまで、すべて永続的です。

基本的な問題

OmniPageでは、最初のバイトを読み取る前に完全な初期化処理が必要であり、最後のバイトを読み取った後にはシャットダウン処理が必要です。すべての呼び出しサイトは、これら両方を管理する必要があります。

// OmniPage: Ceremony required on EVERY entry point — init, process, shutdown
using var engine = new OmniPageEngine();
engine.SetLicenseFile(@"C:\Program Files\OmniPage\license.lic"); // File must exist here
engine.Initialize();   // Network call to license server — can fail for license reasons, not OCR reasons

var document = engine.CreateDocument();
document.AddPage("invoice.jpg");
document.Recognize(new RecognitionSettings { Language = "English" });
string text = document.GetText();
document.Dispose();    // Must not be skipped
engine.Shutdown();     // Must not be skipped — omitting this locks a floating seat
// OmniPage: Ceremony required on EVERY entry point — init, process, shutdown
using var engine = new OmniPageEngine();
engine.SetLicenseFile(@"C:\Program Files\OmniPage\license.lic"); // File must exist here
engine.Initialize();   // Network call to license server — can fail for license reasons, not OCR reasons

var document = engine.CreateDocument();
document.AddPage("invoice.jpg");
document.Recognize(new RecognitionSettings { Language = "English" });
string text = document.GetText();
document.Dispose();    // Must not be skipped
engine.Shutdown();     // Must not be skipped — omitting this locks a floating seat
Imports OmniPage

' OmniPage: Ceremony required on EVERY entry point — init, process, shutdown
Using engine As New OmniPageEngine()
    engine.SetLicenseFile("C:\Program Files\OmniPage\license.lic") ' File must exist here
    engine.Initialize()   ' Network call to license server — can fail for license reasons, not OCR reasons

    Dim document = engine.CreateDocument()
    document.AddPage("invoice.jpg")
    document.Recognize(New RecognitionSettings With {.Language = "English"})
    Dim text As String = document.GetText()
    document.Dispose()    ' Must not be skipped
    engine.Shutdown()     ' Must not be skipped — omitting this locks a floating seat
End Using
$vbLabelText   $csharpLabel
// IronOCR: One NuGet package, one line at startup, one call to read
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // At app startup — once, ever
var text = new IronTesseract().Read("invoice.jpg").Text;
// IronOCR: One NuGet package, one line at startup, one call to read
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // At app startup — once, ever
var text = new IronTesseract().Read("invoice.jpg").Text;
Imports IronOcr

' IronOCR: One NuGet package, one line at startup, one call to read
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" ' At app startup — once, ever
Dim text = New IronTesseract().Read("invoice.jpg").Text
$vbLabelText   $csharpLabel

OmniPage版には、8つの明確なステップ、2つの必須クリーンアップ呼び出し、ネットワーク依存関係、およびファイルシステム依存関係があります。 IronOCR版には2つあります。

IronOCRとKofax OmniPage(タングステン)の機能比較

以下の表は、この移行を評価するチームにとって最も関連性の高い機能を網羅しています。

フィーチャー Kofax OmniPage SDK IronOCR
インストール方法 カスタムSDKインストーラー( NuGet不要) dotnet add package IronOcr
最初のOCR呼び出しまでの時間 4~12週間(調達)+数時間(セットアップ) 30秒
ライセンスメカニズム ディスク上の.licファイル + オプションのライセンスサーバー アプリ起動時の文字列キー
ハードウェアフィンガープリンティング はい(VM移行時の再アクティベーション) なし
ライセンスサーバーが必要です はい(フローティングライセンスの場合) なし
ページごとの実行時課金 利用可能(変動あり) なし
公開価格 いいえ(営業担当者にお問い合わせください) はい ($999 / $1,499 / $2,999 永続的)
年間維持費 ライセンス費用の18~25% オプション
エンジンライフサイクル管理 必須 (Initialize / Shutdown) 不要
ウィンドウズ x64 はい はい
リナックス はい(2026年1月追加) はい(全バージョン)
macOS なし はい
Docker(Docker)/ Kubernetes(クーベルネス) 難易度:高(イメージ内にインストーラーとライセンスファイルが含まれているため) シンプル(NuGetパッケージのみ)
Azure(アジュール)/AWS Lambda(AWSラムダ) 複雑な問題(ライセンスサーバーへの接続性) ストレート
画像入力フォーマット はい JPG、PNG、BMP、TIFF、GIFなど
ネイティブPDF入力 はい(モジュールライセンスが必要な場合があります) はい(内蔵、追加ライセンス不要)
複数ページTIFF はい はい
検索可能なPDF出力 はい はい (result.SaveAsSearchablePdf())
自動前処理 設定オブジェクト構成 組み込みのパイプラインAPIと明示的なパイプラインAPI
対応言語 120歳以上 125個以上(個別のNuGetパッケージ)
構造化データ出力 はい(単語座標) 座標付きのページ、段落、行、単語、文字
信頼度スコア はい はい (result.Confidence、単語ごと)
バーコード読み取り アドオンモジュール(別途ライセンスが必要) 組み込み (ocr.Configuration.ReadBarCodes = true)
スレッドセーフ 複雑な(エンジン共有の制約) 完全 (1 IronTesseract スレッドごとに)
CI/CDパイプラインのサポート 各エージェントにインストーラーが必要です 標準dotnet restore

クイックスタート:Kofax OmniPageからIronOCRへの移行

ステップ1:SDKをNuGetパッケージに置き換える

OmniPageには削除すべきNuGetパッケージはありません。 移行が完了したら、.csprojファイルから手動のDLL参照を削除し、開発マシンからSDKをアンインストールしてください。 次にIronOCRをインストールします。

dotnet add package IronOcr

IronOCR NuGetパッケージには、OCRエンジン、前処理フィルター、およびランタイムコンポーネントが同梱されています。 別個のインストーラーはなく、ネイティブなDLL管理機能もなく、コンポーネントの登録も不要です。

ステップ 2: 名前空間の更新

// Before (Kofax OmniPage)
using Kofax.OmniPage.CSDK;
using Kofax.OmniPageCSDK;
using CSDK;

// After (IronOCR)
using IronOcr;
// Before (Kofax OmniPage)
using Kofax.OmniPage.CSDK;
using Kofax.OmniPageCSDK;
using CSDK;

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

ステップ 3: ライセンスの初期化

アプリケーションの起動時に1行追加してください。これは、engine.Initialize()呼び出しを置き換えます。

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

キーをソースコードではなく、環境変数(appsettings.jsonに保管してください。 鍵はオフラインで読み込まれるため、実行時にネットワーク呼び出しは発生しません。

コード移行の例

エンジン初期化エラーパス置換

OmniPageのライフサイクルモデルで最も危険な点は、正常終了時の処理経路ではなく、エラー発生時の処理経路である。 Shutdown()に到達しない場合、フローティングライセンスシートをロックしたままにする可能性があります。 本番環境のコードでは、すべてのドキュメント処理呼び出しをtry/finallyブロックで囲む必要があります。

Kofax OmniPageのアプローチ:

// OmniPage: try/finally required everywhere to protect license seat release
public string ProcessInvoice(string imagePath)
{
    var engine = new OmniPageEngine();
    engine.SetLicenseFile(@"C:\Program Files\OmniPage\license.lic");

    try
    {
        engine.Initialize(); // Contacts license server — failure here locks nothing
        var document = engine.CreateDocument();

        try
        {
            document.AddPage(imagePath);
            document.Recognize(new RecognitionSettings { Language = "English" });
            return document.GetText();
        }
        catch (RecognitionException ex)
        {
            // Log, rethrow — but Shutdown must still be called
            throw new OcrProcessingException("Recognition failed", ex);
        }
        finally
        {
            document.Dispose(); // Inner finally: release document
        }
    }
    catch (LicenseValidationException ex)
    {
        throw new OcrProcessingException("License validation failed", ex);
    }
    finally
    {
        engine.Shutdown(); // Outer finally: release license seat — MUST execute
    }
}
// OmniPage: try/finally required everywhere to protect license seat release
public string ProcessInvoice(string imagePath)
{
    var engine = new OmniPageEngine();
    engine.SetLicenseFile(@"C:\Program Files\OmniPage\license.lic");

    try
    {
        engine.Initialize(); // Contacts license server — failure here locks nothing
        var document = engine.CreateDocument();

        try
        {
            document.AddPage(imagePath);
            document.Recognize(new RecognitionSettings { Language = "English" });
            return document.GetText();
        }
        catch (RecognitionException ex)
        {
            // Log, rethrow — but Shutdown must still be called
            throw new OcrProcessingException("Recognition failed", ex);
        }
        finally
        {
            document.Dispose(); // Inner finally: release document
        }
    }
    catch (LicenseValidationException ex)
    {
        throw new OcrProcessingException("License validation failed", ex);
    }
    finally
    {
        engine.Shutdown(); // Outer finally: release license seat — MUST execute
    }
}
Imports System

' OmniPage: try/finally required everywhere to protect license seat release
Public Function ProcessInvoice(imagePath As String) As String
    Dim engine As New OmniPageEngine()
    engine.SetLicenseFile("C:\Program Files\OmniPage\license.lic")

    Try
        engine.Initialize() ' Contacts license server — failure here locks nothing
        Dim document = engine.CreateDocument()

        Try
            document.AddPage(imagePath)
            document.Recognize(New RecognitionSettings With {.Language = "English"})
            Return document.GetText()
        Catch ex As RecognitionException
            ' Log, rethrow — but Shutdown must still be called
            Throw New OcrProcessingException("Recognition failed", ex)
        Finally
            document.Dispose() ' Inner finally: release document
        End Try
    Catch ex As LicenseValidationException
        Throw New OcrProcessingException("License validation failed", ex)
    Finally
        engine.Shutdown() ' Outer finally: release license seat — MUST execute
    End Try
End Function
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: なし license seat to release, no engine to shut down
public string ProcessInvoice(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    var ocr = new IronTesseract();
    var result = ocr.Read(input);
    return result.Text;
    // OcrInput disposal is automatic — no license implications on any code path
}
// IronOCR: なし license seat to release, no engine to shut down
public string ProcessInvoice(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    var ocr = new IronTesseract();
    var result = ocr.Read(input);
    return result.Text;
    // OcrInput disposal is automatic — no license implications on any code path
}
Imports IronOcr

Public Function ProcessInvoice(imagePath As String) As String
    Using input As New OcrInput()
        input.LoadImage(imagePath)

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

OcrInputブロックは、ロードされた画像データのメモリクリーンアップを処理します。 ライセンスシートを保護するためのtry/finallyは存在しません。 このメソッド内のどこかで例外が発生しても、メソッド自身のスコープ外には副作用はありません。 スレッドローカルインスタンスを含む設定オプションについては、 IronTesseractのセットアップガイドを参照してください。

ゾーンベース認識の移行

OmniPageの主要な構造化抽出メカニズムはゾーン定義です。文書領域は、ゾーンごとに座標境界と認識タイプ(OCR、ICR、OMR、バーコード)を指定して宣言されます。 開発者は、ドキュメントテンプレートごとにCropRectangleを使用して同じターゲット抽出を達成します。

Kofax OmniPageのアプローチ:

// OmniPage: Zone-based form extraction with template management
public Dictionary<string, string> ExtractInvoiceFields(string invoicePath)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    // Define zones per document template
    var zones = new List<FormZone>
    {
        new FormZone { Name = "InvoiceNumber", Type = "OCR",
            X = 520, Y = 80, Width = 200, Height = 30 },
        new FormZone { Name = "InvoiceDate",   Type = "OCR",
            X = 520, Y = 120, Width = 200, Height = 30 },
        new FormZone { Name = "TotalAmount",   Type = "OCR",
            X = 520, Y = 580, Width = 200, Height = 30 },
        new FormZone { Name = "VendorName",    Type = "OCR",
            X = 50,  Y = 80,  Width = 300, Height = 40 }
    };

    var template = new FormTemplate { Name = "StandardInvoice", Zones = zones };
    var settings = new RecognitionSettings { Language = "English" };

    var document = engine.CreateDocument();
    document.AddPage(invoicePath);
    document.ApplyTemplate(template);
    document.Recognize(settings);

    var fields = new Dictionary<string, string>();
    foreach (var zone in zones)
        fields[zone.Name] = document.GetZoneText(zone.Name);

    document.Dispose();
    engine.Shutdown();
    return fields;
}
// OmniPage: Zone-based form extraction with template management
public Dictionary<string, string> ExtractInvoiceFields(string invoicePath)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    // Define zones per document template
    var zones = new List<FormZone>
    {
        new FormZone { Name = "InvoiceNumber", Type = "OCR",
            X = 520, Y = 80, Width = 200, Height = 30 },
        new FormZone { Name = "InvoiceDate",   Type = "OCR",
            X = 520, Y = 120, Width = 200, Height = 30 },
        new FormZone { Name = "TotalAmount",   Type = "OCR",
            X = 520, Y = 580, Width = 200, Height = 30 },
        new FormZone { Name = "VendorName",    Type = "OCR",
            X = 50,  Y = 80,  Width = 300, Height = 40 }
    };

    var template = new FormTemplate { Name = "StandardInvoice", Zones = zones };
    var settings = new RecognitionSettings { Language = "English" };

    var document = engine.CreateDocument();
    document.AddPage(invoicePath);
    document.ApplyTemplate(template);
    document.Recognize(settings);

    var fields = new Dictionary<string, string>();
    foreach (var zone in zones)
        fields[zone.Name] = document.GetZoneText(zone.Name);

    document.Dispose();
    engine.Shutdown();
    return fields;
}
Imports System
Imports System.Collections.Generic

' OmniPage: Zone-based form extraction with template management
Public Function ExtractInvoiceFields(invoicePath As String) As Dictionary(Of String, String)
    Using engine As New OmniPageEngine()
        engine.SetLicenseFile(licensePath)
        engine.Initialize()

        ' Define zones per document template
        Dim zones As New List(Of FormZone) From {
            New FormZone With {.Name = "InvoiceNumber", .Type = "OCR", .X = 520, .Y = 80, .Width = 200, .Height = 30},
            New FormZone With {.Name = "InvoiceDate", .Type = "OCR", .X = 520, .Y = 120, .Width = 200, .Height = 30},
            New FormZone With {.Name = "TotalAmount", .Type = "OCR", .X = 520, .Y = 580, .Width = 200, .Height = 30},
            New FormZone With {.Name = "VendorName", .Type = "OCR", .X = 50, .Y = 80, .Width = 300, .Height = 40}
        }

        Dim template As New FormTemplate With {.Name = "StandardInvoice", .Zones = zones}
        Dim settings As New RecognitionSettings With {.Language = "English"}

        Dim document = engine.CreateDocument()
        document.AddPage(invoicePath)
        document.ApplyTemplate(template)
        document.Recognize(settings)

        Dim fields As New Dictionary(Of String, String)()
        For Each zone In zones
            fields(zone.Name) = document.GetZoneText(zone.Name)
        Next

        document.Dispose()
        engine.Shutdown()
        Return fields
    End Using
End Function
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: CropRectangle targets specific regions — no template management
public Dictionary<string, string> ExtractInvoiceFields(string invoicePath)
{
    var fields = new Dictionary<string, string>();
    var ocr = new IronTesseract();

    // Extract each field by reading only the target region
    var fieldRegions = new Dictionary<string, CropRectangle>
    {
        ["InvoiceNumber"] = new CropRectangle(520, 80,  200, 30),
        ["InvoiceDate"]   = new CropRectangle(520, 120, 200, 30),
        ["TotalAmount"]   = new CropRectangle(520, 580, 200, 30),
        ["VendorName"]    = new CropRectangle(50,  80,  300, 40)
    };

    foreach (var (fieldName, region) in fieldRegions)
    {
        using var input = new OcrInput();
        input.LoadImage(invoicePath, region);
        fields[fieldName] = ocr.Read(input).Text.Trim();
    }

    return fields;
}
// IronOCR: CropRectangle targets specific regions — no template management
public Dictionary<string, string> ExtractInvoiceFields(string invoicePath)
{
    var fields = new Dictionary<string, string>();
    var ocr = new IronTesseract();

    // Extract each field by reading only the target region
    var fieldRegions = new Dictionary<string, CropRectangle>
    {
        ["InvoiceNumber"] = new CropRectangle(520, 80,  200, 30),
        ["InvoiceDate"]   = new CropRectangle(520, 120, 200, 30),
        ["TotalAmount"]   = new CropRectangle(520, 580, 200, 30),
        ["VendorName"]    = new CropRectangle(50,  80,  300, 40)
    };

    foreach (var (fieldName, region) in fieldRegions)
    {
        using var input = new OcrInput();
        input.LoadImage(invoicePath, region);
        fields[fieldName] = ocr.Read(input).Text.Trim();
    }

    return fields;
}
Imports System.Collections.Generic

' IronOCR: CropRectangle targets specific regions — no template management
Public Function ExtractInvoiceFields(invoicePath As String) As Dictionary(Of String, String)
    Dim fields As New Dictionary(Of String, String)()
    Dim ocr As New IronTesseract()

    ' Extract each field by reading only the target region
    Dim fieldRegions As New Dictionary(Of String, CropRectangle) From {
        {"InvoiceNumber", New CropRectangle(520, 80, 200, 30)},
        {"InvoiceDate", New CropRectangle(520, 120, 200, 30)},
        {"TotalAmount", New CropRectangle(520, 580, 200, 30)},
        {"VendorName", New CropRectangle(50, 80, 300, 40)}
    }

    For Each kvp In fieldRegions
        Dim fieldName = kvp.Key
        Dim region = kvp.Value
        Using input As New OcrInput()
            input.LoadImage(invoicePath, region)
            fields(fieldName) = ocr.Read(input).Text.Trim()
        End Using
    Next

    Return fields
End Function
$vbLabelText   $csharpLabel

(x, y, width, height)を指定します。 OCRエンジンは、ページ全体ではなく、指定された領域のみを処理します。これは、OmniPageのゾーンベース処理が提供するのと同じ効率上の利点です。 地域別OCRガイドには、座標選択パターンが含まれており、OcrInputのマルチリージョンAPIを使用して、1回の画像読み込みから複数のリージョンを抽出する方法が説明されています。

構造化データ出力の移行

OmniPageは独自の書き出しパイプラインを通じて文書構造を公開します。認識された文書にフォーマット設定が適用され、出力は指定されたフォーマット(RTF、XML、CSV、検索可能なPDF)のファイルに書き込まれます。 単語レベルの座標にアクセスするには、明示的な位置クエリを使用して結果イテレータを反復処理する必要があります。 IronOCRは、二次的なエクスポート手順を経ることなく、同じ構造化データを結果オブジェクトに直接表示します。

Kofax OmniPageのアプローチ:

// OmniPage: Structured output requires format configuration and file export
public void ExtractStructuredContent(string imagePath, string outputDir)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var settings = new RecognitionSettings { Language = "English" };
    var document = engine.CreateDocument();
    document.AddPage(imagePath);
    document.Recognize(settings);

    // Word-level coordinates through result iterator
    var iterator = document.GetResultIterator(ResultIteratorLevel.Word);
    while (iterator.MoveNext())
    {
        string word = iterator.GetText();
        var bounds = iterator.GetBoundingBox();
        double confidence = iterator.GetConfidence();
        Console.WriteLine($"Word: {word} at ({bounds.X},{bounds.Y}) conf:{confidence:F1}%");
    }

    // Structured export requires separate output format configuration
    var outputSettings = new OutputSettings
    {
        Format = OutputFormat.XML,
        IncludeCoordinates = true,
        IncludeConfidence = true
    };
    document.SaveAs(Path.Combine(outputDir, "output.xml"), outputSettings);

    document.Dispose();
    engine.Shutdown();
}
// OmniPage: Structured output requires format configuration and file export
public void ExtractStructuredContent(string imagePath, string outputDir)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var settings = new RecognitionSettings { Language = "English" };
    var document = engine.CreateDocument();
    document.AddPage(imagePath);
    document.Recognize(settings);

    // Word-level coordinates through result iterator
    var iterator = document.GetResultIterator(ResultIteratorLevel.Word);
    while (iterator.MoveNext())
    {
        string word = iterator.GetText();
        var bounds = iterator.GetBoundingBox();
        double confidence = iterator.GetConfidence();
        Console.WriteLine($"Word: {word} at ({bounds.X},{bounds.Y}) conf:{confidence:F1}%");
    }

    // Structured export requires separate output format configuration
    var outputSettings = new OutputSettings
    {
        Format = OutputFormat.XML,
        IncludeCoordinates = true,
        IncludeConfidence = true
    };
    document.SaveAs(Path.Combine(outputDir, "output.xml"), outputSettings);

    document.Dispose();
    engine.Shutdown();
}
Imports System
Imports System.IO

Public Sub ExtractStructuredContent(imagePath As String, outputDir As String)
    Using engine As New OmniPageEngine()
        engine.SetLicenseFile(licensePath)
        engine.Initialize()

        Dim settings As New RecognitionSettings With {.Language = "English"}
        Dim document = engine.CreateDocument()
        document.AddPage(imagePath)
        document.Recognize(settings)

        ' Word-level coordinates through result iterator
        Dim iterator = document.GetResultIterator(ResultIteratorLevel.Word)
        While iterator.MoveNext()
            Dim word As String = iterator.GetText()
            Dim bounds = iterator.GetBoundingBox()
            Dim confidence As Double = iterator.GetConfidence()
            Console.WriteLine($"Word: {word} at ({bounds.X},{bounds.Y}) conf:{confidence:F1}%")
        End While

        ' Structured export requires separate output format configuration
        Dim outputSettings As New OutputSettings With {
            .Format = OutputFormat.XML,
            .IncludeCoordinates = True,
            .IncludeConfidence = True
        }
        document.SaveAs(Path.Combine(outputDir, "output.xml"), outputSettings)

        document.Dispose()
        engine.Shutdown()
    End Using
End Sub
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: Structured data directly on OcrResult — no export step
public void ExtractStructuredContent(string imagePath)
{
    var result = new IronTesseract().Read(imagePath);

    Console.WriteLine($"Confidence: {result.Confidence:F1}%");
    Console.WriteLine($"Pages: {result.Pages.Length}");

    foreach (var page in result.Pages)
    {
        foreach (var paragraph in page.Paragraphs)
        {
            Console.WriteLine($"[Paragraph at ({paragraph.X},{paragraph.Y})]");
            Console.WriteLine(paragraph.Text);

            foreach (var word in paragraph.Words)
            {
                // Per-word confidence and coordinates — no iterator needed
                Console.WriteLine(
                    $"  Word: '{word.Text}' " +
                    $"at ({word.X},{word.Y}) " +
                    $"conf: {word.Confidence:F1}%");
            }
        }
    }
}
// IronOCR: Structured data directly on OcrResult — no export step
public void ExtractStructuredContent(string imagePath)
{
    var result = new IronTesseract().Read(imagePath);

    Console.WriteLine($"Confidence: {result.Confidence:F1}%");
    Console.WriteLine($"Pages: {result.Pages.Length}");

    foreach (var page in result.Pages)
    {
        foreach (var paragraph in page.Paragraphs)
        {
            Console.WriteLine($"[Paragraph at ({paragraph.X},{paragraph.Y})]");
            Console.WriteLine(paragraph.Text);

            foreach (var word in paragraph.Words)
            {
                // Per-word confidence and coordinates — no iterator needed
                Console.WriteLine(
                    $"  Word: '{word.Text}' " +
                    $"at ({word.X},{word.Y}) " +
                    $"conf: {word.Confidence:F1}%");
            }
        }
    }
}
Public Sub ExtractStructuredContent(imagePath As String)
    Dim result = New IronTesseract().Read(imagePath)

    Console.WriteLine($"Confidence: {result.Confidence:F1}%")
    Console.WriteLine($"Pages: {result.Pages.Length}")

    For Each page In result.Pages
        For Each paragraph In page.Paragraphs
            Console.WriteLine($"[Paragraph at ({paragraph.X},{paragraph.Y})]")
            Console.WriteLine(paragraph.Text)

            For Each word In paragraph.Words
                ' Per-word confidence and coordinates — no iterator needed
                Console.WriteLine(
                    $"  Word: '{word.Text}' " &
                    $"at ({word.X},{word.Y}) " &
                    $"conf: {word.Confidence:F1}%")
            Next
        Next
    Next
End Sub
$vbLabelText   $csharpLabel

OcrResultオブジェクトの階層 - ページ、段落、行、単語、文字 - は、OmniPageの結果イテレータが公開するのと同じ位置データを提供しますが、順次カーソルではなくナビゲータブルなオブジェクトグラフとして提供されます。 信頼度スコアは、追加設定なしで、結果、ページ、段落、単語の各レベルで利用可能です。 読み取り結果ガイドでは、構造化データのすべてのプロパティについて説明し、信頼度スコアガイドでは、単語ごとの検証パターンについて説明しています。

複数ページTIFF処理の移行

OmniPageの複数ページTIFFワークフローでは、TIFFコンテナからページごとに抽出する必要があり、ページごとに個別の認識呼び出しとドキュメントの破棄処理が必要です。 これにより、定型文と、ページ数に比例したリソース管理領域の両方が生成されます。 IronOCRは、複数フレームのTIFFファイルを1回の呼び出しで読み込みます。

Kofax OmniPageのアプローチ:

// OmniPage: Page-by-page TIFF extraction with per-page lifecycle
public List<string> ExtractFromMultiPageTiff(string tiffPath)
{
    var pageTexts = new List<string>();

    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    // Open TIFF and iterate frames
    var tiffContainer = engine.OpenTiff(tiffPath);
    int pageCount = tiffContainer.GetPageCount();

    var settings = new RecognitionSettings { Language = "English" };

    for (int i = 0; i < pageCount; i++)
    {
        var page = tiffContainer.GetPage(i); // Extract frame
        var document = engine.CreateDocument();

        try
        {
            document.AddPage(page);
            document.Recognize(settings);
            pageTexts.Add(document.GetText());
        }
        finally
        {
            document.Dispose(); // Dispose per page to manage memory
        }
    }

    tiffContainer.Dispose();
    engine.Shutdown();
    return pageTexts;
}
// OmniPage: Page-by-page TIFF extraction with per-page lifecycle
public List<string> ExtractFromMultiPageTiff(string tiffPath)
{
    var pageTexts = new List<string>();

    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    // Open TIFF and iterate frames
    var tiffContainer = engine.OpenTiff(tiffPath);
    int pageCount = tiffContainer.GetPageCount();

    var settings = new RecognitionSettings { Language = "English" };

    for (int i = 0; i < pageCount; i++)
    {
        var page = tiffContainer.GetPage(i); // Extract frame
        var document = engine.CreateDocument();

        try
        {
            document.AddPage(page);
            document.Recognize(settings);
            pageTexts.Add(document.GetText());
        }
        finally
        {
            document.Dispose(); // Dispose per page to manage memory
        }
    }

    tiffContainer.Dispose();
    engine.Shutdown();
    return pageTexts;
}
Imports System.Collections.Generic

' OmniPage: Page-by-page TIFF extraction with per-page lifecycle
Public Function ExtractFromMultiPageTiff(tiffPath As String) As List(Of String)
    Dim pageTexts As New List(Of String)()

    Using engine As New OmniPageEngine()
        engine.SetLicenseFile(licensePath)
        engine.Initialize()

        ' Open TIFF and iterate frames
        Dim tiffContainer = engine.OpenTiff(tiffPath)
        Dim pageCount As Integer = tiffContainer.GetPageCount()

        Dim settings As New RecognitionSettings With {.Language = "English"}

        For i As Integer = 0 To pageCount - 1
            Dim page = tiffContainer.GetPage(i) ' Extract frame
            Dim document = engine.CreateDocument()

            Try
                document.AddPage(page)
                document.Recognize(settings)
                pageTexts.Add(document.GetText())
            Finally
                document.Dispose() ' Dispose per page to manage memory
            End Try
        Next

        tiffContainer.Dispose()
        engine.Shutdown()
    End Using

    Return pageTexts
End Function
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: Multi-frame TIFF loaded in one call — all pages in one result
public List<string> ExtractFromMultiPageTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath); // All frames loaded automatically

    var result = new IronTesseract().Read(input);

    // Each TIFF frame becomes a page in the result
    return result.Pages.Select(page => page.Text).ToList();
}
// IronOCR: Multi-frame TIFF loaded in one call — all pages in one result
public List<string> ExtractFromMultiPageTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath); // All frames loaded automatically

    var result = new IronTesseract().Read(input);

    // Each TIFF frame becomes a page in the result
    return result.Pages.Select(page => page.Text).ToList();
}
Imports System.Collections.Generic
Imports IronOcr

' IronOCR: Multi-frame TIFF loaded in one call — all pages in one result
Public Function ExtractFromMultiPageTiff(tiffPath As String) As List(Of String)
    Using input As New OcrInput()
        input.LoadImageFrames(tiffPath) ' All frames loaded automatically

        Dim result = New IronTesseract().Read(input)

        ' Each TIFF frame becomes a page in the result
        Return result.Pages.Select(Function(page) page.Text).ToList()
    End Using
End Function
$vbLabelText   $csharpLabel

LoadImageFramesは、TIFFコンテナからのすべてのフレームを1回の呼び出しで読み取ります。 結果は、手動のイテレーションループやページごとのクリーンアップを必要とせずに、ページごとの構造を保ちながら、フレームごとに1つのOcrResult.Pageを公開します。生産用のTIFFバッチワークフローについては、TIFFおよびGIF入力ガイドを参照してください。

スレッドセーフな並列処理への移行

OmniPageのエンジンは、共有型のステートフルリソースです。 スレッド間で1つのCreateDocument()を呼び出すと、交錯した状態が生じる可能性があります。 安全なパターン - スレッドごとのエンジンインスタンス - は、エンジンの重い初期化コストと矛盾します。IronOCRのインスタンスは共有状態を持たないため、スレッドごとにIronTesseractを1つ作成してください。

Kofax OmniPageのアプローチ:

// OmniPage: Shared engine with locking to serialize document operations
public ConcurrentDictionary<string, string> ProcessBatchWithEngine(
    string[] imagePaths, string licensePath)
{
    var results = new ConcurrentDictionary<string, string>();
    var engineLock = new object();

    // One engine — document operations must be serialized
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var settings = new RecognitionSettings { Language = "English" };

    Parallel.ForEach(imagePaths, imagePath =>
    {
        lock (engineLock) // Serialize: one recognition at a time
        {
            var document = engine.CreateDocument();
            try
            {
                document.AddPage(imagePath);
                document.Recognize(settings);
                results[imagePath] = document.GetText();
            }
            finally
            {
                document.Dispose();
            }
        }
    });

    engine.Shutdown();
    return results;
}
// OmniPage: Shared engine with locking to serialize document operations
public ConcurrentDictionary<string, string> ProcessBatchWithEngine(
    string[] imagePaths, string licensePath)
{
    var results = new ConcurrentDictionary<string, string>();
    var engineLock = new object();

    // One engine — document operations must be serialized
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var settings = new RecognitionSettings { Language = "English" };

    Parallel.ForEach(imagePaths, imagePath =>
    {
        lock (engineLock) // Serialize: one recognition at a time
        {
            var document = engine.CreateDocument();
            try
            {
                document.AddPage(imagePath);
                document.Recognize(settings);
                results[imagePath] = document.GetText();
            }
            finally
            {
                document.Dispose();
            }
        }
    });

    engine.Shutdown();
    return results;
}
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

' OmniPage: Shared engine with locking to serialize document operations
Public Function ProcessBatchWithEngine(imagePaths As String(), licensePath As String) As ConcurrentDictionary(Of String, String)
    Dim results As New ConcurrentDictionary(Of String, String)()
    Dim engineLock As New Object()

    ' One engine — document operations must be serialized
    Using engine As New OmniPageEngine()
        engine.SetLicenseFile(licensePath)
        engine.Initialize()

        Dim settings As New RecognitionSettings With {.Language = "English"}

        Parallel.ForEach(imagePaths, Sub(imagePath)
                                        SyncLock engineLock ' Serialize: one recognition at a time
                                            Dim document = engine.CreateDocument()
                                            Try
                                                document.AddPage(imagePath)
                                                document.Recognize(settings)
                                                results(imagePath) = document.GetText()
                                            Finally
                                                document.Dispose()
                                            End Try
                                        End SyncLock
                                    End Sub)
        engine.Shutdown()
    End Using

    Return results
End Function
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: One IronTesseract per thread — no locking, genuine parallelism
public ConcurrentDictionary<string, string> ProcessBatchInParallel(string[] imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, imagePath =>
    {
        // Each thread creates its own instance — no shared state, no locks
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);

        var result = ocr.Read(input);
        results[imagePath] = result.Text;
    });

    return results;
}
// IronOCR: One IronTesseract per thread — no locking, genuine parallelism
public ConcurrentDictionary<string, string> ProcessBatchInParallel(string[] imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, imagePath =>
    {
        // Each thread creates its own instance — no shared state, no locks
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);

        var result = ocr.Read(input);
        results[imagePath] = result.Text;
    });

    return results;
}
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
Imports IronOcr

' IronOCR: One IronTesseract per thread — no locking, genuine parallelism
Public Function ProcessBatchInParallel(imagePaths As String()) As ConcurrentDictionary(Of String, String)
    Dim results As New ConcurrentDictionary(Of String, String)()

    Parallel.ForEach(imagePaths, Sub(imagePath)
        ' Each thread creates its own instance — no shared state, no locks
        Dim ocr As New IronTesseract()
        Using input As New OcrInput()
            input.LoadImage(imagePath)

            Dim result = ocr.Read(input)
            results(imagePath) = result.Text
        End Using
    End Sub)

    Return results
End Function
$vbLabelText   $csharpLabel

OmniPage版では、すべての認識処理をロックによって直列化するため、並列処理が無効になります。 IronOCRのバージョンは、調整なしで複数の文書を同時に処理します。 高スループットのバッチワークロードについては、 マルチスレッドの例速度最適化ガイドを参照してください。

スキャンしたアーカイブからの検索可能なPDF生成

OmniPageの検索可能なPDF出力には、保存前に明示的なOutputFormatの設定を伴う認識パイプラインの組み立てが必要です。 IronOCRは、結果オブジェクトに対する単一のメソッド呼び出しから、検索可能なPDFを生成します。

Kofax OmniPageのアプローチ:

// OmniPage: Searchable PDF requires OutputSettings configuration before save
public void ConvertArchiveToSearchable(string[] scannedPdfPaths, string outputDirectory)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var recognitionSettings = new RecognitionSettings
    {
        Language = "English",
        AccuracyMode = "Maximum",
        PreserveLayout = true
    };

    var outputSettings = new OutputSettings
    {
        Format = OutputFormat.SearchablePDF,
        Compression = PDFCompression.Standard,
        ImageQuality = 85,
        EmbedFonts = true
    };

    foreach (var pdfPath in scannedPdfPaths)
    {
        var document = engine.OpenPDF(pdfPath);
        document.RecognizeAll(recognitionSettings);

        string outputPath = Path.Combine(
            outputDirectory,
            Path.GetFileNameWithoutExtension(pdfPath) + "_searchable.pdf");

        document.SaveAs(outputPath, outputSettings);
        document.Dispose();
    }

    engine.Shutdown();
}
// OmniPage: Searchable PDF requires OutputSettings configuration before save
public void ConvertArchiveToSearchable(string[] scannedPdfPaths, string outputDirectory)
{
    using var engine = new OmniPageEngine();
    engine.SetLicenseFile(licensePath);
    engine.Initialize();

    var recognitionSettings = new RecognitionSettings
    {
        Language = "English",
        AccuracyMode = "Maximum",
        PreserveLayout = true
    };

    var outputSettings = new OutputSettings
    {
        Format = OutputFormat.SearchablePDF,
        Compression = PDFCompression.Standard,
        ImageQuality = 85,
        EmbedFonts = true
    };

    foreach (var pdfPath in scannedPdfPaths)
    {
        var document = engine.OpenPDF(pdfPath);
        document.RecognizeAll(recognitionSettings);

        string outputPath = Path.Combine(
            outputDirectory,
            Path.GetFileNameWithoutExtension(pdfPath) + "_searchable.pdf");

        document.SaveAs(outputPath, outputSettings);
        document.Dispose();
    }

    engine.Shutdown();
}
Imports System.IO

' OmniPage: Searchable PDF requires OutputSettings configuration before save
Public Sub ConvertArchiveToSearchable(scannedPdfPaths As String(), outputDirectory As String)
    Using engine As New OmniPageEngine()
        engine.SetLicenseFile(licensePath)
        engine.Initialize()

        Dim recognitionSettings As New RecognitionSettings With {
            .Language = "English",
            .AccuracyMode = "Maximum",
            .PreserveLayout = True
        }

        Dim outputSettings As New OutputSettings With {
            .Format = OutputFormat.SearchablePDF,
            .Compression = PDFCompression.Standard,
            .ImageQuality = 85,
            .EmbedFonts = True
        }

        For Each pdfPath As String In scannedPdfPaths
            Dim document = engine.OpenPDF(pdfPath)
            document.RecognizeAll(recognitionSettings)

            Dim outputPath As String = Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(pdfPath) & "_searchable.pdf")

            document.SaveAs(outputPath, outputSettings)
            document.Dispose()
        Next
    End Using

    engine.Shutdown()
End Sub
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// IronOCR: Searchable PDF output is one method call on the result
public void ConvertArchiveToSearchable(string[] scannedPdfPaths, string outputDirectory)
{
    var ocr = new IronTesseract();

    foreach (var pdfPath in scannedPdfPaths)
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath); // All pages loaded automatically

        var result = ocr.Read(input);

        string outputPath = Path.Combine(
            outputDirectory,
            Path.GetFileNameWithoutExtension(pdfPath) + "_searchable.pdf");

        result.SaveAsSearchablePdf(outputPath);
        Console.WriteLine($"Processed: {Path.GetFileName(pdfPath)} ({result.Pages.Length} pages)");
    }
}
// IronOCR: Searchable PDF output is one method call on the result
public void ConvertArchiveToSearchable(string[] scannedPdfPaths, string outputDirectory)
{
    var ocr = new IronTesseract();

    foreach (var pdfPath in scannedPdfPaths)
    {
        using var input = new OcrInput();
        input.LoadPdf(pdfPath); // All pages loaded automatically

        var result = ocr.Read(input);

        string outputPath = Path.Combine(
            outputDirectory,
            Path.GetFileNameWithoutExtension(pdfPath) + "_searchable.pdf");

        result.SaveAsSearchablePdf(outputPath);
        Console.WriteLine($"Processed: {Path.GetFileName(pdfPath)} ({result.Pages.Length} pages)");
    }
}
Imports System.IO
Imports IronOcr

Public Sub ConvertArchiveToSearchable(scannedPdfPaths As String(), outputDirectory As String)
    Dim ocr As New IronTesseract()

    For Each pdfPath As String In scannedPdfPaths
        Using input As New OcrInput()
            input.LoadPdf(pdfPath) ' All pages loaded automatically

            Dim result = ocr.Read(input)

            Dim outputPath As String = Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(pdfPath) & "_searchable.pdf")

            result.SaveAsSearchablePdf(outputPath)
            Console.WriteLine($"Processed: {Path.GetFileName(pdfPath)} ({result.Pages.Length} pages)")
        End Using
    Next
End Sub
$vbLabelText   $csharpLabel

SaveAsSearchablePdfは、PDFにテキストレイヤーを埋め込み、元のスキャンの視覚的な外観を変更せずに、文書管理システムでインデックス可能にします。 検索可能なPDFガイドではテキストレイヤーのオプションについて説明しており、 PDF OCRの例ではスキャンされたPDFのエンドツーエンド処理を実演しています。

コファックス・オムニページ API からIronOCRへのマッピングリファレンス

コファックス・オムニページ IronOCR相当値
using Kofax.OmniPage.CSDK; using IronOcr;
using Kofax.OmniPageCSDK; using IronOcr;
using CSDK; using IronOcr;
new OmniPageEngine() 不要 — エンジンオブジェクトなし
engine.SetLicenseFile(path) IronOcr.License.LicenseKey = "key";
engine.Initialize() 不要
engine.Shutdown() 不要
engine.CreateDocument() new OcrInput()
document.AddPage(imagePath) input.LoadImage(imagePath)
engine.OpenPDF(pdfPath) input.LoadPdf(pdfPath)
engine.OpenTiff(tiffPath) input.LoadImageFrames(tiffPath)
document.Recognize(settings) new IronTesseract().Read(input)
document.RecognizeAll(settings) new IronTesseract().Read(input) (すべてのページを一度に)
document.GetText() result.Text
document.GetZoneText(zoneName) input.LoadImage(path, cropRectangle) + result.Text
document.Dispose() using var input = new OcrInput() (自動)
iterator.GetText() result.Pages[n].Words[m].Text
iterator.GetBoundingBox() result.Pages[n].Words[m].X / Y / Width / Height
iterator.GetConfidence() result.Pages[n].Words[m].Confidence
engine.LoadLanguageDictionary("German") dotnet add package IronOcr.Languages.German
settings.PrimaryLanguage = "English" ocr.Language = OcrLanguage.English;
settings.SecondaryLanguages = new[] {"German"} ocr.Language = OcrLanguage.English + OcrLanguage.German;
settings.DeskewImage = true input.Deskew();
settings.DespeckleLevel = 2 input.DeNoise();
settings.ContrastEnhancement = true input.Contrast();
settings.AutoRotate = true input.Deskew(); (回転補正を含む)
document.SaveAs(path, outputSettings) result.SaveAsSearchablePdf(path)
OutputFormat.SearchablePDF result.SaveAsSearchablePdf(path)
OutputFormat.XML (座標付き) result.Pages / .Paragraphs / .Wordsオブジェクトグラフ
FormZone (座標境界付き) new CropRectangle(x, y, width, height)
ページごとのライセンスカウント 該当なし
.licファイルの配備 該当なし
ライセンスサーバー構成 該当なし

一般的な移行の問題と解決策

問題1:本番環境でライセンスファイルが見つからない例外が発生する

Kofax OmniPage:すべてのデプロイメントには、アプリケーションプロセスからアクセスできる特定のパスに.licファイルが存在する必要があります。 ライセンスファイルをターゲットサーバーに明示的にコピーしないデプロイメントパイプラインは、エンジン初期化時にLicenseExceptionを引き起こします。 セキュリティチームは、.licファイルをコンテナイメージに埋め込んだり、ソース管理にコミットすることをよく旗揚げします。

解決策: IronOCRは文字列からライセンスを読み取ります。 キーを環境変数として保存し、起動時に読み込む。デプロイするファイルも、設定するパスも不要。

// At application startup — reads IRONOCR_LICENSE_KEY from environment
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IronOCR license key not configured.");
// At application startup — reads IRONOCR_LICENSE_KEY from environment
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IronOCR license key not configured.");
Imports System

' At application startup — reads IRONOCR_LICENSE_KEY from environment
IronOcr.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY"), Throw New InvalidOperationException("IronOCR license key not configured."))
$vbLabelText   $csharpLabel

Dockerでは、--env IRONOCR_LICENSE_KEY=YOUR-KEYを渡します。 Azure App Serviceでは、アプリケーション設定として設定してください。 Kubernetesでは、シークレットを介して注入します。 埋め込みライセンスファイルについては、ファイルのマウント、パスの設定、セキュリティレビューは一切行いません。

問題2:プロセスクラッシュ後にフローティングライセンスシートがロックされる

Kofax OmniPage:アプリケーションプロセスがクラッシュしたり、ウォッチドッグにより終了されたり、またはengine.Shutdown()は実行されません。 フローティングライセンスのシートは、ライセンスサーバーのタイムアウト時間が経過するまで(通常30~60分)、チェックアウトされた状態が維持されます。 コンテナ化された環境では、ポッドが頻繁に再起動するため、この動作によってライセンスプールが枯渇します。

解決策: IronOCRには、貸出中のライセンスシートという概念がありません。 プロセスがクラッシュしても、リソースは解放されず、外部システムもロックされません。 次のプロセスは、座席の空き状況を待つことなくすぐに開始されます。

// IronOCR: Process crash has no license implications whatsoever
// Start processing immediately after any failure
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg"); // なし seat to check out
// IronOCR: Process crash has no license implications whatsoever
// Start processing immediately after any failure
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg"); // なし seat to check out
' IronOCR: Process crash has no license implications whatsoever
' Start processing immediately after any failure
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("document.jpg") ' なし seat to check out
$vbLabelText   $csharpLabel

回復力の高いASP.NET Coreサービスについては、ホスト型サービスとのスムーズな統合と正常なシャットダウンを実現するパターンについて、非同期 OCR ガイドを参照してください。

問題3:Dockerイメージのビルドが失敗する — インストーラーを非対話的に実行できない

Kofax OmniPage:OmniPage SDKインストーラーは、docker build環境では正常に動作しないGUIまたは半インタラクティブなインストーラーです。 SDKをコンテナイメージに組み込もうとするチームは、インストーラーのライセンス契約またはコンポーネント選択の手順でエラーに遭遇します。 回避策(サイレントインストールのスイッチ、事前に抽出したDLLのコピーなど)は文書化されておらず、バージョンによって異なります。

解決策:IronOCRのDockerfileは3行です。

FROM mcr.microsoft.com/dotnet/aspnet:8.0
RUN apt-get update && apt-get install -y libgdiplus  # Single Linux dependency
COPY --from=build /app/publish /app
WORKDIR /app
ENTRYPOINT ["dotnet", "YourApp.dll"]

libgdiplusは唯一のシステム依存です。 IronOCRのNuGetパッケージは、他のパッケージ参照と同様にビルドステージ内でdotnet restoreによって復元されます。 Dockerの導入ガイドでは、 DebianとAlpineの両方のベースイメージについて説明しており、 Linuxの導入ガイドでは、ディストリビューション固有のパッケージ名について説明しています。

問題4:VM移行またはクラウドオートスケーリング後に再アクティベーションが必要

Kofax OmniPage: OmniPageの有効化はハードウェアIDに紐づいています。 物理ホスト間で仮想マシンを移行したり、新しいインスタンスに自動スケーリングしたり、コンテナを新しいイメージに置き換えたりするクラウド環境では、ハードウェアIDの変更が発生し、再アクティベーションが必要になります。 インシデント発生中にTungstenのサポートに連絡して復旧を依頼すると、運用上のリスクが増加する。

解決策: IronOCRのライセンスキーはハードウェアに依存しません。 同じキーは、ライセンスティア内のどのマシン、どのコンテナ、どのクラウドリージョン、どの数の自動スケーリングインスタンスでも機能します。 再アクティベーション不要、サポートへの問い合わせ不要、ダウンタイムなし:

// Identical startup code on any hardware topology
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
bool valid = IronOcr.License.IsLicensed; // Verify without a network call
// Identical startup code on any hardware topology
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
bool valid = IronOcr.License.IsLicensed; // Verify without a network call
' Identical startup code on any hardware topology
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim valid As Boolean = IronOcr.License.IsLicensed ' Verify without a network call
$vbLabelText   $csharpLabel

問題5:RecognitionSettingsオブジェクトにIronOCR相当のオブジェクトが存在しない

Kofax OmniPage:OmniPageは、各ドキュメントでエンジンの動作を構成するためにPreprocessingSettings)を使用します。 移行するチームは、 IronOCRに並行構成オブジェクトが存在することを期待しています。

解決策:IronOCRは、IronTesseractでのエンジン設定の2つの表面で設定を分割します。 インスタンス化できる設定オブジェクトがありません。

// OmniPage settings object → IronOCR method calls on OcrInput
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English;              // RecognitionSettings.Language
// ocr.Configuration.TesseractVersion = ...     // Engine version already optimized

using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew();                                  // settings.DeskewImage = true
input.DeNoise();                                 // settings.DespeckleLevel = 2
input.Contrast();                                // settings.ContrastEnhancement = true

var result = ocr.Read(input);
// OmniPage settings object → IronOCR method calls on OcrInput
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.English;              // RecognitionSettings.Language
// ocr.Configuration.TesseractVersion = ...     // Engine version already optimized

using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew();                                  // settings.DeskewImage = true
input.DeNoise();                                 // settings.DespeckleLevel = 2
input.Contrast();                                // settings.ContrastEnhancement = true

var result = ocr.Read(input);
Imports IronOcr

Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.English

Using input As New OcrInput()
    input.LoadImage(imagePath)
    input.Deskew()
    input.DeNoise()
    input.Contrast()

    Dim result = ocr.Read(input)
End Using
$vbLabelText   $csharpLabel

画像品質補正ガイドには、利用可能なすべての前処理方法が一覧表示され、どのフィルターがどの文書品質プロファイルに適用されるかについてのガイダンスが示されています。

問題6:ゾーンテンプレートファイルを直接移植することはできません

Kofax OmniPage:OmniPageのフォームテンプレートは、フィールド位置、認識タイプ、文書クラスごとの検証ルールを定義する独自の.fpfテンプレートファイルにゾーン定義を保存します。 これらのファイルはIronOCRでインポートできません。

解決策:テンプレートファイルから座標データを抽出し(それらはXMLベースです)、各ゾーンをCropRectangleに変換します。 フィールド名が辞書のキーになります。 ゾーン座標は(x, y, width, height)パラメータに直接マップされます。

// Convert OmniPage zone definition to IronOCR CropRectangle
// OmniPage zone: Name="TotalDue" X="490" Y="612" Width="180" Height="28"
// IronOCR equivalent:
var totalDueRegion = new CropRectangle(490, 612, 180, 28);

using var input = new OcrInput();
input.LoadImage(invoicePath, totalDueRegion);
string totalDue = new IronTesseract().Read(input).Text.Trim();
// Convert OmniPage zone definition to IronOCR CropRectangle
// OmniPage zone: Name="TotalDue" X="490" Y="612" Width="180" Height="28"
// IronOCR equivalent:
var totalDueRegion = new CropRectangle(490, 612, 180, 28);

using var input = new OcrInput();
input.LoadImage(invoicePath, totalDueRegion);
string totalDue = new IronTesseract().Read(input).Text.Trim();
Imports IronOcr

' Convert OmniPage zone definition to IronOCR CropRectangle
' OmniPage zone: Name="TotalDue" X="490" Y="612" Width="180" Height="28"
' IronOCR equivalent:
Dim totalDueRegion As New CropRectangle(490, 612, 180, 28)

Using input As New OcrInput()
    input.LoadImage(invoicePath, totalDueRegion)
    Dim totalDue As String = New IronTesseract().Read(input).Text.Trim()
End Using
$vbLabelText   $csharpLabel

ページごとにゾーンが異なるドキュメントの場合、ファイルを再読み込みするのではなく、画像を同じリージョンに異なるCropRectangle値でロードしてください。領域作物の例は、単一イメージソースからの複数のリージョンの読み取りを示しています。

Kofax OmniPage移行チェックリスト

移行前

コードベース内のすべてのOmniPage統合ポイントを特定します。

# Find all OmniPage namespace references
grep -r "Kofax\|OmniPage\|CSDK" --include="*.cs" --include="*.csproj" .

# Find engine lifecycle calls
grep -r "Initialize\|Shutdown\|SetLicenseFile" --include="*.cs" .

# Find document and zone creation patterns
grep -r "CreateDocument\|AddPage\|FormZone\|RecognitionSettings\|PreprocessingSettings" --include="*.cs" .

# Find output format configuration
grep -r "OutputSettings\|OutputFormat\|SaveAs\|GetText" --include="*.cs" .

# Find license file path references
grep -r "\.lic\|license\.lic\|licensePath" --include="*.cs" --include="*.config" --include="*.json" .
# Find all OmniPage namespace references
grep -r "Kofax\|OmniPage\|CSDK" --include="*.cs" --include="*.csproj" .

# Find engine lifecycle calls
grep -r "Initialize\|Shutdown\|SetLicenseFile" --include="*.cs" .

# Find document and zone creation patterns
grep -r "CreateDocument\|AddPage\|FormZone\|RecognitionSettings\|PreprocessingSettings" --include="*.cs" .

# Find output format configuration
grep -r "OutputSettings\|OutputFormat\|SaveAs\|GetText" --include="*.cs" .

# Find license file path references
grep -r "\.lic\|license\.lic\|licensePath" --include="*.cs" --include="*.config" --include="*.json" .
SHELL

開始前の在庫確認:

  • OmniPage名前空間インポートを含むファイルの数をカウントする
  • すべてのFormZone定義をリストし、座標データを抽出してください
  • 読み込まれた言語辞書を特定し、IronOcr.Languages.* NuGetパッケージにマッピングします
  • 使用されている出力形式(検索可能なPDF、プレーンテキスト、XML)と、それらに対応するIronOCR形式をメモしてください。
  • デプロイメントスクリプトおよび設定でのすべての.licファイル参照を特定します

コードの移行

  1. すべての.csprojファイルからOmniPage DLL参照を削除します
  2. OCRを実行する各プロジェクトでdotnet add package IronOcrを実行します
  3. 使用する言語ごとに言語パックを追加します: dotnet add package IronOcr.Languages.[Language]
  4. 各アプリケーションエントリポイント(Program.cs, Startup.csまたはサービスホスト)でIronOcr.License.LicenseKey = ...;を追加します
  5. すべてのusing Kofax.OmniPage.CSDK;, using CSDK;, および関連する名前空間のインポートをusing IronOcr;で置き換えます
  6. すべてのInitialize呼び出しを削除します
  7. すべてのIDisposableの実装を削除します
  8. engine.CreateDocument() + document.AddPage()new OcrInput() + input.LoadImage() に置き換えます
  9. engine.OpenPDF() + ページごとのイテレーションをinput.LoadPdf() (すべてのページを一度に) に置き換えます
  10. engine.OpenTiff() + フレームごとのループをinput.LoadImageFrames()に置き換えます
  11. new IronTesseract().Read(input)に置き換えます
  12. CropRectangle(x, y, width, height)インスタンスに変換します
  13. input.LoadImage(path, cropRectangle) + result.Textで置き換えます
  14. 検索可能なPDFのresult.SaveAsSearchablePdf(path)で置き換えます
  15. 結果イテレーターのパターンをresult.Pages / .Paragraphs / .Wordsプロパティの移動で置き換えます
  16. input.Deskew(), input.DeNoise(), input.Contrast()メソッド呼び出しで置き換えます
  17. デプロイメントスクリプト、構成ファイル、およびインフラストラクチャ・アズ・コードのテンプレートからライセンスファイルのパスを削除します。

移行後

  • 実際のコーパスから抽出した100件以上の文書の代表サンプルでOCRの精度を検証します。請求書、契約書、フォームについて、OmniPageの出力と行ごとに比較します。
  • OmniPage CropRectangleベースのゾーン抽出が確認されます
  • 複数ページPDFの処理をテストする:ページ数、ページ順序、テキストの連続性を確認する
  • マルチフレームTIFF処理のテスト:すべてのフレームが処理され、フレームシーケンスが保持されていることを確認します。 検索可能なPDF出力が、使用している文書管理システム(SharePoint、OpenTextなど)でインデックス化可能であることを確認します。
  • 50以上の同時ドキュメントで並列処理テストを実行し、スレッドセーフティの問題がないことを確認します。
  • 言語パックカバレッジをテストします: 以前使用されたすべての言語辞書をIronOcr.Languages.*を介して読み込み、認識品質を確認します プロセスクラッシュやコンテナの再起動時にライセンス復旧措置が必要ないことを確認します。
  • DockerビルドをCIエージェントで実行し、dotnet restoreがインストーラーステップなしでIronOCRを解決することを確認します
  • 単語ごとに信頼度スコアが利用可能であり、下流の検証ワークフローのデータ品質要件に合致していることを検証する
  • どのパスにも.licファイルが存在しないときにアプリケーションが正常に起動することを確認します

IronOCRへの移行の主なメリット

デプロイメントの複雑さが数週間から数分に低下します。 以前にSDKインストーラーアクセス、dotnet restore経由で展開されます。 新しい開発者はリポジトリをクローンしてプロジェクトを実行します。 CI/CDパイプラインによって新しい本番サーバーがプロビジョニングされます。コンテナイメージはインストーラーの手順なしで構築されます。

ライセンスリスクは完全に消えます。 フローティングシートが消耗することはなく、チェックアウトタイムアウトを待つ必要もなく、ハードウェアフィンガープリントを再アクティブ化する必要もなく、デプロイメントパイプラインで保護するための.licファイルもありません。 午前3時にアプリケーションがクラッシュしても、何も解放されず、何もロックされない。 待機中のエンジニアがプロセスを再開する。 OCR処理は直ちに再開されます。 IronOCRの製品ページには、すべてのライセンスプランが掲載されています。

クロスプラットフォーム展開が標準的なNuGetターゲットになります。macOS開発マシンはプラットフォーム例外なしで動作します。 Linuxのプロダクションサーバーでは、2026年1月版のSDKは必要ありません。 Dockerコンテナは、1つのシステム依存を持つ標準のmcr.microsoft.com/dotnet/aspnetベースイメージからビルドされます。 同じ.csprojで、Windows、Linux、macOSで動作するビルドを生成します。 クラウド固有の設定については、 Azure デプロイガイドおよびAWS デプロイガイドを参照してください。

並列処理のスループットはハードウェアの性能に比例します。OmniPageの共有エンジンアーキテクチャでは、同時認識を直列化するためのロック機構が必要です。 IronOCRのステートレスIronTesseractインスタンスは、利用可能なCPUコアにリニアにスケールします。 バッチ処理サーバーのコア数を倍増させると、構成変更や追加ライセンスなしでスループットが倍増します。

構造化データアクセスは即時です。OcrResult.Pages, Paragraphs, Lines, Words, およびCharactersは、完全な文書構造をナビゲート可能な.NETオブジェクトグラフとして公開します。 単語ごとの信頼度と座標は、各単語オブジェクトのプロパティです。 位置データにアクセスするために、二次的なエクスポートパイプライン、フォーマット設定、ファイル出力は必要ありません。

費用は固定されており、予測可能です。OmniPageのSDKライセンス、年間保守料金、およびページごとの実行時料金の組み合わせにより、費用は使用量に応じて増加し、毎年発生します。 IronOCRは、$999–$2,999 永久購入です。 年間50万ペー​​ジを処理するワークフローで、ページごとの料金が発生していた場合でも、 IronOCRのライセンス費用は数週間以内に回収できる。 IronOCRのドキュメントハブチュートリアルは、サポート契約なしで利用できます。

ご注意Kofax OmniPage、OpenPDF、およびTesseractは、それぞれの所有者の登録商標です。 このサイトはGoogle、Kofax、またはLibrePDFによって、承認されたものではなく、後援されていません。 すべての製品名、ロゴ、およびブランドは各所有者の所有物です。 比較は情報提供のみを目的としており、執筆時点で公開されている情報を反映しています。

よくある質問

なぜKofax OmniPageからIronOCRに移行する必要があるのですか?

一般的な推進要因には、COM相互接続の複雑さの解消、ファイルベースのライセンス管理の置き換え、ページ単位の課金の回避、Docker/コンテナデプロイの有効化、標準的な.NETツールと統合するNuGetネイティブワークフローの採用などがあります。

Kofax OmniPageからIronOCRに移行する際の主なコード変更は何ですか?

Kofax OmniPageの初期化シーケンスをIronTesseractのインスタンス化に置き換え、COMのライフサイクル管理(明示的なCreate/Load/Closeパターン)を削除し、結果のプロパティ名を更新します。その結果、定型的な行が大幅に減りました。

IronOCRをインストールして移行を開始するにはどうすればいいですか?

パッケージマネージャーコンソールで'Install-Package IronOcr'を実行するか、CLIで'dotnet add package IronOcr'を実行してください。言語パックは別のパッケージです:例えばフランス語の場合は'dotnet add package IronOcr.Languages.French'となります。

IronOCRはKofax OmniPageの標準的なビジネス文書のOCR精度に匹敵しますか?

IronOCRは、請求書、契約書、領収書、入力フォームなどの標準的なビジネスコンテンツで高い精度を達成しています。画像前処理フィルター(傾き補正、ノイズ除去、コントラスト強調)により、劣化した入力の認識をさらに向上させます。

IronOCR は Kofax OmniPage が別途インストールする言語データをどのように扱うのですか?

IronOCRの言語データはNuGetパッケージとして配布されます。'dotnet add package IronOcr.Languages.German'でドイツ語のサポートがインストールされます。手動でのファイル配置やディレクトリパスは必要ありません。

Kofax OmniPage から IronOCR への移行には、導入インフラの変更が必要ですか?

IronOCR は Kofax OmniPage よりもインフラの変更が少なくて済みます。SDK のバイナリパス、ライセンスファイルの配置、ライセンスサーバーの設定は必要ありません。NuGet パッケージには完全な OCR エンジンが含まれ、ライセンスキーはアプリケー ションコードに設定された文字列です。

移行後のIronOCRライセンスの設定方法は?

アプリケーションの起動コードでIronOcr.License.LicenseKey = "YOUR-KEY "を割り当てます。DockerまたはKubernetesでは、キーを環境変数として保存し、スタートアップで読み込む。License.IsValidLicenseを使用して、トラフィックを受け入れる前にバリデーションを行う。

IronOcr は Kofax OmniPage と同じように PDF を処理できますか?

IronOCRはネイティブPDFもスキャンしたPDFも読み取ります。IronTesseractをインスタンス化し、ocr.Read(input)を呼び出し、入力はPDFパスまたはOcrPdfInputであり、OcrResultページを反復します。別のPDFレンダリングパイプラインは必要ありません。

IronOCRはどのように大量処理のスレッディングを処理するのですか?

IronTesseractはスレッド毎にインスタンス化しても安全です。Parallel.ForEachまたはタスクプールでスレッドごとにインスタンスを1つスピンアップし、OCRを同時に実行し、完了したら各インスタンスを破棄します。グローバルステートやロックは必要ありません。

IronOCRはテキスト抽出後、どのような出力形式をサポートしていますか?

IronOCRはテキスト、単語座標、信頼度スコア、ページ構造を含む構造化された結果を返します。エクスポートオプションには、プレーンテキスト、検索可能なPDF、下流処理用の構造化結果オブジェクトが含まれます。

IronOCR の価格は、Kofax OmniPage よりもワークロードのスケーリングが予測できますか?

IronOCRは、定額制の永久ライセンスを採用しており、ページ単位やボリューム単位の料金はかかりません。10,000ページでも1,000万ページでも、ライセンスコストは一定です。ボリュームライセンスとチームライセンスのオプションはIronOCRの価格ページをご覧ください。

Kofax OmniPageからIronOCRに移行した後、既存のテストはどうなりますか?

抽出されたテキストコンテンツをアサートするテストは、移行後もパスし続ける必要があります。APIコールパターンやCOMオブジェクトのライフサイクルを検証するテストは、IronOCRのシンプルな初期化と結果モデルを反映するように更新する必要があります。

Kannaopat Udonpant
ソフトウェアエンジニア
ソフトウェアエンジニアになる前に、Kannapatは北海道大学で環境資源の博士号を修了しました。博士号を追求する間に、彼はバイオプロダクションエンジニアリング学科の一部である車両ロボティクスラボラトリーのメンバーになりました。2022年には、C#のスキルを活用してIron Softwareのエンジニアリングチームに参加し、IronPDFに注力しています。Kannapatは、IronPDFの多くのコードを執筆している開発者から直接学んでいるため、この仕事を大切にしています。同僚から学びながら、Iron Softwareでの働く社会的側面も楽しんでいます。コードやドキュメントを書いていない時は、KannapatはPS5でゲームをしたり、『The Last of Us』を再視聴したりしていることが多いです。

アイアンサポートチーム

私たちは週5日、24時間オンラインで対応しています。
チャット
メール
電話してね