Przejdź do treści stopki
FILMY

Jak zaimplementować OCR w języku C# przy użyciu bibliotek open source

Ten przewodnik jest przeznaczony dla programistów .NET, którzy zintegrowali REST API Klippa i przechodzą na IronOCR dla .NET w celu przetwarzania dokumentów na miejscu. Obejmuje praktyczne kroki mające na celu usunięcie infrastruktury klienta HTTP, wyeliminowanie deseryalizacji JSON oraz zastąpienie przesyłania dokumentów w chmurze lokalnymi wywołaniami OCR, które nigdy nie korzystają z sieci.

Dlaczego warto przejść z Klippa OCR

Klippa to usługa analizy dokumentów dostępna wyłącznie w chmurze, bez zestawu SDK dla platformy .NET. Każda integracja to ręcznie tworzony klient REST. Ta rzeczywistość architektoniczna ma dalsze konsekwencje, które kumulują się w trakcie cyklu życia systemu produkcyjnego.

Brak pakietu NuGet oznacza, że to Ty jesteś właścicielem warstwy integracyjnej. Nie ma nic do instalowania. Koszt wejścia to napisanie wrappera HttpClient, skonfigurowanie nagłówków uwierzytelniania X-Auth-Key, budowanie ciał żądań MultipartFormDataContent, deserializacja schematu odpowiedzi JSON Klippy i podłączenie logiki ponowienia dla tymczasowych awarii. To 2–4 dni przygotowań, zanim pierwszy dokument zostanie niezawodnie przetworzony w środowisku produkcyjnym. Kiedy Klippa aktualizuje schemat swojego API, kod deseryalizacji przestaje działać i wymaga ręcznej konserwacji.

Każde przesłanie dokumentu wiąże się z zależnością od sieci. Klippa przetwarza dokumenty wyłącznie na serwerach hostowanych w UE. Przerwy w działaniu po stronie Klippa, zwiększone opóźnienia lub jakiekolwiek zakłócenia w dostępie do Internetu z serwera aplikacji całkowicie wstrzymują przetwarzanie dokumentów. Nie ma rozwiązania awaryjnego, trybu lokalnego ani ponownej próby, które rozwiązywałyby problem niedostępności usługi w chmurze.

Wrażliwe dokumenty opuszczają Twoją infrastrukturę. Dokumenty finansowe — pokwitowania z danymi płatności, faktury z numerami VAT i kwotami, dokumenty tożsamości z danymi paszportowymi — są przesyłane na serwer strony trzeciej przy każdym wywołaniu API. Przepisy RODO dotyczące przekazywania danych uwzględniają niektóre z tych kwestii w odniesieniu do przetwarzania danych w UE, ale zakres audytu nadal obejmuje infrastrukturę Klippy, zasady przechowywania danych oraz podwykonawców przetwarzających dane. W przypadku zespołów realizujących kontrakty w sektorze opieki zdrowotnej, prawnym, usług finansowych lub rządowym sformułowanie "hostowane w UE" nie spełnia wymogu, aby dane nie opuszczały organizacji.

Ceny za dokument są skalowane bez górnego limitu. Klippa nie publikuje cennika. Przy każdej znaczącej ilości dokumentów — 10 000 rachunków miesięcznie w systemie zarządzania wydatkami, 500 faktur dziennie w procesie automatyzacji rozliczeń — model rozliczeń za dokument generuje koszty, których nigdy nie poniosłabyś w przypadku Licencji wieczystej. Kształtowanie się kosztów jest bezpośrednio powiązane ze wzrostem działalności, co jest przeciwieństwem tego, jak powinny wyglądać wydatki na infrastrukturę.

Zakres kompetencji specjalisty ulega zmianie wraz z rozszerzeniem wymagań. Klippa została przeszkolona w zakresie paragonów, faktur i dokumentów tożsamości. Aplikacja, która zaczyna jako narzędzie do zarządzania wydatkami, rzadko pozostaje tylko tym. Gdy po raz pierwszy pojawia się dokument spoza tych trzech kategorii — zeskanowana umowa o pracę, formularz medyczny, rysunek techniczny, zamówienie o niestandardowym układzie — Klippa nie zwraca żadnych użytecznych wyników.IronOCR przetwarza każdy dokument zawierający tekst, bez ograniczeń dotyczących kategorii.

Wywołania REST wyłącznie asynchroniczne powodują opóźnienia w kontekstach synchronicznych. Każde wywołanie Klippa jest operacją HTTP typu asynchronicznego. Przesłanie jednego dokumentu w obie strony zajmuje od 500 ms do 2000 ms w sieci.IronOCR przetwarza ten sam dokument lokalnie w czasie 100–400 ms bez obciążenia związanego z przetwarzaniem asynchronicznym w scenariuszach, w których przetwarzanie synchroniczne lepiej pasuje do architektury.

Podstawowy problem

Klippa nie posiada zestawu SDK. OCR oznacza skonstruowanie i wysłanie żądania HTTP, a następnie deseryalizację 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
// 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
Imports System.Net.Http
Imports System.IO
Imports System.Text.Json
Imports System.Threading.Tasks

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

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

Dim json As String = Await response.Content.ReadAsStringAsync()
Dim parsed As KlippaResponse = JsonSerializer.Deserialize(Of KlippaResponse)(json) ' your schema, your maintenance
Dim text As String = parsed?.Data?.ParsedDocument?.Text ' nullable chain — breaks when schema changes
$vbLabelText   $csharpLabel

IronOCR zastępuje to wszystko:

// IronOCR: no HTTP, no auth headers, no JSON — just text
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
// IronOCR: no HTTP, no auth headers, no JSON — just text
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
' IronOCR: no HTTP, no auth headers, no JSON — just text
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text = New IronTesseract().Read(imagePath).Text
$vbLabelText   $csharpLabel

IronOCR a Klippa OCR: porównanie funkcji

W poniższej tabeli porównano obie biblioteki pod kątem aspektów, które mają największe znaczenie przy podejmowaniu decyzji o migracji do środowiska produkcyjnego.

