IRONSOFTWAREHOME
ビデオ

AWS TextractからIronOCRへの移行

Kannaopat Udonpant
Kannapat Udonpant
Updated: 2026年6月20日

このガイドでは、クラウドへの依存なしにローカルでドキュメント処理を行う必要がある.NET開発者向けに、AWS TextractからIronOCRへの完全な移行手順を解説します。 このドキュメントでは、認証情報の削除、非同期パイプラインの削除、S3の削除、および各Textract操作をIronOCRの同等の操作に移行するために必要な具体的なコード置換について説明します。

AWS Textractから移行する理由

AWS Textractは優れたマネージドサービスですが、そのアーキテクチャ上、ドキュメントのワークロードが増加するにつれて、金銭的コストと運用コストの両方が増大します。 本格的な文書処理パイプラインを構築するチームは、最終的にこれらの問題点すべてに直面することになる。

AWS認証インフラストラクチャは、あらゆるデプロイメントを複雑化させます。Textractコードを実行するすべての環境には、AWS認証情報が必要です。IAMユーザーまたはロール、アクセスキーとシークレット、リージョン構成、そしてPDF処理の場合はS3バケットのアクセス許可などです。最初のページが処理されるまでに、5つの異なる構成手順が必要になります。 本番デプロイには資格情報の回転ポリシー、DockerコンテナまたはKubernetesポッドへの安全な注入、およびIAMポリシーのドリフトが静かに失敗を引き起こす際のAccessDeniedExceptionの監視が必要です。 IronOCRには、起動時に一度だけ設定するライセンスキーという文字列が1つ必要です。

ページごとの価格に上限はありません。 AnalyzeDocumentをトリガーします。これは基本料金の10倍です。 フォームは1ページにつき0.05ドル追加料金がかかります。 表抽出機能を含む、月間10万ページの混合文書ワークフローの費用は年間1万8000ドルで、この金額は毎年1月にリセットされます。 IronOCRProfessionalライセンスの価格は、2,999ドルの一括払いとなります。 その後は、ページ数に関わらず、1ページあたりの料金はゼロになります。

非同期PDFパイプラインはメンテナンスの責任です。 Textractでの多ページPDFの処理には、S3へのアップロード、StartDocumentTextDetection、ポーリングループ、ページネートされた結果の取得、S3のクリーンアップの5つの異なるフェーズが必要です。各フェーズは独立した失敗モードであり、それぞれにエラーハンドリング、リトライ戦略、タイムアウト管理が必要です。 このパイプラインを本番環境に導入したチームは、構築に費やした時間よりも、保守に費やした時間の方がはるかに長いと一貫して報告している。 IronOCRは、2行のコードでPDFを読み取ります。

**インターネットにアクセスできないと、Textract も利用できません。**隔離されたネットワークセグメント内の Docker コンテナ、オンプレミスサーバー、エアギャップされた研究環境、およびアウトバウンドトラフィックが制限されている産業システムはすべて、Textract が利用できないという共通の特徴を持っています。 IronOCRはNuGetパッケージとしてインストールされ、最初のパッケージダウンロード後はネットワーク呼び出しなしで動作します。

データは、呼び出しのたびにお客様のインフラストラクチャから送信されます。Textractを使用したOCR操作はすべて、ドキュメントの内容をAmazonのサーバーに送信します。 PHIを処理する医療機関、CUIを扱う防衛関連企業、機密通信を処理する法務チーム、決済カード画像を処理する金融機関にとって、これは設定オプションではなく、規制環境におけるTextractの使用を完全に禁止するアーキテクチャ上の制約です。 IronOCRは、お使いのハードウェア上で処理を実行します。 クラウドモードを無効にする機能はありません。 ローカル処理のみが唯一のモードです。

レート制限はバッチスループットを制約します。 デフォルトのStartDocumentTextDetection TPSリミットは1秒あたり5リクエストです。 数百のドキュメントを処理するバッチジョブには、ProvisionedThroughputExceededExceptionの指数的バックオフ、およびレート補充タイマーが必要です。 TPS(1秒あたりのトランザクション数)の増加をリクエストするには、正式なAWSサポートケースを申請する必要があり、必ずしも結果が保証されるわけではありません。 IronOCRはローカルCPUが許す速さで処理します–16コアのサーバーはParallel.ForEachを使用して16のドキュメントを同時に処理し、サービス階層の交渉は必要ありません。

基本的な問題

Textractの導入はすべて、1ページも処理される前に、この儀式から始まります。

// Textract: five environment variables, an IAM role, and an S3 bucket
// — all required before the first OCR call

// Environment must have:
//   AWS_ACCESS_KEY_ID=AKIA...
//   AWS_SECRET_ACCESS_KEY=...
//   AWS_DEFAULT_REGION=us-east-1
//   IAM role: textract:DetectDocumentText, textract:AnalyzeDocument
//   IAM role: s3:PutObject, s3:DeleteObject (for any PDF processing)
//   S3 bucket: my-textract-staging-bucket (with lifecycle policy to prevent cost accumulation)

public class TextractOcrService
{
    private readonly AmazonTextractClient _textractClient;
    private readonly AmazonS3Client _s3Client; // required for PDFs

    public TextractOcrService()
    {
        // Fails with AmazonClientException if credentials not found in chain
        _textractClient = new AmazonTextractClient(Amazon.RegionEndpoint.USEast1);
        _s3Client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1);
    }
}
C#

IronOCRは、認証情報チェーン全体を単一の割り当てに置き換えます。

// IronOCR: one line, one string, done
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Or from environment (no IAM, no rotation, no S3)
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
C#

IronOCRとAWS Textract:機能比較

以下の表は、移行の意思決定において最も重要な側面に関して、両ライブラリの機能をマッピングしたものです。

