Zum Fußzeileninhalt springen
MIT ANDEREN KOMPONENTEN VERGLEICHEN

Vergleich von Open-Source-OCR für Rechnungen: Finden Sie das beste Tool

LEADTOOLS liefert seit 1990 SDK-Software, und seine OCR-Integration trägt dieses Erbe in vollem Umfang: Bevor ein einziges Zeichen erkannt wird, muss Ihre Anwendung zwei Binärdateien auf der Festplatte finden, ein Pairing zwischen LEADTOOLS.LIC und LEADTOOLS.LIC.KEY validieren, eine RasterCodecs Instanz initialisieren, einen Engine-Typ aus drei verschiedenen Optionen auswählen, engine.Startup() mit einem Laufzeitverzeichnispfad aufrufen und dann - und nur dann - die eigentliche Erkennung starten. Für jede Produktionsmaschine müssen die Lizenzdateien in einem bestimmten Pfad bereitgestellt werden. Docker-Container erfordern das Einbinden oder Backen dieser Dateien. CI/CD-Pipelines benötigen die Dateien am richtigen Ort, sonst schlägt die Anwendung beim Start fehl. Und falls der Entwickler das falsche Paket erworben hat, ist das OCR-Modul möglicherweise gar nicht enthalten, da LEADTOOLS die OCR-Funktionen als separates Modul von seinen Bildverarbeitungs-Codecs anbietet.

LEADTOOLS OCRverstehen

LEADTOOLS ist eine Dokumentenverarbeitungsplattform von LEAD Technologies, einem Unternehmen, das seit 1990 kommerzielle SDK-Software vertreibt. Die OCR-Funktion ist ein Modul unter vielen in einem Toolkit, das auch Dokumentenbetrachter, medizinische Bildgebung (DICOM/PACS), Barcode-Lesen, Formularerkennung, Annotationen und PDF-Bearbeitung umfasst. Diese Architektur bedeutet, dass LEADTOOLS keine OCR-Bibliothek ist, sondern eine Bildverarbeitungsplattform mit integrierter OCR-Funktion.

Wichtigste architektonische Merkmale von LEADTOOLS OCR:

  • Drei separate OCR-Engines: Die proprietäre LEAD-Engine (in der Basislizenz enthalten), ein Tesseract-Wrapper (erfordert tessdata-Dateien) und eine OmniPage-Engine (erfordert eine separate Kofax-Lizenzvereinbarung und eine zweite Anbieterbeziehung). Die Wahl der Engine beeinflusst sowohl den Code als auch die Kosten.
  • Dateibasierte Lizenzbereitstellung: Zwei Dateien — LEADTOOLS.LIC und LEADTOOLS.LIC.KEY — müssen zur Laufzeit lesbar sein. Der Pfad ist fest codiert oder wird beim Start aufgelöst. Die Pfadauflösung verhält sich in IIS anders als in Konsolenhosts, in Dockeranders als auf Bare Metal, in Release-Builds anders als im Debug-Modus.
  • RasterCodecs als notwendiger Zwischenschritt: Das Laden von Bildern erfolgt nicht direkt in die OCR-Engine. Jedes Bild — einschließlich PDF-Seiten — wird zunächst über eine RasterCodecs Instanz geladen, die vor dem Starten der Engine initialisiert werden muss.
  • Expliziter Lebenszyklus der Engine: OcrEngineManager.CreateEngine() erstellt die Engine, engine.Startup() lädt sie in den Speicher (500–2000 ms), und engine.Shutdown() muss vor Dispose() aufgerufen werden. Wird der Shutdown-Aufruf in der falschen Reihenfolge übersprungen, entstehen Fehler.
  • Komplexität der Paketpreise: LEADTOOLS veröffentlicht keine Preise öffentlich. Kontaktieren Sie den LEADTOOLS-Vertrieb für ein Angebot basierend auf Ihren spezifischen Anforderungen. Um Aktualisierungen zu erhalten, sind jährliche Wartungsgebühren erforderlich.
  • Großer Bereitstellungsbedarf: Produktionsbereitstellungen umfassen mehrere LEADTOOLS-DLLs, ein OcrRuntime/ Verzeichnis, Lizenzdateien und optional einen tessdata/ Ordner, wenn die Tesseract-Engine verwendet wird.

Die Initialisierungssequenz

LEADTOOLS erfordert eine spezifische, mehrstufige Einrichtung, bevor eine Erkennung erfolgen kann. Die Reihenfolge ist nicht optional — das Aufrufen von Startup() vor SetLicense() oder bevor RasterCodecs initialisiert wurde, führt zu Laufzeitfehlern:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Initialize image codec layer
        _codecs = new RasterCodecs();

        // Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);
        using var document = _ocrEngine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);   // Recognition is not automatic
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown(); // Must call before Dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Initialize image codec layer
        _codecs = new RasterCodecs();

        // Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);
        using var document = _ocrEngine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);   // Recognition is not automatic
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown(); // Must call before Dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System.IO

Public Class LeadtoolsOcrService
    Implements IDisposable

    Private _ocrEngine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        ' Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            "C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText("C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"))

        ' Step 2: Initialize image codec layer
        _codecs = New RasterCodecs()

        ' Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)

        ' Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, Nothing, Nothing,
            "C:\LEADTOOLS\OCR\OcrRuntime")
    End Sub

    Public Function ExtractText(imagePath As String) As String
        Using image = _codecs.Load(imagePath)
            Using document = _ocrEngine.DocumentManager.CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing)
                page.Recognize(Nothing) ' Recognition is not automatic
                Return page.GetText(-1)
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If _ocrEngine IsNot Nothing Then
            _ocrEngine.Shutdown() ' Must call before Dispose
            _ocrEngine.Dispose()
        End If
        If _codecs IsNot Nothing Then
            _codecs.Dispose()
        End If
    End Sub
End Class
$vbLabelText   $csharpLabel

Dies ist die minimale, funktionsfähige Implementierung. Es beinhaltet keine Fehlerbehandlung für Lizenzpfadausfälle, Validierung des Engine-Zustands oder das Speicher-Management, das für die Batch-Verarbeitung erforderlich ist (wo das Vergessen, RasterImage Instanzen freizugeben, den Speicher anhäuft, bis der Prozess abstürzt).

IronOCR verstehen

IronOCR ist eine kommerzielle .NET OCR-Bibliothek, die auf einer optimierten Tesseract 5 LSTM-Engine basiert. Es handelt sich um ein spezialisiertes OCR-Produkt – keine Bildverarbeitungsplattform, bei der OCR nur ein Modul ist. Das Designziel besteht darin, jeglichen Infrastrukturaufwand zwischen einem Entwickler und dem erkannten Text zu eliminieren.

Wichtige Merkmale von IronOCR:

  • Einzelnes NuGet-Paket: dotnet add package IronOcr installiert alles Notwendige, inklusive nativer Abhängigkeiten, ohne zusätzliches Laufzeitverzeichnis, tessdata-Ordner oder Lizenzdatei bereitzustellen.
  • Stringbasierte Lizenzierung: Eine Zeile weist einen Lizenzschlüssel zu. Der Schlüssel kann aus einer Umgebungsvariable, appsettings.json, dem Azure Key Vault oder dem AWS Secrets Manager kommen — jedes bereits verwendete Geheimhaltungsmanagement-Muster. Keine Dateien auf der Festplatte.
  • Kein Lebenszyklus des Engines: IronTesseract initialisiert sich bei der ersten Verwendung mit Lazy Loading. Es gibt keinen Startup()-Aufruf, keinen Shutdown()-Aufruf und keine Anforderung, die Engine selbst zwischen den Operationen freizugeben.
  • Nativer PDF-Input: PDFs werden direkt über OcrInput.LoadPdf() geladen. Kein Seiten-für-Seite Rasterisierungsschleife, keine Byte-Order-Spezifikation, keine manuelle Freigabe von Zwischenobjekten RasterImage.
  • Automatische Vorverarbeitung: Entzerren, Rauschentfernung, Kontrastverbesserung, Binarisierung und Auflösungsnormalisierung sind als einzelne Methodenaufrufe auf OcrInput verfügbar. Sie gelten gleichzeitig für alle Seiten.
  • 125+ Sprachen über NuGet: Jede Sprache ist ein separates NuGet-Paket (IronOcr.Languages.French usw.). Kein zu verwaltendes tessdata-Verzeichnis, keine Pfadkonfiguration.
  • Standardmäßig thread-sicher: IronTesseract Instanzen sind für den gleichzeitigen Gebrauch sicher. Die Parallelverarbeitung erfordert keinen Synchronisierungscode.
  • Dauerhafte Lizenzierung: $999 Lite / $1,499 Plus / $2,999 Professional / $5,999 Unlimited, einmalige Kauf mit einem Jahr Updates inklusive.