Funkcja Klippa OCR IronOCR
Model wdrożenia Wyłącznie w chmurze (serwery w UE) Lokalna, w pełni zlocalizowana
Pakiet .NET SDK / NuGet None Pakiet NuGet IronOcr
Wymagane połączenie z Internetem Tak, przy każdym wywołaniu Nigdy
Dane dokumentu opuszczają sieć Zawsze Nigdy
Uniwersalne OCR Nie (tylko pokwitowania, faktury, dokumenty tożsamości) Tak (dowolny typ dokumentu)
Konfiguracja uwierzytelniania Nagłówek HTTP X-Auth-Key Ciąg znaków IronOcr.License.LicenseKey
Wymagany klient HTTP Tak Nie
Deserializacja odpowiedzi Ręczne parsowanie JSON Typowany obiekt OcrResult
Logika ponownej próby/limitu czasu Ręcznie przygotowane Nie jest wymagane (połączenie lokalne)
Obsługa trybu offline / air-gapped Nie Tak
Plik wejściowy PDF Tak (chmura) Tak (język ojczysty, lokalny)
Wielostronicowy plik wejściowy w formacie TIFF Nieznane Tak
Formaty plików graficznych JPG, PNG (chmura) JPG, PNG, BMP, TIFF, GIF i inne
Wejście strumieniowe i tablica bajtów Brak SDK Tak
Automatyczne przetwarzanie wstępne obrazów Po stronie chmury (nieprzejrzyste) Tak (Deskew, DeNoise, Contrast, Binarize, Sharpen)
Struktura wyjściowa: współrzędne słów Nie Tak
Wyniki pewności dla poszczególnych słów Nie Tak
Wynik w formacie PDF z możliwością wyszukiwania Nie Tak
Odczytywanie BarCode podczas OCR Nie Tak
Obsługa wielu języków Ograniczone do określonych typów dokumentów Ponad 125 języków
Bezpieczeństwo wątków N/A (wywołania HTTP) Tak (jeden IronTesseract na wątek)
Wdrażanie wielopłatformowe Niezależny od REST Windows, Linux, macOS, Docker, Azure, AWS
Zgodność z HIPAA / ITAR / air-gapped Nie Tak
Model cenowy SaaS za dokument (ceny nieopublikowane) Licencja wieczysta od $999
Koszt za stronę przy dużej skali Tak, bez ograniczeń None

Szybki start: Migracja zKlippa OCRdo IronOCR

Krok 1: Zastąp pakiet NuGet

Klippa nie posiada oficjalnego pakietu NuGet. Usuń zależności klienta HTTP, które istnieją wyłącznie w celu obsługi integracji z Klippą:

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

Zainstaluj IronOCR z NuGet:

dotnet add package IronOcr

Krok 2: Aktualizacja przestrzeni nazw

Należy usunąć przestrzenie nazw HTTP i JSON wymagane przez integrację z Klippą. Dodaj pojedynczą przestrzeń nazw 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;
// 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;
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Text.Json
Imports System.Text.Json.Serialization

Imports IronOcr
$vbLabelText   $csharpLabel

Krok 3: Inicjalizacja licencji

Dodaj inicjalizację licencji raz na początek aplikacji — w Program.cs, Startup.cs lub przed pierwszym wywołaniem OCR:

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

Przykłady migracji kodu

Zastąpienie klasy usługi klienta HTTP

Integracja z Klippą wymaga pełnej klasy usługowej obejmującej infrastrukturę HTTP. Nie da się tego uniknąć, ponieważ nie ma SDK.

Podejście 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();
}
// 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();
}
Imports System
Imports System.IO
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.Text.Json

' Klippa: entire service class just to send one HTTP request
Public Class KlippaOcrService
    Implements IDisposable

    Private ReadOnly _httpClient As HttpClient
    Private ReadOnly _baseUrl As String = "https://custom-ocr.klippa.com/api/v1"

    Public Sub New(apiKey As String)
        _httpClient = New HttpClient()
        _httpClient.DefaultRequestHeaders.Add("X-Auth-Key", apiKey)
        _httpClient.Timeout = TimeSpan.FromSeconds(30) ' network timeout required
    End Sub

    Public Async Function ReadDocumentTextAsync(filePath As String) As Task(Of String)
        Using form As New MultipartFormDataContent()
            Dim fileBytes = Await File.ReadAllBytesAsync(filePath)
            form.Add(New ByteArrayContent(fileBytes), "document", Path.GetFileName(filePath))

            Dim response = Await _httpClient.PostAsync($"{_baseUrl}/parseDocument", form)
            response.EnsureSuccessStatusCode()

            Dim json = Await response.Content.ReadAsStringAsync()
            Using doc = JsonDocument.Parse(json)
                ' navigate Klippa's nested JSON schema
                Return doc.RootElement _
                    .GetProperty("data") _
                    .GetProperty("parsed_document") _
                    .GetProperty("text") _
                    .GetString() OrElse String.Empty
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        _httpClient.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

Podejście 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
// 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
Imports IronOcr

Public Class OcrService
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ReadDocumentText(filePath As String) As String
        Return _ocr.Read(filePath).Text
    End Function
End Class

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

' Usage — identical call site, different internals:
Dim service As New OcrService()
Dim text As String = service.ReadDocumentText("invoice.jpg") ' local, synchronous, zero network
$vbLabelText   $csharpLabel

Klasa usługowa Klippa istnieje wyłącznie dlatego, że API wymaga infrastruktury HTTP. RównoważnośćIronOCR sprowadza się do pojedynczego wywołania Read(). Limity czasu, nagłówki uwierzytelniające i wzorce usuwania znikają, ponieważ nie ma sieci. Opcje inicjalizacji można znaleźć w przewodniku konfiguracji IronTesseract, a działający kod w podstawowym przykładzie OCR.

Eliminacja przesyłania formularzy wieloczęściowych