フィーチャーAWS テクストラクトIronOCR
加工場所Amazonクラウド(必須)地域限定/店内飲食のみ
インターネットが必要です。いつも一度もない
認証情報の設定IAMユーザー/ロール + オプションのS3バケット単一ライセンスキー文字列
複数ページPDFS3ステージングと非同期ジョブが必要です同期input.LoadPdf()の直接
パスワードで保護されたPDFサポートされていませんinput.LoadPdf(path, Password: "x")
マルチフレームTIFFサポートされていませんinput.LoadImageFrames("multi.tiff")
非同期ポーリングが必要ですはい(すべてのPDFファイルに対応)いいえ — デフォルトでは同期
料金の制限5 TPS デフォルト (StartDocumentTextDetection)なし — CPUバウンドのみ
ページあたりの料金1ページあたり0.0015ドル~0.065ドルライセンス購入後は0ドル
自動前処理内部仕様のため、設定変更不可傾き補正、ノイズ除去、コントラスト調整、二値化、シャープ化、スケール調整
検索可能なPDF出力不可result.SaveAsSearchablePdf()
hOCRエクスポート不可result.SaveAsHocrFile()
バーコード読み取り不可ocr.Configuration.ReadBarCodes = true
地域ベースのOCRAnalyzeDocument + ブロック関係を介してCropRectangle(x, y, width, height)
構造化された結果フラットなBlockTypeによってフィルタリングされます型付きWords
対応言語英語が主流(追加項目を選択)NuGet経由で125以上の言語パックを利用可能
多言語同時配信サポートされていませんOcrLanguage.French + OcrLanguage.German
エアギャップ展開不可完全サポート
BAAなしのHIPAA不可外部プロセッサ不要 - オンプレミスのみ
DockerデプロイメントAWS認証情報の挿入が必要です認証情報なし — 通常のNuGetパッケージ
クロスプラットフォームAWSマネージド(Linuxのみ)Windows、Linux、macOS、Docker、Azure、AWS EC2
ライセンスモデルページごとの従量課金(継続課金)永続的な一度きりの($999 / $1,499 / $2,999)

クイックスタート:AWS TextractからIronOCRへの移行

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

AWS SDK パッケージを削除します。

dotnet remove package AWSSDK.Textract
dotnet remove package AWSSDK.S3
dotnet remove package AWSSDK.Core
SHELL

NuGetからIronOCRをインストールしてください。

dotnet add package IronOcr

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

すべてのAWSネームスペースのインポートを単一のIronOCRネームスペースに置き換えます。

// Before (AWS Textract)
using Amazon.Textract;
using Amazon.Textract.Model;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.Runtime;

// After (IronOCR)
using IronOcr;
C#

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

アプリケーション起動時にライセンス初期化を一度だけ追加します。AWS認証情報環境変数の設定をすべて削除します。

// Remove from startup:
//   AWS_ACCESS_KEY_ID environment variable
//   AWS_SECRET_ACCESS_KEY environment variable
//   AWS_DEFAULT_REGION environment variable
//   ~/.aws/credentials file entries
//   IAM role bindings on the execution context

// Add instead:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
C#

コード移行の例

AmazonTextractClientコンストラクターとIAMセットアップの置き換え

最も目立つ移行変更点は、クライアントの初期化です。 Textractは、基盤となる認証情報解決機能を備えた依存性注入型クライアントを必要とします。つまり、クライアントとそのすべての依存関係は、すべての展開環境で事前に構成しておく必要があります。 誤った構成は、最初のOCRコールがAmazonClientExceptionをスローするまで静かに失敗します。

AWS Textract のアプローチ:

// Requires: NuGet AWSSDK.Textract, AWSSDK.S3
// Requires: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION in environment
// Requires: IAM policy with textract:* and s3:PutObject, s3:DeleteObject

using Amazon.S3;
using Amazon.Textract;

public class DocumentOcrService
{
    private readonly AmazonTextractClient _textractClient;
    private readonly AmazonS3Client _s3Client;
    private readonly string _stagingBucket;

    public DocumentOcrService(IConfiguration config)
    {
        // Credential chain: environment → ~/.aws/credentials → EC2 instance profile
        // Fails if none found — runtime exception, not compile-time
        _textractClient = new AmazonTextractClient(Amazon.RegionEndpoint.USEast1);
        _s3Client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1);
        _stagingBucket = config["Textract:StagingBucket"]; // bucket must exist and have permissions
    }

    public async Task<string> ReadImageAsync(string imagePath)
    {
        var bytes = File.ReadAllBytes(imagePath);
        var response = await _textractClient.DetectDocumentTextAsync(
            new DetectDocumentTextRequest
            {
                Document = new Document { Bytes = new MemoryStream(bytes) }
            });

        return string.Join("\n", response.Blocks
            .Where(b => b.BlockType == BlockType.LINE)
            .Select(b => b.Text));
    }
}
C#

IronOCRのアプローチ:

// Requires: NuGet IronOcr
// Requires: one license key string — nothing else

using IronOcr;

public class DocumentOcrService
{
    private readonly IronTesseract _ocr;

    public DocumentOcrService()
    {
        IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // or set at Program.cs startup
        _ocr = new IronTesseract();
    }

    public string ReadImage(string imagePath)
    {
        // No credential chain, no region, no bucket — just read
        return _ocr.Read(imagePath).Text;
    }
}
C#

IAMロール、環境変数、~/.aws/credentialsファイル、S3バケットライフサイクルポリシー、リージョン設定など、AWSの資格情報インフラ全体が削除されます。 DocumentOcrServiceコンストラクタは、ランタイムの失敗モードを持つ3つの依存関係挿入サイトから、単一のライセンス割り当てに変わります。 デプロイメントパターンの詳細については、 IronTesseract セットアップガイドを参照してください。

StartDocumentTextDetectionをTIFFマルチフレーム処理に置き換える

Textractの非同期ジョブAPI (StartDocumentTextDetection)は、多ページドキュメントに必須です。 文書のデジタル化パイプラインでよく見られるパターンは、スキャンされた文書をマルチフレームTIFFファイル(スキャンされたページごとに1フレーム)として受け取ることです。 TextractはTIFF形式の入力を直接受け付けることはできません。 ジョブを開始する前に、ドキュメントをPDFに変換してS3にアップロードする必要があります。 IronOCRは、マルチフレームTIFFファイルをネイティブに読み取ることができます。

AWS Textract のアプローチ:

// Textract cannot accept TIFF directly — requires PDF conversion + S3 + async job
// This shows the conversion overhead plus the minimum async pipeline

using Amazon.S3;
using Amazon.S3.Model;
using Amazon.Textract;
using Amazon.Textract.Model;

public async Task<string> ProcessScannedTiffAsync(string tiffPath, string s3Bucket)
{
    // Step 0: Convert TIFF to PDF first (Textract does not accept TIFF for async jobs)
    // Requires a separate PDF conversion library — not shown here
    var pdfPath = Path.ChangeExtension(tiffPath, ".pdf");
    ConvertTiffToPdf(tiffPath, pdfPath); // external dependency required

    // Step 1: Upload converted PDF to S3
    var s3Key = $"staging/{Guid.NewGuid()}.pdf";
    using (var stream = File.OpenRead(pdfPath))
    {
        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = s3Bucket,
            Key = s3Key,
            InputStream = stream
        });
    }

    try
    {
        // Step 2: Start async detection job
        var startResp = await _textractClient.StartDocumentTextDetectionAsync(
            new StartDocumentTextDetectionRequest
            {
                DocumentLocation = new DocumentLocation
                {
                    S3Object = new S3Object { Bucket = s3Bucket, Name = s3Key }
                }
            });

        // Step 3: Poll every 5 seconds — can block for 30–120 seconds on large files
        GetDocumentTextDetectionResponse pollResp;
        do
        {
            await Task.Delay(5000);
            pollResp = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest { JobId = startResp.JobId });
        } while (pollResp.JobStatus == JobStatus.IN_PROGRESS);

        if (pollResp.JobStatus != JobStatus.SUCCEEDED)
            throw new Exception($"Job failed: {pollResp.StatusMessage}");

        // Step 4: Collect paginated results
        var text = new StringBuilder();
        string token = null;
        do
        {
            var page = await _textractClient.GetDocumentTextDetectionAsync(
                new GetDocumentTextDetectionRequest
                {
                    JobId = startResp.JobId,
                    NextToken = token
                });
            foreach (var block in page.Blocks.Where(b => b.BlockType == BlockType.LINE))
                text.AppendLine(block.Text);
            token = page.NextToken;
        } while (token != null);

        return text.ToString();
    }
    finally
    {
        // Step 5: Clean up S3 — orphaned objects accumulate storage costs
        await _s3Client.DeleteObjectAsync(s3Bucket, s3Key);
        File.Delete(pdfPath); // clean up intermediate PDF
    }
}
C#

IronOCRのアプローチ:

// IronOCR reads multi-frame TIFF directly — no conversion, no S3, no polling

using IronOcr;

public string ProcessScannedTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath); // reads all frames natively

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

    // Access per-page results if needed
    foreach (var page in result.Pages)
        Console.WriteLine($"Page {page.PageNumber}: {page.Words.Length} words detected");

    return result.Text;
}
C#

TIFFからPDFへの変換ステップ、S3へのアップロード、非同期ポーリングループ、ページ分割された結果の蓄積、およびS3のクリーンアップはすべて省略されます。 IronOCRの実装はフレームを直接読み取り、result.Pagesを通じてページごとのアクセスを提供します。中間フォーマット変換は行いません。 TIFFおよびGIF入力ガイドでは、フレームの一部のみが必要な場合のフレーム選択について説明しています。

S3ステージングを検索可能なPDF出力に置き換える

Textractの一般的な使用例としては、スキャンしたPDFアーカイブを検索可能な形式に変換することが挙げられます。 Textractの手法では、各PDFをS3にアップロードし、非同期ジョブを実行して抽出されたテキストを収集し、その後、別のPDFライブラリを使用してそのテキストを検索可能なレイヤーとして埋め込む必要があります。 IronOCRは、1回の呼び出しでスキャンを実行し、検索可能なPDFを生成します。

AWS Textract のアプローチ:

// Textract extracts text but cannot produce searchable PDFs
// Requires: S3 upload + async job + separate PDF library to embed the text layer

using Amazon.S3;
using Amazon.S3.Model;
using Amazon.Textract;
using Amazon.Textract.Model;

public async Task<string> ExtractTextForSearchableLayerAsync(
    string scannedPdfPath,
    string s3Bucket)
{
    // Must upload to S3 — cannot pass PDF bytes directly for async jobs
    var key = $"ocr-input/{Guid.NewGuid()}.pdf";

    await using (var fs = File.OpenRead(scannedPdfPath))
    {
        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = s3Bucket,
            Key = key,
            InputStream = fs,
            ContentType = "application/pdf"
        });
    }

    string jobId;
    try
    {
        var startResp = await _textractClient.StartDocumentTextDetectionAsync(
            new StartDocumentTextDetectionRequest
            {
                DocumentLocation = new DocumentLocation
                {
                    S3Object = new S3Object { Bucket = s3Bucket, Name = key }
                }
            });
        jobId = startResp.JobId;
    }
    catch
    {
        await _s3Client.DeleteObjectAsync(s3Bucket, key);
        throw;
    }

    // Poll — minimum 5s wait; typical 15–60s for a 10-page PDF
    GetDocumentTextDetectionResponse pollResp;
    int pollAttempts = 0;
    const int maxAttempts = 120; // 10 minute timeout

    do
    {
        await Task.Delay(5000);
        pollResp = await _textractClient.GetDocumentTextDetectionAsync(
            new GetDocumentTextDetectionRequest { JobId = jobId });

        if (++pollAttempts >= maxAttempts)
            throw new TimeoutException("Textract job timed out after 10 minutes");

    } while (pollResp.JobStatus == JobStatus.IN_PROGRESS);

    await _s3Client.DeleteObjectAsync(s3Bucket, key); // cleanup regardless of outcome

    if (pollResp.JobStatus != JobStatus.SUCCEEDED)
        throw new Exception($"Textract job status: {pollResp.JobStatus}{pollResp.StatusMessage}");

    // Return extracted text — caller must use a separate library to produce searchable PDF
    return string.Join("\n", pollResp.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .Select(b => b.Text));

    // Caller still needs: iTextSharp, PdfSharp, or similar to embed text layer
}
C#

