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

OCRツールを使用して画像からアラビア語のテキストを抽出する方法

このガイドでは、 .NET開発者が GdPicture .NET OCR からIronOCRへ完全に移行する方法を説明します。 本書では、主要なOCRワークフローすべてにおけるパッケージの入れ替え、名前空間の変更、および実用的な変更前後のコードパターンについて解説し、特にGdPictureのリソース管理モデルを定義する整数画像IDライフサイクルの排除に重点を置いています。 比較記事を事前に読む必要はありません。

GdPicture .NETから移行する理由

GdPicture .NETは、スキャナーとの統合、DICOMサポート、PDF編集、注釈付け、OCRといった機能を単一ベンダーから必要とするチーム向けに構築されたドキュメントイメージングプラットフォームです。 OCRが唯一の要件である場合、プラットフォームの価格設定とAPIアーキテクチャは、時間の経過とともに蓄積される摩擦を生み出す。

基本的なOCRワークフローに必要なプラグインの費用。スキャンしたPDFからテキストを抽出し、検索可能な出力を生成するには、3つのライセンスコンポーネントが必要です。コアSDKが約4,000ドル、OCRプラグインが約2,000ドル、PDFプラグインが約2,000ドルです。つまり、初期費用は8,000ドルで、Plus年間保守費用として20%がかかります。 OCR機能のみを必要とするチームでも、文書画像処理プラットフォームの料金体系全体を負担することになる。 IronOCRは、単一のパッケージでイメージOCR、PDF OCR、前処理、検索可能なPDF出力の同じワークフローを$999から$2,999の永続ライセンスでカバーします。機能ごとのライセンス決定はありません。 ライセンス階層の詳細については、 IronOCRのライセンスページをご覧ください。

整数画像IDのライフサイクル。 GdPictureを通してロードされたすべての画像はintを返します。 その整数をOCR操作に渡し、完了したらそれを使用してReleaseGdPictureImageを呼び出します。 このパターンはIDisposableより前から存在しています。 正しく手順に従えば効果を発揮します。 欠落するとメモリリークが発生します。 毎日数百ものドキュメントを処理する本番環境において、エラー分岐でリリース呼び出しが一度でも漏れると、メモリ使用量が急増し、その原因究明が非常に困難になる。 IronOCRのusingステートメントがすべてのクリーンアップの負担を排除します。

バージョン固有の名前空間。 GdPictureは主バージョン番号をその名前空間に埋め込んでいます: using GdPicture14。 次のメジャーリリースへのアップグレードには、GdPictureクラスを参照しているすべてのソースファイルのusing指令の更新が必要です。 OCRが数十ものサービスにまたがる大規模なアプリケーションでは、検索と置換に何時間もかかる上に、​​機能的な改善も得られない。 IronOCRの名前空間は、すべてのメジャーバージョンを通じてIronOcrです。

外部リソースフォルダーの要件。 GdPicture OCRは実行時に.traineddata言語ファイルのディレクトリを指します。そのパスは開発マシン上では機能しますが、Linuxサーバー、Dockerコンテナ、およびAzure App Serviceデプロイメントなど、ディレクトリ構造が存在しない場所では機能しません。IronOCRはNuGetパッケージ内に英語の言語サポートをバンドルしています。 追加言語は、ビルド出力に含まれるNuGetパッケージとしてインストールされます。

三コンポーネント初期化。 GdPictureでのPDF OCRワークフローは、GdPicturePDF—個別の破棄要件がある3つの別々のコンポーネント—およびライセンスマネージャーの登録とリソースフォルダーの割り当てを必要とします。 IronOCRは起動時に1行、呼び出し時に1つのクラスを必要とします。

ネイティブなスレッドセーフティはありません。GdPicture OCRインスタンスはスレッドセーフではありません。 並列文書処理では、状態の破損を防ぐために、インスタンスの慎重な管理と同期が必要となる。 IronOCRは同時使用を想定して設計されています: スレッドごとに1つのIronTesseractを作成するか、ロード時に単一のインスタンスを共有する—どちらのパターンも追加の同期コードなしで機能します。

基本的な問題

GdPictureは、各画像に対してランタイム管理の整数ハンドルとしてメモリを割り当てます。 TIFF処理ループでのすべてのRenderPageToGdPictureImage呼び出しは、新しい割り当てを生成し、手動でリリースする必要があります:

// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
Imports System.Collections.Generic

' GdPicture: every frame = new integer ID = manual release required
Using pdf As New GdPicturePDF()
    pdf.LoadFromFile("multi-page.tiff", False)

    Dim frameIds As New List(Of Integer)()
    Try
        For i As Integer = 1 To pdf.GetPageCount()
            pdf.SelectPage(i)
            Dim frameId As Integer = pdf.RenderPageToGdPictureImage(200, False) ' new allocation
            If frameId <> 0 Then frameIds.Add(frameId)
            ' ... OCR call here ...
        Next
    Finally
        For Each id In frameIds
            _imaging.ReleaseGdPictureImage(id) ' manual per-frame release
        Next
    End Try
End Using
$vbLabelText   $csharpLabel

IronOCRはライフサイクルを完全に排除します。 OcrInputはフレーム列挙とクリーンアップを処理します:

// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
Imports IronOcr

Dim input As New OcrInput()
Using input
    input.LoadImageFrames("multi-page.tiff")
    Dim result = New IronTesseract().Read(input)
End Using
$vbLabelText   $csharpLabel

IronOCRと.NET:機能比較

以下の表は、OCRを中心としたワークフローにおける、2つのライブラリの機能カバレッジを示しています。

フィーチャー GdPicture.NET IronOCR
インストール 複数のNuGetパッケージ dotnet add package IronOcr
ライセンス認証 LicenseManager.RegisterKEY() IronOcr.License.LicenseKey = "..."
メジャーアップグレード時の名前空間 置換が必要 (GdPicture14 → next) 変更されていない (IronOcr)
コンポーネントの初期化 GdPictureImaging + GdPictureOCR + GdPicturePDF new IronTesseract()
リソースメモリモデル 手動整数ID追跡とリリース IDisposable / using
メモリリークのリスク 高い (欠落ReleaseGdPictureImage) なし (コンパイラーによってusingで強制される)
外部リソースフォルダ 必須 (_ocr.ResourceFolder = path) 不要 — パッケージに同梱されています
画像OCR はい はい
PDF OCR はい(PDFプラグインが必要です) 組み込み済み、追加ライセンス不要
複数ページTIFF 手動フレームループ+フレームごとのIDクリーンアップ input.LoadImageFrames()
ストリーム入力 GdPictureImaging ストリームオーバーロードを介して input.LoadImage(stream)
検索可能なPDF出力 pdf.OcrPage() + pdf.SaveToFile() result.SaveAsSearchablePdf()
デスクウ前処理 ドキュメントイメージングプラグインが必要です input.Deskew() — ビルトイン
ノイズ除去 ドキュメントイメージングプラグインが必要です input.DeNoise() — ビルトイン
言語 Tesseract ベースの学習済みデータファイルがフォルダー内にあります NuGetパッケージ経由で125以上
多言語OCR はい OcrLanguage.French + OcrLanguage.German
スレッドセーフ 手動インスタンス管理 スレッドセーフ設計
非同期OCR ビルトインではない ReadAsync()
バーコード読み取り 別売りのバーコードプラグイン ocr.Configuration.ReadBarCodes = true
構造化された出力 インデックスベースのブロック/行/単語アクセス 型付き.Characters
信頼度スコア GetOCRResultConfidence(resultId) result.Confidence
クロスプラットフォーム Windows、Linux、macOS Windows、Linux、macOS、Docker、AWS、Azure
入場料(PDFからのOCR) 約8,000ドル(コア機能+OCR機能+PDFプラグイン) $999–$2,999
価格設定モデル プラグインベースの永久ライセンス + 年間メンテナンス料20% 定額永久プラン、年間更新オプションあり
商業サポート はい はい

クイックスタート:GdPicture .NETからIronOCRへの移行

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

GdPictureパッケージを削除してください。

dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
SHELL

NuGetパッケージページからIronOCRをインストールしてください。

dotnet add package IronOcr

英語以外の言語については、対応する言語パックをインストールしてください。

dotnet add package IronOcr.Languages.French, IronOcr.Languages.German

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

GdPicture名前空間をIronOCR名前空間に置き換えてください。

// Before (GdPicture)
using GdPicture14;

// After (IronOCR)
using IronOcr;
// Before (GdPicture)
using GdPicture14;

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

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

この行をStartup.csに、OCR呼び出しの前に配置します:

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

