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
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
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
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
ステップ 3: ライセンスの初期化
この行をStartup.csに、OCR呼び出しの前に配置します:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
GdPictureのライセンス登録ブロックを完全に削除してください。
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
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
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
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
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
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
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
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
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
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
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
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" .
// 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
問題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
問題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
問題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" .
第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
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
コードを修正する前に、以下の事項を文書化してください。
GdPicturePDF参照を含むファイル- 異なるイメージIDの作成/リリースペアはいくつ存在しますか?
- ドキュメントイメージングプラグイン(デスクスキュー、デスペックル)が使用されているかどうか
- リソースフォルダーにある
traineddata言語ファイル - どのデプロイメントスクリプトまたはDockerファイルがリソースフォルダパスを参照しているか
コードの移行
- プロジェクトファイルからすべての GdPicture NuGetパッケージを削除します。
IronOcrをNuGet経由でインストール- リソースフォルダーに以前あった各言語の
IronOcr.Languages.*パッケージをインストール Startup.csに追加LicenseManager.RegisterKEY()呼び出しとライセンスマネージャーオブジェクトを削除GdPictureImagingフィールド宣言とコンストラクタ初期化をすべて削除- @
ResourceFolder割り当てをすべて削除 - OCRワークフローに使用される
GdPicturePDFフィールド宣言をすべて削除 - 各
int imageId = _imaging.CreateGdPictureImage*(...)ブロックをusing var input = new OcrInput();で置き換えます。 input.Load*(...)`. - 各
_ocr.SetImage(imageId); を置き換えます。 _ocr.Language = "..."; string resultId = _ocr.RunOCR();withvar result = new IronTesseract().Read(input); result.Textで置き換え_imaging.ReleaseGdPictureImage(imageId)の呼び出しをすべて削除- @
GdPictureStatusチェックをTRY/CATCHブロックで置き換えます。 - TIFFフレームループを
input.LoadImageFrames(path)で置き換えます。 pdf.OcrPage(...)+result.SaveAsSearchablePdf(outputPath)で置き換えます。- デプロイスクリプトとDockerイメージからリソースフォルダパスを削除します。
- 影響を受けたすべてのファイルで
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 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のシンプルな初期化と結果モデルを反映するように更新する必要があります。