Klippa otrzymuje dokumenty w formie wieloczęściowych plików przesyłanych za pomocą formularzy. Kod przesyłania jest mechaniczny, ale wrażliwy: odczyt plików, nagłówki typu zawartości, tworzenie granic i zarządzanie rozmiarem przesyłanych plików.

Podejście 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 });
}
// 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 });
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class KlippaUploader
    Private ReadOnly _httpClient As HttpClient

    Public Sub New(httpClient As HttpClient)
        _httpClient = httpClient
    End Sub

    Public Async Function UploadAndParseAsync(filePath As String, Optional documentType As String = "financial") As Task(Of KlippaResult)
        Using form As New MultipartFormDataContent()
            ' read file into memory — entire document in RAM before upload
            Dim fileBytes = Await File.ReadAllBytesAsync(filePath)
            Dim 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
            Dim response = Await _httpClient.PostAsync("https://custom-ocr.klippa.com/api/v1/parseDocument", form)

            If Not response.IsSuccessStatusCode Then
                Dim error = Await response.Content.ReadAsStringAsync()
                Throw New InvalidOperationException($"Klippa API error: {response.StatusCode} — {error}")
            End If

            Dim json = Await response.Content.ReadAsStringAsync()
            Return JsonSerializer.Deserialize(Of KlippaResult)(json, New JsonSerializerOptions With {.PropertyNameCaseInsensitive = True})
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Podejście 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);
// 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);
Imports IronOcr
Imports System.IO

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

' From file path
Using input As New OcrInput()
    input.LoadImage("invoice.jpg")
    Dim result = New IronTesseract().Read(input)

    ' From byte array (same bytes Klippa was uploading)
    Dim fileBytes As Byte() = Await File.ReadAllBytesAsync("invoice.jpg")
    Using inputFromBytes As New OcrInput()
        inputFromBytes.LoadImage(fileBytes)
        Dim resultFromBytes = New IronTesseract().Read(inputFromBytes)

        Console.WriteLine(result.Text)
    End Using
End Using
$vbLabelText   $csharpLabel

Konstrukcja MultipartFormDataContent, nagłówki typu treści oraz sam upload zniknęły.IronOCR czyta bezpośrednio z ścieżki pliku, z tablicy bajtów lub z Stream — te same dane, które Klippa przesyłała do chmury, pozostają lokalne. Przewodnik dotyczący danych wejściowych w postaci obrazów obejmuje wszystkie obsługiwane formaty wejściowe, a przewodnik dotyczący danych wejściowych w postaci strumienia obejmuje ścieżkę strumienia pamięci dla dokumentów, które docierają jako tablice bajtów z procesów nadrzędnych.

Zastąpienie deseryalizacji odpowiedzi JSON

Klippa zwraca zagnieżdżoną strukturę JSON. Nawigacja w tej strukturze wymaga modelu C# odpowiadającego lub inline JsonDocument — oba przerywają się, kiedy Klippa zmienia schemat odpowiedzi.

Podejście 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;
}
// 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;
}
Imports System.Text.Json.Serialization

' Klippa: deserialization model — breaks when API schema changes
Public Class KlippaResponse
    <JsonPropertyName("data")>
    Public Property Data As KlippaData
End Class

Public Class KlippaData
    <JsonPropertyName("parsed_document")>
    Public Property ParsedDocument As KlippaParsedDocument
End Class

Public Class KlippaParsedDocument
    <JsonPropertyName("text")>
    Public Property Text As String

    <JsonPropertyName("amount")>
    Public Property Amount As Decimal?

    <JsonPropertyName("merchant")>
    Public Property Merchant As String

    <JsonPropertyName("date")>
    Public Property Date As String
End Class

' Usage: navigate the nullable chain every time
Public Async Function GetExtractedTextAsync(imagePath As String) As Task(Of String)
    Dim klippaResult = Await UploadAndParseAsync(imagePath)
    ' every property access is nullable — schema drift breaks this silently
    Return If(klippaResult?.Data?.ParsedDocument?.Text, String.Empty)
End Function
$vbLabelText   $csharpLabel

Podejście 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}");
    }
}
// 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}");
    }
}
Imports IronOcr

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

Dim ocr As New IronTesseract()
Dim result = ocr.Read("invoice.jpg")

' Direct property access — no deserialization, no nullable navigation
Dim fullText As String = result.Text
Dim confidence As Double = result.Confidence
Dim pageCount As Integer = result.Pages.Count()

' Structured data: lines and words with coordinates
For Each page In result.Pages
    For Each line In page.Lines
        Console.WriteLine($"Line: '{line.Text}' at Y={line.Y}")
    Next
Next
$vbLabelText   $csharpLabel

OcrResult to typowy obiekt .NET. Nie ma JSON do parsowania, nie ma klasy modelu do utrzymania i nie ma ryzyka, że zmiana schematu zakłóci deseryalizację w środowisku produkcyjnym. Przewodnik odczytywania wyników dokumentuje kompletny model obiektowy OcrResult, w tym współrzędne słów, wyniki pewności i hierarchię strukturalną strony. Dla wzorców ekstrakcji pól specyficznych dla faktur zbudowanych na OcrResult, tutorial OCR faktur obejmuje logikę ekstrakcji od końca do końca.

Usunięcie infrastruktury obsługi błędów i ponownych prób

Integracja Klippa przez HTTP wymaga obsługi błędów dla każdego trybu awarii, jaki może spowodować wywołanie sieciowe: przekroczenie limitu czasu, odpowiedzi 4xx, odpowiedzi 5xx, limity szybkości i częściowy JSON. Zespoły zajmujące się integracjami produkcyjnymi dodają zasady ponownych prób przy użyciu Polly lub logiki niestandardowej. Infrastruktura ta znika wraz z zanikiem połączenia sieciowego.

Podejście 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");
}
// 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");
}
Imports System
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading
Imports System.Threading.Tasks