GdPictureのライセンス登録ブロックを完全に削除してください。

// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
$vbLabelText   $csharpLabel

IronOCRの製品ページから無料トライアルキーを入手して、購入前に評価することができます。

コード移行の例

複数ページTIFFフレーム処理

GdPictureで複数ページのTIFFファイルを処理するには、PDF/イメージングAPIを介して各フレームを選択し、それを新しいイメージIDにレンダリングし、OCRを実行し、IDを解放する必要があります。 finallyブロックでリリースされない単一のフレームは、DPIに応じて10–50 MBのメモリをリークします。

GdPicture .NETアプローチ:

using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
Imports GdPicture14
Imports System.Text

Public Class GdPictureTiffProcessor
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Dim text As New StringBuilder()

        ' Load TIFF through the imaging component
        Dim tiffId As Integer = _imaging.CreateGdPictureImageFromFile(tiffPath)

        If tiffId = 0 Then
            Throw New Exception($"TIFF load failed: {_imaging.GetStat()}")
        End If

        ' Outer try: release the original TIFF handle
        Try
            Dim frameCount As Integer = _imaging.GetPageCount(tiffId)

            For i As Integer = 1 To frameCount
                ' Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i)

                ' Clone frame to a new image ID for OCR
                Dim frameId As Integer = _imaging.CloneImage(tiffId)

                If frameId = 0 Then Continue For

                ' Inner try: release each cloned frame ID
                Try
                    _ocr.SetImage(frameId)
                    _ocr.Language = "eng"

                    Dim resultId As String = _ocr.RunOCR()

                    If Not String.IsNullOrEmpty(resultId) Then
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}")
                    End If
                Finally
                    ' Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId)
                End Try
            Next
        Finally
            ' Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId)
        End Try

        Return text.ToString()
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
Imports IronOcr

Public Class IronOcrTiffProcessor
    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Using input As New OcrInput()
            input.LoadImageFrames(tiffPath) ' all frames loaded, all cleanup automatic

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

            ' Per-frame text is available on result.Pages
            For Each page In result.Pages
                Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}")
            Next

            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

usingブロックは、スコープの終わりですべてのフレームに関連するメモリを処理します。 維持する必要のあるtry/finallyブロックも必要ありません。 TIFFおよびGIF入力ガイドでは、フレーム選択とマルチフォーマット処理について詳しく解説しています。

ストリームベース入力置換プラグインの初期化

サーバーアプリケーションは、HTTPアップロード、メッセージキュー、データベースのブロブなどから、ファイルパスではなくストリームとしてドキュメントを受け取ることがよくあります。 GdPictureはストリームをGdPictureImagingを通じてロードする必要があり、それ自体がすべての操作に先立つコンポーネント初期化シーケンスとリソースフォルダー構成を要求します。

GdPicture .NETアプローチ:

using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

        return new IronTesseract().Read(input).Text;
    }
}
using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

        return new IronTesseract().Read(input).Text;
    }
}
Imports IronOcr

Public Class IronOcrStreamOcr
    Public Function ExtractTextFromStream(documentStream As Stream) As String
        Using input As New OcrInput()
            input.LoadImage(documentStream) ' stream accepted directly — no imaging component

            Return New IronTesseract().Read(input).Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

GdPicture方式では、最初のストリームを消費する前に、3つのオブジェクトを構築し、ファイルシステムパスを設定する必要があります。 IronOCRは事前設定なしでOcrInputにストリームを直接受け入れます。ストリーム入力ガイド は、テンポラリファイル書き込みが望ましくないパイプラインアーキテクチャのために、バイト配列、FileStreamパターンをカバーしています。

非同期OCRがステータスコードポーリングを置き換える

GdPicture OCRは同期型です。 ASP.NET Coreエンドポイントやバックグラウンドサービスでドキュメントを処理するアプリケーションは、リクエストスレッドをブロックしないようにTask.Runでラップする必要があります。そして、そのスレッド境界を越えた画像IDライフサイクルを管理する必要があります。 IronOCRはReadAsyncを通じて一級の非同期サポートを提供します。

GdPicture .NETアプローチ:

using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
Imports GdPicture14
Imports System.Threading.Tasks

