如何在C#中使用開源庫實現OCR
本指南適用於已整合Klippa的REST API並希望轉往使用IronOCR進行內部文件處理的.NET開發者。 它涵蓋了實際步驟,如移除HTTP客戶端基礎架構、消除JSON反序列化,以及將依賴雲端的文件上傳替換成從不接觸網路的本地OCR調用。
為什麼要從Klippa OCR遷移
Klippa是一個僅限於雲端的文件智能服務,沒有.NET的SDK。 每個整合都是一個手工建立的REST客戶端。 這種架構現實對生產系統的生命週期有著下游影響。
沒有NuGet包意味著您擁有整合層。 沒有什麼需要安裝的。 入口成本是寫MultipartFormDataContent請求主體、反序列化Klippa的JSON響應架構,以及為瞬時失敗設定重試邏輯。 這需要2-4天的管道工作,才能在生產中可靠地處理第一個文件。 當Klippa更新他們的API架構時,您的反序列化程式碼會崩潰,需要手動維護。
每次文件上傳都是一個網路依賴。 Klippa僅在託管於EU的伺服器上處理文件。 Klippa端的生產停機、升高的延遲,或者任何出站互聯網存取中斷,會使您的應用伺服器完全停止處理文件。 沒有備援,沒有本地模式,沒有解決雲服務不可用的重試方法。
敏感文件離開您的基礎架構。 財務文件——帶有支付細節的收據、帶有VAT號碼和金額的發票、帶有護照資料的身份文件——在每次API調用時會傳送到第三方伺服器。 GDPR的資料傳輸規定解決了一些EU基於處理的問題,但審計範圍仍延伸到Klippa的基礎架構、資料保留政策和次處理器。 對於擁有醫療、法律、金融服務或政府合同的團隊來說,"EU託管"並不滿足資料不得離開組織的要求。
按文件計費模式無上限地擴展。 Klippa不公佈價格。 在任何有意義的文件量——每月10,000張收據的費用管理系統,每天500張發票的AP自動化工作流程——按文件計費模式產生的成本是永久授權永遠不會產生的。 成本軌跡直接與業務增長綁定,這與基礎架構支出應有的做法相反。
當需求擴展時,專家範圍破裂。 Klippa在收據、發票和身份文件上受過訓練。 一個作為費用管理開始的應用很少會停留在那裡。 第一次出現這三類別以外的文件型別時——掃描的就業合同、醫療表單、技術圖紙、具有非標準佈局的採購訂單——Klippa返回的都是無用的。 IronOCR處理任何包含文字的文件,沒有類別限制。
僅限非同步的REST調用在同步上下文中增加延遲。 每次Klippa調用都是一個非同步HTTP操作。 一個文件來回的網路往返時間為500ms至2000ms。 IronOCR本地處理相同文件僅需100-400ms,沒有非同步的負擔,當同步處理更符合架構時。
根本問題
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
IronOCR替換了這一切:
// IronOCR: no HTTP, no auth headers, no JSON — just text
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
IronOCR和Klippa OCR:功能比較
下表比較了這兩個庫在生產遷移決策中最重要的維度。
| 功能 | Klippa OCR | IronOCR |
|---|---|---|
| 部署模型 | 僅限雲端(歐盟伺服器) | 本地、完全本地 |
| .NET SDK / NuGet套件 | None | IronOcr NuGet 套件 |
| 需要網際網路 | 是的,在每次調用中 | 絕不需要 |
| 文件資料離開網路 | 總是需要 | 絕不需要 |
| 通用OCR | 否(僅收據、發票、身份證) | 是(任何文件型別) |
| 驗證設置 | X-Auth-Key HTTP 標頭 | IronOcr.License.LicenseKey 字串 |
| 需要HTTP客戶端 | 是 | 不是 |
| 響應反序列化 | 手動JSON解析 | 型別化的OcrResult 物件 |
| 重試/超時邏輯 | 手工撰寫 | 不需要(本地調用) |
| 離線/氣隙支持 | 不是 | 是 |
| PDF 輸入 | 是的(雲端) | 是的(本地,內生) |
| 多頁TIFF輸入 | 未知 | 是 |
| 圖像輸入格式 | JPG, PNG(雲端) | JPG、PNG、BMP、TIFF、GIF等 |
| 流與字節陣列輸入 | 無SDK | 是 |
| 自動圖像預處理 | 雲端端(不透明) | 是的(Deskew, DeNoise, Contrast, Binarize, Sharpen) |
| 結構化輸出:單詞坐標 | 不是 | 是 |
| 每個單詞的置信度分數 | 不是 | 是 |
| 可搜尋的 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
從NuGet安裝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;
步驟3:初始化許可證
在應用啟動時新增一次性授權初始化——在Startup.cs中或首次OCR調用之前:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"程式碼遷移範例
替換HTTP客戶端服務類
Klippa整合需要完整的服務類來包裝HTTP基礎架構。 這是不可避免的,因為沒有SDK。
Klippa方法:
// 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();
}
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
Klippa服務類完全因為API需要HTTP基礎架構而存在。 IronOCR的一個等價縮減到一個Read()調用。 超時、驗證標頭和處置模式全都消失,因為沒有網路。 參見IronTesseract設置指南以瞭解初始化選項,並參考基本OCR範例以瞭解工作程式碼。
消除多部分表單上傳
Klippa通過多部分表單上傳接收文件。 上傳程式碼是機械式但脆弱的:文件讀取,內容型別標頭,邊界構建和上傳大小管理。
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 });
}
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);
MultipartFormDataContent構建、內容型別標頭和上傳本身都消失了。 IronOCR直接從文件路徑、字節陣列或Stream中讀取——Klippa傳輸到雲端的相同資料保持在本地。 圖像輸入指南涵蓋了所有支持的輸入格式,而流輸入指南涵盖字節陣列從上游過程來的文件的記憶體流路徑。
替換JSON響應反序列化
Klippa返回一個巢狀的JSON結構。 導航該結構需要匹配的C#模型或內聯JsonDocument遍歷——Klippa變更其響應架構時,這兩者都會崩潰。
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;
}
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}");
}
}
OcrResult是一個型別化的.NET物件。 沒有JSON可解析,沒有模型類需要維護,沒有架構漂移破壞生產反序列化的風險。 讀取結果指南記錄了完整的OcrResult物件模型,包括單詞坐標、自信度分數和結構化頁面層次結構。 對於基於OcrResult構建的發票特定字段提取模式,發票OCR教程涵蓋了端到端的提取邏輯。
移除錯誤處理和重試基礎架構
Klippa整合需要對HTTP產生的每一種錯誤模式進行錯誤處理:超時、4xx響應、5xx響應、速率限制和部分JSON。 運行生產整合的團隊使用Polly或自定邏輯新增重試政策。 當網路調用消失時,這種基礎架構便消失了。
Klippa方法:
// 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");
}
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;
}
整個重試基礎架構——迴圈、延遲計算、TaskCanceledException捕獲塊——僅因為網路而存在。 移除網路調用,所有這些都會消失。 如果輸入文件缺失或無法讀取,本地OCR調用會快速失敗並拋出型別化異常,否則成功。速度優化指南涵蓋了如果在遷移後吞吐量是問題時IronOCR性能調校的措施。
處理不需雲端上傳的多頁PDF
Klippa通過相同的parseDocument端點接受PDF上傳。 多頁的PDF仍然離開您的網路。 IronOCR原生讀取PDF,處理時可逐頁獲取結果。
Klippa方法:
// 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;
}
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");
IronOCR原生讀取PDF文件,不需要任何轉換步驟。每頁都能獨立存取,具有完整的行、單詞、和字元層次結構。 SaveAsSearchablePdf()調用從掃描文件中生成一個文字層PDF——Klippa不提供這種能力。 PDF輸入指南涵蓋了載入選項,而可搜尋PDF指南涵蓋了包括PDF/A的存檔符合選項。
##Klippa OCRAPI到IronOCR的映射參考
Klippa是一個REST API,而不是一個型別化的SDK。 下方映射將Klippa's整合介面翻譯為IronOCR的等效物。
| Klippa概念 | IronOCR 等效 |
|---|---|
X-Auth-Key標頭一起 | IronTesseract實例——不需要驗證設置 |
MultipartFormDataContent | OcrInput.LoadPdf(path) |
POST /api/v1/parseDocument | IronTesseract.Read(input) |
await _client.PostAsync(...) | await |
response.EnsureSuccessStatusCode() | 不需要——無HTTP響應 |
JsonSerializer.Deserialize<KlippaResponse>(json) | 型別化的OcrResult——無需反序列化 |
KlippaResponse.Data.ParsedDocument.Text | OcrResult.Text |
KlippaResponse.Data.ParsedDocument.Amount | 自訂正則表達式於OcrResult.Lines |
KlippaResponse.Data.ParsedDocument.Merchant | OcrResult.Pages[0].Lines[0].Text |
帶Task.Delay的重試迴圈 | 不需要——無網路失敗模式 |
CancellationTokenSource(TimeSpan.FromSeconds(30)) | 不需要——本地執行 |
| 速率限制處理(HTTP 429) | 不需要——無速率限制 |
| 雲端文件路由至EU伺服器 | 本地內處理執行 |
KlippaService.Dispose() / HttpClient.Dispose() | using語句處置 |
| 結構化的JSON響應字段 | OcrResult.Text + OcrResult.Pages + OcrResult.Words |
| SaaS API訂閱 | IronOcr.License.LicenseKey字串——永久 |
常見的遷移問題与解決方案
問題1:HTTP消除後的僅限非同步調用站點
**Klippa:**因為HTTP調用需要,所以Klippa整合全部是非同步的。 貴方程式碼庫中的控制器、服務、後台工作者全部調用await ProcessDocumentAsync(...)。 刪除HTTP調用意味著不再需要async的方法簽名仍然保留。
**解決方案:**IronOCR提供同步和非同步API。對於必須保持非同步的調用站點(ASP.NET核心控制器,采用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;
}
非同步OCR指南涵蓋了對ASP.NET核心和託管服務模式中CancellationToken的整合。
問題2:依賴注入註冊
Klippa: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;
}
一個IronTesseract實例註冊為單件,處理並發請求。 每次調用Read()都是執行緒安全的。
問題3:沒有預先解析的JSON的結構化字段提取
**Klippa:**Klippa返回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();
基於區域的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;
}
無MultipartFormDataContent構建,無HTTP POST。流直接進入OcrInput。 流輸入指南涵蓋了流型別和處置模式。
問題5:依賴於HTTP Mocking的整合測試
**Klippa:**Klippa程式碼的整合測試mock了WireMock, MockHttp)來模擬API回應。 這些測試模仿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);
}
以前需要實時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}%");
圖像質量校正指南涵蓋了所有預處理過濾器,以及應用它們的順序以應對不同的文件劣化型別。
Klippa 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" .
清單註釋:
- 記錄每個包裝
HttpClient為Klippa調用的類 - 列出所有JSON反序列化模型類(
KlippaParsedDocument等) - 記錄所有消耗Klippa預先解析JSON屬性的字段映射
- 註明任何專為Klippa構建的Polly重試政策或自定重試迴圈
程式碼遷移
- 安裝
IronOcrNuGet包(dotnet add package IronOcr) - 在應用啟動時新增
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" - 從Klippa服務文件中移除
Newtonsoft.Json的引入 - 刪除
IronTesseract調用替換其主體,保持介面) - 在DI容器中註冊
IronTesseract為單件 - 用
MultipartFormDataContent上傳塊 - 刪除JSON響應模型類(
KlippaParsedDocument) - 用
.Data?.ParsedDocument?.Text) - 移除Klippa調用站點的重試迴圈和
CancellationTokenSource超時 - 移除速率限制處理(HTTP 429 捕獲塊)
- 用
await ProcessDocumentAsync(...) - 為低質量文件輸入新增
Contrast) - 用真實文件樣板測試替換HTTP模擬測試基礎設施
- 刪除針對Klippa調用限定的Polly重試政策或自定重試中介件
遷移後
- 驗證文字提取輸出與已知測試文件的預期內容相符
- 確認信心分數超過可接受門檻(通常是70%以上)以滿足生產文件型別
- 測試PDF輸入:本地載入多頁PDF並通過
result.Pages驗證每頁文字存取 - 測試流輸入:傳遞
OcrInput.LoadImage(stream)產生正確的輸出 - 驗證預處理過濾器比未處理基線提高對低質量掃描的準確性
- 確認DI注入的
IronTesseract單例能無爭議地處理並發請求 - 離線運行整合測試(無網路連接)——所有測試應該在不存取雲端的情況下通過
- 使用
result.SaveAsSearchablePdf("output.pdf")驗證可搜PDF輸出以滿足掃描文件流 - 在ASP.NET核心控制器上下文中測試
CancellationToken傳播 - 確認
using var input = new OcrInput()處置模式不會在持續負載下導致記憶體洩漏
遷移至IronOCR的主要好處
從第一天起就具備資料主權。 遷移後,敏感的財務文件、身份掃描和機密發票不再離開您的基礎架構。 審計範圍內沒有第三方處理器,沒有資料保留政策需要審查,沒有資料轉移協議需要維護。 先前使Klippa成為問題的HIPAA、ITAR、CMMC和FedRAMP限制現在預設滿足。 部署在Docker、AWS或Azure上,將所有東西都保持在您自己的基礎架構邊界內。
基礎架構復雜性消除。 服務類、HTTP客戶端、表單上傳程式碼、JSON模型、重試政策、超時配置——它們全都是為了包裝一個網路調用而存在的。 移除網路調用,所有這些也會消失。 結果程式碼庫更小、更容易閱讀,而且故障模式更少。 通過DI注入的一個IronTesseract實例替換整個HTTP整合層。
無論量有多大,成本可預測。 在$999 (Lite) 一個永久的IronOCR授權,$1,499 (Professional) 或 $2,999 (Enterprise) 可覆盖無限的文件處理。 每月處理500個文件或500,000個文件,成本相同。 按文件計費動態在大規模上曾使Klippa昂貴的情形在架構上不存在。 IronOCR授權頁面詳細說明了所有級別及其包括的內容。
沒有邊界的文件範圍。 IronOCR處理任何包含文字的文件。 掃描的合同、技術圖紙、醫療表單、採購訂單、手寫筆記、截圖、TIFF存檔——所有這些都由相同的Read()調用並由相同的API處理。 需要第二個系統來處理Klippa受訓類別之外的文件的專家範圍限制不復存在。 一個庫,一個整合點,任何文件型別。
現在支持離線和受限網路環境。 部署在銀行網路、政府系統、邊緣環境或任何具有受限出境流量的基礎架構中的應用程式運行方式與在開放環境中一樣。 沒有連接性檢查,沒有健康ping到雲端端點,也不會在網路不可用時降級模式。 無需修改即可工作在氣隙部署。 Linux部署指南和Docker部署指南涵蓋了這些環境的容器化和伺服器端部署路徑。
完全控制影像增強。 雲端預處理是一個黑箱——Klippa應用了它,您觀察結果,您沒有參數可調整。 IronOCR的預處理管道是顯式和可組合的:Deskew(), DeNoise(), Contrast(), Binarize(), Sharpen(), Scale(), Dilate(), DeepCleanBackgroundNoise()。 每個濾鏡都是可選的並且有順序。 準確性改進是可衡量的、可再現的,並且在您的控制之下。 圖像質量校正指南和預處理功能頁面涵蓋了完整的濾鏡目錄,輔以何時應用每一種的指南。