Public Class KlippaService
    Private ReadOnly _httpClient As HttpClient

    Public Sub New(httpClient As HttpClient)
        _httpClient = httpClient
    End Sub

    ' Klippa: retry policy required — cloud calls fail unpredictably
    Public Async Function ReadWithRetryAsync(filePath As String, Optional maxRetries As Integer = 3) As Task(Of String)
        Dim delay As TimeSpan = TimeSpan.FromSeconds(1)

        For attempt As Integer = 1 To maxRetries
            Try
                Using form As New MultipartFormDataContent()
                    form.Add(New ByteArrayContent(Await File.ReadAllBytesAsync(filePath)), "document", Path.GetFileName(filePath))

                    Using cts As New CancellationTokenSource(TimeSpan.FromSeconds(30))
                        Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://custom-ocr.klippa.com/api/v1/parseDocument", form, cts.Token)

                        If response.StatusCode = System.Net.HttpStatusCode.TooManyRequests Then
                            ' rate limited — back off and retry
                            Await Task.Delay(delay * attempt)
                            Continue For
                        End If

                        response.EnsureSuccessStatusCode()
                        Dim json As String = Await response.Content.ReadAsStringAsync(cts.Token)
                        Dim parsed As KlippaResponse = JsonSerializer.Deserialize(Of KlippaResponse)(json)
                        Return If(parsed?.Data?.ParsedDocument?.Text, String.Empty)
                    End Using
                End Using
            Catch ex As HttpRequestException When attempt < maxRetries
                Await Task.Delay(delay * attempt) ' exponential backoff
            Catch ex As TaskCanceledException When attempt < maxRetries
                Await Task.Delay(delay * attempt) ' timeout — retry
            End Try
        Next

        Throw New InvalidOperationException($"Klippa API failed after {maxRetries} attempts")
    End Function
End Class

Public Class KlippaResponse
    Public Property Data As KlippaData
End Class

Public Class KlippaData
    Public Property ParsedDocument As ParsedDocument
End Class

Public Class ParsedDocument
    Public Property Text As String
End Class
$vbLabelText   $csharpLabel

Podejście 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)
{
    // Nie retry loop. Nie CancellationTokenSource. Nie HTTP status checks.
    // Nie rate limit handling. Nie partial-JSON guards.
    var result = new IronTesseract().Read(filePath);
    return result.Text;
}
// 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)
{
    // Nie retry loop. Nie CancellationTokenSource. Nie HTTP status checks.
    // Nie rate limit handling. Nie partial-JSON guards.
    var result = new IronTesseract().Read(filePath);
    return result.Text;
}
' IronOCR: no network, no retry policy needed — local call either works or throws once
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Public Function ReadDocument(filePath As String) As String
    ' Nie retry loop. Nie CancellationTokenSource. Nie HTTP status checks.
    ' Nie rate limit handling. Nie partial-JSON guards.
    Dim result = New IronTesseract().Read(filePath)
    Return result.Text
End Function
$vbLabelText   $csharpLabel

Cała infrastruktura ponowienia — pętla, obliczenie opóźnienia, CancellationTokenSource, rozgałęzienie kodu statusu HTTP, blok catch TaskCanceledException — istnieją wyłącznie z powodu sieci. Usuń wywołanie sieciowe, a wszystko zniknie. Lokalne wywołanie OCR kończy się szybkim błędem z podanym wyjątkiem, jeśli plik wejściowy jest nieobecny lub nieczytelny, a w przeciwnym razie kończy się powodzeniem. Przewodnik po optymalizacji szybkości obejmuje dostrajanie wydajności IronOCR, jeśli po migracji pojawiają się obawy dotyczące przepustowości.

Przetwarzanie wielostronicowych plików PDF bez przesyłania do chmury

Klippa akceptuje uploady PDF poprzez ten sam punkt końcowy parseDocument. Wielostronicowe pliki PDF nadal opuszczają Twoją sieć.IronOCR odczytuje pliki PDF natywnie, w trakcie przetwarzania, z dostępem do wyników strona po stronie.

Podejście 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;
}
// 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;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class PdfExtractor
    Private ReadOnly _httpClient As HttpClient

    Public Sub New(httpClient As HttpClient)
        _httpClient = httpClient
    End Sub

    ' Klippa: PDF upload — entire document transmitted, results depend on cloud availability
    Public Async Function ExtractPdfPagesAsync(pdfPath As String) As Task(Of List(Of String))
        Dim pages As New List(Of String)()

        ' Klippa parses the entire PDF server-side and returns combined results
        ' You cannot control per-page processing or access raw page text
        Using form As New MultipartFormDataContent()
            form.Add(New ByteArrayContent(Await File.ReadAllBytesAsync(pdfPath)), "document", Path.GetFileName(pdfPath))

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

            Dim json = Await response.Content.ReadAsStringAsync()
            Dim result = JsonSerializer.Deserialize(Of KlippaResponse)(json)
            ' Klippa returns the combined parsed text — no per-page breakdown in basic API
            pages.Add(If(result?.Data?.ParsedDocument?.Text, String.Empty))
        End Using

        Return pages
    End Function
End Class

Public Class KlippaResponse
    Public Property Data As KlippaData
End Class

Public Class KlippaData
    Public Property ParsedDocument As ParsedDocument
End Class

Public Class ParsedDocument
    Public Property Text As String
End Class
$vbLabelText   $csharpLabel

Podejście 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: 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");
Imports IronOcr

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

Using input As New OcrInput()
    input.LoadPdf("multi-page-invoice.pdf") ' reads locally — no HTTP

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

    ' Per-page access — not available from Klippa's combined response
    For Each page In result.Pages
        Console.WriteLine($"Page {page.PageNumber}: {page.Lines.Count()} lines")
        Console.WriteLine(page.Text)
    Next

    ' Or produce a searchable PDF from the scanned original
    result.SaveAsSearchablePdf("searchable-output.pdf")
End Using
$vbLabelText   $csharpLabel