Public Class GdPictureAsyncWrapper
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR
    Private ReadOnly _lock As New SemaphoreSlim(1, 1)

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' Must acquire lock: GdPictureOCR is not thread-safe
        Await _lock.WaitAsync()

        Try
            Return Await Task.Run(Function()
                                      Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(imagePath)

                                      If imageId = 0 Then
                                          Throw New Exception($"Load failed: {_imaging.GetStat()}")
                                      End If

                                      Try
                                          _ocr.SetImage(imageId)
                                          _ocr.Language = "eng"

                                          Dim resultId As String = _ocr.RunOCR()

                                          If String.IsNullOrEmpty(resultId) Then
                                              Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                                          End If

                                          Return _ocr.GetOCRResultText(resultId)
                                      Finally
                                          _imaging.ReleaseGdPictureImage(imageId)
                                      End Try
                                  End Function)
        Finally
            _lock.Release()
        End Try
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

public class IronOcrAsyncService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
using IronOcr;

public class IronOcrAsyncService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
Imports IronOcr
Imports System.IO
Imports System.Threading.Tasks

Public Class IronOcrAsyncService
    Private ReadOnly _ocr As New IronTesseract()

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' ReadAsync is natively async — no Task.Run wrapper, no lock required
        Dim result = Await _ocr.ReadAsync(imagePath)
        Return result.Text
    End Function

    Public Async Function ExtractFromStreamAsync(stream As Stream) As Task(Of String)
        Using input As New OcrInput()
            input.LoadImage(stream)

            Dim result = Await _ocr.ReadAsync(input)
            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

GdPictureのアプローチでは、共有Task.Runと、そのラムダ内の完全な画像IDライフサイクルが必要です。 IronOCRのReadAsyncは本当にノンブロッキングでスレッドセーフです。 非同期OCRガイドでは、 ASP.NET Coreミドルウェアおよびホスト型バックグラウンドサービスとの統合について解説しています。

スレッドセーフティを備えた並列バッチ処理

スキャンした文書のフォルダをできるだけ高速に処理するには、並列処理が必要です。 GdPictureはスレッドごとに1つのGdPictureOCRインスタンスを必要とします—単一のインスタンスを共有すると非決定的な障害が発生します。 各スレッドごとのインスタンスには、それ自身のGdPictureImagingコンポーネントとリソースフォルダー構成が必要で、ファクトリーパターンなしではスレッドプールアプローチが非現実的になります。

GdPicture .NETアプローチ:

using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

        return results;
    }
}
using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

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

