Wie man in C# Bildfarben zum Lesen korrigiert
Dieser Leitfaden führt .NET -Entwickler durch die Umstellung von OCR.space's REST-API-Integration auf IronOCR , eine native .NET -Bibliothek, die als einzelnes NuGet Paket bereitgestellt wird. Es umfasst den Pakettausch, die Namensraumbereinigung und vier konkrete Code-Migrationsszenarien, die spezifisch für den Übergang von REST zu lokal sind: Eliminierung von Multipart-Uploads, Entfernung der Base64-Codierung, Austausch der OCR-Engine-Auswahl und Extraktion strukturierter Daten. Entwickler, die den Vergleichsartikel zu Phase 1 gelesen haben, werden feststellen, dass sich dieser Leitfaden auf die mechanischen Schritte der Migration selbst konzentriert und nicht auf den Funktionsvergleich.
Warum von OCR.space migrieren?
OCR.space füllt eine echte Marktlücke: Entwickler können kostenlos experimentieren und OCR an einem Nachmittag testen, ohne etwas installieren zu müssen. Das Problem ist, dass die kostenlose Version für Prototyping und nicht für die Produktion konzipiert ist. Sobald eine .NET Anwendung in Richtung realer Dokumentenmengen, Compliance-Anforderungen oder Teamentwicklung geht, wirkt sich jede Eigenschaft der OCR.space-Integration negativ auf die Anwendung aus.
Ohne NuGet Paket gibt es kein SDK und keine IntelliSense-Funktion. OCR.space bietet einen REST-Endpunkt und eine Dokumentation. Die .NET Integration – HTTP-Client-Erstellung, Anfrage-Serialisierung, Antwort-Deserialisierung, Fehlerbehandlung und Wiederholungslogik – liegt vollständig in der Verantwortung des Entwicklers. Das ist keine geringfügige Unannehmlichkeit. Der minimal funktionsfähige Client besteht aus mehr als 80 Zeilen Infrastrukturcode, bevor die erste Methode der Geschäftslogik geschrieben wird. Dieser Code ist in jeder OCR.space-Integration in jeder .NET Codebasis identisch und führt im Laufe der Zeit zu einer Anhäufung von Fehlern und einem erhöhten Wartungsaufwand.
Ratenbegrenzungen setzen Produktionsanwendungen künstliche Obergrenzen. Im kostenlosen Tarif sind 60 Anfragen pro Minute und 500 Anfragen pro Tag und IP-Adresse beschränkt. Beide Grenzen sind harte Wände. Eine Anwendung, die zwischen Mitternacht und der nächsten Mitternacht mehr als 500 Anfragen sendet, erhält Fehlermeldungen, bis der Zähler zurückgesetzt wird. Produktionssysteme, die in gemeinsam genutzten Büronetzwerken oder gemeinsam genutzten CI/CD-Umgebungen laufen, können ihr Tageskontingent bereits vor Geschäftsschluss aufbrauchen.
Bei jedem Anruf verlassen Dokumente Ihre Infrastruktur. OCR.space bietet keine Option für die lokale Bereitstellung. Bei jeder Anfrage wird das Dokument – Rechnungen, Krankenakten, Verträge, Ausweisdokumente – an die Cloud-Server von OCR.space übermittelt. HIPAA, DSGVO und interne Datenklassifizierungsrichtlinien, die die Übermittlung sensibler Dokumente an Dritte verbieten, machen OCR.space architektonisch inkompatibel, ungeachtet vertraglicher Kontrollen.
Die kostenlose Version erzeugt durchsuchbare PDFs mit Wasserzeichen. Anwendungen, die durchsuchbare PDFs als Ergebnis liefern – Dokumentenarchivierungssysteme, Compliance-Plattformen, kundenorientierte Dokumentenportale – können die kostenlose Version von OCR.space für diesen Zweck nicht nutzen. Das Wasserzeichen ist in die Ausgabedatei (PDF) eingebettet und kann ohne kostenpflichtiges Abonnement nicht entfernt werden.
Die Preise für Abonnements steigen mit dem Volumen; Der OCR.space PRO-Tarif von 144 $ pro Jahr überschreitet den unbefristeten Einstiegspreis von IronOCRs $999 vor Jahr sechs. Teams, die ein Dokumentvolumenwachstum über die Freigrenze hinaus erwarten, sehen sich mit anwachsenden Abonnementkosten im Vergleich zu einer festen unbefristeten Lizenz konfrontiert. Die $999 Lite-Lizenz deckt einen Entwickler und einen Einsatzort ab, ohne pro Anfrage Gebühren bei beliebigem Volumen zu erheben. Auf der IronOCR -Lizenzseite finden Sie Details zu den Lizenzstufen.
Das grundsätzliche Problem
OCR.space erfordert, dass Sie einen vollständigen HTTP-Client erstellen, bevor Sie ein einzelnes Dokument verarbeiten können:
// OCR.space: 80+ lines of infrastructure before business logic
public class OcrSpaceApiClient : IDisposable
{
private readonly HttpClient _httpClient;
private readonly string _apiKey;
private readonly SemaphoreSlim _rateLimiter; // You implement this
public OcrSpaceApiClient(string apiKey)
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(120);
_rateLimiter = new SemaphoreSlim(60, 60); // Free tier: 60/min
}
// ... 70+ more lines of HTTP plumbing follow
}
// OCR.space: 80+ lines of infrastructure before business logic
public class OcrSpaceApiClient : IDisposable
{
private readonly HttpClient _httpClient;
private readonly string _apiKey;
private readonly SemaphoreSlim _rateLimiter; // You implement this
public OcrSpaceApiClient(string apiKey)
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(120);
_rateLimiter = new SemaphoreSlim(60, 60); // Free tier: 60/min
}
// ... 70+ more lines of HTTP plumbing follow
}
Imports System
Imports System.Net.Http
Imports System.Threading
' OCR.space: 80+ lines of infrastructure before business logic
Public Class OcrSpaceApiClient
Implements IDisposable
Private ReadOnly _httpClient As HttpClient
Private ReadOnly _apiKey As String
Private ReadOnly _rateLimiter As SemaphoreSlim ' You implement this
Public Sub New(apiKey As String)
_httpClient = New HttpClient()
_httpClient.Timeout = TimeSpan.FromSeconds(120)
_rateLimiter = New SemaphoreSlim(60, 60) ' Free tier: 60/min
End Sub
' ... 70+ more lines of HTTP plumbing follow
Public Sub Dispose() Implements IDisposable.Dispose
_httpClient.Dispose()
_rateLimiter.Dispose()
End Sub
End Class
IronOCR ist ein NuGet Paket. Der gesamte Client ist bereits geschrieben:
// IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
// IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
Imports IronOcr
' IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("document.jpg")
Console.WriteLine(result.Text)
IronOCR vs. OCR.space: Funktionsvergleich
Die folgende Tabelle ordnet die Konzepte und Einschränkungen von OCR.space direkt den entsprechenden IronOCR Elementen zu.
| Feature | OCR.space | IronOCR |
|---|---|---|
| NuGet -Paket | Keine – nur REST-API | IronOcr — native .NET |
| SDK / IntelliSense | Keine — manuelles JSON | Vollständige typisierte API |
| Kundenspezifische Modelle erforderlich | Nein | Nein |
| Verarbeitungsort | OCR.space Cloud-Server | Lokal — in Bearbeitung |
| Internetabhängigkeit | Für jeden Aufruf erforderlich | None |
| Air-Gap-Bereitstellung | Nicht unterstützt | Vollständig unterstützt |
| Ratenbegrenzungen | 60/Minute, 500/Tag (kostenlos) | None |
| Dateigrößenbeschränkung | 5 MB (kostenlose Version) | Nur verfügbarer Speicher |
| PDF-Eingabe | Ja (begrenzt, 5 MB) | Ja – nativ, keine Größenbeschränkung |
| Durchsuchbare PDF-Ausgabe | Im kostenlosen Tarif mit Wasserzeichen versehen | Saubere Ausgabe, alle Stufen |
| Automatische Vorverarbeitung | Serverseitig, keine Entwicklerkontrolle | Entzerren, Rauschen entfernen, Kontrast erhöhen, Binärisierung, Schärfen |
| Sprachunterstützung | ~25 Sprachen | Über 125 Sprachpakete via NuGet |
| Mehrsprachigkeit pro Dokument | Nicht unterstützt | Ja — OcrLanguage.French + OcrLanguage.German |
| Strukturierte Ausgabe (Wörter, Zeilen) | Nur reiner Text | Seiten, Absätze, Zeilen, Wörter mit Koordinaten |
| Konfidenzwerte auf Wortebene | Nicht verfügbar | Ja — word.Confidence |
| Regionsbasierte OCR | Nicht unterstützt | Ja — CropRectangle |
| Barcode-Lesung | Nicht unterstützt | Ja — ReadBarCodes = true |
| durchsuchbare PDF-Generierung | Mit Wasserzeichen (kostenlos), ohne Wasserzeichen (kostenpflichtig) | Saubere Ausgabe – alle Lizenzstufen |
| HIPAA-/DSGVO-Kompatibilität | Risiko – extern übermittelte Daten | Ja – keine externe Datenübertragung |
| Preismodell | Monatliches Abonnement | Einmalig, ewig |
| Eintrittspreis | 12 US-Dollar/Monat (144 US-Dollar/Jahr) | $999 einmalig |
| .NET -Kompatibilität | HttpClient — jeder .NET |
.NET 4.6.2+, .NET 5/6/7/8/9 |
| Plattformübergreifende Bereitstellung | Erfordert ausgehende Internetverbindung | Windows, Linux, macOS, Docker, Azure, AWS |
Schnellstart: Migration von OCR.space zu IronOCR
Schritt 1: Ersetzen des NuGet-Pakets
OCR.space verfügt über kein NuGet Paket, das deinstalliert werden kann. Entfernen Sie allen OCR.space-bezogenen Infrastruktur-Code aus dem Projekt: die HttpClient Wrapper-Klasse, den SemaphoreSlim Geschwindigkeitsbegrenzer, die benutzerdefinierten Ergebnis-Modelle und die benutzerdefinierten Ausnahme-Typen. All dies wird durch IronOCRs NuGet-Paket ersetzt.
Installieren Sie IronOCR von der IronOCR NuGet -Seite :
dotnet add package IronOcr
Schritt 2: Namespaces aktualisieren
Entfernen Sie die HTTP- und JSON-Namespaces von OCR.space. Fügen Sie den IronOCR Namespace hinzu:
// Before (OCR.space — manually written infrastructure)
using System.Net.Http;
using System.Text.Json;
using System.Threading;
// After (IronOCR)
using IronOcr;
// Before (OCR.space — manually written infrastructure)
using System.Net.Http;
using System.Text.Json;
using System.Threading;
// After (IronOCR)
using IronOcr;
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading
Imports IronOcr
Schritt 3: Lizenz initialisieren
Fügen Sie die Lizenzinitialisierung einmalig beim Anwendungsstart hinzu – nicht pro Anfrage:
// Program.cs or application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Program.cs or application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronOcr
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Beispiele für die Code-Migration
Ersetzen von MultipartFormDataContent-Datei-Uploads
OCR.space erfordert den Aufbau von MultipartFormDataContent mit den Datei-Bytes und dem API-Schlüssel, um dann an den Cloud-Endpunkt zu POST-en. Das Dokument hinterlässt bei jedem Anruf Spuren in Ihrer Infrastruktur.
OCR.space-Ansatz:
// MultipartFormDataContent: file upload to cloud on every request
public async Task<string> UploadAndExtract(string imagePath)
{
using var content = new MultipartFormDataContent();
var imageBytes = File.ReadAllBytes(imagePath);
// Document is transmitted to OCR.space servers here
content.Add(new ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath));
content.Add(new StringContent(_apiKey), "apikey");
content.Add(new StringContent("eng"), "language");
content.Add(new StringContent("2"), "OCREngine"); // Select Engine 2
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
// Navigate JSON tree manually — no typed result
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
// MultipartFormDataContent: file upload to cloud on every request
public async Task<string> UploadAndExtract(string imagePath)
{
using var content = new MultipartFormDataContent();
var imageBytes = File.ReadAllBytes(imagePath);
// Document is transmitted to OCR.space servers here
content.Add(new ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath));
content.Add(new StringContent(_apiKey), "apikey");
content.Add(new StringContent("eng"), "language");
content.Add(new StringContent("2"), "OCREngine"); // Select Engine 2
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
// Navigate JSON tree manually — no typed result
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class YourClassName
Private _apiKey As String
Private _httpClient As HttpClient
Public Async Function UploadAndExtract(imagePath As String) As Task(Of String)
Using content As New MultipartFormDataContent()
Dim imageBytes = File.ReadAllBytes(imagePath)
' Document is transmitted to OCR.space servers here
content.Add(New ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath))
content.Add(New StringContent(_apiKey), "apikey")
content.Add(New StringContent("eng"), "language")
content.Add(New StringContent("2"), "OCREngine") ' Select Engine 2
Dim response = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
response.EnsureSuccessStatusCode()
Dim json As String = Await response.Content.ReadAsStringAsync()
Using doc = JsonDocument.Parse(json)
' Navigate JSON tree manually — no typed result
Return doc.RootElement _
.GetProperty("ParsedResults")(0) _
.GetProperty("ParsedText") _
.GetString() OrElse String.Empty
End Using
End Using
End Function
End Class
IronOCR Ansatz:
// OcrInput replaces the entire upload + JSON pipeline
public string ExtractFromFile(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath); // Stays local — no network call
var ocr = new IronTesseract();
var result = ocr.Read(input);
return result.Text; // Typed property — no JSON navigation
}
// OcrInput replaces the entire upload + JSON pipeline
public string ExtractFromFile(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath); // Stays local — no network call
var ocr = new IronTesseract();
var result = ocr.Read(input);
return result.Text; // Typed property — no JSON navigation
}
Imports IronTesseract
Public Function ExtractFromFile(ByVal imagePath As String) As String
Using input As New OcrInput()
input.LoadImage(imagePath) ' Stays local — no network call
Dim ocr As New IronTesseract()
Dim result = ocr.Read(input)
Return result.Text ' Typed property — no JSON navigation
End Using
End Function
OcrInput ist die lokale Ersetzung für MultipartFormDataContent. Es akzeptiert Dateipfade, Byte-Arrays, Datenströme und mehrseitige TIFFs über eine einheitliche API. Das Einspritzen von HttpClient, der API-Schlüssel und die JSON-Navigation verschwinden vollständig. Die Anleitung zur Bildeingabe behandelt alle unterstützten Eingabeformate.
Eliminierung der Base64-Kodierung
Wenn OCR.space-Integrationen den base64Image Formular-Parameter anstelle des Datei-Upload-Parameters verwenden, liest der Code die Datei zu Bytes, kodiert sie in Base64, konstruiert einen Daten-URI-String und bettet sie in FormUrlEncodedContent ein.IronOCR akzeptiert Rohbytes direkt ohne Kodierungsschritt.
OCR.space-Ansatz:
// base64Image parameter: read → encode → embed in form → POST → parse
public async Task<string> ExtractViaBase64(string imagePath)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64Image = Convert.ToBase64String(imageBytes); // Mandatory encoding step
// Embed as data URI — adds 33% overhead to payload size
string mimeType = "image/png";
string dataUri = $"data:{mimeType};base64,{base64Image}";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", dataUri),
new KeyValuePair<string, string>("language", "eng"),
new KeyValuePair<string, string>("isOverlayRequired", "false")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
// base64Image parameter: read → encode → embed in form → POST → parse
public async Task<string> ExtractViaBase64(string imagePath)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64Image = Convert.ToBase64String(imageBytes); // Mandatory encoding step
// Embed as data URI — adds 33% overhead to payload size
string mimeType = "image/png";
string dataUri = $"data:{mimeType};base64,{base64Image}";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", dataUri),
new KeyValuePair<string, string>("language", "eng"),
new KeyValuePair<string, string>("isOverlayRequired", "false")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class ImageProcessor
Private _apiKey As String
Private _httpClient As HttpClient
Public Sub New(apiKey As String, httpClient As HttpClient)
_apiKey = apiKey
_httpClient = httpClient
End Sub
' base64Image parameter: read → encode → embed in form → POST → parse
Public Async Function ExtractViaBase64(imagePath As String) As Task(Of String)
Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
Dim base64Image As String = Convert.ToBase64String(imageBytes) ' Mandatory encoding step
' Embed as data URI — adds 33% overhead to payload size
Dim mimeType As String = "image/png"
Dim dataUri As String = $"data:{mimeType};base64,{base64Image}"
Dim formContent As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
New KeyValuePair(Of String, String)("apikey", _apiKey),
New KeyValuePair(Of String, String)("base64Image", dataUri),
New KeyValuePair(Of String, String)("language", "eng"),
New KeyValuePair(Of String, String)("isOverlayRequired", "false")
})
Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent)
Dim json As String = Await response.Content.ReadAsStringAsync()
Using doc As JsonDocument = JsonDocument.Parse(json)
Return doc.RootElement _
.GetProperty("ParsedResults")(0) _
.GetProperty("ParsedText") _
.GetString() OrElse String.Empty
End Using
End Function
End Class
IronOCR Ansatz:
// LoadImage(bytes): raw bytes accepted directly — no encoding
public string ExtractFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); //NeinBase64, no data URI, no overhead
var result = new IronTesseract().Read(input);
return result.Text;
}
// LoadImage(bytes): raw bytes accepted directly — no encoding
public string ExtractFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); //NeinBase64, no data URI, no overhead
var result = new IronTesseract().Read(input);
return result.Text;
}
Imports IronOcr
Public Function ExtractFromBytes(imageBytes As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageBytes) 'NeinBase64, no data URI, no overhead
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
End Function
Der Base64-Codierungsschritt existiert in IronOCR nicht, da es keine HTTP-Transportschicht gibt. Rohe Bytes gehen direkt in OcrInput.LoadImage(). Der Overhead der Daten-URI – die Base64-Codierung vergrößert die Nutzdatengröße um etwa 33 % – entfällt ebenfalls. Der Eingabestrom-Leitfaden zeigt dasselbe Muster für Stream Eingaben, welches nützlich ist, wenn die Bytes von einem Upload-Handler oder einem Speicherpuffer anstelle einer Datei stammen.
Ersetzen der OCR-Engine-Auswahl durch Bildvorverarbeitung
OCR.space stellt über den OCREngine Formular-Parameter zwei OCR-Engines bereit: Engine 1 ist schneller, aber mit geringerer Genauigkeit bei komplexen Layouts; Engine 2 ist langsamer, bietet aber bei den meisten Dokumenttypen eine höhere Genauigkeit. Entwickler wählen die Engine pro Aufruf anhand der Dokumenteigenschaften aus.IronOCR verwendet eine einzige optimierte Tesseract 5-Engine, bietet aber explizite Vorverarbeitungsfilter, die die eigentliche Ursache – die Dokumentqualität – angehen, anstatt zwischen verschiedenen Engine-Modi zu wechseln.
OCR.space-Ansatz:
// OCREngine parameter: binary choice, no control over why accuracy differs
public async Task<string> ExtractWithEngineSelection(
string imagePath,
bool useHighAccuracyEngine = true)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64 = Convert.ToBase64String(imageBytes);
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
new KeyValuePair<string, string>("language", "eng"),
// Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
new KeyValuePair<string, string>("OCREngine", useHighAccuracyEngine ? "2" : "1"),
new KeyValuePair<string, string>("scale", "true"),
new KeyValuePair<string, string>("detectOrientation", "true")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
// OCREngine parameter: binary choice, no control over why accuracy differs
public async Task<string> ExtractWithEngineSelection(
string imagePath,
bool useHighAccuracyEngine = true)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64 = Convert.ToBase64String(imageBytes);
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
new KeyValuePair<string, string>("language", "eng"),
// Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
new KeyValuePair<string, string>("OCREngine", useHighAccuracyEngine ? "2" : "1"),
new KeyValuePair<string, string>("scale", "true"),
new KeyValuePair<string, string>("detectOrientation", "true")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class OCRService
Private _apiKey As String
Private _httpClient As HttpClient
Public Sub New(apiKey As String, httpClient As HttpClient)
_apiKey = apiKey
_httpClient = httpClient
End Sub
' OCREngine parameter: binary choice, no control over why accuracy differs
Public Async Function ExtractWithEngineSelection(imagePath As String, Optional useHighAccuracyEngine As Boolean = True) As Task(Of String)
Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
Dim base64 As String = Convert.ToBase64String(imageBytes)
Dim formContent As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
New KeyValuePair(Of String, String)("apikey", _apiKey),
New KeyValuePair(Of String, String)("base64Image", $"data:image/png;base64,{base64}"),
New KeyValuePair(Of String, String)("language", "eng"),
' Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
New KeyValuePair(Of String, String)("OCREngine", If(useHighAccuracyEngine, "2", "1")),
New KeyValuePair(Of String, String)("scale", "true"),
New KeyValuePair(Of String, String)("detectOrientation", "true")
})
Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent)
Dim json As String = Await response.Content.ReadAsStringAsync()
Using doc As JsonDocument = JsonDocument.Parse(json)
Return doc.RootElement _
.GetProperty("ParsedResults")(0) _
.GetProperty("ParsedText") _
.GetString() OrElse String.Empty
End Using
End Function
End Class
IronOCR Ansatz:
// Preprocessing pipeline: fix the document, not the engine selection
public string ExtractWithPreprocessing(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath);
// Apply filters that match the document's specific quality issues
input.Deskew(); // Correct rotation — replaces detectOrientation
input.DeNoise(); // Remove noise from fax/photocopier artifacts
input.Contrast(); // Enhance contrast on low-quality scans
input.Scale(200); // Upscale small or low-DPI images
var ocr = new IronTesseract();
var result = ocr.Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%"); //Neinequivalent in OCR.space
return result.Text;
}
// Preprocessing pipeline: fix the document, not the engine selection
public string ExtractWithPreprocessing(string imagePath)
{
using var input = new OcrInput();
input.LoadImage(imagePath);
// Apply filters that match the document's specific quality issues
input.Deskew(); // Correct rotation — replaces detectOrientation
input.DeNoise(); // Remove noise from fax/photocopier artifacts
input.Contrast(); // Enhance contrast on low-quality scans
input.Scale(200); // Upscale small or low-DPI images
var ocr = new IronTesseract();
var result = ocr.Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%"); //Neinequivalent in OCR.space
return result.Text;
}
Imports IronOcr
Public Function ExtractWithPreprocessing(imagePath As String) As String
Using input As New OcrInput()
input.LoadImage(imagePath)
' Apply filters that match the document's specific quality issues
input.Deskew() ' Correct rotation — replaces detectOrientation
input.DeNoise() ' Remove noise from fax/photocopier artifacts
input.Contrast() ' Enhance contrast on low-quality scans
input.Scale(200) ' Upscale small or low-DPI images
Dim ocr As New IronTesseract()
Dim result = ocr.Read(input)
Console.WriteLine($"Confidence: {result.Confidence}%") 'Neinequivalent in OCR.space
Return result.Text
End Using
End Function
Der OCR.space OCREngine Parameter ist ein Proxy für die Dokumentqualität — wenn Engine 1 bei einem Dokument versagt, wechseln Entwickler zu Engine 2 in der Hoffnung, dass der andere Algorithmus das ausgleicht. Die Vorverarbeitungspipeline von IronOCR adressiert das Qualitätsproblem direkt: Deskew() korrigiert verzerrte Scans, DeNoise() behandelt Fax-Artefakte und Contrast() stellt Text aus kontrastarmen Fotokopien wieder her. Die Confidence Eigenschaft des Ergebnisses quantifiziert die Extraktionsqualität, die durch OCREngine Wechsel nicht bereitgestellt werden kann. Der Leitfaden zur Bildqualitätskorrektur und der Filter-Assistent dokumentieren die Wirkung jedes Filters auf verschiedene Dokumenttypen.
Mehrsprachige OCR ohne Sprachumschaltung pro Anruf
OCR.space akzeptiert einen language Parameter pro API-Aufruf. Bei Dokumenten, die mehrere Sprachen enthalten, sind für jede Sprache separate Aufrufe erforderlich, deren Ergebnisse manuell zusammengeführt werden.IronOCR verarbeitet mehrere Sprachen gleichzeitig in einem einzigen Lesevorgang, indem der + Operator auf OcrLanguage Werte angewendet wird.
OCR.space-Ansatz:
// OCR.space: one language per call — multi-language requires multiple requests
public async Task<string> ExtractMultiLanguage(string imagePath)
{
// First pass: English
string englishText = await ExtractWithLanguage(imagePath, "eng");
// Second pass: French (consumes another rate-limit slot, another API call)
string frenchText = await ExtractWithLanguage(imagePath, "fre");
// Manually merge results — no way to know which text belongs to which language
return $"{englishText}\n{frenchText}";
}
private async Task<string> ExtractWithLanguage(string imagePath, string langCode)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64 = Convert.ToBase64String(imageBytes);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
new KeyValuePair<string, string>("language", langCode) // One language per call
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
// OCR.space: one language per call — multi-language requires multiple requests
public async Task<string> ExtractMultiLanguage(string imagePath)
{
// First pass: English
string englishText = await ExtractWithLanguage(imagePath, "eng");
// Second pass: French (consumes another rate-limit slot, another API call)
string frenchText = await ExtractWithLanguage(imagePath, "fre");
// Manually merge results — no way to know which text belongs to which language
return $"{englishText}\n{frenchText}";
}
private async Task<string> ExtractWithLanguage(string imagePath, string langCode)
{
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
string base64 = Convert.ToBase64String(imageBytes);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
new KeyValuePair<string, string>("language", langCode) // One language per call
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
string json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
return doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("ParsedText")
.GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class OCRSpace
Private _apiKey As String
Private _httpClient As HttpClient
Public Async Function ExtractMultiLanguage(imagePath As String) As Task(Of String)
' First pass: English
Dim englishText As String = Await ExtractWithLanguage(imagePath, "eng")
' Second pass: French (consumes another rate-limit slot, another API call)
Dim frenchText As String = Await ExtractWithLanguage(imagePath, "fre")
' Manually merge results — no way to know which text belongs to which language
Return $"{englishText}{vbLf}{frenchText}"
End Function
Private Async Function ExtractWithLanguage(imagePath As String, langCode As String) As Task(Of String)
Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
Dim base64 As String = Convert.ToBase64String(imageBytes)
Dim content = New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
New KeyValuePair(Of String, String)("apikey", _apiKey),
New KeyValuePair(Of String, String)("base64Image", $"data:image/png;base64,{base64}"),
New KeyValuePair(Of String, String)("language", langCode) ' One language per call
})
Dim response = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
Dim json As String = Await response.Content.ReadAsStringAsync()
Using doc = JsonDocument.Parse(json)
Return doc.RootElement _
.GetProperty("ParsedResults")(0) _
.GetProperty("ParsedText") _
.GetString() OrElse String.Empty
End Using
End Function
End Class
IronOCR Ansatz:
// IronOCR: multiple languages in a single read — one pass, correct output
public string ExtractMultiLanguage(string imagePath)
{
var ocr = new IronTesseract();
// Combine languages with + operator — processed simultaneously
ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;
var result = ocr.Read(imagePath);
return result.Text; // Correctly interleaved multilingual output
}
// IronOCR: multiple languages in a single read — one pass, correct output
public string ExtractMultiLanguage(string imagePath)
{
var ocr = new IronTesseract();
// Combine languages with + operator — processed simultaneously
ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;
var result = ocr.Read(imagePath);
return result.Text; // Correctly interleaved multilingual output
}
Imports IronOcr
Public Function ExtractMultiLanguage(imagePath As String) As String
Dim ocr As New IronTesseract()
' Combine languages with + operator — processed simultaneously
ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German
Dim result = ocr.Read(imagePath)
Return result.Text ' Correctly interleaved multilingual output
End Function
Die Beschränkung von OCR.space auf eine Sprache pro Aufruf zwingt Entwickler dazu, N API-Aufrufe für ein N-sprachiges Dokument durchzuführen und zu raten, wie die Ergebnisse in Einklang gebracht werden sollen.IronOCR kombiniert Sprachmodelle in einem einzigen Durchlauf der Engine, wodurch eine korrekt verschachtelte Ausgabe ohne Nachbearbeitung erzeugt wird. Sprachpakete werden als NuGet-Pakete installiert — IronOcr.Languages.French, IronOcr.Languages.German usw. — und arbeiten offline. Der How-to zu mehreren Sprachen behandelt die Paketinstallation und die + Operator-Syntax für alle 125+ unterstützten Sprachen.
Strukturierte Datenextraktion mit Wortkoordinaten
OCR.space liefert reinen Text von ParsedResults[0].ParsedText. Es gibt keine Daten auf Wortebene, keine Begrenzungsrahmen, keine Linienbegrenzungen und keine Konfidenzwerte pro Element. Anwendungen, die bestimmte Felder finden müssen – beispielsweise ein Datum in der oberen rechten Ecke einer Rechnung oder eine Summe in der unteren rechten Zelle einer Tabelle – haben keine strukturierte Grundlage, auf der sie in der Antwort von OCR.space aufbauen können.IronOCR bietet eine vollständige Dokumenthierarchie: Seiten, Absätze, Zeilen, Wörter und Zeichen, jeweils mit Pixelkoordinaten und Konfidenzwerten.
OCR.space-Ansatz:
// OCR.space: plain text only — no structure, no coordinates
public async Task<string> ExtractInvoiceFields(string invoicePath)
{
byte[] invoiceBytes = await File.ReadAllBytesAsync(invoicePath);
string base64 = Convert.ToBase64String(invoiceBytes);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:application/pdf;base64,{base64}"),
new KeyValuePair<string, string>("filetype", "PDF"),
new KeyValuePair<string, string>("language", "eng"),
// isOverlayRequired=true returns word boxes, but only as raw JSON coordinates
new KeyValuePair<string, string>("isOverlayRequired", "true")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
string json = await response.Content.ReadAsStringAsync();
// Navigate deeply-nested JSON to find word boxes — no typed models
using var doc = JsonDocument.Parse(json);
var overlay = doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("TextOverlay");
// Parse word coordinate arrays manually — fragile JSON path traversal
var wordData = new List<(string word, int x, int y)>();
foreach (var line in overlay.GetProperty("Lines").EnumerateArray())
{
foreach (var word in line.GetProperty("Words").EnumerateArray())
{
string wordText = word.GetProperty("WordText").GetString() ?? "";
int left = word.GetProperty("Left").GetInt32();
int top = word.GetProperty("Top").GetInt32();
wordData.Add((wordText, left, top));
}
}
// Reconstruct full text from raw JSON — still no typed result
return string.Join(" ", wordData.Select(w => w.word));
}
// OCR.space: plain text only — no structure, no coordinates
public async Task<string> ExtractInvoiceFields(string invoicePath)
{
byte[] invoiceBytes = await File.ReadAllBytesAsync(invoicePath);
string base64 = Convert.ToBase64String(invoiceBytes);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("apikey", _apiKey),
new KeyValuePair<string, string>("base64Image", $"data:application/pdf;base64,{base64}"),
new KeyValuePair<string, string>("filetype", "PDF"),
new KeyValuePair<string, string>("language", "eng"),
// isOverlayRequired=true returns word boxes, but only as raw JSON coordinates
new KeyValuePair<string, string>("isOverlayRequired", "true")
});
var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
string json = await response.Content.ReadAsStringAsync();
// Navigate deeply-nested JSON to find word boxes — no typed models
using var doc = JsonDocument.Parse(json);
var overlay = doc.RootElement
.GetProperty("ParsedResults")[0]
.GetProperty("TextOverlay");
// Parse word coordinate arrays manually — fragile JSON path traversal
var wordData = new List<(string word, int x, int y)>();
foreach (var line in overlay.GetProperty("Lines").EnumerateArray())
{
foreach (var word in line.GetProperty("Words").EnumerateArray())
{
string wordText = word.GetProperty("WordText").GetString() ?? "";
int left = word.GetProperty("Left").GetInt32();
int top = word.GetProperty("Top").GetInt32();
wordData.Add((wordText, left, top));
}
}
// Reconstruct full text from raw JSON — still no typed result
return string.Join(" ", wordData.Select(w => w.word));
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks
Public Class InvoiceProcessor
Private _apiKey As String
Private _httpClient As HttpClient
Public Sub New(apiKey As String, httpClient As HttpClient)
_apiKey = apiKey
_httpClient = httpClient
End Sub
Public Async Function ExtractInvoiceFields(invoicePath As String) As Task(Of String)
Dim invoiceBytes As Byte() = Await File.ReadAllBytesAsync(invoicePath)
Dim base64 As String = Convert.ToBase64String(invoiceBytes)
Dim content As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
New KeyValuePair(Of String, String)("apikey", _apiKey),
New KeyValuePair(Of String, String)("base64Image", $"data:application/pdf;base64,{base64}"),
New KeyValuePair(Of String, String)("filetype", "PDF"),
New KeyValuePair(Of String, String)("language", "eng"),
New KeyValuePair(Of String, String)("isOverlayRequired", "true")
})
Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
Dim json As String = Await response.Content.ReadAsStringAsync()
Using doc As JsonDocument = JsonDocument.Parse(json)
Dim overlay = doc.RootElement _
.GetProperty("ParsedResults")(0) _
.GetProperty("TextOverlay")
Dim wordData As New List(Of (word As String, x As Integer, y As Integer))()
For Each line In overlay.GetProperty("Lines").EnumerateArray()
For Each word In line.GetProperty("Words").EnumerateArray()
Dim wordText As String = word.GetProperty("WordText").GetString() OrElse ""
Dim left As Integer = word.GetProperty("Left").GetInt32()
Dim top As Integer = word.GetProperty("Top").GetInt32()
wordData.Add((wordText, left, top))
Next
Next
Return String.Join(" ", wordData.Select(Function(w) w.word))
End Using
End Function
End Class
IronOCR Ansatz:
// IronOCR: full document hierarchy — typed, no JSON, no coordinates parsing
public void ExtractInvoiceFields(string invoicePath)
{
var ocr = new IronTesseract();
var result = ocr.Read(invoicePath);
// Access the full document hierarchy — all strongly typed
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
}
foreach (var word in page.Words)
{
// Word-level confidence — identify low-quality extractions
if (word.Confidence < 70)
Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})");
}
}
// Or use region-based OCR to target specific invoice zones directly
var totalRegion = new CropRectangle(400, 700, 200, 50); // Bottom-right total field
using var input = new OcrInput();
input.LoadImage(invoicePath, totalRegion);
string totalText = ocr.Read(input).Text;
Console.WriteLine($"Invoice total: {totalText}");
}
// IronOCR: full document hierarchy — typed, no JSON, no coordinates parsing
public void ExtractInvoiceFields(string invoicePath)
{
var ocr = new IronTesseract();
var result = ocr.Read(invoicePath);
// Access the full document hierarchy — all strongly typed
foreach (var page in result.Pages)
{
foreach (var paragraph in page.Paragraphs)
{
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
}
foreach (var word in page.Words)
{
// Word-level confidence — identify low-quality extractions
if (word.Confidence < 70)
Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})");
}
}
// Or use region-based OCR to target specific invoice zones directly
var totalRegion = new CropRectangle(400, 700, 200, 50); // Bottom-right total field
using var input = new OcrInput();
input.LoadImage(invoicePath, totalRegion);
string totalText = ocr.Read(input).Text;
Console.WriteLine($"Invoice total: {totalText}");
}
Imports IronOcr
Public Sub ExtractInvoiceFields(invoicePath As String)
Dim ocr As New IronTesseract()
Dim result = ocr.Read(invoicePath)
' Access the full document hierarchy — all strongly typed
For Each page In result.Pages
For Each paragraph In page.Paragraphs
Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}")
Next
For Each word In page.Words
' Word-level confidence — identify low-quality extractions
If word.Confidence < 70 Then
Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})")
End If
Next
Next
' Or use region-based OCR to target specific invoice zones directly
Dim totalRegion As New CropRectangle(400, 700, 200, 50) ' Bottom-right total field
Using input As New OcrInput()
input.LoadImage(invoicePath, totalRegion)
Dim totalText As String = ocr.Read(input).Text
Console.WriteLine($"Invoice total: {totalText}")
End Using
End Sub
Das OCR.space isOverlayRequired=true Flagge liefert JSON-Wortkoordinaten, aber die Antwortstruktur erfordert die Navigation durch verschachtelte JSON-Arrays mit auf Zeichenfolgen basierender Eigenschaftszugriff — kein typisiertes Modell, keine IntelliSense und fragiler Pfadabruf, der zerbricht, wenn sich die Antwortstruktur ändert. IronOCRs result.Pages, result.Words und result.Lines sind typisierte .NET-Objekte. Der CropRectangle Ansatz zielt auf bestimmte Dokumentbereiche direkt ab, anstatt das gesamte Dokument zu extrahieren und anschließend nach Koordinaten zu filtern. Die Anleitung zur Leseergebnisseerfassung und der regionsbasierte OCR-Leitfaden behandeln beide Muster im Detail.
OCR.space API zu IronOCR Mapping-Referenz
| OCR.space-Konzept | IronOCR-Äquivalent |
|---|---|
| Kein NuGet Paket | dotnet add package IronOcr |
HttpClient Konstruktion |
Nicht erforderlich – keine HTTP-Schicht |
SemaphoreSlim Geschwindigkeitsbegrenzer |
Nicht erforderlich – keine Ratenbegrenzungen |
FormUrlEncodedContent / MultipartFormDataContent |
OcrInput |
base64Image Daten-URI-Parameter |
input.LoadImage(bytes) |
file Upload-Parameter |
input.LoadImage(path) |
apikey Header / Formularfeld |
IronOcr.License.LicenseKey (einmal beim Start) |
language Parameter (einer pro Anruf) |
ocr.Language = OcrLanguage.English + OcrLanguage.French |
OCREngine=1 (schnell) |
Standard-Engine (optimiertes Tesseract 5) |
OCREngine=2 (hohe Genauigkeit) |
input.Deskew(); input.DeNoise(); input.Contrast(); |
scale=true Parameter |
input.Scale(200) |
detectOrientation=true Parameter |
input.Deskew() |
isOverlayRequired=true Parameter |
result.Pages[n].Words (immer verfügbar, typisiert) |
isCreateSearchablePdf=true Parameter |
result.SaveAsSearchablePdf("output.pdf") |
filetype=PDF Parameter |
input.LoadPdf(path) |
ParsedResults[0].ParsedText |
result.Text |
ParsedResults[n] (Text pro Seite) |
result.Pages[n].Text |
TextOverlay.Lines[n].Words[n].WordText |
result.Pages[n].Words[n].Text |
TextOverlay.Lines[n].Words[n].Left/Top |
result.Pages[n].Words[n].X / .Y |
IsErroredOnProcessing JSON-Flagge |
Standard Exception mit Nachricht |
FileParseExitCode pro-Seiten-Flagge |
Standard Exception mit Nachricht |
| HTTP 429 Zu viele Anfragen | Nicht anwendbar – keine Ratenbegrenzungen |
Benutzerdefinierte OcrResult POCO (benutzerdefiniert) |
IronOcr.OcrResult (bereitgestellt durch NuGet) |
Benutzerdefinierte OcrSpaceException (benutzerdefiniert) |
Standard .NET -Ausnahmetypen |
Gängige Migrationsprobleme und Lösungen
Problem 1: Asynchroner Code, der nur für HTTP existierte
OCR.space: Jeder OCR-Aufruf ist async, da er eine HTTP-Rundreise zur Cloud beinhaltet. Servicemethoden, Controller-Aktionen und Hintergrundprozesse wurden asynchron gestaltet, um zu vermeiden, dass der Thread durch Netzwerkwartezeiten blockiert wird.
Lösung: Die Methode Read() von IronOCR ist synchron. Entfernen Sie await aus Methoden, die nur asynchron waren, weil OCR.space es erforderte. In ASP.NET Core-Kontexten, in denen nicht blockierende Ausführung wichtig ist, wickeln Sie die synchronen Aufrufe in Task.Run() ein oder verwenden Sie die asynchronen Muster, die im asynchronen OCR-Handbuch dokumentiert sind. Fügen Sie nicht reflexartig await zu IronOCR-Aufrufen hinzu — es ist nicht erforderlich und fügt unnötigen Overhead in Nicht-Web-Kontexten hinzu.
// Before: async because OCR.space required network I/O
public async Task<string> ProcessDocumentAsync(string path)
{
return await _ocrSpaceClient.ExtractTextAsync(path); // Network wait
}
// After: synchronous — no network, no async needed
public string ProcessDocument(string path)
{
return _ocr.Read(path).Text; // Local execution
}
// Before: async because OCR.space required network I/O
public async Task<string> ProcessDocumentAsync(string path)
{
return await _ocrSpaceClient.ExtractTextAsync(path); // Network wait
}
// After: synchronous — no network, no async needed
public string ProcessDocument(string path)
{
return _ocr.Read(path).Text; // Local execution
}
Imports System.Threading.Tasks
' Before: async because OCR.space required network I/O
Public Async Function ProcessDocumentAsync(path As String) As Task(Of String)
Return Await _ocrSpaceClient.ExtractTextAsync(path) ' Network wait
End Function
' After: synchronous — no network, no async needed
Public Function ProcessDocument(path As String) As String
Return _ocr.Read(path).Text ' Local execution
End Function
Problem 2: Infrastruktur für die Speicherung und Rotation von API-Schlüsseln
OCR.space: Der API-Schlüssel muss in jede Anfrage injiziert werden. Teams speichern ihn typischerweise in appsettings.json oder Umgebungsvariablen, injizieren ihn durch IOptions<t> oder Konstruktoreinspritzung und rotieren ihn, wenn er offengelegt wird. Für den Schlüsselwechsel ist es erforderlich, jede Bereitstellungsumgebung zu aktualisieren und die Anwendung neu zu starten.
Lösung: Der IronOCR-Lizenzschlüssel wird einmalig beim Start festgelegt und während der Ausführung nie wieder verwendet. Entfernen Sie das Muster der Schlüsseleinschleusung pro Anfrage. Entfernen Sie die IOptions<OcrSpaceSettings> Konfigurationsklasse. Das wichtigste Initialisierungsmuster besteht aus einer Zeile:
// Startup.cs or Program.cs — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
// Startup.cs or Program.cs — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
Imports System
' Startup.vb or Program.vb — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
Es gibt keine Eingabe von Anmeldeinformationen pro Anfrage, kein Schlüsselrotationsverfahren und kein Risiko, dass der Schlüssel versehentlich in den Anfrageprotokollen protokolliert wird.
Problem 3: Logik zur Vorvalidierung der Dateigröße
OCR.space: Die kostenlose Version lehnt Dateien über 5 MB mit einer Fehlermeldung ab. Der Produktionscode fügt vor jeder Anfrage eine Dateigrößenprüfung hinzu, um zu vermeiden, dass ein Ratenbegrenzungsplatz für einen Aufruf verschwendet wird, der fehlschlägt:
// OCR.space: pre-validation to avoid wasting quota on large files
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > 5 * 1024 * 1024)
throw new InvalidOperationException("File exceeds 5MB free tier limit.");
// OCR.space: pre-validation to avoid wasting quota on large files
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > 5 * 1024 * 1024)
throw new InvalidOperationException("File exceeds 5MB free tier limit.");
Dim fileInfo As New FileInfo(filePath)
If fileInfo.Length > 5 * 1024 * 1024 Then
Throw New InvalidOperationException("File exceeds 5MB free tier limit.")
End If
Lösung: Diese Prüfung komplett entfernen. IronOCRs OcrInput.LoadPdf() und OcrInput.LoadImage() haben keine Größenbeschränkung, die über den verfügbaren Systemspeicher hinausgehen. Die künstliche 5-MB-Grenze existiert nur, weil sie im kostenlosen Tarif von OCR.space aus Gründen der Serverkapazität festgelegt ist. Eine 50 MB große gescannte PDF-Datei wird genauso geladen wie eine 500 KB große.
Problem 4: Anfälligkeit der JSON-Antwortnavigation
OCR.space: Die Antwortanalyse basiert auf dem Navigieren JsonDocument mit auf Zeichenfolgen basierendem Eigenschaftszugriff. Code wie doc.RootElement.GetProperty("ParsedResults")[0].GetProperty("ParsedText") wirft KeyNotFoundException, wenn sich die Antwortform ändert, und IndexOutOfRangeException, wenn ParsedResults leer ist. Beide Varianten erfordern durchgehend try-catch-Abfragen oder Nullprüfungen.
Lösung:IronOCR gibt ein typisiertes OcrResult Objekt zurück. Die .Text Eigenschaft ist immer ein string — niemals null, niemals fehlend. Wenn OCR keine Ausgabe erzeugt (leere Seite, nicht lesbares Bild), ist result.Text ein leerer String. Es gibt kein JSON zu navigieren und keine Eigenschaftspfad-Zerbrechlichkeit zu bewachen. Für vertrauensbasiertes Filtern gibt result.Confidence ein double zurück, das Sie direkt vergleichen können:
// IronOCR: typed result — no JSON path fragility
var result = new IronTesseract().Read("document.jpg");
if (result.Confidence < 50)
Console.WriteLine("Low confidence — consider preprocessing");
else
Console.WriteLine(result.Text);
// IronOCR: typed result — no JSON path fragility
var result = new IronTesseract().Read("document.jpg");
if (result.Confidence < 50)
Console.WriteLine("Low confidence — consider preprocessing");
else
Console.WriteLine(result.Text);
Imports IronOcr
Dim result = New IronTesseract().Read("document.jpg")
If result.Confidence < 50 Then
Console.WriteLine("Low confidence — consider preprocessing")
Else
Console.WriteLine(result.Text)
End If
Die Anleitung zur Berechnung von Konfidenzwerten umfasst Konfidenzschwellenwerte pro Wort und pro Dokument.
Problem 5: Erschöpfung der Ratenbegrenzung für gemeinsam genutzte IP-Adressen in CI/CD
OCR.space: CI/CD-Pipelines, die Integrationstests gegen OCR.space ausführen, verwenden dieselbe ausgehende IP-Adresse wie das Netzwerk des Entwicklungsbüros. Kostenlose Konten sind auf 500 Anfragen pro Tag und IP-Adresse beschränkt. Eine Pipeline, die 200 Testdokumente pro Durchlauf verarbeitet, kann das Tageskontingent bereits vor dem ersten manuellen Testlauf eines Entwicklers ausschöpfen. Teams umgehen dieses Problem, indem sie OCR.space-Antworten in Tests simulieren, was den Sinn von Integrationstests jedoch untergräbt.
Lösung:IronOCR verarbeitet Daten lokal. Die Testsuite ruft new IronTesseract().Read(testImagePath).Text direkt auf – kein Mocking erforderlich, kein Kontingent zu erschöpfen, keine Netzwerkabhängigkeit. Integrationstests werden in CI/CD mit den gleichen realen OCR-Ergebnissen wie in der Produktion ohne Ratenbegrenzungsmanagement oder Testisolationsmuster ausgeführt.
Problem 6: IDisposable Muster vom HttpClient-Verwaltung
OCR.space: Die HttpClient Wrapper-Klasse implementiert IDisposable, um den HTTP-Verbindungspool freizugeben. Jeder Verbraucher des OCR-Dienstes muss entweder einen Singleton injizieren, using Blöcke verwenden oder es im Lebenszyklus des DI-Container-Abbaus registrieren. Wird das Entsorgen der Steckdose vergessen, kommt es unter Last zu deren Erschöpfung.
Lösung: IronTesseract verwaltet keine Netzwerkverbindungen. Es implementiert nicht IDisposable. Erstellen Sie eine Instanz pro Thread (oder pro Anfrage in ASP.NET), rufen Sie .Read() auf und lassen Sie es vom GC sammeln. Die OcrInput Klasse implementiert IDisposable und sollte in using Blöcke gewickelt werden, wenn Vorverarbeitung angewendet wird, aber die primäre IronTesseract Klasse benötigt keine Lebenszyklusverwaltung. Entfernen Sie die IDisposable Implementierung aus Ihrem OCR-Dienst-Wrapper und vereinfachen Sie die DI-Registrierung von Scoped/Transient mit Abbau zu einer einfachen Fabrik oder Singleton.
OCR.space-Migrationscheckliste
Vor der Migration anfallende Aufgaben
Überprüfen Sie den Quellcode, um alle OCR.space-Integrationspunkte zu identifizieren:
# Find all OCR.space HTTP calls
grep -rn "ocr.space" --include="*.cs" .
# Find all base64 encoding related to OCR
grep -rn "base64Image\|Convert.ToBase64String" --include="*.cs" .
# Find rate limiter and retry logic
grep -rn "SemaphoreSlim\|TooManyRequests\|exponential" --include="*.cs" .
# Find JSON parsing for OCR responses
grep -rn "ParsedResults\|IsErroredOnProcessing\|FileParseExitCode" --include="*.cs" .
# Find custom OCR models and exception types
grep -rn "OcrSpaceException\|OcrResult\b" --include="*.cs" .
# Find API key configuration
grep -rn "apikey\|OcrSpaceApiKey\|ocr_space" --include="*.cs" --include="*.json" .
# Find all OCR.space HTTP calls
grep -rn "ocr.space" --include="*.cs" .
# Find all base64 encoding related to OCR
grep -rn "base64Image\|Convert.ToBase64String" --include="*.cs" .
# Find rate limiter and retry logic
grep -rn "SemaphoreSlim\|TooManyRequests\|exponential" --include="*.cs" .
# Find JSON parsing for OCR responses
grep -rn "ParsedResults\|IsErroredOnProcessing\|FileParseExitCode" --include="*.cs" .
# Find custom OCR models and exception types
grep -rn "OcrSpaceException\|OcrResult\b" --include="*.cs" .
# Find API key configuration
grep -rn "apikey\|OcrSpaceApiKey\|ocr_space" --include="*.cs" --include="*.json" .
Dokumentieren Sie die Liste der Dateien, die OCR.space-Code enthalten. Notieren Sie sich, welche Methoden async allein wegen OCR.space's HTTP-Abhängigkeit sind — diese können nach der Migration synchron gemacht werden.
Aufgaben der Code-Aktualisierung
- Installieren Sie das
IronOcrNuGet-Paket:dotnet add package IronOcr - Fügen Sie
IronOcr.License.LicenseKey = "..."zum Anwendungsstart hinzu - Löschen Sie die
OcrSpaceApiClientKlasse und alle unterstützenden Infrastrukturen - Löschen Sie das benutzerdefinierte
OcrResultPOCO (ersetzt durchIronOcr.OcrResult) - Löschen Sie die benutzerdefinierte
OcrSpaceExceptionKlasse (ersetzt durch Standard .NET-Ausnahmen) - Löschen Sie den
SemaphoreSlimGeschwindigkeitsbegrenzer und die damit verbundene Task.Delay-Logik - Entfernen Sie alle
Convert.ToBase64String()Aufrufe, die zur OCR-Bildkodierung verwendet wurden - Ersetzen Sie
FormUrlEncodedContent/MultipartFormDataContentKonstruktion durchOcrInput - Ersetzen Sie
_httpClient.PostAsync(...)Aufrufe durchnew IronTesseract().Read(input) - Ersetzen Sie
JsonDocumentParsing vonParsedResults[0].ParsedTextmitresult.Text - Ersetzen Sie
TextOverlayJSON-Koordinaten-Parsing mitresult.Pages[n].Words - Ersetzen Sie
OCREngineParameterumschaltung mit geeigneten Vorverarbeitungsfiltern - Ersetzen Sie
languageParameter-Strings durchOcrLanguageEnum-Werte - Entfernen der Vorabprüfung der Dateigröße (die 5-MB-Grenze gilt nicht mehr)
- Konvertieren Sie
async Task<string>OCR-Methoden in synchronestring, wo HTTP der einzige asynchrone Grund war - Entfernen Sie den OCR.space-API-Schlüssel aus den Konfigurationsdateien und der Umgebungsvariablen-Einrichtung.
Post-Migrationstests
- Überprüfen Sie, ob die Textextraktion bei denselben Testdokumenten eine gleichwertige oder höhere Genauigkeit liefert.
- Bestätigen, dass große Dateien (über 5 MB) fehlerfrei verarbeitet werden.
- Testen Sie mehrsprachige Dokumente mit
OcrLanguage.English + OcrLanguage.Frenchund überprüfen Sie die verflochtene Ausgabe - Führen Sie die CI/CD-Pipeline mit echten OCR-Aufrufen aus – stellen Sie sicher, dass bei keinem Dokumentenvolumen Ratenbegrenzungsfehler auftreten.
- Sicherstellen, dass die durchsuchbare PDF-Ausgabe keine Wasserzeichen enthält
- Prüfen Sie, ob zuvor asynchrone Controller-Aktionen nach der synchronen Konvertierung weiterhin korrekt reagieren.
- Testen Sie, ob in abgeschotteten oder netzwerkbeschränkten Bereitstellungsumgebungen Dokumente fehlerfrei verarbeitet werden.
- Bestätigen Sie, dass
result.ConfidenceWerte auf Dokumenten akzeptabel sind, die zuvorOCREngine=2erforderten - Verifizieren Sie, dass
result.Pages[n].WordsKoordinaten die erwarteten Feldpositionen in strukturierten Dokumenten entsprechen - Prüfen Sie, ob die Lizenzinitialisierung beim Anwendungsstart vor dem ersten OCR-Aufruf erfolgreich ist.
Wichtigste Vorteile der Migration zu IronOCR
Die Infrastrukturgebühr für mehr als 80 Zeilen entfällt. Jede OCR.space-Integration beinhaltet einen HTTP-Client, einen Ratenbegrenzer, einen JSON-Deserialisierer, benutzerdefinierte Ausnahmetypen und benutzerdefinierte Ergebnismodelle. Keiner dieser Codeabschnitte erfüllt eine Funktion, die die Anwendung tatsächlich benötigt – er dient lediglich dazu, das fehlende SDK von OCR.space zu kompensieren. Nach der Migration wird dieser Code gelöscht. Die OCR-Oberfläche im Codebestand schrumpft zu new IronTesseract().Read(path).Text an der Aufrufstelle und einer Lizenz-Initialisierungszeile beim Start.
Die Dokumentenverarbeitungsgeschwindigkeit wird zu einer Funktion der lokalen Hardware. OCR.space berücksichtigt bei jedem Verarbeitungsvorgang Netzwerklatenz, die Länge der OCR.space-Serverwarteschlange und die geografische Roundtrip-Zeit.IronOCR wird im Prozess ausgeführt. Eine lokale Workstation verarbeitet Dokumente schneller als jede Cloud-API, unabhängig vom Durchsatz, und das ohne die Beschränkung auf 60 Anfragen pro Minute, die die Stapelverarbeitung serialisiert. Parallelverarbeitung mit Parallel.ForEach über mehrere IronTesseract Instanzen skaliert mit CPU-Kernen — siehe das Multithreading-Beispiel.
Sensible Dokumente verbleiben dauerhaft in Ihrer Infrastruktur. Nach der Migration verlassen medizinische Daten, Finanzdokumente, Verträge und Ausweisdokumente den Anwendungsserver nicht mehr. Die Überprüfung der Einhaltung von HIPAA, DSGVO, SOC 2 und internen Datenklassifizierungsrichtlinien muss die Datenverarbeitungspraktiken von OCR.space nicht mehr in ihren Geltungsbereich einbeziehen. Der Prüfgegenstand reduziert sich auf Ihre eigene Infrastruktur. Der Docker-Bereitstellungsleitfaden und der Azure-Bereitstellungsleitfaden beschreiben die Bereitstellung von IronOCR in containerisierten und Cloud-Umgebungen, die die Einhaltung der Datenresidenzvorschriften erfordern.
Strukturiertes Ergebnis ermöglicht Dokument-Intelligenz-Anwendungen. Die ParsedText Zeichenfolge von OCR.space ist das Ende der Straße für die Dokumentenanalyse. IronOCRs result.Pages, result.Words und result.Lines mit Koordinaten und per Wort-Vertrauensbewertungen ermöglichen Anwendungen, spezifische Felder zu lokalisieren, die Extraktionsqualität zu validieren, Tabellendaten zu extrahieren und nachgelagerte Dokument-Intelligenz-Pipelines zu erstellen. Funktionen, die bisher die Entwicklung einer benutzerdefinierten Layoutanalyse auf Basis der Klartextausgabe von OCR.space erforderten, werden nun durch direkte API-Aufrufe ermöglicht. Die Anleitung zur Tabellenextraktion und die Anleitung zur Verarbeitung gescannter Dokumente veranschaulichen, was diese strukturierte Grundlage ermöglicht.
Die Kosten sind unabhängig vom Volumen fix und vorhersehbar. Das kostenlose Kontingent von OCR.space umfasst 25.000 Anfragen pro Monat. Darüber hinaus steigen die Abonnementkosten mit der Nutzung. IronOCRs $999 Lite unbefristete Lizenz erhebt keine pro-Dokument Gebühr bei beliebigem Volumen. Ein Team, das 100.000 Dokumente pro Monat verarbeitet, zahlt die gleiche Lizenzgebühr wie ein Team, das 1.000 Dokumente pro Monat verarbeitet. Die Budgetprognose für Dokumentenverarbeitungsanwendungen wird zu einer fixen jährlichen Kostenposition anstatt zu einem variablen Kostenposten, der mit dem Geschäftserfolg wächst. Auf der IronOCR Produktseite ist eine kostenlose Testversion enthalten, mit der Teams die Genauigkeit für ihre spezifischen Dokumenttypen vor dem Kauf überprüfen können.
Häufig gestellte Fragen
Warum sollte ich von OCR.space API zu IronOCR migrieren?
Zu den häufigsten Gründen gehören die Beseitigung der Komplexität der COM-Interoperabilität, die Ablösung der dateibasierten Lizenzverwaltung, die Vermeidung der seitenweisen Abrechnung, die Ermöglichung der Docker-/Container-Bereitstellung und die Einführung eines NuGet-nativen Workflows, der sich in die Standard-.NET-Werkzeuge integriert.
Was sind die wichtigsten Code-Änderungen bei der Migration von OCR.space API zu IronOCR?
Ersetzen Sie OCR.space-Initialisierungssequenzen durch IronTesseract-Instanziierung, entfernen Sie das COM-Lebenszyklusmanagement (explizite Create/Load/Close-Muster) und aktualisieren Sie die Namen der Ergebniseigenschaften. Das Ergebnis sind deutlich weniger Boilerplate-Zeilen.
Wie installiere ich IronOCR, um die Migration zu beginnen?
Führen Sie 'Install-Package IronOcr' in der Paketmanager-Konsole oder 'dotnet add package IronOcr' in der CLI aus. Sprachpakete sind separate Pakete: 'dotnet add package IronOcr.Languages.French' für Französisch, zum Beispiel.
Kann IronOCR die OCR-Genauigkeit von OCR.space API für Standardgeschäftsdokumente erreichen?
IronOCR erzielt eine hohe Genauigkeit bei Standardgeschäftsinhalten wie Rechnungen, Verträgen, Quittungen und getippten Formularen. Bildvorverarbeitungsfilter (Schräglagenkorrektur, Rauschunterdrückung, Kontrastverbesserung) verbessern die Erkennungsgenauigkeit bei verschlechterten Eingaben weiter.
Wie geht IronOCR mit den Sprachdaten um, die von OCR.space API separat installiert werden?
Die Sprachdaten in IronOCR werden als NuGet-Pakete verteilt. mit 'dotnet add package IronOcr.Languages.German' wird die deutsche Unterstützung installiert. Es sind keine manuellen Dateiplatzierungen oder Verzeichnispfade erforderlich.
Erfordert die Migration von OCR.space API zu IronOCR Änderungen an der Bereitstellungsinfrastruktur?
IronOCR erfordert weniger Änderungen an der Infrastruktur als OCR.space API. Es gibt keine SDK-Binärpfade, keine Platzierung von Lizenzdateien oder Lizenzserverkonfigurationen. Das NuGet-Paket enthält die komplette OCR-Engine, und der Lizenzschlüssel ist eine im Anwendungscode festgelegte Zeichenfolge.
Wie konfiguriere ich die IronOCR-Lizenzierung nach der Migration?
Weisen Sie IronOcr.License.LicenseKey = "YOUR-KEY" im Startup-Code der Anwendung zu. In Docker oder Kubernetes speichern Sie den Schlüssel als Umgebungsvariable und lesen ihn beim Starten aus. Verwenden Sie License.IsValidLicense zur Validierung, bevor Sie den Datenverkehr akzeptieren.
Kann IronOCR PDFs auf die gleiche Weise verarbeiten wie OCR.space?
Ja, IronOCR liest sowohl native als auch gescannte PDFs. Instanziieren Sie IronTesseract, rufen Sie ocr.Read(input) auf, wobei input ein PDF-Pfad oder OcrPdfInput ist, und iterieren Sie die OcrResult-Seiten. Es ist keine separate PDF-Rendering-Pipeline erforderlich.
Wie handhabt IronOCR das Threading bei der Verarbeitung großer Datenmengen?
IronTesseract kann sicher pro Thread instanziiert werden. Sie können eine Instanz pro Thread in einem Parallel.ForEach- oder Task-Pool aufsetzen, OCR gleichzeitig ausführen und jede Instanz nach Abschluss entsorgen. Es ist kein globaler Zustand oder Sperren erforderlich.
Welche Ausgabeformate unterstützt IronOCR nach der Textextraktion?
IronOCR liefert strukturierte Ergebnisse mit Text, Wortkoordinaten, Konfidenzwerten und Seitenstruktur. Zu den Exportoptionen gehören reiner Text, durchsuchbare PDF-Dateien und strukturierte Ergebnisobjekte für die nachgeschaltete Verarbeitung.
Ist die Preisgestaltung von IronOCR vorhersehbarer als die von OCR.space API für die Skalierung von Workloads?
IronOCR verwendet eine pauschale, unbefristete Lizenzierung ohne Seiten- oder Volumengebühren. Egal, ob Sie 10.000 oder 10 Millionen Seiten verarbeiten, die Lizenzkosten bleiben konstant. Optionen für Volumen- und Teamlizenzen finden Sie auf der IronOCR-Preisseite.
Was passiert mit meinen bestehenden Tests nach der Migration von OCR.space API zu IronOCR?
Tests, die extrahierte Textinhalte überprüfen, sollten auch nach der Migration bestehen. Tests, die API-Aufrufmuster oder den Lebenszyklus von COM-Objekten validieren, müssen aktualisiert werden, um das einfachere Initialisierungs- und Ergebnismodell von IronOCR widerzuspiegeln.