IronOCR odczytuje pliki PDF natywnie, bez konieczności konwersji. Każda strona jest dostępna indywidualnie wraz z pełną hierarchią wierszy, słów i znaków. Wywołanie SaveAsSearchablePdf() produkuje PDF z warstwą tekstową z zeskanowanego dokumentu — funkcjonalność, której Klippa nie oferuje. Podręcznik w formacie PDF dotyczący danych wejściowych obejmuje opcje ładowania, a podręcznik w formacie PDF z funkcją wyszukiwania obejmuje opcje wyjściowe, w tym format PDF/A zapewniający zgodność z wymogąmi archiwizacji.

Klippa OCRAPI do IronOCR– dokumentacja API dla mapowania

Klippa to REST API, a nie typowany zestaw SDK. Poniższe zestawienie przedstawia odpowiedniki funkcji integracyjnych Klippy w IronOCR.

Koncepcja Klippa Odpowiednik IronOCR
HttpClient z nagłówkiem X-Auth-Key Instancja IronTesseract — brak konfiguracji uwierzytelniania
MultipartFormDataContent OcrInput.LoadImage(path) lub OcrInput.LoadPdf(path)
POST /api/v1/parseDocument IronTesseract.Read(input)
await _client.PostAsync(...) ocr.Read(input) — synchroniczne, bez potrzeby await
response.EnsureSuccessStatusCode() Niepotrzebne — brak odpowiedzi HTTP
JsonSerializer.Deserialize<KlippaResponse>(json) Typowany OcrResult — bez deserializacji
KlippaResponse.Data.ParsedDocument.Text OcrResult.Text
KlippaResponse.Data.ParsedDocument.Amount Niestandardowy regex na OcrResult.Text lub OcrResult.Lines
KlippaResponse.Data.ParsedDocument.Merchant OcrResult.Pages[0].Lines[0].Text
Pętla ponowienia z Task.Delay Nie jest wymagane — brak trybu awarii sieci
CancellationTokenSource(TimeSpan.FromSeconds(30)) Nie jest wymagane — lokalne wykonanie
Obsługa limitów szybkości (HTTP 429) Nie jest wymagane — brak limitów stawek
Przekierowywanie dokumentów w chmurze na serwery w UE Lokalne wykonywanie w trakcie procesu
KlippaService.Dispose() / HttpClient.Dispose() Zarządzanie usuwaniem OcrInput poprzez instrukcję using
Strukturalne pola odpowiedzi JSON OcrResult.Text + OcrResult.Pages + OcrResult.Words
Subskrypcja SaaS API Ciąg znaków IronOcr.License.LicenseKey — wieczyste

Typowe problemy związane z migracją i ich rozwiązania

Problem 1: Miejsca wywołań wyłącznie asynchronicznych po usunięciu HTTP

Klippa: Cała integracja z Klippą jest asynchroniczna, ponieważ wymagają tego wywołania HTTP. Kontrolery, serwisy i procesy w tle w całym kodzie wywołują await ProcessDocumentAsync(...). Usunięcie wywołania HTTP oznacza, że await nie jest już potrzebny, ale sygnatury metod async pozostają.

Rozwiązanie:IronOCR dostarcza zarówno synchronizowane, jak i asynchroniczne API. Dla miejsc, które muszą pozostać asynchroniczne (kontrolery ASP.NET Core, serwisy w tle z CancellationToken), użyj 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;
}
// 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;
}
Imports System.Threading
Imports System.Threading.Tasks

Public Class DocumentProcessor
    Public Async Function ProcessDocumentAsync(filePath As String, Optional cancellationToken As CancellationToken = Nothing) As Task(Of String)
        Dim ocr As New IronTesseract()
        Dim result = Await ocr.ReadAsync(filePath)
        Return result.Text
    End Function
End Class
$vbLabelText   $csharpLabel

Przewodnik asynchronicznego OCR obejmuje integrację ReadAsync i CancellationToken dla ASP.NET Core i wzorców serwisów hostowanych.

Problem 2: Rejestracja wstrzykiwania zależności

Klippa: Klasa KlippaService jest rejestrowana w DI jako singleton lub usługą skopowaną i obejmuje HttpClient. Usunięcie tego oznacza aktualizację rejestracji DI i wszystkich punktów wstrzykiwania.

Rozwiązanie: Zarejestruj IronTesseract jako singleton (jest bezpieczny dla wielu wątków) i wstrzyknij go bezpośrednio, lub stwórz cienki wrapper, który odzwierciedla istniejący interfejs serwisów:

// 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;
}
// 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;
}
Imports Microsoft.Extensions.DependencyInjection

' In Program.vb or Startup.vb
builder.Services.AddSingleton(Of IronTesseract)()

' Or wrap for interface compatibility
builder.Services.AddSingleton(Of IOcrService, IronOcrService)()

Public Class IronOcrService
    Implements IOcrService

    Private ReadOnly _ocr As IronTesseract

    Public Sub New(ocr As IronTesseract)
        _ocr = ocr
    End Sub

    Public Function ReadDocument(path As String) As String Implements IOcrService.ReadDocument
        Return _ocr.Read(path).Text
    End Function
End Class
$vbLabelText   $csharpLabel

Jedna instancja IronTesseract zarejestrowana jako singleton obsługuje równoczesne żądania. Każde wywołanie Read() jest bezpieczne dla wątków.

Problem 3: Pobieranie ustrukturyzowanych pól bez wstępnego parsowania JSON

Klippa: Klippa zwraca amount, merchant, date i vat_amount jako typowane właściwości JSON. Przejście na IronOCR oznacza, że pola te nie są już dostarczane w postaci wstępnie przetworzonej.

Rozwiązanie: OcrResultIronOCR dostarcza surowego tekstu i współrzędnych na poziomie słowa do zbudowania równoważnej ekstrakcji. W przypadku dokumentów o przewidywalnym układzie, OCR oparty na regionach kieruje się bezpośrednio do określonych pól:

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();
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();
Imports IronOcr

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

' Target specific layout regions instead of relying on pre-parsed cloud fields
Dim totalRegion As New CropRectangle(350, 580, 250, 50) ' bottom-right total area
Dim merchantRegion As New CropRectangle(50, 30, 400, 60) ' top header area