Public Class GdPictureParallelBatch
    Private ReadOnly _resourceFolder As String = "C:\GdPicture\Resources\OCR"

    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' Each thread must have its own component instances
        Parallel.ForEach(imagePaths, Sub(imagePath)
            ' Create per-thread instances — shared instances cause failures
            Using threadImaging As New GdPictureImaging()
                Using threadOcr As New GdPictureOCR()
                    threadOcr.ResourceFolder = _resourceFolder

                    ' Re-register license per thread (may be required depending on SDK version)
                    Dim lm As New LicenseManager()
                    lm.RegisterKEY("GDPICTURE-LICENSE-KEY")

                    Dim imageId As Integer = threadImaging.CreateGdPictureImageFromFile(imagePath)

                    If imageId = 0 Then
                        results(imagePath) = $"ERROR: {threadImaging.GetStat()}"
                        Return
                    End If

                    Try
                        threadOcr.SetImage(imageId)
                        threadOcr.Language = "eng"

                        Dim resultId As String = threadOcr.RunOCR()
                        results(imagePath) = If(String.IsNullOrEmpty(resultId), $"ERROR: {threadOcr.GetStat()}", threadOcr.GetOCRResultText(resultId))
                    Finally
                        threadImaging.ReleaseGdPictureImage(imageId)
                    End Try
                End Using
            End Using
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

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

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

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

Public Class IronOcrParallelBatch
    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' IronTesseract is thread-safe — one instance handles all threads
        Dim ocr As New IronTesseract()

        Parallel.ForEach(imagePaths, Sub(imagePath)
            Try
                results(imagePath) = ocr.Read(imagePath).Text
            Catch ex As Exception
                results(imagePath) = $"ERROR: {ex.Message}"
            End Try
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

GdPictureの並列実装では、スレッドごとに3つのオブジェクトが作成され、スレッドごとのライセンス登録が必要です。 IronOCRは、同期のオーバーヘッドなしで単一のIronTesseractインスタンスから同時読み取りを処理します。 マルチスレッディングの例 では、大量のドキュメント処理ワークロードのためのスループットベンチマークとParallel.ForEachパターンを示しています。

バイト配列入力と構造化段落抽出

データベースやオブジェクトストレージからドキュメントを取得するアプリケーションは、ファイルパスではなくバイト配列を扱うことが多い。 GdPictureは、バイト配列をストリームに変換し、それをGdPictureImagingを通じてロードする必要があります。 結果から構造化された段落レベルのデータを抽出するには、ブロック/行インデックスの階層構造をたどる必要があります。

GdPicture .NETアプローチ:

using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
Imports GdPicture14
Imports System.IO
Imports System.Text

Public Class GdPictureByteArrayOcr
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Dim paragraphs As New List(Of String)()

        ' Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        Using ms As New MemoryStream(imageBytes)
            Dim imageId As Integer = _imaging.CreateGdPictureImageFromStream(ms)

            If imageId = 0 Then
                Throw New Exception($"Byte array load failed: {_imaging.GetStat()}")
            End If

            Try
                _ocr.SetImage(imageId)
                _ocr.Language = "eng"

                Dim resultId As String = _ocr.RunOCR()

                If String.IsNullOrEmpty(resultId) Then
                    Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                End If

                ' Paragraph-level data requires iterating block structure
                Dim blockCount As Integer = _ocr.GetOCRResultBlockCount(resultId)

                For b As Integer = 0 To blockCount - 1
                    Dim blockText As New StringBuilder()
                    Dim lineCount As Integer = _ocr.GetOCRResultBlockLineCount(resultId, b)

                    For l As Integer = 0 To lineCount - 1
                        Dim wordCount As Integer = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l)

                        For w As Integer = 0 To wordCount - 1
                            blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w))
                            blockText.Append(" "c)
                        Next
                    Next

                    Dim text As String = blockText.ToString().Trim()
                    If Not String.IsNullOrEmpty(text) Then
                        paragraphs.Add(text)
                    End If
                Next
            Finally
                _imaging.ReleaseGdPictureImage(imageId)
            End Try
        End Using

        Return paragraphs
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
Imports IronOcr

Public Class IronOcrByteArrayOcr
    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Using input As New OcrInput()
            input.LoadImage(imageBytes) ' byte array accepted directly

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

            ' Paragraphs are a first-class typed collection
            Return result.Paragraphs _
                .Select(Function(p) p.Text) _
                .Where(Function(t) Not String.IsNullOrWhiteSpace(t)) _
                .ToList()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCRは、中間的なbyte[]を直接受け入れます。 結果は、ブロック/行/単語のトリプルループを必要としない、型付けされLINQクエリー可能なコレクションとして.Paragraphsを公開します。 読み取り結果ガイドでは、請求書およびフォーム処理ワークフローにおける座標アクセス、信頼性フィルタリング、および構造化出力パターンについて説明します。 文書の特定領域をスキャンする場合は、領域ベースのOCRを参照してください。

GdPicture .NET API からIronOCRへのマッピング リファレンス

GdPicture.NET IronOCR相当値
using GdPicture14; using IronOcr;
LicenseManager.RegisterKEY("key") IronOcr.License.LicenseKey = "key"
new GdPictureImaging() 不要 — OcrInputに内部
new GdPictureOCR() new IronTesseract()
new GdPicturePDF() 不要 — OcrInput.LoadPdf()がこれを処理
_ocr.ResourceFolder = path 必須ではありません — NuGetにバンドルされているリソース
imaging.CreateGdPictureImageFromFile(path) input.LoadImage(path)
imaging.CreateGdPictureImageFromStream(stream) input.LoadImage(stream)
imaging.CreateGdPictureImageFromBytes(bytes) input.LoadImage(bytes)
フレームごとにimaging.CloneImage(tiffId) input.LoadImageFrames(tiffPath)
imaging.ReleaseGdPictureImage(imageId) using var input = new OcrInput() — 自動
ocr.SetImage(imageId) 不要 — OcrInputが画像を保持
ocr.Language = "eng" ocr.Language = OcrLanguage.English
ocr.RunOCR()resultId文字列 ocr.Read(input) → 型付きOcrResult
ocr.GetOCRResultText(resultId) result.Text
ocr.GetOCRResultConfidence(resultId) result.Confidence
ocr.GetOCRResultBlockCount(resultId) result.Pages[i].Paragraphs.Count
ocr.GetOCRResultBlockLineWordText(resultId, b, l, w) result.Words[i].Text
imaging.GetStat() / ocr.GetStat() .NET Standardの例外
各呼び出し後にGdPictureStatus.OKチェック 必須ではありません — 例外が伝播します
pdf.OcrPage("eng", resourcePath, "", 200) result.SaveAsSearchablePdf(outputPath)
pdf.RenderPageToGdPictureImage(200, false) 不要 — IronOCRは内部的にレンダリングします
pdf.SelectPage(i) 必須ではありません — すべてのページはデフォルトで処理されます
pdf.GetPageCount() result.Pages.Count
Task.Run(() => ocr.RunOCR()) + SemaphoreSlim await ocr.ReadAsync(input)

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