Funktionsvergleich

Feature LEADTOOLS OCR IronOCR
Komplexität der Einrichtung Hoch — 4-stufige Initialisierungssequenz Niedrig – ein NuGet Paket
Lizenzbereitstellung Zwei Dateien (.LIC + .LIC.KEY) auf jedem Computer Zeichenkettenschlüssel, beliebig speichern
Preismodell Kontaktieren Sie den LEADTOOLS-Vertrieb für Preise. $5,999 einmalig dauerhaft
PDF-Unterstützung Manuelle seitenweise Rasterisierung Native LoadPdf()
Vorverarbeitung Manuell — separate Bildverarbeitungsbefehle Eingebaute Filtermethoden
Lebensdauer des Motors Manuelle Startup() / Shutdown() erforderlich Automatisch, faul
NuGet -Pakete Mehrere (Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Pdf) Eins (IronOcr)
Thread-Sicherheit Erfordert sorgfältiges Management Eingebaut

Detaillierter Funktionsvergleich

Feature LEADTOOLS OCR IronOCR
Lizenzierung
Lizenzmechanismus .LIC + .LIC.KEY Dateipaar String-Schlüssel
Lizenzbereitstellung Dateien auf jeder Produktionsmaschine Umgebungsvariable oder Konfiguration
Preistransparenz Verkaufsberatung erforderlich Auf der Website veröffentlicht
Unbefristete Option Nein (jährliche Wartung erforderlich) Ja
Einrichtung und Installation
Erforderliche NuGet Pakete Mindestens 3–4 (mehr für PDF) 1
Laufzeitdateien erforderlich Ja — OcrRuntime/ Verzeichnis Nein
Motorinitialisierung Handbuch Startup() mit Laufzeitpfad None
Motor abgestellt Handbuch Shutdown() vor Dispose() None
tessdata management Erforderlich für die Tesseract-Motoroption Nein
OCR-Fähigkeiten
Motoroptionen LEAD, Tesseract, OmniPage (separat lizenzierbar) IronTesseract (optimiertes Tesseract 5 LSTM)
Sprachen 60–120 (motorabhängig) 125+ über NuGet
Sprachbereitstellung tessdata files or engine-bundled NuGet Sprachpakete
Konfidenzwerte page.RecognizeStatus result.Confidence (Prozentsatz)
Strukturierte Ausgabe Seite, Zonenebene Seite, Absatz, Zeile, Wort, Zeichen
Barcode-Lesung Separates LEADTOOLS Barcode-Modul Eingebaut (ReadBarCodes = true)
PDF-Verarbeitung
PDF-Eingabe Seitenweise Rasterisierungsschleife Native LoadPdf()
Passwort-PDFs Erfordert das Modul Leadtools.Pdf (zusätzliche Lizenz) Eingebauter Parameter Password
Durchsuchbare PDF-Ausgabe DocumentWriter Konfiguration + document.Save() result.SaveAsSearchablePdf()
Seitenbereichsauswahl Manuelle Schleifengrenzen LoadPdfPages(path, start, end)
Vorverarbeitung
Entschiefen DeskewCommand (manuell pro Image) input.Deskew()
Rauschunterdrückung DespeckleCommand (manuell pro Image) input.DeNoise()
Binarisieren AutoBinarizeCommand (manuell pro Image) input.Binarize()
Kontrastverbesserung ContrastBrightnessCommand (manuell) input.Contrast()
Auflösungsverbesserung Manuelle Graustufen- und Resampling-Befehle input.EnhanceResolution(300)
Einsatz
Docker LIC/KEY-Dateien müssen eingebunden oder gebacken werden. Standard dotnet publish
Linux Unterstützt durch native Abhängigkeiten Unterstützt, Abhängigkeiten gebündelt
Luftgetrennt Ja Ja
CI/CD-Komplexität Lizenzdateien + Laufzeitpfad in jeder Umgebung Lizenzschlüssel im Geheimnismanager

Lizenzarchitektur: Dateibereitstellung vs. Zeichenkettenschlüssel

Der Unterschied in der Lizenzarchitektur zwischen LEADTOOLS und IronOCR ist nicht nur eine Frage der Entwicklerergonomie – er wirkt sich direkt auf Bereitstellungspipelines, Containerstrategien und den Betriebsaufwand aus.

LEADTOOLS-Ansatz

LEADTOOLS benötigt beim Anwendungsstart zwei physische Dateien, die vorhanden und lesbar sein müssen. Der Code in den Quelldateien .cs bestätigt dieses Muster:

// From leadtools-migration-examples.cs
public void InitializeLicense()
{
    // Option 1: Absolute paths — deployment dependent
    string licPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC";
    string keyPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY";

    // Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC");
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY");

    // Read key file content (not the path — the content)
    string key = File.ReadAllText(keyPath);

    // Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key);

    // Verify license is valid for the module you purchased
    if (!RasterSupport.IsLocked(RasterSupportType.Document))
    {
        throw new InvalidOperationException("Document module not licensed");
    }
}
// From leadtools-migration-examples.cs
public void InitializeLicense()
{
    // Option 1: Absolute paths — deployment dependent
    string licPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC";
    string keyPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY";

    // Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC");
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY");

    // Read key file content (not the path — the content)
    string key = File.ReadAllText(keyPath);

    // Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key);

    // Verify license is valid for the module you purchased
    if (!RasterSupport.IsLocked(RasterSupportType.Document))
    {
        throw new InvalidOperationException("Document module not licensed");
    }
}
Imports System
Imports System.IO

Public Sub InitializeLicense()
    ' Option 1: Absolute paths — deployment dependent
    Dim licPath As String = "C:\LEADTOOLS\License\LEADTOOLS.LIC"
    Dim keyPath As String = "C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"

    ' Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC")
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY")

    ' Read key file content (not the path — the content)
    Dim key As String = File.ReadAllText(keyPath)

    ' Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key)

    ' Verify license is valid for the module you purchased
    If Not RasterSupport.IsLocked(RasterSupportType.Document) Then
        Throw New InvalidOperationException("Document module not licensed")
    End If
End Sub
$vbLabelText   $csharpLabel

Es gibt mehrere Fehlerursachen, und jede erfordert eine separate Fehlerbehebung. Die Pfadauflösung verhält sich zwischen IIS und einem Konsolenhost unterschiedlich. Relative Pfade in bin/Debug stimmen nicht mit Pfaden in bin/Release oder in einem Docker-Container überein, es sei denn, Sie ordnen sie explizit zu. Die LIC- und KEY-Dateien müssen aus demselben Download stammen – Dateien aus verschiedenen Downloads führen zu einem Fehler "Schlüssel stimmt nicht mit der Lizenzdatei überein". Wenn die Lizenz nur das Dokumentenpaket abdeckt, der Code aber eine Funktion aus dem Erkennungspaket verwendet, gibt IsLocked() false zurück, und die Anwendung muss die Diskrepanz beim Start behandeln.