Using merchantInput As New OcrInput()
    merchantInput.LoadImage("receipt.jpg", merchantRegion)
    Dim merchantName As String = New IronTesseract().Read(merchantInput).Text.Trim()
End Using

Using totalInput As New OcrInput()
    totalInput.LoadImage("receipt.jpg", totalRegion)
    Dim totalText As String = New IronTesseract().Read(totalInput).Text.Trim()
End Using
$vbLabelText   $csharpLabel

Przewodnik optymalizacji regionu OCR szczegółowo opisuje użycie CropRectangle. Aby uzyskać pełne wzorce wyodrębniania danych z różnych układów paragonów i faktur, samouczek dotyczący skanowania paragonów zawiera kompletny, działający kod.

Problem 4: Dokumenty przychodzące jako strumienie z usług nadrzędnych

Klippa: Klippa odbiera dokumenty w postaci wieloczęściowych przesyłanych formularzy — bajtów plików zawartych w treści formularza HTTP. Jeśli Twoja aplikacja odbiera dokumenty jako strumienie z S3, Azure Blob Storage lub wewnętrznych interfejsów API, odczytywałeś strumień do bajtów, a następnie przesyłałeś te bajty do Klippa.

Rozwiązanie:IronOCR akceptuje obiekty Stream bezpośrednio. Krok konwersji bajtów znika:

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;
}
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;
}
Imports System.IO
Imports System.Threading.Tasks
Imports IronOcr

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

Public Async Function ProcessDocumentStreamAsync(documentStream As Stream) As Task(Of String)
    Using input As New OcrInput()
        input.LoadImage(documentStream) ' accepts Stream directly

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

Brak ReadAllBytes, brak konstrukcji MultipartFormDataContent, brak HTTP POST. Strumień wchodzi bezpośrednio do OcrInput. Przewodnik po danych wejściowych strumieniowych obejmuje typy strumieni i wzorce usuwania.

Problem 5: Testy integracyjne zależne od symulacji HTTP

Klippa: Testy integracji kodu Klippa symulują HttpClient lub używają interfejsów HTTP (np. WireMock, MockHttp) do symulacji odpowiedzi API. Testy te symulują warstwę HTTP, a nie logikę OCR.

Rozwiązanie: Testy IronOCR wykorzystują prawdziwe dokumenty o znanym oczekiwanym wyniku. Nie jest wymagana infrastruktura testowa. Testy przeprowadzane w trybie offline:

[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);
}
[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);
}
<Fact>
Public Sub ReadDocument_ReturnsExpectedText()
    IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
    Dim ocr = New IronTesseract()

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

    Assert.Contains("Invoice", result.Text, StringComparison.OrdinalIgnoreCase)
    Assert.True(result.Confidence > 70)
End Sub
$vbLabelText   $csharpLabel

Testy, które wcześniej wymagały aktywnego połączenia z Klippą lub skomplikowanej konfiguracji mocków HTTP, teraz działają w CI bez dostępu do sieci.

Problem 6: Dokumenty niskiej jakości, które Klippa ulepszyła po stronie serwera

Klippa: Przetwarzanie w chmurze stosuje poprawę jakości obrazu przed rozpoznaniem. Programiści nigdy tego nie konfigurują — dzieje się to automatycznie na serwerach Klippa. Podczas migracji dokumenty, które Klippa przetwarzała w tle, mogą charakteryzować się niższą dokładnością bez wyraźnego przetwarzania wstępnego w IronOCR.

Rozwiązanie: Należy wyraźnie zastosować filtry przetwarzania wstępnego IronOCR. Zestaw filtrów odzwierciedla to, co usługi w chmurze stosują po stronie serwera:

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}%");
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}%");
Imports IronOcr

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

Using input As 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

    Dim result = New IronTesseract().Read(input)
    Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
$vbLabelText   $csharpLabel

Przewodnik po korekcji jakości obrazu obejmuje wszystkie filtry przetwarzania wstępnego oraz kolejność ich stosowania w przypadku różnych rodzajów uszkodzeń dokumentów.

Lista kontrolna migracji Klippa OCR

Przed migracją

Przed usunięciem czegokolwiek sprawdź swój kod źródłowy, aby zlokalizować cały kod specyficzny dla 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" .
# 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

Uwagi dotyczące zasobów:

  • Zarejestruj każdą klasę, która opakowuje HttpClient dla wywołań Klippa
  • Wylistuj wszystkie modelowe klasy deserializacji JSON (KlippaResponse, KlippaParsedDocument, itd.)
  • Udokumentuj wszystkie mapowania pól, które wykorzystują wstępnie przeanalizowane właściwości JSON Klippy
  • Zwróć uwagę na wszelkie zasady ponownych prób Polly lub niestandardowe pętle ponownych prób stworzone dla Klippa

Migracja kodu

  1. Zainstaluj pakiet NuGet IronOcr (dotnet add package IronOcr)
  2. Dodaj IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" na początek aplikacji
  3. Usuń importy System.Net.Http, System.Text.Json, Newtonsoft.Json z plików serwisowych Klippa
  4. Usuń klasę KlippaService (lub zastąp jej ciało wywołaniami IronTesseract, zachowując interfejs)
  5. Zarejestruj IronTesseract jako singleton w pojemniku DI
  6. Zastąp bloki uploadu MultipartFormDataContent z OcrInput.LoadImage() lub OcrInput.LoadPdf()
  7. Usuń klasy modelowe odpowiedzi JSON (KlippaResponse, KlippaData, KlippaParsedDocument)
  8. Zastąp łańcuchy nawigacyjne nullable JSON (.Data?.ParsedDocument?.Text) z result.Text
  9. Usuń pętle ponowienia i limity czasowe CancellationTokenSource z miejsc wywołań Klippa
  10. Usunąć obsługę limitów szybkości (bloki przechwytujące HTTP 429)
  11. Zastąp await ProcessDocumentAsync(...) przez await ocr.ReadAsync(...) lub synchroniczne ocr.Read(...)
  12. Dodaj filtry preprocesowania OcrInput (Deskew, DeNoise, Contrast) dla wpisów o niskiej jakości dokumentach
  13. Zastąp infrastrukturę testów mock HTTP prawdziwymi testami z wykorzystaniem dokumentów
  14. Usuń zasady ponownych prób Polly lub niestandardowe oprogramowanie pośredniczące do ponownych prób w zakresie wywołań Klippa