IronOCRのアプローチ:

// IronOCR reads the PDF and produces a searchable PDF output directly
// No S3, no polling, no external PDF library needed

using IronOcr;

public void ConvertToSearchablePdf(string scannedPdfPath, string outputPath)
{
    var ocr = new IronTesseract();

    using var input = new OcrInput();
    input.LoadPdf(scannedPdfPath);

    var result = ocr.Read(input);

    // Embed extracted text as searchable layer in one call
    result.SaveAsSearchablePdf(outputPath);

    Console.WriteLine($"Pages processed: {result.Pages.Length}");
    Console.WriteLine($"Overall confidence: {result.Confidence:F1}%");
}
C#

ポーリングのタイムアウトロジック、S3へのアップロードとクリーンアップのパターン、および外部PDFライブラリへの依存関係はすべてなくなりました。 SaveAsSearchablePdfは認識されたテキストを出力ファイルに直接埋め込み、スキャンされたすべてのページが2番目のライブラリなしで全文検索可能になります。 検索可能なPDFガイドでは、ページ選択、圧縮オプション、メタデータ埋め込みについて解説しています。 PDF OCRパイプラインのより広範なコンテキストについては、 PDF入力ガイドを参照してください。

AnalyzeDocument ブロックグラフトラバーサルを構造化ページ結果に置き換える

TextractのRelationshipType.CHILD ID配列でリンクされています。 文書の論理構造を再構築するには、この関係グラフをたどる必要がある。 IronOCRは、ページ、段落、行、単語といった階層構造を型付けして返します。各階層には座標へのアクセス権があります。

AWS Textract のアプローチ:

// AnalyzeDocument with TABLES returns blocks that must be graph-traversed
// to determine which words belong to which paragraphs

using Amazon.Textract;
using Amazon.Textract.Model;

public async Task<List<DocumentSection>> ExtractDocumentStructureAsync(string imagePath)
{
    var bytes = File.ReadAllBytes(imagePath);

    var response = await _textractClient.AnalyzeDocumentAsync(
        new AnalyzeDocumentRequest
        {
            Document = new Document { Bytes = new MemoryStream(bytes) },
            FeatureTypes = new List<string> { "TABLES", "FORMS" }
            // Note: AnalyzeDocument (TABLES) costs $0.015/page — 10x DetectDocumentText
        });

    var sections = new List<DocumentSection>();

    // Filter LINE blocks for paragraph reconstruction
    // LINE blocks are not grouped into paragraphs — must infer from Y proximity
    var lineBlocks = response.Blocks
        .Where(b => b.BlockType == BlockType.LINE)
        .OrderBy(b => b.Geometry?.BoundingBox?.Top ?? 0)
        .ToList();

    // Group lines into pseudo-paragraphs by vertical gap heuristic
    var currentParagraph = new List<Block>();
    float? lastBottom = null;
    const float paragraphGapThreshold = 0.02f; // 2% of page height

    foreach (var line in lineBlocks)
    {
        var top = line.Geometry?.BoundingBox?.Top ?? 0;
        var height = line.Geometry?.BoundingBox?.Height ?? 0;

        if (lastBottom.HasValue && (top - lastBottom.Value) > paragraphGapThreshold)
        {
            if (currentParagraph.Any())
            {
                sections.Add(new DocumentSection
                {
                    Text = string.Join(" ", currentParagraph.Select(b => b.Text)),
                    LineCount = currentParagraph.Count,
                    // Confidence: average of all LINE block confidence values
                    Confidence = (float)currentParagraph.Average(b => b.Confidence ?? 0)
                });
                currentParagraph.Clear();
            }
        }

        currentParagraph.Add(line);
        lastBottom = top + height;
    }

    if (currentParagraph.Any())
        sections.Add(new DocumentSection
        {
            Text = string.Join(" ", currentParagraph.Select(b => b.Text)),
            LineCount = currentParagraph.Count,
            Confidence = (float)currentParagraph.Average(b => b.Confidence ?? 0)
        });

    return sections;
}

public class DocumentSection
{
    public string Text { get; set; }
    public int LineCount { get; set; }
    public float Confidence { get; set; }
}
C#

IronOCRのアプローチ:

// IronOCR returns a typed hierarchy — paragraphs are first-class objects
// No block graph, no heuristic gap detection, no confidence averaging

using IronOcr;

public List<DocumentSection> ExtractDocumentStructure(string imagePath)
{
    var ocr = new IronTesseract();
    var result = ocr.Read(imagePath);

    var sections = new List<DocumentSection>();

    foreach (var page in result.Pages)
    {
        foreach (var paragraph in page.Paragraphs)
        {
            sections.Add(new DocumentSection
            {
                Text = paragraph.Text,
                LineCount = paragraph.Lines.Length,
                // Coordinate access: exact pixel position on the page
                LocationX = paragraph.X,
                LocationY = paragraph.Y,
                Width = paragraph.Width,
                Height = paragraph.Height,
                Confidence = paragraph.Confidence
            });
        }
    }

    return sections;
}