問題1:リファクタリング後もコード内に画像ID変数が残っている

GdPicture.NET: 既存のコードはメソッドの先頭でint imageIdを宣言し、try/finallyでそれを追跡し、複数のGdPicture呼び出しに渡します。 GdPicture呼び出しを置き換えた後、これらの変数とそのReleaseGdPictureImage呼び出しは孤立したデッドコードになります。

解決策:画像IDパターン全体を削除します。 宣言、using var input = new OcrInput()ブロックで置き換えます。 削除する必要があるすべてのクリーンアップ呼び出しを見つけるためにReleaseGdPictureImageをグレップします:

grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
SHELL
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
' Remove all of this
Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(path)
Try
    _ocr.SetImage(imageId)
    Dim resultId As String = _ocr.RunOCR()
    Return _ocr.GetOCRResultText(resultId)
Finally
    _imaging.ReleaseGdPictureImage(imageId)
End Try

' Replace with
Using input As New OcrInput()
    input.LoadImage(path)
    Return New IronTesseract().Read(input).Text
End Using
$vbLabelText   $csharpLabel

問題2:デプロイされた環境でリソースフォルダパスが見つかりません

GdPicture.NET: _ocr.ResourceFolderで設定されたパスは開発マシンでは解決しますが、本番環境では失敗します。 一般的な症状は、空の結果を返すサイレントOCR障害、または消失したファイルを名前で特定しない一般的なGdPictureStatusエラーです。

解決策: ResourceFolder割り当てを完全に削除します。 IronOCR NuGetパッケージには英語サポートが組み込まれています。 追加言語はNuGetパッケージとしてインストールされます。 設定またはデプロイするためのファイルシステムパスがありません。

# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
SHELL

問題3:GdPictureStatusのエラー処理が例外処理に置き換えられました

GdPicture.NET: すべての操作はGdPictureStatus列挙値を返すかセットし、直ちにチェックする必要があります。 コードはif (status != GdPictureStatus.OK)ガードで密集しています。 一部のステータスコードは一般的です(例: InvalidParameter)であり、根本的な原因を判断するために文書を参照する必要があります。

解決策: IronOCRは型付き.NET例外をスローします。 ステータスチェックをtry/catchブロックに置き換えてください。 標準のFileNotFoundExceptionは入力不良をカバーします; IronOcr.Exceptions.OcrExceptionはOCR固有のエラーをカバーします。 推奨されるエラー処理パターンについては、 IronTesseractのセットアップガイドを参照してください。

try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
Imports IronOcr
Imports System.IO

Try
    Dim result = New IronTesseract().Read(imagePath)
    Return result.Text
Catch ex As FileNotFoundException
    _logger.LogError("Input file missing: {Path}", ex.FileName)
    Throw
Catch ex As IronOcr.Exceptions.OcrException
    _logger.LogError("OCR processing failed: {Message}", ex.Message)
    Throw
End Try
$vbLabelText   $csharpLabel

問題4: 複数のファイル内のGdPicture14名前空間

GdPicture.NET: 名前空間のバージョン番号は、プロジェクト全体で何十ものファイルにusing GdPicture14;ディレクティブが存在することを意味します。 移行後、これらすべてをusing IronOcr;に置き換える必要があります。

解決策: すべての.csファイルでグローバルな検索と置換を使用し、GdPicture参照が残っていないことを確認します:

# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
SHELL

第5号:TIFFフレームカウントロジック