Po migracji

  • Sprawdź, czy wynik wyodrębnienia tekstu odpowiada oczekiwanej treści znanych dokumentów testowych
  • Sprawdź, czy wyniki pewności przekraczają dopuszczalny próg (zazwyczaj 70%+) dla typów dokumentów produkcyjnych
  • Testuj wejście PDF: załaduj wielostronicowe PDF-y natywnie i zweryfikuj dostęp do tekstu na stronę poprzez result.Pages
  • Testuj wejście strumienia: przekaż MemoryStream i zweryfikuj, że OcrInput.LoadImage(stream) produkuje poprawny wynik
  • Filtry przetwarzania wstępnego zwiększają dokładność skanów o niskiej jakości w porównaniu z nieprzetworzonymi skanami bazowymi
  • Potwierdź, że wstrzyknięty przez DI singleton IronTesseract obsługuje równoczesne żądania bez sporów
  • Uruchom testy integracyjne w trybie offline (bez połączenia z siecią) — wszystkie testy powinny zakończyć się powodzeniem bez dostępu do chmury
  • Zweryfikuj wyjście wyszukiwanego PDF z result.SaveAsSearchablePdf("output.pdf") dla przepływów dokumentów zeskanowanych
  • Testuj ReadAsync w kontekście kontrolera ASP.NET Core z propagacją CancellationToken
  • Potwierdź, że wzorzec usuwania using var input = new OcrInput() nie wycieka pamięci przy ciągłym obciążeniu

Kluczowe korzyści z migracji do IronOCR

Suwerenność danych od pierwszego dnia. Po migracji poufne dokumenty finansowe, skany dokumentów tożsamości i poufne faktury nigdy nie opuszczają Twojej infrastruktury. W zakresie audytu nie ma podmiotów przetwarzających dane, nie ma polityki przechowywania danych do przeglądu ani umowy o przekazywaniu danych do utrzymania. Ograniczenia HIPAA, ITAR, CMMC i FedRAMP, które wcześniej sprawiały, że korzystanie z Klippy było problematyczne, są domyślnie spełnione. Wdrożenie na Dockerze, AWS lub Azure pozwala utrzymać wszystko w granicach własnej infrastruktury.

Eliminacja złożoności infrastruktury. Klasa usługowa, klient HTTP, kod przesyłania formularzy, modele JSON, zasady ponawiania prób, konfiguracja limitów czasu — wszystko to istniało po to, aby opakować wywołanie sieciowe. Usuń wywołanie sieciowe, a wszystko inne pójdzie za nim. Powstały kod jest mniejszy, łatwiejszy do odczytania i ma mniej trybów awarii. Jedna instancja IronTesseract wstrzyknięta przez DI zastępuje całą warstwę integracji HTTP.

Przewidywalny koszt bez względu na ilość. Wieczysta licencja IronOCR w $999 (Lite), $1 499 (Professional) lub $2 999 (Enterprise) obejmuje nieograniczone przetwarzanie dokumentów. Przetwarzanie 500 dokumentów miesięcznie lub 500 000 dokumentów miesięcznie kosztuje tyle samo. Brakuje struktury rozliczeń za dokument, która sprawiała, że Klippa była droga przy większej skali. Strona licencyjna IronOCR zawiera szczegółowe informacje na temat wszystkich poziomów i tego, co każdy z nich obejmuje.

Nieograniczony zakres dokumentów.IronOCR przetwarza każdy dokument zawierający tekst. Skanowane umowy, rysunki techniczne, formularze medyczne, zlecenia zakupu, odręczne notatki, zrzuty ekranu, archiwa TIFF — wszystko obsługiwane przez to samo wywołanie Read() z tym samym API. Zniknęło ograniczenie zakresu specjalistycznego, które wymagało drugiego systemu dla dokumentów spoza kategorii, na których przeszkolono Klippę. Jedna biblioteka, jeden punkt integracji, dowolny typ dokumentu.

Obsługa środowisk offline i sieci o ograniczonym dostępie. Aplikacje wdrożone w sieciach bankowych, systemach rządowych, środowiskach brzegowych lub dowolnej infrastrukturze z ograniczonym dostępem do sieci zewnętrznej działają dokładnie tak samo, jak w środowiskach otwartych. Nie ma sprawdzania łączności, nie ma pingowania stanu punktu końcowego w chmurze ani trybu awaryjnego, gdy internet jest niedostępny. Wdrożenia typu air-gapped działają bez modyfikacji. Przewodnik wdrożeniowy dla systemu Linux oraz przewodnik wdrożeniowy dla Docker opisują ścieżki wdrożenia w środowiskach kontenerowych i po stronie serwera.

Pełna kontrola nad poprawianiem obrazów. Przetwarzanie wstępne w chmurze było czarną skrzynką — Klippa je stosowała, Ty obserwowałeś wyniki, nie miałeś żadnych parametrów do dostosowania. Pipeline przetwarzania wstępnego IronOCR jest jawny i kompozycyjny: Deskew(), DeNoise(), Contrast(), Binarize(), Sharpen(), Scale(), Dilate(), DeepCleanBackgroundNoise(). Każdy filtr jest opcjonalny i ma określoną kolejność. Poprawa dokładności jest mierzalna, powtarzalna i pozostaje pod Państwa kontrolą. Przewodnik po korekcji jakości obrazu oraz strona poświęcona funkcjom przetwarzania wstępnego obejmują pełny katalog filtrów wraz z wskazówkami dotyczącymi tego, kiedy należy stosować poszczególne z nich.