public class DocumentSection
{
    public string Text { get; set; }
    public int LineCount { get; set; }
    public int LocationX { get; set; }
    public int LocationY { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public double Confidence { get; set; }
}
C#

段落、行、単語は型付きコレクションとして.Confidenceプロパティで直接アクセス可能です。 バウンディングボックスの正規化、ギャップ閾値のヒューリスティック、ブロックタイプのフィルタリングは行いません。 読み取り結果ガイドでは、文字レベルの座標アクセスを含む完全なOcrResult階層が文書化されています。 この構造に依存する請求書および領収書のワークフローについては、請求書OCRチュートリアルを参照してください。

処理速度制限のあるバッチ処理を、制約のない並列実行に置き換える

バッチ画像処理では、TextractのTPS制限が最も顕著に運用コストに影響を与えます。DetectDocumentText同期APIにはレート制限があります; 1秒あたり5以上のリクエストを送信するとProvisionedThroughputExceededExceptionが発生します。 トランザクションハンドリングにはSemaphoreSlimのスロットリング、バックオフ付きリトライロジック、および処理中のリクエストの慎重な計算が必要です。 IronOCRにはレート制限がありません。スループットは利用可能なCPUコア数によってのみ制限されます。

AWS Textract のアプローチ:

// Batch processing requires SemaphoreSlim throttle + retry on rate limit exceeded

using Amazon.Textract;
using Amazon.Textract.Model;
using System.Collections.Concurrent;

public async Task<Dictionary<string, string>> ProcessImageBatchAsync(
    IReadOnlyList<string> imagePaths,
    IProgress<(int Completed, int Total)> progress = null)
{
    var results = new ConcurrentDictionary<string, string>();
    var semaphore = new SemaphoreSlim(5); // 5 concurrent — Textract default TPS limit
    var tasks = new List<Task>();
    int completed = 0;

    foreach (var path in imagePaths)
    {
        await semaphore.WaitAsync();

        tasks.Add(Task.Run(async () =>
        {
            try
            {
                string text = null;
                int retryCount = 0;

                while (text == null && retryCount < 3)
                {
                    try
                    {
                        var bytes = await File.ReadAllBytesAsync(path);
                        var response = await _textractClient.DetectDocumentTextAsync(
                            new DetectDocumentTextRequest
                            {
                                Document = new Document { Bytes = new MemoryStream(bytes) }
                            });

                        text = string.Join("\n", response.Blocks
                            .Where(b => b.BlockType == BlockType.LINE)
                            .Select(b => b.Text));
                    }
                    catch (AmazonTextractException ex)
                        when (ex.ErrorCode == "ProvisionedThroughputExceededException")
                    {
                        // Exponential backoff on rate limit — blocks the entire thread
                        await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, retryCount)));
                        retryCount++;
                    }
                }

                results[path] = text ?? string.Empty;
                var done = Interlocked.Increment(ref completed);
                progress?.Report((done, imagePaths.Count));
            }
            finally
            {
                semaphore.Release();
            }
        }));
    }

    await Task.WhenAll(tasks);
    return results.ToDictionary(x => x.Key, x => x.Value);
}
C#

IronOCRのアプローチ:

// No rate limits, no semaphore, no retry logic — Parallel.ForEach saturates all cores

using IronOcr;
using System.Collections.Concurrent;

public Dictionary<string, string> ProcessImageBatch(
    IReadOnlyList<string> imagePaths,
    IProgress<(int Completed, int Total)> progress = null)
{
    var ocr = new IronTesseract();
    var results = new ConcurrentDictionary<string, string>();
    int completed = 0;

    Parallel.ForEach(imagePaths, path =>
    {
        var result = ocr.Read(path);
        results[path] = result.Text;

        var done = Interlocked.Increment(ref completed);
        progress?.Report((done, imagePaths.Count));
    });

    return results.ToDictionary(x => x.Key, x => x.Value);
}
C#

ProvisionedThroughputExceededExceptionキャッチブロックはすべて削除されます。 IronTesseractはスレッドセーフで、スレッド間で共有される単一インスタンスがロックなしで完全な並列負荷を処理します。 8コアのマシンでは、設定不要で8つのドキュメントを同時に処理できます。 32コアで、32コアを同時に処理します。 マルチスレッドの例では完全なパターンを示しており、速度最適化ガイドではスループット重視のデプロイメントにおけるエンジン構成のチューニングについて解説しています。

AnalyzeDocument Form Extraction を Region-Based CropRectangle OCR に置き換える

TextractのRelationshipType.VALUEの関係でリンクして返します。 フォームフィールドのキーと値のペアを再構築するには、WORDブロックを取得してテキストを組み立てる必要があります。 フィールド位置が固定されている固定形式フォームの場合、IronOCRのCropRectangleは関係グラフのトラバースをせずに各フィールドを直接抽出し、1ページ当たりのコストはゼロです。

AWS Textract のアプローチ:

// FORMS mode costs $0.05/page — the most expensive Textract tier
// Relationship graph traversal required to reconstruct key-value pairs

using Amazon.Textract;
using Amazon.Textract.Model;

public async Task<Dictionary<string, string>> ExtractInvoiceFieldsAsync(string imagePath)
{
    var bytes = File.ReadAllBytes(imagePath);

    // $0.05/page for FORMS analysis
    var response = await _textractClient.AnalyzeDocumentAsync(
        new AnalyzeDocumentRequest
        {
            Document = new Document { Bytes = new MemoryStream(bytes) },
            FeatureTypes = new List<string> { "FORMS" }
        });

    var allBlocks = response.Blocks;
    var fields = new Dictionary<string, string>();

    // Find KEY blocks only
    var keyBlocks = allBlocks.Where(b =>
        b.BlockType == BlockType.KEY_VALUE_SET &&
        b.EntityTypes?.Contains("KEY") == true);

    foreach (var keyBlock in keyBlocks)
    {
        // Assemble key text from CHILD WORD blocks
        var keyText = GetTextFromBlock(allBlocks, keyBlock);

        // Find associated VALUE block via VALUE relationship
        var valueBlockId = keyBlock.Relationships?
            .FirstOrDefault(r => r.Type == RelationshipType.VALUE)?
            .Ids.FirstOrDefault();

        if (valueBlockId == null) continue;

        var valueBlock = allBlocks.FirstOrDefault(b => b.Id == valueBlockId);
        if (valueBlock == null) continue;

        var valueText = GetTextFromBlock(allBlocks, valueBlock);
        fields[keyText.TrimEnd(':')] = valueText;
    }

    return fields;
}

private string GetTextFromBlock(IList<Block> allBlocks, Block block)
{
    if (block.Relationships == null) return string.Empty;

    var childWordIds = block.Relationships
        .Where(r => r.Type == RelationshipType.CHILD)
        .SelectMany(r => r.Ids);

    return string.Join(" ", allBlocks
        .Where(b => b.BlockType == BlockType.WORD && childWordIds.Contains(b.Id))
        .Select(b => b.Text));
}
C#

IronOCRのアプローチ:

// CropRectangle extracts each field zone directly — no relationship graph
// Works for any fixed-format form where field positions are known

