IRONSOFTWAREHOME
ビデオ

オープンソースライブラリを使用してC#でOCRを実装する方法

Kannaopat Udonpant
Kannapat Udonpant
Updated: 2026年8月1日

このガイドは、KlippaのREST APIを統合済みで、オンプレミスでの文書処理にIronOCRへの移行を検討している.NET開発者向けです。 本書では、HTTPクライアントインフラストラクチャの削除、JSON逆シリアル化の排除、クラウドに依存するドキュメントアップロードをネットワークを一切使用しないローカルOCR呼び出しに置き換えるための実践的な手順について解説します。

Klippa OCRから移行する理由

Klippaは、 .NET SDKを必要としない、クラウド専用のドキュメントインテリジェンスサービスです。 すべての統合は、手作業で構築されたRESTクライアントです。 そのアーキテクチャ上の現実がもたらす影響は、生産システムのライフサイクル全体にわたって累積していく。

**NuGetパッケージが不要なということは、統合レイヤーを所有しているということです。**インストールするものは何もありません。 エントリーコストは、HttpClient ラッパーの作成、X-Auth-Key 認証ヘッダーの設定、MultipartFormDataContent リクエストボディの構築、Klippa の JSON レスポンススキーマのデシリアライズ、および一時的な障害のためのリトライロジックの設定です。 つまり、最初の文書が確実に本番環境で処理されるまでに、2~4日間の準備期間が必要になるということです。 KlippaがAPIスキーマを更新すると、デシリアライゼーションコードが動作しなくなり、手動でのメンテナンスが必要になります。

ドキュメントのアップロードはすべてネットワーク依存です。Klippaはドキュメント処理をEU域内のサーバーのみで行います。 Klippa側のシステム障害、レイテンシの上昇、またはアプリケーションサーバーからのインターネット接続の中断が発生すると、ドキュメント処理が完全に停止します。 クラウドサービスが利用できない場合でも、代替手段、ローカルモード、再試行機能は一切ありません。

**機密文書がお客様のインフラストラクチャから送信されます。**支払い詳細が記載された領収書、VAT番号と金額が記載された請求書、パスポートデータが記載された身分証明書などの財務文書は、API呼び出しのたびにサードパーティのサーバーに送信されます。 GDPRのデータ転送に関する規定は、EU域内での処理に関してこれらの問題の一部に対処していますが、監査の範囲は依然としてKlippaのインフラストラクチャ、データ保持ポリシー、およびサブプロセッサーにまで及びます。 医療、法律、金融サービス、または政府との契約を持つチームにとって、"EUホスト型"では、データが組織外に持ち出されないという要件を満たしません。

ドキュメントごとの料金体系に上限はありません。Klippaは料金表を公開していません。 経費管理システムで月間1万件の領収書、買掛金自動化ワークフローで1日500件の請求書など、ある程度の量の文書を処理する場合、文書ごとの課金モデルでは、永久ライセンスでは決して発生しないコストが発生します。 コストの推移は事業成長に直接的に連動しており、これはインフラ投資が本来果たすべき役割とは正反対である。

**専門家の業務範囲は、要件が拡大すると途切れる。**クリッパは、領収書、請求書、身分証明書類に関する研修を受けている。 経費管理アプリとして始まったものが、そのまま経費管理にとどまることは稀である。 これら3つのカテゴリ以外の文書タイプ(スキャンされた雇用契約書、医療フォーム、技術図面、非標準レイアウトの発注書など)が初めて出現した場合、Klippaは有用な情報を何も返しません。 IronOCRは、カテゴリの制限なく、テキストを含むあらゆる文書を処理します。

非同期専用のREST呼び出しは、同期コンテキストにおいてレイテンシを増加させます。Klippaのすべての呼び出しは非同期HTTP操作です。 単一の文書の往復には、ネットワーク上で500ミリ秒から2000ミリ秒かかります。 IronOCRは、同期処理の方がアーキテクチャに適しているシナリオでは、非同期処理のオーバーヘッドなしに、同じドキュメントをローカルで100~400ミリ秒で処理します。

基本的な問題

KlippaにはSDKがありません。 OCRとは、HTTPリクエストを構築して送信し、JSONを逆シリアル化することを意味します。

// Klippa: 15+ lines of HTTP plumbing before you read a single character
var content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(File.ReadAllBytes(imagePath)), "document", "receipt.jpg");
_client.DefaultRequestHeaders.Add("X-Auth-Key", _apiKey); // auth header — rotates, breaks, leaks