GdPicture.NET: TIFFフレームを反復するコードは、ファイルのロード方法によってGdPicturePDF.GetPageCount()の呼び出しを混在させていることがよくあります。 フレームインデックスは1から始まります。

解決策: input.LoadImageFrames(path)はすべてのフレームを自動的に処理します。 既存のコードが特定のフレームのみを処理する場合、0ベースのインデックス配列でinput.LoadImageFrames(path, frameNumbers)を使用します。 フレームごとの結果にはゼロインデックス化されたresult.Pagesを通じてアクセスします。 TIFF入力ガイドには、インデックスの動作が明示的に記載されています。

問題6:前処理には文書イメージングプラグインが必要です

GdPicture.NET: 傾き補正およびゴミ取り操作はGdPictureDocumentImagingプラグインに属し、別途ライセンスの購入が必要です。 プラグインを導入しなかったチームは、傾きやノイズの多いスキャン文書において、OCRの精度に問題が生じることが多い。

解決策: IronOCRの前処理方法は基本パッケージに含まれています。 OcrInputに追加します。 画像品質補正ガイドは、DeepCleanBackgroundNoise()を含む、すべての利用可能なフィルターを扱っています。

using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

var result = new IronTesseract().Read(input);
using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

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

Using input As New OcrInput()
    input.LoadImage("scanned-document.tiff")
    input.Deskew() ' no separate plugin license
    input.DeNoise()
    input.Contrast()

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

GdPicture .NET移行チェックリスト

移行前

変更を加える前に、コードベースを監査して、GdPictureへの依存関係をすべて特定してください。

# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
SHELL

コードを修正する前に、以下の事項を文書化してください。

  • GdPicturePDF参照を含むファイル
  • 異なるイメージIDの作成/リリースペアはいくつ存在しますか?
  • ドキュメントイメージングプラグイン(デスクスキュー、デスペックル)が使用されているかどうか
  • リソースフォルダーにあるtraineddata言語ファイル
  • どのデプロイメントスクリプトまたはDockerファイルがリソースフォルダパスを参照しているか