using IronOcr;

// Define the field zones for your form template once
private static readonly Dictionary<string, CropRectangle> InvoiceFieldZones =
    new Dictionary<string, CropRectangle>
    {
        { "InvoiceNumber", new CropRectangle(450, 80,  300, 35) },
        { "InvoiceDate",   new CropRectangle(450, 120, 300, 35) },
        { "VendorName",    new CropRectangle(50,  160, 400, 35) },
        { "TotalAmount",   new CropRectangle(450, 680, 200, 35) },
        { "DueDate",       new CropRectangle(450, 720, 200, 35) }
    };

public Dictionary<string, string> ExtractInvoiceFields(string imagePath)
{
    var ocr = new IronTesseract();
    var fields = new Dictionary<string, string>();

    foreach (var zone in InvoiceFieldZones)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath, zone.Value); // load only the defined region

        var result = ocr.Read(input);
        fields[zone.Key] = result.Text.Trim();
    }

    return fields;
}
C#

GetTextFromBlockヘルパーは排除されます。 各フィールドは、それを含むピクセル領域を正確に読み取ります。それ以上でもそれ以下でもありません。 領域ベースのOCRガイドは、CropRectangleの座標とテンプレート測定からのゾーンの定義方法を説明しています。 請求書固有のワークフローについては、請求書OCRに関するブログ記事領収書スキャンチュートリアルで、フィールド抽出パイプライン全体を解説しています。

AWS テクストラクト API からIronOCRへのマッピング リファレンス

AWS テクストラクトIronOCR相当値
AmazonTextractClientIronTesseract
AmazonS3Client不要
DetectDocumentTextRequestinput.LoadImage()
DetectDocumentTextResponseOcrResult
AnalyzeDocumentRequest (TABLES/FORMS)CropRectangle
StartDocumentTextDetectionRequestinput.LoadPdf() — 同期、ジョブ開始なし
GetDocumentTextDetectionRequest該当なし — 結果は即座に判明します
Document.Bytesinput.LoadImage(stream)
S3Object (ドキュメントステージング)ファイルパスまたはストリーム - ステージングは​​不要
Block (BlockType.LINE)result.Lines (型付きコレクション)
Block (BlockType.WORD)result.Words (型付きコレクション)
Block (BlockType.TABLE)result.Wordsが座標の近接によってグループ化されます
Block (BlockType.KEY_VALUE_SET)CropRectangle フィールドごとの領域抽出
Block.Confidenceword.Confidence / result.Confidence
Block.Geometry.BoundingBoxword.X, word.Y, word.Width, word.Height
RelationshipType.CHILDのトラバース型付き結果オブジェクトへのプロパティの直接アクセス
JobStatus.IN_PROGRESS該当なし — 非同期状態なし
JobStatus.SUCCEEDED該当なし — 同期リターン
response.NextToken (ページネーション)該当なし — 結果がページ分けされていません
ProvisionedThroughputExceededException該当なし — TPS制限なし
AccessDeniedException該当なし — 認証チェーンなし
input.LoadImageFrames()マルチフレームTIFFの直接サポート(Textractには同等の機能はありません)
result.SaveAsSearchablePdf()検索可能なPDF出力(Textractのような機能はありません)

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

問題1:新規展開環境における認証情報の設定ミス

AWS Textract: ~/.aws/credentials、EC2インスタンスプロファイル、ECSタスクロールのチェーンから資格情報を解決します。 新しいDockerコンテナまたはCI環境では、これらが設定されていない場合、クライアントはエラーなしにコンストラクトされますが、すべてのAPIコールがAmazonClientException: No credentials specifiedをスローします。 この障害は実行時まで目に見えない。

**解決策:**認証情報チェーンを完全に削除する。 IronOCRのライセンスキーを環境変数から設定します。環境変数は設定が簡単で、管理に必要なIAM権限も必要ありません。

// Single environment variable — no IAM, no rotation, no chain resolution
var key = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
if (string.IsNullOrEmpty(key))
    throw new InvalidOperationException("IRONOCR_LICENSE environment variable is not set");

IronOcr.License.LicenseKey = key;
C#

問題2:コードベース全体における非同期呼び出し箇所

AWS Textract: SDK全体が非同期専用であるため (async Task<t>で伝播します。 IronOCRの同期APIへの移行には、各拠点での決定が必要です。

**解決策:**バックグラウンド処理サービスおよびコントローラアクションの場合、IronOCRの同期呼び出しはバックグラウンドスレッド上でも安全です。 既存のコールチェーンを非同期のままにする必要がある場合のみ、Task.Runでラップします。

// If the call site must remain async (e.g., an ASP.NET controller action):
public async Task<IActionResult> ProcessUpload(IFormFile file)
{
    using var ms = new MemoryStream();
    await file.CopyToAsync(ms);

    // Offload synchronous OCR to thread pool — keeps controller non-blocking
    var text = await Task.Run(() =>
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(ms.ToArray());
        return ocr.Read(input).Text;
    });

    return Ok(text);
}
C#

既に非UIスレッドで動作しているバッチプロセッサやバックグラウンドサービスの場合、Task.Runはそのコンテキストで利益なしにオーバーヘッドを追加します。 非同期OCRガイドでは、推奨されるパターンについて説明しています。

問題3:S3バケットのクリーンアップロジックがコード全体に散在している

AWS Textract: Textract処理のためにS3にアップロードされるコードは、処理完了後にS3から削除する必要があります。 このクリーンアップはfinallyブロックで頻繁に行われ、エラーパスで省略されることがあり、ストレージコストを伴うオブジェクトが孤立してしまいます。 移行作業中、S3のクリーンアップコードはOCRとは概念的に関連がないため、見落とされやすい。

解決策: S3へのアップロードとクリーンアップのパターン全体には、 IronOCRに相当する機能はありません。 すべてのtry/finallyブロックを完全に削除します。 IronOCRはローカルパスまたはストリームから直接読み取ります。

// Before: upload → job → poll → extract → cleanup (50+ lines)
// After: two lines, no cleanup required

using var input = new OcrInput();
input.LoadPdf(localPdfPath);
var text = new IronTesseract().Read(input).Text;
C#