Häufige Fehler in der Produktion:

  • "License file not found at specified path" — Pfad zum falschen Verzeichnis aufgelöst
  • "License key does not match license file" — Dateien aus verschiedenen Downloads oder beim Übertragen beschädigt
  • "Document module not licensed" — falsches Paket gekauft
  • "License has expired" — Testlizenz abgelaufen oder Wartungsvertrag abgelaufen

IronOCR-Ansatz

Die IronOCR Lizenzierung ist eine einzelne Zeichenkettenzuweisung. Keine Dateien, keine Pfadauflösung, keine Zwei-Teile-Verifizierung:

// From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY";

// Production: pull from environment variable
IronOcr.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration["IronOCR:LicenseKey"];
// From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY";

// Production: pull from environment variable
IronOcr.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration["IronOCR:LicenseKey"];
' From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY"

' Production: pull from environment variable
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")

' Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration("IronOCR:LicenseKey")
$vbLabelText   $csharpLabel

Der Schlüssel kann in Azure Key Vault, AWS Secrets Manager, Kubernetes Secrets oder einer Docker-Umgebungsvariablen gespeichert werden. Es müssen keine Dateien in das Docker-Image aufgenommen werden. Kein CI/CD-Pipeline-Schritt kopiert Lizenzartefakte auf Build-Agenten. Auf der IronOCR -Lizenzseite werden die verfügbaren Stufen direkt und ohne Verkaufsgespräch aufgeführt.

Motorkonfiguration und Ausführlichkeit

Der Codeunterschied zwischen LEADTOOLS und IronOCR für eine einfache OCR-Aufgabe verdeutlicht die API-Philosophie der jeweiligen Bibliothek.

LEADTOOLS-Ansatz

Eine minimale, funktionierende LEADTOOLS-Implementierung (direkt übernommen von leadtools-vs-ironocr-examples.cs) benötigt zehn verschiedene Operationen, bevor Text zurückgegeben wird:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: License files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Codec layer
        _codecs = new RasterCodecs();

        // Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);          // Step 5: Load via codecs
        using var document = _ocrEngine.DocumentManager     // Step 6: Create document
                                       .CreateDocument();
        var page = document.Pages.AddPage(image, null);     // Step 7: Add page
        page.Recognize(null);                               // Step 8: Explicit recognize
        return page.GetText(-1);                            // Step 9: Extract text
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown();  // Step 10: Shutdown before dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: License files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Codec layer
        _codecs = new RasterCodecs();

        // Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);          // Step 5: Load via codecs
        using var document = _ocrEngine.DocumentManager     // Step 6: Create document
                                       .CreateDocument();
        var page = document.Pages.AddPage(image, null);     // Step 7: Add page
        page.Recognize(null);                               // Step 8: Explicit recognize
        return page.GetText(-1);                            // Step 9: Extract text
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown();  // Step 10: Shutdown before dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System.IO

Public Class LeadtoolsOcrService
    Implements IDisposable

    Private _ocrEngine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        ' Step 1: License files
        RasterSupport.SetLicense(
            "C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText("C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"))

        ' Step 2: Codec layer
        _codecs = New RasterCodecs()

        ' Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)

        ' Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, Nothing, Nothing,
            "C:\LEADTOOLS\OCR\OcrRuntime")
    End Sub

    Public Function ExtractText(imagePath As String) As String
        Using image = _codecs.Load(imagePath) ' Step 5: Load via codecs
            Using document = _ocrEngine.DocumentManager ' Step 6: Create document
                                           .CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing) ' Step 7: Add page
                page.Recognize(Nothing) ' Step 8: Explicit recognize
                Return page.GetText(-1) ' Step 9: Extract text
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        _ocrEngine?.Shutdown() ' Step 10: Shutdown before dispose
        _ocrEngine?.Dispose()
        _codecs?.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

Die Kette DocumentManager.CreateDocument() / Pages.AddPage() / page.Recognize() / page.GetText() ist nicht zusammenklappbar. Jeder Schritt ist ein separater API-Aufruf. Lässt man page.Recognize(null) vor page.GetText(-1) weg, wird ein leerer Text zurückgegeben – die Erkennung wird durch das Hinzufügen einer Seite nicht automatisch ausgelöst.

IronOCR-Ansatz

Die entsprechende IronOCR Implementierung (aus derselben Vergleichsdatei) besteht aus einer einzigen Zeile für die Kernoperation und benötigt kein Lebenszyklusmanagement:

using IronOcr;