コードの移行

  1. プロジェクトファイルからすべての GdPicture NuGetパッケージを削除します。
  2. IronOcrをNuGet経由でインストール
  3. リソースフォルダーに以前あった各言語のIronOcr.Languages.*パッケージをインストール
  4. Startup.csに追加
  5. LicenseManager.RegisterKEY()呼び出しとライセンスマネージャーオブジェクトを削除
  6. GdPictureImagingフィールド宣言とコンストラクタ初期化をすべて削除
  7. @ResourceFolder割り当てをすべて削除
  8. OCRワークフローに使用されるGdPicturePDFフィールド宣言をすべて削除
  9. int imageId = _imaging.CreateGdPictureImage*(...)ブロックをusing var input = new OcrInput();で置き換えます。 input.Load*(...)`.
  10. _ocr.SetImage(imageId); を置き換えます。 _ocr.Language = &quot;...&quot;; string resultId = _ocr.RunOCR(); with var result = new IronTesseract().Read(input);
  11. result.Textで置き換え
  12. _imaging.ReleaseGdPictureImage(imageId)の呼び出しをすべて削除
  13. @GdPictureStatusチェックをTRY/CATCHブロックで置き換えます。
  14. TIFFフレームループをinput.LoadImageFrames(path)で置き換えます。
  15. pdf.OcrPage(...) + result.SaveAsSearchablePdf(outputPath)で置き換えます。
  16. デプロイスクリプトとDockerイメージからリソースフォルダパスを削除します。
  17. 影響を受けたすべてのファイルでusing IronOcr;に更新

移行後

すべてのコード変更が完了したら、本番環境にデプロイする前に、以下の点を確認してください。

  • 単一画像OCRは、削除されたコンポーネントからNullReferenceExceptionなしで期待されるテキストを返します
  • マルチページTIFF処理はすべてのフレームをカバーし、result.Pages経由でページごとのテキストを生成します。
  • PDF OCRは、50以上の文書をバッチ処理してもメモリ使用量を増やすことなく、すべてのページを処理します。
  • ストリーム入力は中間ファイル書き込みなしでFileStreamを受け入れます
  • Async OCR は、スレッド プールをブロックすることなくASP.NET Coreリクエスト ハンドラーと統合されます
  • @Parallel.ForEachを使用した並列バッチ処理は、すべてのスレッドで正確な結果を生成します
  • すべての言語パック(フランス語、ドイツ語など)は、 NuGetパッケージを通じて正しく有効化されます。
  • 前処理フィルター(傾き補正、ノイズ除去)により、スキャンした文書の精度が向上します。 検索可能なPDF出力は、PDFビューアおよびテキスト検索アプリケーションで読み取り可能です。
  • マイグレーション後、.csファイルにGdPictureの名前空間参照は残っていません ・メモリプロファイルは、持続的な負荷下でも安定した使用状況を示しています(イメージのメモリリークは発生していません)。 LinuxおよびDockerターゲットへのデプロイは、ファイルシステムパスエラーなしで成功しました。

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

コンパイラによるメモリ安全性の強制。GdPictureで開発者が手動で管理する必要があったイメージIDのライフサイクルは完全に不要になります。 usingブロックが例外パスを含めてすべてのスコープの終了時にクリーンアップを強制します。 維持するfinallyブロックもなく、リリース呼び出しの遺漏による本番メモリインシデントもありません。

すべてのOCRシナリオに対する単一パッケージ。 イメージOCR、PDF OCR、マルチページTIFF処理、検索可能なPDF生成、前処理フィルター、バーコード読み取り、および125以上の言語パックがすべてIronOcr NuGetパッケージとその言語パートナーから利用可能です。 共通のワークフローを実現するために、2つ目または3つ目のライセンスを購入する必要が生じるような機能制限はありません。 機能一覧の詳細は、 IronOCRの機能概要をご覧ください。

ネイティブの非同期とスレッドセーフティ。 Task.Runラッパーではありません。 IronTesseractは同期なしでスレッド間で安全に使用できます。 以前はスレッドごとのコンポーネント初期化とセマフォ直列化を必要としたドキュメント処理サービスは、Parallel.ForEachを使用して単一の共有インスタンスに減少します。 非同期OCRガイドでは、 ASP.NET Coreとホスト型サービスの両方パターンを取り上げています。

デプロイメント構成は不要です。IronOCRは、ファイルシステムパス、外部言語ファイル、ネイティブバイナリの配置、デプロイメントスクリプトを一切必要としません。NuGetの復元手順で、アプリケーションに必要なすべてが提供されます。 Dockerイメージ、Azure App Serviceデプロイメント、Linuxサーバーはすべて、開発環境と全く同じように動作します。DockerデプロイメントガイドAzureデプロイメントガイドでは、本番環境ですぐに使用できる構成例を示しています。

バージョン安定の名前空間。 using IronOcrはメジャーバージョンのリリースの間で変更されていません。 NuGetのバージョン番号は、標準的なパッケージ管理モデルを通じてバージョン管理を行います。 今後の大規模なアップグレードでは、コードベース全体で名前空間のインポートを検索して置換する必要はありません。

予測可能な永続ライセンス。 IronOCRは$999(ライト)で$1,499(プラス)、$2,999(プロフェッショナル)、$5,999(アンリミテッド)で価格設定されており、1年間のアップデートと年次更新のオプションを含む一回限りの永続購入です。 すべての機能はどのプランでも利用可能です。 機能ごとのプラグイン料金やページごとの費用は一切なく、最初の1年以降はメンテナンス義務もありません。 これまでOCRのみのワークフローのためにGdPictureプラグインのライセンスに8,000ドル以上を費やしてきたチームは、最初のライセンスサイクル内でその費用を回収できる。 価格の詳細については、 IronOCRのライセンスページをご覧ください。

ご注意GdPicture.NET および Tesseract は、それぞれの所有者の登録商標です。 このサイトは、Google、Nutrient、または ORPALIS に関連しておらず、承認または支援されていません。 すべての製品名、ロゴ、およびブランドは各所有者の所有物です。 比較は情報提供のみを目的としており、執筆時点で公開されている情報を反映しています。

よくある質問

なぜGdPicture.NET OCRからIronOCRに移行する必要があるのですか?

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

GdPicture.NET OCRからIronOCRに移行する際の主なコード変更は何ですか?

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

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

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

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

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

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

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

GdPicture.NET OCRからIronOCRに移行する場合、導入インフラの変更は必要ですか?

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

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

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

IronOCRはGdPicture.NETと同じようにPDFを処理できますか?

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

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

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

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

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

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

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

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

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

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

アイアンサポートチーム

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