移行後、S3ステージングバケットを廃止してください。 PDF入力ガイドストリーム入力ガイドは、 S3ステージングされたドキュメントアクセスを置き換えるすべての入力パターンを網羅しています。

問題4:ブロックグラフ走査コードには直接的な同等物がない

AWS Textract: RelationshipType.CHILD ID配列からテーブルセル、フォームフィールド、段落グループを再構築するコードは、移行に最も時間がかかります。 IronOCRは関係グラフではなく型付きコレクションを返すため、1対1の置換は不可能です。

**解決策:**各トラバーサルパターンを適切な型付きプロパティに置き換えます。 リレーションシップIDの検索が、プロパティへの直接アクセスとなる。

// Before: filter by BlockType + traverse relationship IDs
var paragraphText = string.Join(" ", allBlocks
    .Where(b => b.BlockType == BlockType.WORD &&
                childIds.Contains(b.Id))
    .Select(b => b.Text));

// After: direct paragraph text (no filtering, no relationship lookup)
foreach (var page in result.Pages)
    foreach (var para in page.Paragraphs)
        Console.WriteLine(para.Text); // already assembled
C#

result.Wordsの単語座標グループ化を使用します。 表の読み方ガイドでは、座標に基づくアプローチについて説明しています。

問題5:ProvisionedThroughputExceededExceptionキャッチブロック

AWS Textract: ロバストなバッチ処理コードは、ErrorCode == "ProvisionedThroughputExceededException"でキャッチし、バックオフ付きのリトライを実装します。 このエラーコードはTextract固有の概念であり、 IronOCRには同等のコードはありません。

解決策: すべてのProvisionedThroughputExceededExceptionキャッチブロックを削除します。 IronOCRにはTPS(1秒あたりの処理速度)の制限はありません。 完全なスロットルバッチパターンをParallel.ForEachに置き換えます。

// Delete: SemaphoreSlim, retry loops, ProvisionedThroughputExceededException handlers
// Replace with:
Parallel.ForEach(imagePaths, path =>
{
    var result = new IronTesseract().Read(path);
    results[path] = result.Text;
});
C#

問題6:クライアントコンストラクタに組み込まれたリージョン構成

AWS Textract: new AmazonTextractClient(Amazon.RegionEndpoint.USEast1)はリージョンをハードコーディングします。 複数リージョン展開には、複数のクライアントインスタンスまたは動的なリージョン選択が必要です。 Textractが新しい地域でのサポートを追加する場合、コードを更新する必要があります。

解決策: IronOCRには領域の概念がありません。 すべてのAmazon.RegionEndpointリファレンスを削除します。 IronTesseractコンストラクタはネットワーク構成を受け取らず、処理はローカルです。 AWSインフラストラクチャ上で各リージョンが独自のコンピューティングを実行するマルチリージョン展開の場合、各IronOCRインスタンスは、リージョン間呼び出しを行うことなく、そのコンピューティング境界内でドキュメントをローカルに処理します。

AWS テクストラクト 移行チェックリスト

移行前

コードベース内のTextractおよびS3 SDKの使用状況をすべて監査する。

grep -rn "Amazon.Textract\|AmazonTextractClient\|DetectDocumentText" --include="*.cs" .
grep -rn "StartDocumentTextDetection\|GetDocumentTextDetection\|JobStatus" --include="*.cs" .
grep -rn "AmazonS3Client\|PutObjectRequest\|DeleteObjectAsync" --include="*.cs" .
grep -rn "BlockType\|RelationshipType\|KEY_VALUE_SET" --include="*.cs" .
grep -rn "ProvisionedThroughputExceededException\|AmazonTextractException" --include="*.cs" .
grep -rn "AWSSDK\|Amazon.RegionEndpoint" --include="*.csproj" .
SHELL

代替コードを作成する前に、以下の項目を確認してください。

  • AmazonTextractClientを含むすべてのファイルをカウントします—各ファイルが置換対象です
  • すべてのFORMSの使用があるかどうかを確認します
  • すべての非同期ポーリングループを特定します (do { await Task.Delay } while JobStatus == IN_PROGRESS)
  • すべてのS3クリーンアップfinallyブロックを見つけます—これらはまるごと削除され、置換はしません
  • すべてのProvisionedThroughputExceededExceptionキャッチブロックをカウントします—削除し、置換はしません
  • すべてのBlockType.KEY_VALUE_SETトラバースロジックを示しておきます—それぞれに構造化された出力置換が必要です

コードの移行

  1. すべてのAWSSDK.Coreを削除します
  2. OCRを実行する各プロジェクトでdotnet add package IronOcrを実行します
  3. アプリケーション起動時にIronOcr.License.LicenseKey = ...を1度追加します (Program.cs または同等のもの)
  4. すべてのusing Amazon.Runtime;文を削除します
  5. 以前にTextract名前空間をインポートしていた各ファイルにusing IronOcr;を追加します
  6. new IronTesseract()に置き換えます
  7. PutObjectAsync / DeleteObjectAsync呼び出しを直接ファイルパスまたはストリームリードに置き換えます
  8. すべてのDetectDocumentTextAsync呼び出しを置き換えます: var text = ocr.Read(path).Text
  9. すべてのStartDocumentTextDetectionAsync + ポーリングループをinput.LoadPdf(path) + ocr.Read(input)に置き換えます
  10. すべての多フレームTIFFパイプライン (TIFF → PDF → S3 → 非同期) をinput.LoadImageFrames(tiffPath)に置き換えます
  11. BlockType.LINE / result.Lines / result.Wordsに置き換えます
  12. CropRectangleのゾーン抽出に置き換えます
  13. すべてのSemaphoreSlimスロットルを削除します
  14. スロットルバッチパターンを共有のParallel.ForEachで置き換えます
  15. デプロイマニフェストとCIパイプラインから、すべてのAWS認証情報環境変数設定を削除します。
  16. すべての処理コードの移行と検証が完了したら、S3ステージングバケットを廃止します。