var response = await _client.PostAsync(
    "https://custom-ocr.klippa.com/api/v1/parseDocument", content);
response.EnsureSuccessStatusCode(); // throws on 4xx/5xx — no retry, document lost

var json = await response.Content.ReadAsStringAsync();
var parsed = JsonSerializer.Deserialize<KlippaResponse>(json); // your schema, your maintenance
var text = parsed?.Data?.ParsedDocument?.Text; // nullable chain — breaks when schema changes
C#

IronOCRはそれらすべてを置き換えます。

// IronOCR: no HTTP, no auth headers, no JSON — just text
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
C#

IronOCRとKlippa OCR:機能比較

以下の表は、本番環境への移行を決定する上で最も重要な要素に基づいて、2つのライブラリを比較したものです。

フィーチャークリッパOCRIronOCR
展開モデルクラウド専用(EUサーバー)オンプレミス、完全ローカル
.NET SDK / NuGetパッケージNoneIronOcr NuGet パッケージ
インターネット接続が必要ですはい、すべての通話で一度もない
文書データがネットワークから流出するいつも一度もない
汎用OCRいいえ(領収書、請求書、身分証明書のみ)はい(あらゆる文書タイプに対応)
認証設定X-Auth-Key HTTP ヘッダーIronOcr.License.LicenseKey 文字列
HTTPクライアントが必要ですはいなし
レスポンスの逆シリアル化手動JSON解析型指定された OcrResult オブジェクト
再試行/タイムアウトロジック手巻き不要(市内通話)
オフライン/エアギャップ対応なしはい
PDF入力はい(クラウド)はい(ネイティブ、地元)
複数ページTIFF入力不明はい
画像入力フォーマットJPG、PNG(クラウド)JPG、PNG、BMP、TIFF、GIFなど
ストリームとバイト配列の入力SDKなしはい
画像の自動前処理雲側(不透明)はい(傾き補正、ノイズ除去、コントラスト調整、二値化、シャープ化)
構造化出力:単語座標なしはい
単語ごとの信頼度スコアなしはい
検索可能なPDF出力なしはい
OCR中のバーコード読み取りなしはい
多言語対応訓練された文書タイプに限定125以上の言語
スレッドセーフティ該当なし(HTTP呼び出し)はい(スレッドごとに IronTesseract 一つ)
クロスプラットフォーム展開RESTに依存しないWindows、Linux、macOS、Docker、Azure、AWS
HIPAA / ITAR / エアギャップ準拠なしはい
価格設定モデルドキュメント単位のSaaS(料金は非公開)$999 からの永続ライセンス
大規模化に伴うページあたりのコストはい、無制限ですNone

クイックスタート:Klippa OCRからIronOCRへの移行

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

Klippaには公式のNuGetパッケージがありません。 Klippaとの統合をサポートするためだけに存在するHTTPクライアントの依存関係を削除します。

# Remove Klippa-related packages (if installed for REST support)
dotnet remove package Newtonsoft.Json
dotnet remove package System.Net.Http.Json
SHELL

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

dotnet add package IronOcr

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

Klippaとの連携に必要なHTTPおよびJSON名前空間を削除します。 IronOCRの単一名前空間を追加します。

// Before (Klippa integration)
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;

// After (IronOCR)
using IronOcr;
C#

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

ライセンスの初期化をアプリケーションの起動時に一度行います— Startup.cs または最初の OCR 呼び出しの前で:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

コード移行の例

HTTPクライアントサービスクラスの置き換え

Klippaとの統合には、HTTPインフラストラクチャをラップする完全なサービスクラスが必要です。 SDKが存在しないため、これを回避する方法はありません。

クリッパ・アプローチ:

// Klippa: entire service class just to send one HTTP request
public class KlippaOcrService : IDisposable
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl = "https://custom-ocr.klippa.com/api/v1";

    public KlippaOcrService(string apiKey)
    {
        _httpClient = new HttpClient();
        _httpClient.DefaultRequestHeaders.Add("X-Auth-Key", apiKey);
        _httpClient.Timeout = TimeSpan.FromSeconds(30); // network timeout required
    }

    public async Task<string> ReadDocumentTextAsync(string filePath)
    {
        using var form = new MultipartFormDataContent();
        var fileBytes = await File.ReadAllBytesAsync(filePath);
        form.Add(new ByteArrayContent(fileBytes), "document", Path.GetFileName(filePath));

        var response = await _httpClient.PostAsync($"{_baseUrl}/parseDocument", form);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        using var doc = JsonDocument.Parse(json);
        // navigate Klippa's nested JSON schema
        return doc.RootElement
            .GetProperty("data")
            .GetProperty("parsed_document")
            .GetProperty("text")
            .GetString() ?? string.Empty;
    }

    public void Dispose() => _httpClient.Dispose();
}
C#