public class OcrService
{
    public string ExtractText(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
using IronOcr;

public class OcrService
{
    public string ExtractText(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
Imports IronOcr

Public Class OcrService
    Public Function ExtractText(imagePath As String) As String
        Return New IronTesseract().Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

Für den Produktionseinsatz, bei dem die Instanz IronTesseract über mehrere Aufrufe hinweg wiederverwendet wird:

public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string ExtractText(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string ExtractText(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
Imports IronTesseract

Public Class OcrService
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ExtractText(imagePath As String) As String
        Return _ocr.Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

Kein Startup(), kein Shutdown(), keine Codec-Schicht, kein Dokumentencontainer, kein expliziter Erkennungsaufruf. Die IronTesseract-API-Referenz zeigt die gesamte Oberfläche an. Die Einrichtungsanleitung beschreibt die Konfigurationsoptionen für Produktionsszenarien.

PDF-Verarbeitung

Bei der PDF-OCR wird das seitenweise Rasterisierungsmodell von LEADTOOLS am deutlichsten sichtbar. LEADTOOLS verfügt über keinen nativen PDF-Erkennungspfad – jede PDF-Seite muss als Rasterbild über RasterCodecs geladen, dann zu einem IOcrDocument hinzugefügt, dann einzeln erkannt und anschließend der Text einzeln extrahiert werden.

LEADTOOLS-Ansatz

Von leadtools-pdf-processing.cs, der grundlegende PDF-Workflow:

public string ExtractTextFromPdf(string pdfPath)
{
    var text = new StringBuilder();

    // Get page count first — separate call
    var pdfInfo = _codecs.GetInformation(pdfPath, true);
    int totalPages = pdfInfo.TotalPages;

    using var document = _ocrEngine.DocumentManager.CreateDocument();

    for (int pageNum = 1; pageNum <= totalPages; pageNum++)
    {
        // Load each page as a raster image — must dispose each
        using var pageImage = _codecs.Load(
            pdfPath,
            0,                            // bitsPerPixel
            CodecsLoadByteOrder.BgrOrGray,
            pageNum,                      // firstPage
            pageNum);                     // lastPage

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
public string ExtractTextFromPdf(string pdfPath)
{
    var text = new StringBuilder();

    // Get page count first — separate call
    var pdfInfo = _codecs.GetInformation(pdfPath, true);
    int totalPages = pdfInfo.TotalPages;

    using var document = _ocrEngine.DocumentManager.CreateDocument();

    for (int pageNum = 1; pageNum <= totalPages; pageNum++)
    {
        // Load each page as a raster image — must dispose each
        using var pageImage = _codecs.Load(
            pdfPath,
            0,                            // bitsPerPixel
            CodecsLoadByteOrder.BgrOrGray,
            pageNum,                      // firstPage
            pageNum);                     // lastPage

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
Imports System.Text

Public Function ExtractTextFromPdf(ByVal pdfPath As String) As String
    Dim text As New StringBuilder()

    ' Get page count first — separate call
    Dim pdfInfo = _codecs.GetInformation(pdfPath, True)
    Dim totalPages As Integer = pdfInfo.TotalPages

    Using document = _ocrEngine.DocumentManager.CreateDocument()

        For pageNum As Integer = 1 To totalPages
            ' Load each page as a raster image — must dispose each
            Using pageImage = _codecs.Load(pdfPath, 0, CodecsLoadByteOrder.BgrOrGray, pageNum, pageNum)
                Dim page = document.Pages.AddPage(pageImage, Nothing)
                page.Recognize(Nothing)
                text.AppendLine(page.GetText(-1))
            End Using
        Next
    End Using

    Return text.ToString()
End Function
$vbLabelText   $csharpLabel

Die Verarbeitung einer passwortgeschützten PDF-Datei führt zu einer weiteren Abhängigkeit. Von leadtools-pdf-processing.cs:

// Requires Leadtools.Pdf module — additional license
using Leadtools.Pdf;

public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    var pdfFile = new PDFFile(pdfPath);
    pdfFile.Password = password;

    var loadOptions = new CodecsLoadOptions();
    _codecs.Options.Pdf.Load.Password = password;
    // ... same page iteration loop follows
}
// Requires Leadtools.Pdf module — additional license
using Leadtools.Pdf;

public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    var pdfFile = new PDFFile(pdfPath);
    pdfFile.Password = password;

    var loadOptions = new CodecsLoadOptions();
    _codecs.Options.Pdf.Load.Password = password;
    // ... same page iteration loop follows
}
Imports Leadtools.Pdf

Public Function ExtractFromEncryptedPdf(ByVal pdfPath As String, ByVal password As String) As String
    Dim pdfFile As New PDFFile(pdfPath)
    pdfFile.Password = password

    Dim loadOptions As New CodecsLoadOptions()
    _codecs.Options.Pdf.Load.Password = password
    ' ... same page iteration loop follows
End Function
$vbLabelText   $csharpLabel

Der Namespace Leadtools.Pdf ist ein separates Modul. Wenn das Entwicklerteam das OCR-Modul, aber nicht das PDF-Modul erworben hat, ist die Unterstützung für verschlüsselte PDFs ohne den Kauf einer separaten Lizenz nicht verfügbar.

Für die Erstellung einer durchsuchbaren PDF-Ausgabe muss vor dem Speichern ein DocumentWriter konfiguriert werden:

// From leadtools-pdf-processing.cs
var pdfOptions = new PdfDocumentOptions
{
    DocumentType = PdfDocumentType.Pdf,
    ImageOverText = true,
    Linearized = false,
    Title = Path.GetFileNameWithoutExtension(inputPdfPath)
};

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
document.Save(outputPdfPath, DocumentFormat.Pdf, null);
// From leadtools-pdf-processing.cs
var pdfOptions = new PdfDocumentOptions
{
    DocumentType = PdfDocumentType.Pdf,
    ImageOverText = true,
    Linearized = false,
    Title = Path.GetFileNameWithoutExtension(inputPdfPath)
};

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
document.Save(outputPdfPath, DocumentFormat.Pdf, null);
Imports System.IO

Dim pdfOptions As New PdfDocumentOptions With {
    .DocumentType = PdfDocumentType.Pdf,
    .ImageOverText = True,
    .Linearized = False,
    .Title = Path.GetFileNameWithoutExtension(inputPdfPath)
}

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions)
document.Save(outputPdfPath, DocumentFormat.Pdf, Nothing)
$vbLabelText   $csharpLabel

IronOCR-Ansatz

IronOCR verarbeitet PDFs nativ. Die gleichen drei Szenarien – einfaches PDF, passwortgeschütztes PDF und durchsuchbares PDF – reduzieren sich jeweils auf zwei bis drei Zeilen:

using IronOcr;

// Basic PDF — all pages, automatic handling
public string ExtractTextFromPdf(string pdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return new IronTesseract().Read(input).Text;
}

// Password-protected PDF — no additional module required
public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return new IronTesseract().Read(input).Text;
}

// Durchsuchbare PDF-Ausgabe — one method call
public void CreateSearchablePdf(string inputPdfPath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(inputPdfPath);
    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
using IronOcr;

// Basic PDF — all pages, automatic handling
public string ExtractTextFromPdf(string pdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return new IronTesseract().Read(input).Text;
}

// Password-protected PDF — no additional module required
public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return new IronTesseract().Read(input).Text;
}

// Durchsuchbare PDF-Ausgabe — one method call
public void CreateSearchablePdf(string inputPdfPath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(inputPdfPath);
    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
Imports IronOcr

' Basic PDF — all pages, automatic handling
Public Function ExtractTextFromPdf(pdfPath As String) As String
    Using input As New OcrInput()
        input.LoadPdf(pdfPath)
        Return New IronTesseract().Read(input).Text
    End Using
End Function

' Password-protected PDF — no additional module required
Public Function ExtractFromEncryptedPdf(pdfPath As String, password As String) As String
    Using input As New OcrInput()
        input.LoadPdf(pdfPath, Password:=password)
        Return New IronTesseract().Read(input).Text
    End Using
End Function

' Durchsuchbare PDF-Ausgabe — one method call
Public Sub CreateSearchablePdf(inputPdfPath As String, outputPdfPath As String)
    Using input As New OcrInput()
        input.LoadPdf(inputPdfPath)
        Dim result = New IronTesseract().Read(input)
        result.SaveAsSearchablePdf(outputPdfPath)
    End Using
End Sub
$vbLabelText   $csharpLabel

Der PDF-Eingabeleitfaden behandelt die Auswahl des Seitenbereichs, die Eingabe von Datenströmen und den Zugriff auf die Ergebnisse pro Seite. Das durchsuchbare PDF-Beispiel zeigt den kompletten Ausgabeworkflow. Informationen zur Vorverarbeitung von gescannten PDFs mit geringer Qualität vor der Bilderkennung finden Sie im Leitfaden zur Bildqualitätskorrektur .

Vorverarbeitung: Manuelle Befehle vs. integrierte Filter

LEADTOOLS stellt Bildverarbeitungsbefehle über einen separaten Leadtools.ImageProcessing Namespace bereit. Diese Befehle müssen einzeln auf jede RasterImage Instanz angewendet werden, bevor das Bild an die OCR-Engine übergeben wird.

LEADTOOLS-Ansatz

Von leadtools-pdf-processing.cs, Vorverarbeitung einer PDF-Seite:

using Leadtools.ImageProcessing;

public string ProcessLowQualityPdf(string pdfPath)
{
    var text = new StringBuilder();
    var pdfInfo = _codecs.GetInformation(pdfPath, true);

    using var document = _engine.DocumentManager.CreateDocument();

    for (int i = 1; i <= pdfInfo.TotalPages; i++)
    {
        using var pageImage = _codecs.Load(pdfPath, 0,
            CodecsLoadByteOrder.BgrOrGray, i, i);

        // Each command is a separate instantiation and Run() call
        var deskewCommand = new DeskewCommand();
        deskewCommand.Run(pageImage);

        var despeckleCommand = new DespeckleCommand();
        despeckleCommand.Run(pageImage);

        if (pageImage.BitsPerPixel > 8)
        {
            var grayscaleCommand = new GrayscaleCommand(8);
            grayscaleCommand.Run(pageImage);
        }

        var binarizeCommand = new AutoBinarizeCommand();
        binarizeCommand.Run(pageImage);

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
using Leadtools.ImageProcessing;

public string ProcessLowQualityPdf(string pdfPath)
{
    var text = new StringBuilder();
    var pdfInfo = _codecs.GetInformation(pdfPath, true);

    using var document = _engine.DocumentManager.CreateDocument();

    for (int i = 1; i <= pdfInfo.TotalPages; i++)
    {
        using var pageImage = _codecs.Load(pdfPath, 0,
            CodecsLoadByteOrder.BgrOrGray, i, i);

        // Each command is a separate instantiation and Run() call
        var deskewCommand = new DeskewCommand();
        deskewCommand.Run(pageImage);

        var despeckleCommand = new DespeckleCommand();
        despeckleCommand.Run(pageImage);

        if (pageImage.BitsPerPixel > 8)
        {
            var grayscaleCommand = new GrayscaleCommand(8);
            grayscaleCommand.Run(pageImage);
        }

        var binarizeCommand = new AutoBinarizeCommand();
        binarizeCommand.Run(pageImage);

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
Imports Leadtools.ImageProcessing
Imports System.Text

Public Function ProcessLowQualityPdf(pdfPath As String) As String
    Dim text As New StringBuilder()
    Dim pdfInfo = _codecs.GetInformation(pdfPath, True)

    Using document = _engine.DocumentManager.CreateDocument()
        For i As Integer = 1 To pdfInfo.TotalPages
            Using pageImage = _codecs.Load(pdfPath, 0, CodecsLoadByteOrder.BgrOrGray, i, i)
                ' Each command is a separate instantiation and Run() call
                Dim deskewCommand As New DeskewCommand()
                deskewCommand.Run(pageImage)

                Dim despeckleCommand As New DespeckleCommand()
                despeckleCommand.Run(pageImage)

                If pageImage.BitsPerPixel > 8 Then
                    Dim grayscaleCommand As New GrayscaleCommand(8)
                    grayscaleCommand.Run(pageImage)
                End If

                Dim binarizeCommand As New AutoBinarizeCommand()
                binarizeCommand.Run(pageImage)

                Dim page = document.Pages.AddPage(pageImage, Nothing)
                page.Recognize(Nothing)
                text.AppendLine(page.GetText(-1))
            End Using
        Next
    End Using

    Return text.ToString()
End Function
$vbLabelText   $csharpLabel

Jeder Vorverarbeitungsschritt erfordert das Instanziieren einer Befehlsklasse und den Aufruf von .Run() für das Bild. Der Entwickler verwaltet die Reihenfolge und Anwendbarkeit jeder Transformation. Wenn das Bild bereits binär ist, kann AutoBinarizeCommand die Qualität beeinträchtigen. Die Überprüfung der Bedingung BitsPerPixel liegt in der Verantwortung des Entwicklers.

IronOCR-Ansatz

Die IronOCR Vorverarbeitung wird auf das Objekt OcrInput angewendet und betrifft alle geladenen Seiten gleichzeitig:

using IronOcr;

public string ProcessLowQualityPdf(string pdfPath)
{
    var ocr = new IronTesseract();

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

    // Applied to all pages
    input.Deskew();
    input.DeNoise();
    input.Binarize();
    input.Contrast();
    input.EnhanceResolution(300);

    var result = ocr.Read(input);
    Console.WriteLine($"Confidence: {result.Confidence}%");
    return result.Text;
}
using IronOcr;

public string ProcessLowQualityPdf(string pdfPath)
{
    var ocr = new IronTesseract();

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

    // Applied to all pages
    input.Deskew();
    input.DeNoise();
    input.Binarize();
    input.Contrast();
    input.EnhanceResolution(300);

    var result = ocr.Read(input);
    Console.WriteLine($"Confidence: {result.Confidence}%");
    return result.Text;
}
Imports IronOcr

Public Function ProcessLowQualityPdf(pdfPath As String) As String
    Dim ocr = New IronTesseract()

    Using input As New OcrInput()
        input.LoadPdf(pdfPath)

        ' Applied to all pages
        input.Deskew()
        input.DeNoise()
        input.Binarize()
        input.Contrast()
        input.EnhanceResolution(300)

        Dim result = ocr.Read(input)
        Console.WriteLine($"Confidence: {result.Confidence}%")
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

Fünf Vorverarbeitungsschritte, die einheitlich auf alle Seiten angewendet werden, ohne seitenweise Schleife. Die automatische Vorverarbeitung von IronOCR wird standardmäßig bei jedem Read()-Aufruf ausgeführt und behebt häufige Scanprobleme ohne explizite Filteraufrufe. Das Tutorial zu Bildfiltern behandelt den gesamten Filterkatalog. Das Beispiel eines Scans mit geringer Qualität zeigt den Vor- und Nachher-Vergleich schwieriger Dokumente.

API-Mapping-Referenz

LEADTOOLS API IronOCR-Äquivalent
RasterSupport.SetLicense(licPath, key) IronOcr.License.LicenseKey = "key"
RasterCodecs OcrInput
_codecs.Load(path) input.LoadImage(path) oder input.LoadPdf(path)
_codecs.GetInformation(path, true).TotalPages Automatisch – keine Seitenzählung erforderlich
OcrEngineManager.CreateEngine(OcrEngineType.LEAD) new IronTesseract()
engine.Startup(_codecs, null, null, runtimePath) Nicht erforderlich
engine.Shutdown() Nicht erforderlich
engine.DocumentManager.CreateDocument() Nicht erforderlich
document.Pages.AddPage(image, null) input.LoadImage(path)
page.Recognize(null) ocr.Read(input) (Erkennung ist Teil von Read)
page.GetText(-1) result.Text
page.RecognizeStatus result.Confidence
OcrZone mit Bounds = new LeadRect(x, y, w, h) new CropRectangle(x, y, w, h) wurde an input.LoadImage() weitergeleitet.
OcrZoneType.Text Standardmäßig – keine Typangabe erforderlich
page.Zones.Add(zone) input.LoadImage(path, cropRect)
DeskewCommand().Run(image) input.Deskew()
DespeckleCommand().Run(image) input.DeNoise()
AutoBinarizeCommand().Run(image) input.Binarize()
PdfDocumentOptions { ImageOverText = true } Bearbeitet von result.SaveAsSearchablePdf()
_engine.DocumentWriterInstance.SetOptions(...) Nicht erforderlich
document.Save(path, DocumentFormat.Pdf, null) result.SaveAsSearchablePdf(path)
CodecsLoadByteOrder.BgrOrGray Nicht erforderlich – wird automatisch erledigt
_codecs.Options.Pdf.Load.Password = password input.LoadPdf(path, Password: password)

Wenn Teams einen Wechsel von LEADTOOLS OCRzu IronOCR erwägen

Das OCR-Projekt, das kein Imaging Toolkit benötigt

LEADTOOLS ist aus finanzieller und architektonischer Sicht sinnvoll, wenn ein Team mehrere Module benötigt – Dokumentenbetrachter, medizinische Bildgebung, Formularerkennung und OCR, die in einer integrierten Plattform zusammenarbeiten. Wenn es um die Extraktion von Text aus Bildern und PDFs geht, ändert sich die Berechnung. LEADTOOLS-Lizenzierungskosten erfordern ein Verkaufsengagement für Angebote — kontaktieren Sie LEADTOOLS für aktuelle Preise. Zusätzlich zu den Lizenzkosten ist eine jährliche Wartung erforderlich.IronOCR bei $2,999 für die Professional-Stufe umfasst 10 Entwickler ohne Erneuerungsanforderung für die fortgesetzte Nutzung. Teams, die am Ende eines LEADTOOLS-Verlängerungszyklus angelangt sind und die Kosten neu bewerten, stellen oft fest, dass das OCR-Modul das Einzige aus dem Paket war, das sie genutzt haben.

Containerisierte und serverlose Bereitstellungen

Die dateibasierte Lizenzierung von LEADTOOLS stellt in modernen Bereitstellungsarchitekturen einen aktiven Reibungspunkt dar. Ein Docker-Container benötigt zwei physische Lizenzdateien, die entweder in das Image eingebunden werden – wodurch sie in der Layer-Historie sichtbar werden – oder zur Laufzeit mit Volume-Koordination in jeder Orchestrierungsumgebung eingebunden werden. Azure Functions und AWS Lambda bieten keinen offensichtlichen Mechanismus für die Bereitstellung von Lizenzdateien ohne Workarounds. LEADTOOLS führt außerdem einen blockierenden Engine-Start durch, der Laufzeitdateien in den Speicher lädt, was die Kaltstartzeit um 500–2000 ms verlängert – was insbesondere für serverlose Funktionen relevant ist, da sich Latenzzeiten direkt auf die Benutzererfahrung auswirken.IronOCR wird als Standard NuGet Referenz bereitgestellt, legt einen Lizenzschlüssel aus einer Umgebungsvariablen fest und wird bei der ersten Verwendung verzögert initialisiert. Der Docker-Bereitstellungsleitfaden und der AWS-Bereitstellungsleitfaden beschreiben die Besonderheiten gängiger containerisierter Szenarien.

Das Problem mit dem falschen Paket

Die Modulstruktur von LEADTOOLS schafft eine Problemkategorie, die IronOCR nicht hat: den Kauf des falschen Tarifs. OCR ist nicht in jedem LEADTOOLS-Paket enthalten. Die Unterstützung passwortgeschützter PDFs erfordert ein separates PDF-Modul, das nicht Bestandteil jeder OCR-fokussierten Lizenz ist. Die Option für eine höhere Genauigkeit der Engine erfordert zusätzlich zum Kauf von LEADTOOLS eine separate Vereinbarung mit dem Anbieter. Teams, die davon ausgingen, dass ihr Kauf eine benötigte Funktion abdeckt – und erst zur Laufzeit in der Produktion feststellten, dass dem nicht so ist –, müssen mit dem Vertrieb neu verhandeln, bevor die Funktion aktiviert werden kann.IronOCR-Lizenzen decken alle Funktionen jeder Stufe ab. Es gibt kein separates PDF-Modul, kein Add-on für passwortgeschützte Dokumente und keinen Zweitanbieter für eine präzisere Engine.

Komplexität der Instandhaltung und des Ressourcenmanagements

Der Lebenszyklus des LEADTOOLS-Motors ist nicht nur eine Einrichtungszeremonie – er schafft eine kontinuierliche Wartungsoberfläche. Der Motor muss in der richtigen Reihenfolge gestartet, benutzt, abgestellt und anschließend entsorgt werden; Abweichungen von dieser Reihenfolge führen zu Fehlern. Speicherlecks in LEADTOOLS-Stapelverarbeitungsimplementierungen lassen sich typischerweise auf nicht freigegebene Zwischenbildobjekte, nach der Verarbeitung geöffnete Dokumentcontainer oder mehrfach erstellte Engine-Instanzen ohne ordnungsgemäße Bereinigung zurückführen. Produktionsbasierte Stapelverarbeitungsprogramme verwenden häufig erzwungene Garbage-Collection-Aufrufe zwischen Dokumentblöcken als Kompensationsmechanismus – ein Muster, das darauf hindeutet, dass das zugrundeliegende Objektmodell mit der Laufzeitumgebung in Konflikt gerät. Teams, die nachts um 2 Uhr Speicherwachstum in einem Dokumentenverarbeitungsdienst debuggen, finden die Ursache oft im LEADTOOLS-Freigabemuster.IronOCR verwendet die standardmäßigen .NET -Disposal-Scopes. Nur der Eingabecontainer muss explizit freigegeben werden. Der Motor selbst ist zustandslos und threadsicher.

Konsistenz bei der Bereitstellung in mehreren Umgebungen

Entwicklungs-, Test- und Produktionsumgebungen benötigen LEADTOOLS-Lizenzdateien in einheitlichen Pfaden Plus ein Laufzeitverzeichnis unter dem exakten Pfad, den die Anwendung beim Start erwartet. Eine Diskrepanz zwischen den Umgebungen – beispielsweise ein Testserver, dessen Laufzeitverzeichnispfad sich vom Produktionsserver um einen einzigen Laufwerksbuchstaben unterscheidet – führt zu einem umgebungsspezifischen Fehler, der eine Code- oder Konfigurationsänderung zur Behebung erfordert. Der Lizenzschlüssel von IronOCR und das zugehörige NuGet Paket verhalten sich in allen Umgebungen identisch. Der Lizenzschlüssel ist der einzige umgebungsspezifische Wert und folgt den gleichen Geheimnisverwaltungsmustern, die jedes .NET Team bereits für Datenbankverbindungszeichenfolgen und API-Schlüssel verwendet.

Gemeinsame Überlegungen zur Migration

Motorlebenszyklus-Entfernung

LEADTOOLS-Code umschließt die Engine in einer Dienstklasse, die IDisposable implementiert, genau weil der Lebenszyklus verwaltet werden muss. Durch die Migration entfällt diese Anforderung vollständig:

// LEADTOOLS: Service class required for lifecycle management
public class LeadtoolsService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;

    public LeadtoolsService()
    {
        RasterSupport.SetLicense(licPath, key);
        _codecs = new RasterCodecs();
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);
        _engine.Startup(_codecs, null, null, runtimePath);
    }

    public string Process(string path)
    {
        using var image = _codecs.Load(path);
        using var doc = _engine.DocumentManager.CreateDocument();
        var page = doc.Pages.AddPage(image, null);
        page.Recognize(null);
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _engine?.Shutdown();
        _engine?.Dispose();
        _codecs?.Dispose();
    }
}

// IronOCR:Neinlifecycle to manage
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string Process(string path) => _ocr.Read(path).Text;
}
// LEADTOOLS: Service class required for lifecycle management
public class LeadtoolsService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;

    public LeadtoolsService()
    {
        RasterSupport.SetLicense(licPath, key);
        _codecs = new RasterCodecs();
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);
        _engine.Startup(_codecs, null, null, runtimePath);
    }

    public string Process(string path)
    {
        using var image = _codecs.Load(path);
        using var doc = _engine.DocumentManager.CreateDocument();
        var page = doc.Pages.AddPage(image, null);
        page.Recognize(null);
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _engine?.Shutdown();
        _engine?.Dispose();
        _codecs?.Dispose();
    }
}

// IronOCR:Neinlifecycle to manage
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string Process(string path) => _ocr.Read(path).Text;
}
Imports System
Imports Leadtools
Imports Leadtools.Codecs
Imports Leadtools.Ocr

' LEADTOOLS: Service class required for lifecycle management
Public Class LeadtoolsService
    Implements IDisposable

    Private _engine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        RasterSupport.SetLicense(licPath, key)
        _codecs = New RasterCodecs()
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)
        _engine.Startup(_codecs, Nothing, Nothing, runtimePath)
    End Sub

    Public Function Process(path As String) As String
        Using image = _codecs.Load(path)
            Using doc = _engine.DocumentManager.CreateDocument()
                Dim page = doc.Pages.AddPage(image, Nothing)
                page.Recognize(Nothing)
                Return page.GetText(-1)
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If _engine IsNot Nothing Then
            _engine.Shutdown()
            _engine.Dispose()
        End If
        If _codecs IsNot Nothing Then
            _codecs.Dispose()
        End If
    End Sub
End Class

' IronOCR: Neinlifecycle to manage
Public Class OcrService

    Private ReadOnly _ocr As New IronTesseract()

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

Die IronTesseract Instanz ist thread-sicher und kann als Singleton geteilt werden. Es ist nicht notwendig, IDisposable in der Dienstklasse zu implementieren, um der Engine Vorteile zu bieten.

Zonenbasierte OCR-Migration

Die LEADTOOLS-Zonenkonfiguration verwendet OcrZone mit LeadRect Grenzen und erfordert das Löschen automatisch erkannter Zonen, bevor benutzerdefinierte hinzugefügt werden.IronOCR verwendet CropRectangle, das direkt an LoadImage() übergeben wird:

// LEADTOOLS zone setup
var zone = new OcrZone
{
    Bounds = new LeadRect(x, y, width, height),
    ZoneType = OcrZoneType.Text,
    CharacterFilters = OcrZoneCharacterFilters.None,
    RecognitionModule = OcrZoneRecognitionModule.Auto
};
page.Zones.Clear();  // Must clear auto-detected zones first
page.Zones.Add(zone);

//IronOCR equivalent
using var input = new OcrInput();
input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
var text = new IronTesseract().Read(input).Text;
// LEADTOOLS zone setup
var zone = new OcrZone
{
    Bounds = new LeadRect(x, y, width, height),
    ZoneType = OcrZoneType.Text,
    CharacterFilters = OcrZoneCharacterFilters.None,
    RecognitionModule = OcrZoneRecognitionModule.Auto
};
page.Zones.Clear();  // Must clear auto-detected zones first
page.Zones.Add(zone);

//IronOCR equivalent
using var input = new OcrInput();
input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
var text = new IronTesseract().Read(input).Text;
Imports Leadtools
Imports IronOcr

' LEADTOOLS zone setup
Dim zone As New OcrZone With {
    .Bounds = New LeadRect(x, y, width, height),
    .ZoneType = OcrZoneType.Text,
    .CharacterFilters = OcrZoneCharacterFilters.None,
    .RecognitionModule = OcrZoneRecognitionModule.Auto
}
page.Zones.Clear() ' Must clear auto-detected zones first
page.Zones.Add(zone)

' IronOCR equivalent
Using input As New OcrInput()
    input.LoadImage(imagePath, New CropRectangle(x, y, width, height))
    Dim text As String = New IronTesseract().Read(input).Text
End Using
$vbLabelText   $csharpLabel

Der regionsbasierte OCR-Leitfaden umfasst Extraktionsmuster für einzelne Regionen und für mehrere Regionen. Das Beispiel des Regionsausschnitts zeigt die Extraktion von Rechnungskopfdaten als praktischen Anwendungsfall.

NuGet -Paketbereinigung

LEADTOOLS benötigt mehrere Pakete. Die Migration entfernt alle diese Elemente und fügt eines hinzu:

# Remove LEADTOOLS packages
dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Pdf

# Add IronOCR
dotnet add package IronOcr
# Remove LEADTOOLS packages
dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Pdf

# Add IronOCR
dotnet add package IronOcr
SHELL

Die Reduzierung des Installationsaufwands ist beträchtlich. Aus der Build-Ausgabe verschwunden: LEADTOOLS.LIC, LEADTOOLS.LIC.KEY, das OcrRuntime/ Verzeichnis, mehrere LEADTOOLS-DLLs und jeder tessdata/ Ordner von der Tesseract-Engine-Option. Was bleibt, ist eine einzelne Paketreferenz. Das IronOCR NuGet Paket enthält alle nativen Abhängigkeiten.

Zugriff auf den Konfidenzwert

LEADTOOLS zeigt die Erkennungsqualität durch page.RecognizeStatus als Enum an (OcrPageRecognizeStatus.Done zeigt den Abschluss an, jedoch nicht den Genauigkeitsgrad).IronOCR bietet einen direkten Prozentsatz über result.Confidence:

var result = new IronTesseract().Read("document.jpg");
Console.WriteLine($"Confidence: {result.Confidence}%");

// Branch on quality threshold
if (result.Confidence < 60)
{
    // Apply additional preprocessing and retry
    using var input = new OcrInput();
    input.LoadImage("document.jpg");
    input.Deskew();
    input.DeNoise();
    input.EnhanceResolution(300);
    result = new IronTesseract().Read(input);
}
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine($"Confidence: {result.Confidence}%");

// Branch on quality threshold
if (result.Confidence < 60)
{
    // Apply additional preprocessing and retry
    using var input = new OcrInput();
    input.LoadImage("document.jpg");
    input.Deskew();
    input.DeNoise();
    input.EnhanceResolution(300);
    result = new IronTesseract().Read(input);
}
Imports System
Imports IronOcr

Dim result = New IronTesseract().Read("document.jpg")
Console.WriteLine($"Confidence: {result.Confidence}%")

' Branch on quality threshold
If result.Confidence < 60 Then
    ' Apply additional preprocessing and retry
    Using input As New OcrInput()
        input.LoadImage("document.jpg")
        input.Deskew()
        input.DeNoise()
        input.EnhanceResolution(300)
        result = New IronTesseract().Read(input)
    End Using
End If
$vbLabelText   $csharpLabel

Der Leitfaden zu Konfidenzwerten umfasst die Auswahl von Schwellenwerten und qualitätsbasierte Wiederholungsmuster.

Zusätzliche Funktionen von IronOCR

Über die oben genannten Vergleichspunkte hinaus bietet IronOCR Funktionen, die entweder in LEADTOOLS OCRfehlen oder den Kauf zusätzlicher Module erfordern:

  • Barcode-Erkennung während OCR: Setzen Sie ocr.Configuration.ReadBarCodes = true und Barcodes werden neben dem Text in einem einzigen Read() Durchgang extrahiert. Für das LEADTOOLS Barcode-Modul ist keine separate Lizenz erforderlich. Siehe die Anleitung zum Lesen von Barcodes und das Beispiel für Barcode-OCR .
  • Strukturierte Datenerfassung: result.Pages, result.Paragraphs, result.Lines, result.Words, und result.Characters zeigen die gesamte Dokumentenhierarchie mit Begrenzungsrahmen und vertrauenswürdigen Punktzahlen pro Element. Der Leitfaden zu den Leseergebnissen beschreibt das vollständige Ausgabemodell.
  • hOCR-Export: result.SaveAsHocrFile() erzeugt HTML mit eingebetteten Positionsdaten für die nachgelagerte Layoutanalyse. Siehe den hOCR-Exportleitfaden .
  • Unterstützung für mehr als 125 Sprachen: Jede Sprache ist ein NuGet Paket. Kein tessdata-Verzeichnis, keine Dateipfadkonfiguration. Das vollständige Sprachverzeichnis und den Leitfaden für mehrere Sprachen finden Sie hier.
  • Asynchrones OCR: await ocr.ReadAsync(input) für nicht blockierende Dokumentenverarbeitung in ASP.NET und Hintergrunddiensten. Siehe den Leitfaden zur asynchronen OCR .
  • Spezielle Dokumentenerkennung: Integrierte Unterstützung für Pässe, Kfz-Kennzeichen, MICR-Schecks und Handschrift. Siehe die Seite mit den speziellen Funktionen .
  • Fortschrittsverfolgung: ocr.Configuration.ProgressCallback berichtet über seitenweise Fortschritte bei langen Batch-Jobs. Siehe die Anleitung zur Fortschrittsverfolgung .

.NET-Kompatibilität und Zukunftsfähigkeit

IronOCR zielt auf .NET 6, .NET 7, .NET 8, .NET 9 und .NET Standard 2.0 ab – letzteres umfasst .NET Framework 4.6.2 und höher. Die plattformübergreifende Unterstützung umfasst Windows (x86 und x64), Linuxx64, macOS, Azure App Service, AWS Lambda und Docker, wobei alle nativen Abhängigkeiten im NuGet Paket enthalten sind. Es ist keine plattformspezifische Konfiguration erforderlich; Das Paket wählt zur Laufzeit die korrekte native Binärdatei aus. LEADTOOLS unterstützt die plattformübergreifende .NET Bereitstellung, benötigt jedoch plattformspezifische Laufzeitdateien und die entsprechende Pfadkonfiguration für jede Zielumgebung. Für Teams, die neben Windows-Produktionsservern auch Linux-Container oder macOS-Entwicklungsmaschinen einsetzen, entfällt durch die Einzelpaketbereitstellung von IronOCR die plattformspezifische Konfigurationsebene.

Abschluss

LEADTOOLS OCR ist eine ausgereifte Technologie innerhalb einer umfassenden Bildverarbeitungsplattform, auf deren Entwicklung 35 Jahre zurückblicken. Für Organisationen, die LEADTOOLS bereits als Standard für Dokumentenanzeige, medizinische Bildgebung oder Formularerkennung nutzen, ist die Hinzunahme von OCR zu dieser bestehenden Investition eine sinnvolle Entscheidung – der Integrationsaufwand ist bereits bezahlt, und die einheitliche API-Oberfläche bietet einen Mehrwert.

Für Teams, deren Anforderung die Extraktion von Text aus Bildern und PDFs ist, sieht die Berechnung anders aus. Die vierstufige Initialisierungssequenz von LEADTOOLS, die dateibasierte Lizenzbereitstellung, die separate Codec-Schicht und der explizite Engine-Lebenszyklus sind keine Komplexitäten, die OCR-Genauigkeit oder -Fähigkeit liefern. Es handelt sich um Infrastruktur-Overhead, den jeder Entwickler im Team verstehen muss, den jede Bereitstellungsumgebung berücksichtigen muss und den jede CI/CD-Pipeline mit sich bringen muss. Der Kauf des falschen Pakets – beispielsweise eines OCR-Moduls ohne das PDF-Modul oder der LEAD-Engine ohne die OmniPage-Genauigkeitsstufe – führt zu stillen Fehlern, die erst im Produktivbetrieb und nicht schon beim Kauf sichtbar werden.

IronOCRs einzelnes NuGet Paket, die stringbasierte Lizenzierung und der einzeilige Erkennungspfad eliminieren diesen Overhead, ohne die für die produktive OCR wichtigen Funktionen zu beeinträchtigen: automatische Vorverarbeitung, native PDF-Unterstützung, Verarbeitung passwortgeschützter Dokumente, strukturierte Ausgabeextraktion, Unterstützung von mehr als 125 Sprachen und threadsichere Parallelverarbeitung. Der Preisunterschied — $2,999 dauerhaft im Vergleich zu LEADTOOLS' mehrjährigen Lizenz- und Wartungsgebühren — ist signifikant. Es ist der Unterschied zwischen dem einmaligen Kauf eines Ingenieurwerkzeugs und einem laufenden Abonnement, das eine jährliche Budgetbegründung erfordert.

Das anfängliche Problem – Lizenzdateien auf jedem Produktionssystem, Verwirrung bei der Paketverwaltung und eine Initialisierungszeremonie, bevor ein Zeichen gelesen wird – spiegelt die tatsächlichen Bereitstellungs- und Betriebskosten wider. Teams, die beide Optionen evaluieren, sollten die LEADTOOLS-Initialisierungssequenz vor der endgültigen Entscheidung mit ihrer Containerstrategie, ihrer CI/CD-Pipeline und ihrem Geheimnismanagement-Ansatz abgleichen. Die Antwort klärt oft die Entscheidung.

Hinweis:Kofax OmniPage, LEADTOOLS und Tesseract sind eingetragene Marken ihrer jeweiligen Inhaber. Diese Seite ist nicht mit, von oder durch Apryse, Google, Kofax oder LEAD Technologies gefördert oder gesponsert. Alle Produktnamen, Logos und Marken sind Eigentum ihrer jeweiligen Eigentümer. Vergleiche dienen nur zu Informationszwecken und spiegeln öffentlich zugängliche Informationen zum Zeitpunkt des Schreibens wider.

Häufig gestellte Fragen

Was ist LEADTOOLS OCR?

LEADTOOLS OCR ist eine OCR-Lösung, die von Entwicklern und Unternehmen zur Extraktion von Text aus Bildern und Dokumenten verwendet wird. Sie ist eine von mehreren OCR-Optionen, die neben IronOCR for .NET Application Development evaluiert wurden.

Wie ist IronOCR im Vergleich zu LEADTOOLS OCR for .NET-Entwicklern?

IronOCR ist eine NuGet-native OCR-Bibliothek für .NET, die IronTesseract als Kern-Engine verwendet. Im Vergleich zu LEADTOOLS OCR bietet sie eine einfachere Bereitstellung (keine SDK-Installationsprogramme), Pauschalpreise und eine saubere C#-API ohne COM-Interop oder Cloud-Abhängigkeiten.

Ist IronOCR einfacher einzurichten als LEADTOOLS OCR?

IronOCR wird über ein einziges NuGet-Paket installiert. Es gibt keine SDK-Installationsprogramme, keine Lizenzdateien, die kopiert werden müssen, keine COM-Komponenten, die registriert werden müssen, und keine separaten Laufzeit-Binärdateien, die verwaltet werden müssen. Die gesamte OCR-Engine ist in diesem Paket enthalten.

Welche Genauigkeitsunterschiede gibt es zwischen LEADTOOLS OCR und IronOCR?

IronOCR erreicht eine hohe Erkennungsgenauigkeit für Standardgeschäftsdokumente, Rechnungen, Quittungen und gescannte Formulare. Bei stark degradierten Dokumenten oder ungewöhnlichen Skripten variiert die Genauigkeit je nach Qualität der Quelle. IronOCR enthält Bildvorverarbeitungsfilter zur Verbesserung der Erkennung bei Eingaben von geringer Qualität.

Unterstützt IronOCR die PDF-Textextraktion?

Ja, IronOCR extrahiert Text sowohl aus nativen PDF-Dateien als auch aus gescannten PDF-Bildern in einem einzigen Aufruf. Es unterstützt auch mehrseitige TIFF-Dateien, Bilder und Streams. Bei gescannten PDFs wird die OCR seitenweise mit seitenweisen Ergebnisobjekten angewendet.

Wie ist die Lizenzierung von LEADTOOLS OCR im Vergleich zu IronOCR?

IronOCR verwendet eine unbefristete Pauschallizenz, bei der keine Gebühren pro Seite oder pro Scan anfallen. Unternehmen, die große Dokumentenmengen verarbeiten, zahlen unabhängig vom Volumen die gleichen Lizenzkosten. Einzelheiten und Volumenpreise finden Sie auf der IronOCR-Lizenzierungsseite.

Welche Sprachen unterstützt IronOCR?

IronOCR unterstützt 127 Sprachen über separate NuGet-Sprachpakete. Das Hinzufügen einer Sprache erfordert einen einzigen Befehl 'dotnet add package IronOcr.Languages.{Language}'. Es ist keine manuelle Dateiablage oder Pfadkonfiguration erforderlich.

Wie installiere ich IronOCR in einem .NET -Projekt?

Installation über NuGet: 'Install-Package IronOcr' in der Paketmanager-Konsole oder 'dotnet add package IronOcr' in der CLI. Zusätzliche Sprachpakete werden auf die gleiche Weise installiert. Es ist kein natives SDK-Installationsprogramm erforderlich.

Ist IronOCR im Gegensatz zu LEADTOOLS OCR für Docker und containerisierte Implementierungen geeignet?

Ja, IronOCR funktioniert in Docker-Containern über sein NuGet-Paket. Der Lizenzschlüssel wird über eine Umgebungsvariable festgelegt. Für die OCR-Engine selbst sind keine Lizenzdateien, SDK-Pfade oder Volume-Mounts erforderlich.

Kann ich IronOCR im Vergleich zu LEADTOOLS OCR vor dem Kauf ausprobieren?

Ja. Der IronOCR-Testmodus verarbeitet Dokumente und liefert OCR-Ergebnisse mit einem Wasserzeichen als Overlay auf der Ausgabe. Sie können die Genauigkeit an Ihren eigenen Dokumenten überprüfen, bevor Sie eine Lizenz erwerben.

Unterstützt IronOCR neben der Textextraktion auch das Lesen von Barcodes?

IronOCR konzentriert sich auf die Textextraktion und OCR. Für das Lesen von Barcodes bietet Iron Software IronBarcode als Begleitbibliothek an. Beide sind einzeln oder als Teil des Iron Suite-Pakets erhältlich.

Ist es einfach, von LEADTOOLS OCR zu IronOCR zu migrieren?

Die Migration von LEADTOOLS OCR zu IronOCR umfasst in der Regel das Ersetzen von Initialisierungssequenzen durch IronTesseract-Instanziierung, das Entfernen des COM-Lifecycle-Managements und die Aktualisierung von API-Aufrufen. Die meisten Migrationen reduzieren die Komplexität des Codes erheblich.

Kannaopat Udonpant
Software Ingenieur
Bevor er Software-Ingenieur wurde, absolvierte Kannapat ein PhD in Umweltressourcen an der Hokkaido University in Japan. Während seines Studiums wurde Kannapat auch Mitglied des Vehicle Robotics Laboratory, das Teil der Fakultät für Bioproduktionstechnik ist. Im Jahr 2022 nutzte er seine C#-Kenntnisse, um dem Engineering-Team von Iron Software ...
Weiterlesen

Iron-Support-Team

Wir sind 24 Stunden am Tag, 5 Tage die Woche online.
Chat
E-Mail
Rufen Sie mich an