移行後

  • アプリケーションがIRONOCR_LICENSEを設定したままクリーンに起動し、すべてのAWS環境変数が削除されていることを確認します Textractで以前に処理した同じサンプル画像に対してOCRを実行し、抽出されたテキストの精度を比較します。
  • 複数ページのPDFを直接処理し、S3や非同期ポーリングを使用せずにすべてのページが抽出されていることを確認します。
  • マルチフレームTIFFを処理し、ページ数が同じドキュメントに対するTextractの出力と一致することを確認します。
  • 50以上の画像セットでバッチ処理をテストし、ProvisionedThroughputExceededException相当が発生しないことを確認します
  • アプリケーションをインターネットへの外部アクセスがないDockerコンテナで実行し、OCRが正常に完了することを確認します。 検索可能なPDF出力がAdobe Readerで正しく開き、全文検索が可能であることを確認します。
  • デプロイ環境からAWS_SECRET_ACCESS_KEYを削除しても何も壊れないことを確認します
  • フォームや請求書の抽出ワークフローをTextractの既知の出力と比較してテストし、フィールドの正確性を検証する 代表的な文書セットの処理遅延を測定し、最小5秒のポーリング待機が解消されたことを確認する。

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

インフラストラクチャを単一のNuGetパッケージに統合。3つの AWS SDK パッケージ、ライフサイクル ポリシーを含む S3 バケット、すべてのデプロイ環境にわたる IAM ロール、および AWS 認証情報のローテーション手順が、1 つのNuGetパッケージに置き換えられます。 dotnet add package IronOcrです。 AWS認証情報管理に伴うあらゆる下流工程(セキュリティ監査、ローテーションスケジュール、環境変数管理、Dockerシークレットの設定など)は、これと共に消滅します。

**総所有コストの予測可能性。**ページ単位の課金モデルでは、文書量に応じて変動するコストが際限なく増加します。 IronOCRに移行後は、処理量に関わらず、追加ページあたりのコストはゼロになります。 Textract AnalyzeDocument料金で1か月に200,000ページを処理するチームは、OCRにのみ年間$36,000を費やします。 IronOCR Enterpriseライセンス(2,999ドル)は、請求が発生しないことで31日以内にその費用を回収できます。 ライセンス階層の詳細およびSaaS再配布条件については、 IronOCRのライセンスページをご覧ください。

同期処理により、5段階の非同期処理の複雑さが解消されます。S3へのアップロード、ジョブの開始、ポーリングループ、ページ分割された結果の収集、およびクリーンアップの最終ブロックは、Textract PDFパイプラインにおける5つの独立した障害モードを表しています。移行後、PDFは2行で読み込まれます。 エラーハンドリングはocr.Read()呼び出しの周りの単一のtry/catchに減少します。 ポーリングのタイムアウトロジック、nextTokenページネーションアキュムレータ—これらの概念はIronOCRコードベースには存在しません。 メンテナンスの負担は、削除されたコードの量に比例して減少する。

完全な導入柔軟性。Textractは、OCR処理のたびにインターネット接続を必要とします。 IronOCRは、インストール時にNuGetパッケージをダウンロードするためだけにインターネットアクセスを必要とします。その後は、エアギャップネットワーク、アウトバウンドルールが設定されていないDockerコンテナ、オンプレミスサーバー、およびTextractへのアクセス権限を持たないAWS EC2インスタンスで動作します。 Windows Server上で本番環境で実行されるバイナリは、Linuxコンテナ内でも実行されます。 Docker導入ガイドLinux導入ガイドでは、これまでTextractの使用が制限されていたコンテナ環境向けの具体的な構成について説明しています。

データ主権は構成ではなくアーキテクチャによって実現されます。IronOCRにはネットワーク送信モードを無効にする機能はありません。ローカル処理のみが唯一のモードです。 IronOCRで処理された文書は、ホストマシンから外部に持ち出されることはありません。PHI(保護対象医療情報)を処理する医療アプリケーション、CUI(機密情報)を処理する防衛アプリケーション、および決済カード画像を処理する金融アプリケーションにとって、これはBAA(事業提携契約)の交渉、地域別データ所在地の設定、およびAmazonのデータ処理ポリシーの監査を必要としないコンプライアンス体制です。 コンプライアンスの範囲は、既に管理している自社のインフラストラクチャの境界です。 IronOCRの製品ページには、コンプライアンスレビューを実施するチーム向けに、機能概要と導入に関する詳細なドキュメントが掲載されています。

文書品質管理のための設定可能な前処理。Textractの内部前処理機能はアクセスも設定もできません。 スキャンした文書の仕上がりが悪い場合、唯一の対処法は出力結果を受け入れるか、再スキャンすることである。 IronOCRは完全な前処理パイプラインを公開します: DeepCleanBackgroundNoise()。 スキャン結果の信頼性が低いという理由でTextractからドキュメントを移行したチームは、回転、ノイズ、低コントラスト、解像度不足といった特定の欠陥に合わせたフィルターを使用することで、根本原因に直接対処できます。 前処理機能ページ画像品質補正ガイドには、利用可能なフィルターとその適切な使用例が記載されています。

ご注意: AWS Textract, PDFSharp, Tesseract、およびiTextはそれぞれの所有者の登録商標です。 このサイトはAmazon Web Services、Google、empira Software GmbH、iText Groupとの関連、支持、またはスポンサーされておりません。すべての製品名、ロゴ、およびブランドはそれぞれの所有者の財産です。 比較は情報提供のみを目的としており、執筆時点で公開されている情報を反映しています。

関連する記事

Key in blue circle

無料の30日間トライアルキーをすぐに入手してください。

Your trial license will be sent to your email address

制限なし。100% ロック解除済み。クレジットカード不要。

bullet_checkedクレジットカードやアカウントの作成は不要です。制限なし。100% ロック解除済み。クレジットカード不要。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
義務のない相談を受ける
下記のフォームを記入するか、sales@ironsoftware.comにメールしてください。
あなたの詳細は常に守秘されます。
世界中の数百万人のエンジニアから信頼されています。
ライセンスはより安く
あなたの無料30日間の試用キーをすぐに入手。
クレジットカードやアカウントの作成は不要です。