IronOCRのアプローチ:

// IronOCR: no HTTP, no JSON navigation, no Dispose plumbing
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string ReadDocumentText(string filePath)
    {
        return _ocr.Read(filePath).Text;
    }
}

// At startup:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Usage — identical call site, different internals:
var service = new OcrService();
var text = service.ReadDocumentText("invoice.jpg"); // local, synchronous, zero network
C#

Klippaサービス クラスが存在するのは、APIがHTTPインフラストラクチャを必要とするためです。 IronOCR の対応は単一の Read() 呼び出しに集約されます。 ネットワークが存在しないため、タイムアウト、認証ヘッダー、および破棄パターンはすべて消滅します。 初期化オプションについてはIronTesseractのセットアップガイドを、動作するコードについては基本的なOCRの例を参照してください。

マルチパートフォームアップロードの排除

Klippaは、マルチパート形式のフォームアップロードとしてドキュメントを受け取ります。 アップロードコードは機械的だが脆弱である。ファイル読み込み、コンテンツタイプヘッダー、境界構築、アップロードサイズ管理などが含まれる。

クリッパ・アプローチ:

// Klippa: multipart upload — every document is an HTTP form POST
public async Task<KlippaResult> UploadAndParseAsync(
    string filePath, string documentType = "financial")
{
    using var form = new MultipartFormDataContent();

    // read file into memory — entire document in RAM before upload
    var fileBytes = await File.ReadAllBytesAsync(filePath);
    var byteContent = new ByteArrayContent(fileBytes);
    byteContent.Headers.ContentType =
        new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");

    form.Add(byteContent, "document", Path.GetFileName(filePath));
    form.Add(new StringContent(documentType), "DocumentType");

    // document leaves your server here
    var response = await _httpClient.PostAsync(
        "https://custom-ocr.klippa.com/api/v1/parseDocument", form);

    if (!response.IsSuccessStatusCode)
    {
        var error = await response.Content.ReadAsStringAsync();
        throw new InvalidOperationException($"Klippa API error: {response.StatusCode}{error}");
    }

    var json = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<KlippaResult>(json,
        new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
C#

IronOCRのアプローチ:

// IronOCR: load from file path, byte array, or stream — no upload, no form
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// From file path
using var input = new OcrInput();
input.LoadImage("invoice.jpg");
var result = new IronTesseract().Read(input);

// From byte array (same bytes Klippa was uploading)
byte[] fileBytes = await File.ReadAllBytesAsync("invoice.jpg");
using var inputFromBytes = new OcrInput();
inputFromBytes.LoadImage(fileBytes);
var resultFromBytes = new IronTesseract().Read(inputFromBytes);

Console.WriteLine(result.Text);
C#

構築、コンテンツタイプのヘッダー、アップロード自体がすべてなくなりました。 IronOCR はファイルパス、バイト配列、または Stream から直接読み取ります—Klippa がクラウドに送信していたのと同じデータがローカルに残ります。 画像入力ガイドでは、サポートされているすべての入力フォーマットについて説明しており、ストリーム入力ガイドでは、上流プロセスからバイト配列として送られてくるドキュメントのメモリストリームパスについて説明しています。

JSONレスポンスの逆シリアル化の置き換え

KlippaはネストされたJSON構造を返します。 その構造をナビゲートするためには、対応する C# モデルまたはインラインの JsonDocument トラバーサルが必要です—どちらも Klippa がレスポンススキーマを変更するときに破損します。

クリッパ・アプローチ:

// Klippa: deserialization model — breaks when API schema changes
public class KlippaResponse
{
    [JsonPropertyName("data")]
    public KlippaData Data { get; set; }
}

public class KlippaData
{
    [JsonPropertyName("parsed_document")]
    public KlippaParsedDocument ParsedDocument { get; set; }
}

public class KlippaParsedDocument
{
    [JsonPropertyName("text")]
    public string Text { get; set; }

    [JsonPropertyName("amount")]
    public decimal? Amount { get; set; }

    [JsonPropertyName("merchant")]
    public string Merchant { get; set; }

    [JsonPropertyName("date")]
    public string Date { get; set; }
}

// Usage: navigate the nullable chain every time
public async Task<string> GetExtractedTextAsync(string imagePath)
{
    var klippaResult = await UploadAndParseAsync(imagePath);
    // every property access is nullable — schema drift breaks this silently
    return klippaResult?.Data?.ParsedDocument?.Text ?? string.Empty;
}
C#

IronOCRのアプローチ:

// IronOCR: typed result object — no JSON schema, no nullable chains
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();
var result = ocr.Read("invoice.jpg");

// Direct property access — no deserialization, no nullable navigation
string fullText   = result.Text;
double confidence = result.Confidence;
int pageCount     = result.Pages.Count();

// Structured data: lines and words with coordinates
foreach (var page in result.Pages)
{
    foreach (var line in page.Lines)
    {
        Console.WriteLine($"Line: '{line.Text}' at Y={line.Y}");
    }
}
C#

OcrResult は型付き .NET オブジェクトです。 解析すべきJSONデータも、保守すべきモデルクラスも存在せず、スキーマのずれによって本番環境の逆シリアル化が壊れるリスクもありません。 結果の読込みガイドはワード座標、信頼スコア、および構造化されたページ階層を含むOcrResult オブジェクトモデルを完全に文書化しています。 請求書固有のフィールド抽出パターンを OcrResult の上に構築するために、請求書 OCR チュートリアルは、エンドツーエンドの抽出ロジックを網羅しています。

エラー処理と再試行インフラストラクチャの削除

HTTP を介した Klippa の統合には、ネットワーク呼び出しで発生する可能性のあるすべての障害モード(タイムアウト、4xx レスポンス、5xx レスポンス、レート制限、部分的な JSON など)に対するエラー処理が必要です。 本番環境への統合を実行するチームは、Pollyまたはカスタムロジックを使用して再試行ポリシーを追加します。 ネットワーク呼び出しがなくなると、そのインフラストラクチャも消滅する。

クリッパ・アプローチ:

// Klippa: retry policy required — cloud calls fail unpredictably
public async Task<string> ReadWithRetryAsync(string filePath, int maxRetries = 3)
{
    var delay = TimeSpan.FromSeconds(1);

    for (int attempt = 1; attempt <= maxRetries; attempt++)
    {
        try
        {
            using var form = new MultipartFormDataContent();
            form.Add(
                new ByteArrayContent(await File.ReadAllBytesAsync(filePath)),
                "document",
                Path.GetFileName(filePath));

            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
            var response = await _httpClient.PostAsync(
                "https://custom-ocr.klippa.com/api/v1/parseDocument", form, cts.Token);

            if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
            {
                // rate limited — back off and retry
                await Task.Delay(delay * attempt);
                continue;
            }

            response.EnsureSuccessStatusCode();
            var json = await response.Content.ReadAsStringAsync(cts.Token);
            var parsed = JsonSerializer.Deserialize<KlippaResponse>(json);
            return parsed?.Data?.ParsedDocument?.Text ?? string.Empty;
        }
        catch (HttpRequestException) when (attempt < maxRetries)
        {
            await Task.Delay(delay * attempt); // exponential backoff
        }
        catch (TaskCanceledException) when (attempt < maxRetries)
        {
            await Task.Delay(delay * attempt); // timeout — retry
        }
    }

    throw new InvalidOperationException($"Klippa API failed after {maxRetries} attempts");
}
C#

IronOCRのアプローチ:

// IronOCR: no network, no retry policy needed — local call either works or throws once
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

public string ReadDocument(string filePath)
{
    // なし retry loop. なし CancellationTokenSource. なし HTTP status checks.
    // なし rate limit handling. なし partial-JSON guards.
    var result = new IronTesseract().Read(filePath);
    return result.Text;
}
C#

全体のリトライインフラストラクチャ—ループ、遅延計算、CancellationTokenSource、HTTP ステータスコードの分岐、TaskCanceledException キャッチブロック—はネットワークのためだけに存在します。 ネットワーク呼び出しを削除すれば、すべて消えます。 ローカルOCR呼び出しは、入力ファイルが見つからないか読み取り不能な場合は、型付き例外を伴ってすぐに失敗し、それ以外の場合は成功します。移行後にスループットが懸念される場合は、速度最適化ガイドでIronOCRのパフォーマンスチューニングについて説明しています。

クラウドアップロードなしで複数ページのPDFを処理する

Klippa は同じ parseDocument エンドポイントを通じて PDF のアップロードを受け入れます。 複数ページのPDFファイルは、依然としてネットワーク外に送信されます。 IronOCRはPDFをネイティブに、処理内で読み取り、ページごとの結果にアクセスできます。

クリッパ・アプローチ:

// Klippa: PDF upload — entire document transmitted, results depend on cloud availability
public async Task<List<string>> ExtractPdfPagesAsync(string pdfPath)
{
    var pages = new List<string>();

    // Klippa parses the entire PDF server-side and returns combined results
    // You cannot control per-page processing or access raw page text
    using var form = new MultipartFormDataContent();
    form.Add(
        new ByteArrayContent(await File.ReadAllBytesAsync(pdfPath)),
        "document",
        Path.GetFileName(pdfPath));

    var response = await _httpClient.PostAsync(
        "https://custom-ocr.klippa.com/api/v1/parseDocument", form);
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    var result = JsonSerializer.Deserialize<KlippaResponse>(json);
    // Klippa returns the combined parsed text — no per-page breakdown in basic API
    pages.Add(result?.Data?.ParsedDocument?.Text ?? string.Empty);

    return pages;
}
C#

IronOCRのアプローチ:

// IronOCR: native PDF OCR with per-page structured access — no upload
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

using var input = new OcrInput();
input.LoadPdf("multi-page-invoice.pdf"); // reads locally — no HTTP

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

// Per-page access — not available from Klippa's combined response
foreach (var page in result.Pages)
{
    Console.WriteLine($"Page {page.PageNumber}: {page.Lines.Count()} lines");
    Console.WriteLine(page.Text);
}

// Or produce a searchable PDF from the scanned original
result.SaveAsSearchablePdf("searchable-output.pdf");
C#

IronOCRは、変換処理を一切行わずにPDFファイルをネイティブに読み取ります。各ページは個別にアクセス可能で、行、単語、文字の階層構造を完全に把握できます。 SaveAsSearchablePdf() 呼び出しはスキャン文書からテキストレイヤー付きの PDF を生成します—Klippa が提供しない機能です。 PDF入力ガイドには読み込みオプションが記載されており、検索可能なPDFガイドにはアーカイブ準拠のためのPDF/Aを含む出力オプションが記載されています。

##クリッパOCRAPIからIronOCRへのマッピングリファレンス

KlippaはREST APIであり、型付きSDKではありません。 以下のマッピングは、Klippaの統合面をIronOCRの同等の領域に変換したものです。

クリッパコンセプトIronOCR相当値
HttpClientX-Auth-Key ヘッダーIronTesseract インスタンス—認証セットアップ不要
MultipartFormDataContentOcrInput.LoadImage(path) または OcrInput.LoadPdf(path)
POST /api/v1/parseDocumentIronTesseract.Read(input)
await _client.PostAsync(...)ocr.Read(input) — 同期的で、await 不要
response.EnsureSuccessStatusCode()不要 — HTTPレスポンスなし
JsonSerializer.Deserialize<KlippaResponse>(json)型指定された OcrResult — デシリアライズが不要
KlippaResponse.Data.ParsedDocument.TextOcrResult.Text
KlippaResponse.Data.ParsedDocument.AmountOcrResult.Text または OcrResult.Lines でのカスタム正規表現
KlippaResponse.Data.ParsedDocument.MerchantOcrResult.Pages[0].Lines[0].Text
Task.Delay 付きのリトライループ不要 — ネットワーク障害モードなし
CancellationTokenSource(TimeSpan.FromSeconds(30))不要 — ローカル実行
レート制限処理(HTTP 429)不要 - レート制限なし
EUサーバーへのクラウド文書ルーティングローカルプロセス内実行
KlippaService.Dispose() / HttpClient.Dispose()OcrInputusing ステートメントによる処分
構造化されたJSONレスポンスフィールドOcrResult.Text + OcrResult.Pages + OcrResult.Words
SaaS APIサブスクリプションIronOcr.License.LicenseKey 文字列—永続的

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

問題1:HTTP削除後の非同期専用呼び出しサイト

Klippa: HTTP呼び出しには非同期処理が必要なため、Klippaとの統合はすべて非同期で行われます。 コードベース全体でawait ProcessDocumentAsync(...) を呼び出すコントローラー、サービス、およびバックグラウンドワーカー HTTP 呼び出しの削除は、await が不要になることを意味しますが、async のメソッドシグネチャは残ります。

解決策: IronOCR は同期および非同期 API の両方を提供します。非同期である必要がある呼び出しサイト (ASP.NET Core コントローラー、CancellationToken を使用したバックグラウンドサービス) には、ReadAsync を使用してください:

// Keep async method signatures — switch the implementation
public async Task<string> ProcessDocumentAsync(
    string filePath, CancellationToken cancellationToken = default)
{
    // Previously: await _httpClient.PostAsync(...)
    // Now: local call, same awaitable pattern
    var ocr = new IronTesseract();
    var result = await ocr.ReadAsync(filePath);
    return result.Text;
}
C#

非同期 OCR ガイドは、ASP.NET Core およびホストサービスパターンのための ReadAsyncCancellationToken の統合を網羅しています。

課題2:依存性注入の登録

Klippa: KlippaService クラスはシングルトンまたはスコープサービスとして DI に登録され、HttpClient をラップします。 それを削除するということは、DI登録とすべてのインジェクションポイントを更新することを意味します。

解決策: IronTesseract をスレッドセーフであるシングルトンとして登録し、直接注入するか、既存のサービスインターフェースを反映する薄いラッパーを作成してください:

// In Program.cs or Startup.cs
builder.Services.AddSingleton<IronTesseract>();

// Or wrap for interface compatibility
builder.Services.AddSingleton<IOcrService, IronOcrService>();

public class IronOcrService : IOcrService
{
    private readonly IronTesseract _ocr;
    public IronOcrService(IronTesseract ocr) => _ocr = ocr;

    public string ReadDocument(string path) => _ocr.Read(path).Text;
}
C#

一つの IronTesseract インスタンスがシングルトンとして登録され、同時リクエストを処理します。 Read() への各呼び出しはスレッドセーフです。

課題3:事前解析済みJSONなしでの構造化フィールド抽出

Klippa: Klippa は date、および vat_amount を型付き JSON プロパティとして返します。 IronOCRへの移行により、これらのフィールドは事前に解析された状態では届かなくなります。

解決策: IronOCR の OcrResult は生テキストおよび単語レベルの座標を提供し、同等の抽出を構築します。 レイアウトが予測可能な文書の場合、領域ベースのOCRは特定のフィールドを直接対象とします。

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Target specific layout regions instead of relying on pre-parsed cloud fields
var totalRegion   = new CropRectangle(350, 580, 250, 50); // bottom-right total area
var merchantRegion = new CropRectangle(50, 30, 400, 60);  // top header area

using var merchantInput = new OcrInput();
merchantInput.LoadImage("receipt.jpg", merchantRegion);
var merchantName = new IronTesseract().Read(merchantInput).Text.Trim();

using var totalInput = new OcrInput();
totalInput.LoadImage("receipt.jpg", totalRegion);
var totalText = new IronTesseract().Read(totalInput).Text.Trim();
C#

領域ベースの OCR ガイドは、CropRectangle の使用について詳しく説明しています。 レシートと請求書のレイアウト全体にわたる完全な抽出パターンについては、レシートスキャンチュートリアルに完全な動作コードが記載されています。

問題4:上流サービスからストリームとして到着するドキュメント

Klippa: Klippaは、マルチパートフォームアップロードとしてドキュメントを受け取ります。これは、HTTPフォームコンテンツでラップされたファイルバイトです。 アプリケーションがS3、Azure Blob Storage、または内部APIからドキュメントをストリームとして受信する場合、ストリームをバイト列に読み込んでから、そのバイト列をKlippaにアップロードしていました。

解決策: IronOCR は Stream オブジェクトを直接受け入れます。 バイト変換の手順が不要になります。

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Stream from S3, Azure Blob, or any upstream source
public async Task<string> ProcessDocumentStreamAsync(Stream documentStream)
{
    using var input = new OcrInput();
    input.LoadImage(documentStream); // accepts Stream directly

    var ocr = new IronTesseract();
    var result = ocr.Read(input);
    return result.Text;
}
C#

ReadAllBytes なし、MultipartFormDataContent 構築なし、HTTP POST なし。ストリームは OcrInput に直接入ります。 河川流入ガイドでは、河川の種類と排水パターンについて説明しています。

課題5:HTTPモックに依存する統合テスト

Klippa: Klippa コードの統合テストは HttpClient をモックしたり、API レスポンスをシミュレートするために HTTP インターセプター (例:MockHttp) を使用します。 これらのテストはHTTPレイヤーを模倣するものであり、OCRロジックを模倣するものではありません。

解決策: IronOCRのテストでは、出力結果が既知の実際の文書を使用します。 モック化のためのインフラストラクチャは不要です。 オフラインで実行されるテスト:

[Fact]
public void ReadDocument_ReturnsExpectedText()
{
    IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
    var ocr = new IronTesseract();

    // Use a real test fixture — no HTTP mocking, runs fully offline
    var result = ocr.Read("test-fixtures/sample-invoice.jpg");

    Assert.Contains("Invoice", result.Text, StringComparison.OrdinalIgnoreCase);
    Assert.True(result.Confidence > 70);
}
C#

これまでKlippaへのライブ接続や複雑なHTTPモック設定が必要だったテストが、ネットワークアクセスなしでCI環境で実行できるようになりました。

問題6:Klippaがサーバー側で強化した低品質ドキュメント

**Klippa:**クラウド処理では、認識前に画像強調処理が適用されます。 開発者がこれを設定する必要は一切ありません。Klippaのサーバー上で自動的に行われます。 移行時に、Klippa がサイレントに処理したドキュメントは、 IronOCRで明示的な前処理を行わないと精度が低下する可能性があります。

解決策: IronOCRの前処理フィルターを明示的に適用する。 このフィルタセットは、クラウドサービスがサーバー側で適用するフィルタセットを反映しています。

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

using var input = new OcrInput();
input.LoadImage("low-quality-scan.jpg");
input.Deskew();    // fix rotation from camera or scanner
input.DeNoise();   // remove compression noise
input.Contrast();  // boost faded ink
input.Binarize();  // clean background for clearer character edges

var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
C#

画像品質補正ガイドでは、すべての前処理フィルターと、さまざまな文書劣化タイプに対するそれらの適用順序について説明しています。

##クリッパOCR移行チェックリスト

移行前

何かを削除する前に、コードベースを監査してKlippa固有のコードをすべて特定してください。

# Find all files containing Klippa HTTP integration code
grep -r "X-Auth-Key" --include="*.cs" .
grep -r "klippa.com" --include="*.cs" .
grep -r "KlippaService\|KlippaResponse\|KlippaResult\|KlippaData" --include="*.cs" .

# Find all files with MultipartFormDataContent (likely Klippa upload code)
grep -r "MultipartFormDataContent" --include="*.cs" .

# Find all JSON deserialization models that map to Klippa response fields
grep -r "parsed_document\|vat_amount\|merchant\|X-Auth-Key" --include="*.cs" .

# Find all async methods that wrap Klippa calls
grep -r "ParseDocumentAsync\|ProcessReceiptAsync\|UploadAndParseAsync" --include="*.cs" .

# Find test files with HTTP mocks for Klippa
grep -r "MockHttp\|WireMock\|klippa" --include="*.cs" .
SHELL

在庫に関する注記:

  • Klippa 呼び出しのために HttpClient をラップするすべてのクラスを記録してください
  • すべての JSON デシリアライズモデルクラスをリストアップしてください (例:KlippaParsedDocument など)
  • Klippaの事前解析済みJSONプロパティを使用するすべてのフィールドマッピングを文書化する
  • PollyのリトライポリシーやKlippa用に構築されたカスタムリトライループに注意してください。

コードの移行

  1. IronOcr NuGet パッケージをインストールしてください (例:dotnet add package IronOcr)
  2. アプリケーション起動時に IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" を追加してください
  3. Klippa サービスファイルから Newtonsoft.Json のインポートを削除してください
  4. KlippaService クラスを削除 (またはその本体を IronTesseract 呼び出しで置き換え、インターフェースを保持)
  5. IronTesseract を DI コンテナにシングルトンとして登録してください
  6. MultipartFormDataContent アップロードブロックを OcrInput.LoadImage() または OcrInput.LoadPdf() に置き換えてください
  7. JSON レスポンスモデルクラスを削除してください (例:KlippaParsedDocument)
  8. NULL 可能な JSON ナビゲーションチェーン (例:.Data?.ParsedDocument?.Text) を result.Text に置き換えてください
  9. Klippa 呼び出しサイトからリトライループと CancellationTokenSource タイムアウトを削除してください
  10. レート制限処理(HTTP 429 キャッチブロック)を削除する
  11. await ProcessDocumentAsync(...)await ocr.ReadAsync(...) または同期的な ocr.Read(...) に置き換えてください
  12. 低品質の文書入力のために OcrInput 前処理フィルター (Contrast) を追加してください
  13. HTTPモックテストインフラストラクチャを実際のドキュメントフィクスチャテストに置き換える
  14. Klippa呼び出しにスコープされたPollyリトライポリシーまたはカスタムリトライミドルウェアを削除します。

移行後

  • テキスト抽出結果が既知のテスト文書の想定される内容と一致することを確認する
  • 生産文書の種類について、信頼度スコアが許容しきい値(通常70%以上)を超えていることを確認する
  • PDF 入力のテスト:ネイティブにマルチページ PDF を読み込み、result.Pages を介した各ページのテキストアクセスを検証する
  • ストリーム入力のテスト:MemoryStream を通過させ、OcrInput.LoadImage(stream) が正しい出力を生成することを検証する
  • 前処理フィルターが未処理のベースラインと比較して低品質スキャンの精度を向上させることを検証する
  • DI で注入された IronTesseract シングルトンが同時リクエストをコンテンションなしで処理することを確認する
  • オフライン(ネットワーク接続なし)で統合テストを実行する — クラウドアクセスなしで全てのテストが合格するはずです
  • スキャンされた文書フローのために result.SaveAsSearchablePdf("output.pdf") を使った検索可能な PDF 出力を確認する
  • ASP.NET Core コントローラーコンテキストで ReadAsyncCancellationToken 伝播とともにテストする
  • 持続的な負荷の下でメモリリークのない using var input = new OcrInput() 廃棄パターンを確認する

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

**データ主権は初日から確保されます。**移行後、機密性の高い財務書類、本人確認書類、機密性の高い請求書は、お客様のインフラストラクチャから外部に持ち出されることはありません。 監査対象には第三者処理業者は含まれておらず、レビューすべきデータ保持ポリシーも、維持すべきデータ転送契約もありません。 これまでKlippaに問題を引き起こしていたHIPAA、ITAR、CMMC、およびFedRAMPの制約は、デフォルトで満たされています。 DockerAWS 、またはAzureへのデプロイにより、すべてが自社のインフラストラクチャ境界内に収まります。

**インフラストラクチャの複雑さが解消されました。**サービス クラス、HTTP クライアント、フォームアップロード コード、JSON モデル、再試行ポリシー、タイムアウト設定など、すべてはネットワーク呼び出しをラップするために存在していました。 ネットワーク呼び出しを削除すれば、それらすべてが削除されます。 その結果、コードベースはより小さく、読みやすく、障害発生箇所も少なくなる。 DI を通じて注入された単一の IronTesseract インスタンスは、すべての HTTP 統合レイヤーを置き換えます。

ボリュームにかかわらず予測可能なコスト。 $499 (Lite)、$1,499 (Professional)、または $2,999 (Enterprise) の IronOCR 永続ライセンスは、無制限の文書処理をカバーします。 1ヶ月に500件の文書を処理する場合も、50万件を処理する場合も、費用は同じです。 Klippaを大規模に利用する際のコスト要因となっていた、ドキュメントごとの課金システムは、構造的に排除されている。 IronOCRのライセンスページには、すべてのティアとそれぞれの内容が詳しく記載されています。

文書の範囲に制限はありません。IronOCRは、テキストを含むあらゆる文書を処理できます。 スキャンされた契約書、技術図面、医療フォーム、注文書、手書きのメモ、スクリーンショット、TIFF アーカイブ — すべて同じ Read() 呼び出しと同じ API で処理されます。 Klippaの専門分野外の文書については別のシステムが必要だったという、専門分野に関する制約は解消された。 1つのライブラリ、1つの統合ポイント、あらゆるドキュメントタイプに対応。

**オフライン環境および制限付きネットワーク環境がサポートされるようになりました。**銀行ネットワーク、政府システム、エッジ環境、または外部への通信が制限されているあらゆるインフラストラクチャに展開されたアプリケーションは、オープン環境とまったく同じように動作します。 接続チェックも、クラウドエンドポイントへのヘルスチェックピングも、インターネット接続が利用できない場合の劣化モードもありません。 エアギャップ方式の展開は、変更なしで機能します。 Linux導入ガイドDocker導入ガイドでは、これらの環境におけるコンテナ化およびサーバーサイド導入の手順について説明しています。

**画像補正を完全に制御できます。**クラウド前処理はブラックボックスでした。Klippaが前処理を適用し、ユーザーは結果を確認するだけで、調整できるパラメータはありませんでした。 IronOCR の前処理パイプラインは明示的かつ組み合わせ可能です:DeepCleanBackgroundNoise()。 各フィルターはオプションであり、順番に並んでいます。 精度向上は測定可能で再現性があり、かつあなたの管理下にあります。 画像品質補正ガイド前処理機能のページでは、すべてのフィルターカタログを網羅し、それぞれのフィルターを適用するタイミングに関するガイダンスを提供しています。

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

関連する記事

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日間の試用キーをすぐに入手。
クレジットカードやアカウントの作成は不要です。