Zwróć uwagęKlippa i Tesseract są zarejestrowanymi znakami towarowymi swoich odpowiednich właścicieli. Ta strona nie jest powiązana z, wspierana ani sponsorowana przez Google czy Klippa. Wszystkie nazwy produktów, logo i marki są własnością ich odpowiednich właścicieli. Porównania mają charakter wyłącznie informacyjny i odzwierciedlają informacje dostępne publicznie w momencie pisania.

Często Zadawane Pytania

Dlaczego warto przejść z Klippa OCR API na IronOCR?

Typowe czynniki motywujące to eliminacja złożoności interoperacyjności COM, zastąpienie zarządzania licencjami opartego na plikach, uniknięcie rozliczeń za stronę, umożliwienie wdrażania w Dockerze/kontenerach oraz przyjęcie natywnego dla NuGet przepływu pracy, który integruje się ze standardowymi narzędziami .NET.

Jakie są główne zmiany w kodzie podczas migracji z Klippa OCR API do IronOCR?

Zastąp sekwencje inicjalizacji Klippa instancjonowaniem IronTesseract, usuń zarządzanie cyklem życia COM (jawne wzorce Create/Load/Close) i zaktualizuj nazwy właściwości wyników. W rezultacie znacznie zmniejsza się liczba powtarzających się linii kodu.

Jak zainstalować IronOCR, aby rozpocząć migrację?

Uruchom polecenie „Install-Package IronOcr” w konsoli menedżera pakietów lub „dotnet add package IronOcr” w interfejsie CLI. Pakiety językowe są oddzielnymi pakietami: na przykład „dotnet add package IronOcr.Languages.French” dla języka francuskiego.

Czy IronOCR dorównuje dokładnością OCR interfejsowi API Klippa OCR w przypadku standardowych dokumentów biznesowych?

IronOCR zapewnia wysoką dokładność w przypadku standardowych treści biznesowych, w tym faktur, umów, paragonów i formularzy wypełnionych na komputerze. Filtry przetwarzania wstępnego obrazu (prostowanie, usuwanie szumów, wzmacnianie kontrastu) dodatkowo poprawiają rozpoznawanie w przypadku pogorszonej jakości danych wejściowych.

W jaki sposób IronOCR obsługuje dane językowe, które Klippa OCR API instaluje oddzielnie?

Dane językowe w IronOCR są dystrybuowane jako pakiety NuGet. Polecenie „dotnet add package IronOcr.Languages.German” instaluje obsługę języka niemiećkiego. Nie wymaga to ręcznego umieszczania plików ani podawania ścieżek katalogów.

Czy migracja z Klippa OCR API do IronOCR wymaga zmian w infrastrukturze wdrożeniowej?

IronOCR wymaga mniej zmian w infrastrukturze niż Klippa OCR API. Nie ma ścieżek binarnych SDK, lokalizacji plików licencyjnych ani konfiguracji serwerów licencyjnych. Pakiet NuGet zawiera kompletny silnik OCR, a klucz licencyjny jest ciągiem znaków ustawionym w kodzie aplikacji.

Jak skonfigurować licencjonowanie IronOCR po migracji?

W kodzie uruchamiającym aplikację przypisz IronOcr.License.LicenseKey = „YOUR-KEY”. W Dockerze lub Kubernetesie zapisz klucz jako zmienną środowiskową i odczytaj go podczas uruchamiania. Użyj License.IsValidLicense do sprawdzenia ważności przed przyjęciem ruchu.

Czy IronOCR może przetwarzać pliki PDF w taki sam sposób jak Klippa?

Tak. IronOCR odczytuje zarówno natywne, jak i zeskanowane pliki PDF. Należy utworzyć instancję IronTesseract, wywołać ocr.Read(input), gdzie input jest ścieżką do pliku PDF lub obiektem OcrPdfInput, a następnie iterować strony OcrResult. Nie jest wymagany oddzielny proces renderowania plików PDF.

W jaki sposób IronOCR radzi sobie z wątkami podczas przetwarzania dużych ilości danych?

IronTesseract można bezpiecznie instancjonować dla każdego wątku. Uruchom jedną instancję na wątek w Parallel.ForEach lub puli zadań, uruchom OCR równolegle i usuń każdą instancję po zakończeniu. Nie jest wymagany żaden stan globalny ani blokowanie.

Jakie formaty wyjściowe obsługuje IronOCR po wyodrębnieniu tekstu?

IronOCR zwraca ustrukturyzowane wyniki, w tym tekst, współrzędne słów, wyniki pewności i strukturę strony. Opcje eksportu obejmują zwykły tekst, PDF z możliwością wyszukiwania oraz obiekty wyników ustrukturyzowanych do dalszego przetwarzania.

Czy ceny IronOCR są bardziej przewidywalne niż ceny Klippa OCR API w przypadku skalowania obciążeń?

IronOCR stosuje licencję wieczystą z opłatą ryczałtową, bez opłat za stronę lub wolumen. Niezależnie od tego, czy przetwarzasz 10 000, czy 10 milionów stron, koszt licencji pozostaje stały. Opcje licencji wolumenowych i zespołowych znajdują się na stronie z cennikiem IronOCR.

Co stanie się z moimi istniejącymi testami po migracji z Klippa OCR API do IronOCR?

Testy sprawdzające wyodrębnioną treść tekstową powinny nadal przechodzić pomyślnie po migracji. Testy weryfikujące wzorce wywołań API lub cykl życia obiektów COM będą wymagały aktualizacji, aby odzwierciedlały prostszy model inicjalizacji i wyników IronOCR.

Kannaopat Udonpant
Inżynier oprogramowania
Zanim stał się inżynierem oprogramowania, Kannapat ukończył doktorat z zasobów środowiskowych na Uniwersytecie Hokkaido w Japonii. W czasie studiowania, Kannapat również został członkiem Laboratorium Robotyki Pojazdów, które jest częścią Wydziału Inżynierii Bioprodukcji. W 2022 roku wykorzystał swoje umiejętności w ...
Czytaj więcej

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie