IRONSOFTWAREHOME
VIDEOS

Wie man OCR in NET Maui durchführt

Kannaopat Udonpant
Kannapat Udonpant
Updated: 28. Juni 2026

Dieser Leitfaden führt .NET -Entwickler durch eine vollständige Migration von LEADTOOLS OCRzu IronOCR . Es deckt jeden Schritt ab, vom Ersetzen von NuGet -Paketen bis zur vollständigen Code-Migration, mit Vorher-Nachher-Beispielen für die Muster, die am stärksten von der Initialisierungszeremonie, der Multi-Namespace-Struktur und dem dateibasierten Lizenzbereitstellungsmodell von LEADTOOLS betroffen sind.

Warum von LEADTOOLS OCRmigrieren?

LEADTOOLS OCR ist in eine Enterprise -Imaging-Plattform integriert, deren Wurzeln bis ins Jahr 1990 zurückreichen, und die API spiegelt diese Herkunft wider. Die minimale Arbeitskonfiguration erfordert vier NuGet Pakete, vier Namespaces, zwei physische Lizenzdateien, die in einem bekannten Pfad bereitgestellt werden, eine Codec-Schicht, die vor der Engine initialisiert wird, die Auswahl eines Engine-Typs aus drei Optionen und einen blockierenden Startaufruf, der Laufzeitbinärdateien in den Speicher lädt. All das geschieht, bevor auch nur ein einziges Zeichen erkannt wird. Teams, die auf IronOCR umsteigen, eliminieren diese gesamte Ebene – ein Paket, ein Namespace, eine Zeile zum Festlegen eines Lizenzschlüssels.

Dateibasiertes Lizenzbereitstellungsproblem in Containern. LEADTOOLS erfordert zwei physische Dateien — LEADTOOLS.LIC und LEADTOOLS.LIC.KEY —, die an einem bestimmten Pfad auf jeder Maschine, auf der die Anwendung läuft, lesbar sein müssen. In Docker-Containern müssen diese Dateien entweder in das Image eingebunden werden (wodurch sie in der Layer-Historie sichtbar werden) oder zur Laufzeit eingebunden werden (was in jeder Orchestrierungsumgebung eine Volume-Koordination erfordert). Azure Functions und AWS Lambda bieten keinen Mechanismus für die Bereitstellung von Lizenzdateien ohne Workarounds. CI/CD-Pipelines benötigen die Dateien unter dem exakten Pfad, der beim Startaufruf verwendet wird, andernfalls löst die Anwendung eine Fehlermeldung aus, bevor sie auch nur ein einziges Dokument verarbeiten kann.IronOCR ersetzt beide Dateien durch eine Zeichenkette, die in eine Umgebungsvariable, ein Kubernetes-Secret oder eine Azure Key Vault-Referenz passt.

Vier Pakete für eine Aufgabe. Ein funktionierendes LEADTOOLS-OCR-Projekt erfordert mindestens Leadtools, Leadtools.Ocr, Leadtools.Codecs und Leadtools.Forms.DocumentWriters. Passwortgeschützte PDF-Unterstützung erfordert ein zusätzliches Leadtools.Pdf-Modul, das möglicherweise nicht im gekauften Bundle enthalten ist. Alle Pakete müssen vorhanden, kompatibel und versioniert sein.IronOCR wird als ein einzelnes NuGet Paket ausgeliefert. Alle Funktionen – native PDF-Eingabe, durchsuchbare PDF-Ausgabe, Vorverarbeitung, Barcode-Lesung – sind enthalten.

Der Lebenszyklus des Motors schafft eine Wartungsoberfläche. LEADTOOLS umschließt den OCR-Motor in einer IDisposable-Dienstklasse, nicht aus idiomatischen .NET-Gründen, sondern weil der Shutdown()-Aufruf Dispose() vorangehen muss, sonst treten Anwendungsfehler auf. Produktionsimplementierungen von LEADTOOLS-Batchprozessoren beinhalten häufig GC.Collect() / GC.WaitForPendingFinalizers()-Aufrufe zwischen Dokumentenstücken, um RasterImage-Instanzen auszugleichen, die sich ansammeln.IronOCR verwendet Standard-using-Blöcke. OcrInput ist das einzige Objekt, das entsorgt werden muss.

Verwirrung um die Paketpreise tritt in der Produktion auf. LEADTOOLS veröffentlicht keine Preise. Das Document Imaging SDK – die Stufe, die OCR beinhaltet – kostet schätzungsweise 3.000 bis 8.000 US-Dollar pro Entwickler und Jahr. Teams, die das OCR-Modul ohne das PDF-Modul gekauft haben, entdecken die Lücke, wenn RasterSupport.IsLocked() bei passwortgeschützten Dokumenten in der Produktion wahr zurückgibt. Für die Genauigkeitsstufe der OmniPage-Engine ist zusätzlich zum Kauf von LEADTOOLS eine separate Kofax-Lizenzvereinbarung erforderlich.IronOCR lizenziert alle Funktionen in jeder Stufe. Es gibt keine sekundäre Lieferantenbeziehung, kein separates Modul für verschlüsselte Dokumente.

Initialisierungskosten beeinflussen Kaltstarts. engine.Startup() ist ein blockierender Aufruf, der Laufzeitdateien in den Speicher lädt. In serverlosen Umgebungen, in denen die Kaltstartlatenz eine Rolle spielt – Azure Functions, AWS Lambda – stellt eine blockierende Initialisierung von 500–2000 ms, bevor überhaupt eine Erkennungsarbeit stattfindet, ein strukturelles Problem dar.IronOCR verwendet verzögerte Initialisierung. Die IronTesseract-Instanz initialisiert sich beim ersten Gebrauch, und nachfolgende Aufrufe im selben Prozess verursachen keine Initialisierungskosten.

Das grundsätzliche Problem

LEADTOOLS benötigt vier Namensräume, vier NuGet Pakete und eine obligatorische Startzeremonie, bevor ein Zeichen erkannt wird:

// LEADTOOLS: Four namespaces, four packages, six steps before recognition
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath)); // Step 1: two files on disk
var codecs = new RasterCodecs();                              // Step 2: codec layer
var engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD); // Step 3: engine factory
engine.Startup(codecs, null, null, runtimePath);              // Step 4: blocking startup
// ... still need to create document, add page, call Recognize(), extract text
C#
// IronOCR: One namespace, one package, one line
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read("document.jpg").Text;
C#

##IronOCR vs. LEADTOOLS OCR: Funktionsvergleich

Die folgende Tabelle stellt die Funktionen der beiden Bibliotheken direkt gegenüber.

FeatureLEADTOOLS OCRIronOCR
Erforderliche NuGet PaketeMindestens 4 (mehr für PDF)1 (IronOcr)
Lizenzmechanismus.LIC + .LIC.KEY DateipaarString-Schlüssel
LizenzbereitstellungDateien auf jeder ProduktionsmaschineUmgebungsvariable oder Konfiguration
Preismodell3.000–15.000+ US-Dollar/Entwickler/Jahr (geschätzt)$999–2.999 $ einmalige unbefristete
MotorinitialisierungManuelles Startup() mit LaufzeitpfadAutomatisch, faul
Motor abgestelltManuelles Shutdown() vor Dispose()Nicht erforderlich
Codec-SchichtRasterCodecs erforderlich für das Laden aller BilderNicht erforderlich
PDF-EingabeSeitenweise RasterisierungsschleifeNatives LoadPdf()
Passwortgeschütztes PDFErfordert separates Leadtools.Pdf-ModulEingebauter Password-Parameter
Durchsuchbare PDF-AusgabeDocumentWriter + PdfDocumentOptions + document.Save()result.SaveAsSearchablePdf()
VorverarbeitungSeparate Befehlsklassen (DeskewCommand, DespeckleCommand, usw.)Eingebaute Filtermethoden auf OcrInput
Mehrseitiges TIFFManuelle Rahmeniteration mit CodecsLoadByteOrderinput.LoadImageFrames()
Strukturierte AusgabeSeiten- und ZonenebeneSeite, Absatz, Zeile, Wort, Zeichen mit Koordinaten
KonfidenzbewertungOcrPageRecognizeStatus Enumresult.Confidence als Prozentsatz
Barcode-LesungSeparates LEADTOOLS Barcode-ModulEingebaut (ReadBarCodes = true)
Thread-SicherheitErfordert sorgfältiges ManagementVoll (ein IronTesseract pro Thread)
Unterstützte Sprachen60–120 (motorabhängig)Mehr als 125 Sprachpakete via NuGet
Sprachbereitstellungtessdata files or engine-bundled filesNuGet Paket pro Sprache
PlattformübergreifendUnterstützt durch plattformspezifische LaufzeitkonfigurationWindows, Linux, macOS, Docker, Azure, AWS
Docker-Bereitstellung.KEY-Dateien müssen gemountet oder gebacken werdenStandard-dotnet publish
Kommerzielle UnterstützungJaJa

Schnellstart: Migration von LEADTOOLS OCRzu IronOCR

Schritt 1: Ersetzen des NuGet-Pakets

Entfernen Sie alle LEADTOOLS-Pakete:

dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Forms.DocumentWriters
dotnet remove package Leadtools.Pdf
SHELL

Installieren Sie IronOCR über NuGet :

dotnet add package IronOcr

Schritt 2: Namespaces aktualisieren

Ersetzen Sie alle LEADTOOLS-using-Direktiven mit einem einzigen IronOCR-Import:

// Before (LEADTOOLS)
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

// After (IronOCR)
using IronOcr;
C#

Schritt 3: Lizenz initialisieren

Entfernen Sie alle RasterSupport.SetLicense()-Aufrufe und die .LIC / .LIC.KEY-Dateireferenzen. Fügen Sie den IronOCR-Lizenzschlüssel beim Start der Anwendung hinzu:

// Single line replaces the entire file-based license setup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Production pattern: pull from environment variable or secrets manager
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
C#

Der Lizenzschlüssel kann in jedem Standard- .NET-Geheimnisverwaltungsmuster gespeichert werden — appsettings.json, Azure Key Vault, AWS Secrets Manager oder ein Kubernetes-Geheimnis. Es müssen keine Dateien zusammen mit der Anwendungsdatei bereitgestellt werden.

Beispiele für die Code-Migration

Entfernung des Motorstart- und -abschaltzyklus

LEADTOOLS schreibt ein striktes Service-Class-Muster vor, da der Lebenszyklus der Engine explizit verwaltet werden muss. Der Konstruktor startet den Motor, Dispose() schaltet ihn in der richtigen Reihenfolge aus, und jeder Codepfad, der Shutdown() vor Dispose() überspringt, erzeugt einen Laufzeitfehler.

LEADTOOLS OCR-Ansatz:

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

// Service class required purely to manage engine lifecycle
public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;
    private readonly string _runtimePath;

    public LeadtoolsOcrService(string licPath, string keyPath, string runtimePath)
    {
        _runtimePath = runtimePath;

        // License setup — two files, both must be present
        RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath));

        // Codec layer — required before engine creation
        _codecs = new RasterCodecs();

        // Engine factory — engine type determines capability and cost
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Blocking startup — loads runtime into memory (500–2000ms)
        _engine.Startup(_codecs, null, null, _runtimePath);
    }

    public bool IsReady => _engine?.IsStarted ?? false;

    public string Process(string imagePath)
    {
        if (!IsReady)
            throw new InvalidOperationException("Engine not started");

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

    public void Dispose()
    {
        // Order is mandatory: Shutdown before Dispose
        if (_engine?.IsStarted == true)
            _engine.Shutdown();

        _engine?.Dispose();
        _codecs?.Dispose();
    }
}
C#

IronOCR Ansatz:

using IronOcr;

// No lifecycle management needed — the service class becomes trivial
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    // Always ready — no IsStarted check needed
    public string Process(string imagePath) => _ocr.Read(imagePath).Text;

    // No Dispose() needed for the engine
    // No Startup(), no Shutdown(), no codec layer
}
C#

Die IronTesseract-Instanz initialisiert sich beim ersten Gebrauch. Keine Konstruktorargumente, kein Laufzeitpfad, kein Startup()-Aufruf. Die oben genannte Dienstklasse muss IDisposable überhaupt nicht implementieren - der Motor ist zustandslos, und die OcrInput-Objekte, die in jedem Read()-Aufruf verwendet werden, verwalten ihre eigene Bereinigung über das Standard-using-Muster. Der IronTesseract-Einrichtungsleitfaden behandelt Konfigurationsoptionen, einschließlich Sprachauswahl und Leistungsoptimierung für Produktionsszenarien.

Stapelverarbeitung von TIFF-Bildern mit mehreren Einzelbildern

LEADTOOLS verarbeitet mehrseitige TIFF-Dateien, indem der Codec nach der gesamten Rahmenanzahl abgefragt wird und dann mit expliziten lastPage-Parametern bei jedem _codecs.Load()-Aufruf iteriert wird. Jedes Einzelbild muss manuell gelöscht werden, sonst füllt sich der Speicherplatz.

LEADTOOLS OCR-Ansatz:

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

public class LeadtoolsTiffBatchService
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public List<string> ProcessMultiFrameTiff(string tiffPath)
    {
        var pageTexts = new List<string>();

        // Must query page count before iterating
        var info = _codecs.GetInformation(tiffPath, true);
        int frameCount = info.TotalPages;

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

        for (int frameNum = 1; frameNum <= frameCount; frameNum++)
        {
            // Load one frame at a time — must specify firstPage/lastPage
            using var frameImage = _codecs.Load(
                tiffPath,
                0,                            // bitsPerPixel
                CodecsLoadByteOrder.BgrOrGray,
                frameNum,                     // firstPage
                frameNum);                    // lastPage

            var page = document.Pages.AddPage(frameImage, null);
            page.Recognize(null);
            pageTexts.Add(page.GetText(-1));

            // GC pressure accumulates if disposal is missed on any frame
        }

        return pageTexts;
    }

    public Dictionary<string, List<string>> ProcessTiffDirectory(string directoryPath)
    {
        var results = new Dictionary<string, List<string>>();

        foreach (var tiffFile in Directory.GetFiles(directoryPath, "*.tiff"))
        {
            results[tiffFile] = ProcessMultiFrameTiff(tiffFile);

            // Manual GC between files to prevent memory growth
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        return results;
    }
}
C#

IronOCR Ansatz:

using IronOcr;

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

    public List<string> ProcessMultiFrameTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // All frames loaded automatically

        var result = _ocr.Read(input);

        // Per-frame text available through result.Pages
        return result.Pages.Select(p => p.Text).ToList();
    }

    public Dictionary<string, List<string>> ProcessTiffDirectory(string directoryPath)
    {
        var results = new Dictionary<string, List<string>>();

        foreach (var tiffFile in Directory.GetFiles(directoryPath, "*.tiff"))
        {
            results[tiffFile] = ProcessMultiFrameTiff(tiffFile);
        }

        return results;
    }

    // Parallel processing across files — thread-safe out of the box
    public Dictionary<string, List<string>> ProcessTiffDirectoryParallel(string directoryPath)
    {
        var concurrentResults = new System.Collections.Concurrent.ConcurrentDictionary<string, List<string>>();
        var tiffFiles = Directory.GetFiles(directoryPath, "*.tiff");

        Parallel.ForEach(tiffFiles, tiffFile =>
        {
            using var input = new OcrInput();
            input.LoadImageFrames(tiffFile);
            var result = new IronTesseract().Read(input);
            concurrentResults[tiffFile] = result.Pages.Select(p => p.Text).ToList();
        });

        return new Dictionary<string, List<string>>(concurrentResults);
    }
}
C#

LoadImageFrames() liest alle Rahmen aus dem TIFF in einem Aufruf. Keine Abfrage der Frame-Anzahl, keine Schleife, keine explizite Freigabe pro Frame. Die parallele Version erstellt eine IronTesseract-Instanz pro Thread, was das korrekte Muster ist — siehe das Multithreading-Beispiel für das vollständige Threading-Modell. Für TIFF-spezifische Eingabeoptionen bietet der TIFF- und GIF-Eingabeleitfaden Informationen zur Frame-Auswahl und zur Verarbeitung mehrerer Formate.

Vereinfachung der Dokumentenschreiber-Pipeline

Die Erstellung suchbarer PDF-Dateien mit LEADTOOLS erfordert die Konfiguration einer DocumentWriter-Instanz auf dem Motor, das Erstellen eines PdfDocumentOptions-Objekts mit Ausgabetyp und Überlagerungseinstellungen, das Anwenden der Optionen über SetOptions() und dann das Aufrufen von document.Save() mit dem Format-Enum. Jeder dieser Schritte stellt ein separates Objekt und einen separaten API-Aufruf dar.

LEADTOOLS OCR-Ansatz:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

public class LeadtoolsDocumentWriterService
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public void CreateSearchablePdfFromImages(string[] imagePaths, string outputPath)
    {
        using var document = _engine.DocumentManager.CreateDocument();

        foreach (var imagePath in imagePaths)
        {
            using var image = _codecs.Load(imagePath);
            var page = document.Pages.AddPage(image, null);
            page.Recognize(null);
        }

        // DocumentWriter configuration — four properties to set before save
        var pdfOptions = new PdfDocumentOptions
        {
            DocumentType = PdfDocumentType.Pdf,
            ImageOverText = true,     // Image layer visible, text layer searchable
            Linearized = false,
            Title = "Searchable Output"
        };

        // Apply options to the engine's writer instance
        _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);

        // Save with format enum — the format must match the options set above
        document.Save(outputPath, DocumentFormat.Pdf, null);
    }

    public void CreateSearchablePdfFromPdf(string inputPdfPath, string outputPath)
    {
        var pdfInfo = _codecs.GetInformation(inputPdfPath, true);
        using var document = _engine.DocumentManager.CreateDocument();

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

            var page = document.Pages.AddPage(pageImage, null);
            page.Recognize(null);
        }

        var pdfOptions = new PdfDocumentOptions
        {
            DocumentType = PdfDocumentType.Pdf,
            ImageOverText = true,
            Title = Path.GetFileNameWithoutExtension(inputPdfPath)
        };

        _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
        document.Save(outputPath, DocumentFormat.Pdf, null);
    }
}
C#

IronOCR Ansatz:

using IronOcr;

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

    public void CreateSearchablePdfFromImages(string[] imagePaths, string outputPath)
    {
        using var input = new OcrInput();
        foreach (var imagePath in imagePaths)
            input.LoadImage(imagePath);

        var result = _ocr.Read(input);
        result.SaveAsSearchablePdf(outputPath);  // DocumentWriter pipeline: gone
    }

    public void CreateSearchablePdfFromPdf(string inputPdfPath, string outputPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(inputPdfPath);

        var result = _ocr.Read(input);
        result.SaveAsSearchablePdf(outputPath);
    }

    // Get bytes directly — useful for streaming responses in ASP.NET
    public byte[] CreateSearchablePdfBytes(string inputPdfPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(inputPdfPath);
        return _ocr.Read(input).SaveAsSearchablePdfBytes();
    }
}
C#

SaveAsSearchablePdf() ersetzt die gesamte PdfDocumentOptions + SetOptions() + document.Save() Kette. Das Verhalten der Bild-über-Text-Ebene erfolgt automatisch. Eine vollständige Dokumentation zur Ausgabe von durchsuchbaren PDFs finden Sie im Leitfaden zur Erstellung durchsuchbarer PDFs. Dieser beschreibt die Ausgabeoptionen, und das Beispiel zur Erstellung durchsuchbarer PDFs zeigt die Integration mit ASP.NET Antwortströmen.

Migration zur Extraktion von Mehrzonenfeldern

Das zonenbasierte OCR von LEADTOOLS verwendet OcrZone-Objekte mit LeadRect-Grenzen, OcrZoneType und OcrZoneCharacterFilters-Eigenschaften. Mehrere Zonen werden auf einer einzigen Seite hinzugefügt und in einem page.Recognize()-Aufruf erkannt, dann durch Zonenindex extrahiert. Der Zonenindex entspricht der Einfügereihenfolge, was bedeutet, dass die Extraktionsschleife diese Reihenfolge beibehalten muss.

LEADTOOLS OCR-Ansatz:

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

public class LeadtoolsFormFieldExtractor
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    // Invoice field extraction using named zones
    public InvoiceFields ExtractInvoiceFields(string invoicePath)
    {
        using var image = _codecs.Load(invoicePath);
        using var document = _engine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);

        // Must clear auto-detected zones before adding custom ones
        page.Zones.Clear();

        // Zone definitions — index order matters for extraction
        var zoneDefinitions = new[]
        {
            new { Name = "InvoiceNumber", X = 450, Y = 80,  W = 200, H = 30 },
            new { Name = "InvoiceDate",   X = 450, Y = 115, W = 200, H = 30 },
            new { Name = "VendorName",    X = 50,  Y = 150, W = 300, H = 40 },
            new { Name = "TotalAmount",   X = 450, Y = 600, W = 200, H = 30 }
        };

        foreach (var def in zoneDefinitions)
        {
            var zone = new OcrZone
            {
                Bounds = new LeadRect(def.X, def.Y, def.W, def.H),
                ZoneType = OcrZoneType.Text,
                CharacterFilters = OcrZoneCharacterFilters.None,
                RecognitionModule = OcrZoneRecognitionModule.Auto
            };
            page.Zones.Add(zone);
        }

        page.Recognize(null);

        // Extract by index — must match insertion order exactly
        return new InvoiceFields
        {
            InvoiceNumber = page.Zones[0].Text?.Trim(),
            InvoiceDate   = page.Zones[1].Text?.Trim(),
            VendorName    = page.Zones[2].Text?.Trim(),
            TotalAmount   = page.Zones[3].Text?.Trim()
        };
    }
}

public class InvoiceFields
{
    public string InvoiceNumber { get; set; }
    public string InvoiceDate   { get; set; }
    public string VendorName    { get; set; }
    public string TotalAmount   { get; set; }
}
C#

IronOCR Ansatz:

using IronOcr;

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

    // Each field gets its own CropRectangle-scoped Read() call
    // No zone index management, no zone ordering dependency
    public InvoiceFields ExtractInvoiceFields(string invoicePath)
    {
        return new InvoiceFields
        {
            InvoiceNumber = ReadRegion(invoicePath, 450, 80,  200, 30),
            InvoiceDate   = ReadRegion(invoicePath, 450, 115, 200, 30),
            VendorName    = ReadRegion(invoicePath, 50,  150, 300, 40),
            TotalAmount   = ReadRegion(invoicePath, 450, 600, 200, 30)
        };
    }

    private string ReadRegion(string imagePath, int x, int y, int width, int height)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
        return _ocr.Read(input).Text.Trim();
    }

    // Batch: extract the same field from many invoices in parallel
    public Dictionary<string, string> ExtractInvoiceNumbersBatch(string[] invoicePaths)
    {
        var results = new System.Collections.Concurrent.ConcurrentDictionary<string, string>();

        Parallel.ForEach(invoicePaths, invoicePath =>
        {
            using var input = new OcrInput();
            input.LoadImage(invoicePath, new CropRectangle(450, 80, 200, 30));
            results[invoicePath] = new IronTesseract().Read(input).Text.Trim();
        });

        return new Dictionary<string, string>(results);
    }
}
C#

CropRectangle direkt an LoadImage() übergeben ersetzt das gesamte OcrZone-Setup. Es gibt keinen zu überwachenden Zonenindex, keinen page.Zones.Clear()-Aufruf erforderlich und keine Erkennungsstatusüberprüfung notwendig. Der regionsbasierte OCR-Leitfaden umfasst Extraktionsmuster für einzelne und mehrere Regionen. Eine vollständige Anleitung zur Extraktion von Rechnungsfeldern finden Sie im Tutorial zur Rechnungs-OCR .

Strukturierte Datenextraktion mit Wortkoordinaten

LEADTOOLS arbeitet mit strukturierter Ausgabe auf Seiten- und Zonenebene. Um Wort-Ebenen-Daten mit Begrenzungsrahmenkoordinaten zu erhalten, greift der Entwickler auf OcrWord-Objekte innerhalb einer erkannten Zone zu. Die API erfordert, dass nach der Erkennung die Zonensammlung durchgearbeitet und die Wortliste für jede Zone iteriert wird.

LEADTOOLS OCR-Ansatz:

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

public class LeadtoolsStructuredExtractor
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public List<WordLocation> ExtractWordsWithLocations(string imagePath)
    {
        var wordLocations = new List<WordLocation>();

        using var image = _codecs.Load(imagePath);
        using var document = _engine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);

        // Access words through the zone collection
        foreach (OcrZone zone in page.Zones)
        {
            foreach (OcrWord word in zone.Words)
            {
                wordLocations.Add(new WordLocation
                {
                    Text       = word.Value,
                    X          = word.Bounds.X,
                    Y          = word.Bounds.Y,
                    Width      = word.Bounds.Width,
                    Height     = word.Bounds.Height,
                    Confidence = word.Confidence
                });
            }
        }

        return wordLocations;
    }
}

public class WordLocation
{
    public string Text       { get; set; }
    public int    X          { get; set; }
    public int    Y          { get; set; }
    public int    Width      { get; set; }
    public int    Height     { get; set; }
    public int    Confidence { get; set; }
}
C#

IronOCR Ansatz:

using IronOcr;

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

    public List<WordLocation> ExtractWordsWithLocations(string imagePath)
    {
        var result = _ocr.Read(imagePath);

        // Five-level hierarchy: Pages > Paragraphs > Lines > Words > Characters
        return result.Pages
            .SelectMany(page => page.Paragraphs)
            .SelectMany(para => para.Lines)
            .SelectMany(line => line.Words)
            .Select(word => new WordLocation
            {
                Text       = word.Text,
                X          = word.X,
                Y          = word.Y,
                Width      = word.Width,
                Height     = word.Height,
                Confidence = (int)word.Confidence
            })
            .ToList();
    }

    // Paragraph-level extraction with position data
    public void PrintDocumentStructure(string imagePath)
    {
        var result = _ocr.Read(imagePath);
        Console.WriteLine($"Document confidence: {result.Confidence}%");

        foreach (var page in result.Pages)
        {
            Console.WriteLine($"Page {page.PageNumber}:");
            foreach (var paragraph in page.Paragraphs)
            {
                Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):");
                Console.WriteLine($"  {paragraph.Text}");
            }
        }
    }
}
C#

Die Ergebnishierarchie von IronOCR steigt von Pages über Paragraphs, Lines, Words und Characters ab. Jede Ebene gibt X, Y, Width, Height, Text und Confidence frei. Das zonenbasierte Zugriffsmuster von LEADTOOLS entfällt – es ist keine Zoneniteration mehr erforderlich, um auf die Wortdaten zuzugreifen. Die Anleitung zum Lesen von Ergebnissen beschreibt das vollständige Ausgabemodell mit Koordinatenzugriffsmustern. Die OcrResult-API-Referenz dokumentiert jede Eigenschaft der Ergebnishierarchie.

LEADTOOLS OCRAPI zu IronOCR Mapping-Referenz

LEADTOOLS OCRIronOCR
RasterSupport.SetLicense(licPath, keyContent)IronOcr.License.LicenseKey = "key"
new RasterCodecs()Nicht erforderlich
OcrEngineManager.CreateEngine(OcrEngineType.LEAD)new IronTesseract()
engine.Startup(codecs, null, null, runtimePath)Nicht erforderlich
engine.IsStartedNicht erforderlich (immer bereit)
engine.Shutdown()Nicht erforderlich
engine.Dispose()Nicht erforderlich
_codecs.Load(imagePath)input.LoadImage(imagePath)
_codecs.Load(path, 0, BgrOrGray, page, page)input.LoadPdf(path) oder input.LoadImageFrames(path)
_codecs.GetInformation(path, true).TotalPagesNicht erforderlich – automatisch
engine.DocumentManager.CreateDocument()Nicht erforderlich
document.Pages.AddPage(image, null)input.LoadImage(imagePath)
page.Recognize(null)ocr.Read(input) (Erkennung ist Teil von Read())
page.GetText(-1)result.Text
page.RecognizeStatusresult.Confidence (Prozentsatz)
OcrZone { Bounds = new LeadRect(x, y, w, h) }new CropRectangle(x, y, w, h)
page.Zones.Clear()Nicht erforderlich
page.Zones.Add(zone)input.LoadImage(path, cropRect)
zone.Words / word.Boundsresult.Pages[n].Words / word.X, word.Y
DeskewCommand().Run(image)input.Deskew()
DespeckleCommand().Run(image)input.DeNoise()
AutoBinarizeCommand().Run(image)input.Binarize()
ContrastBrightnessCommand().Run(image)input.Contrast()
new PdfDocumentOptions { ImageOverText = true }Automatisch von SaveAsSearchablePdf() behandelt
engine.DocumentWriterInstance.SetOptions(format, opts)Nicht erforderlich
document.Save(path, DocumentFormat.Pdf, null)result.SaveAsSearchablePdf(path)
_codecs.Options.Pdf.Load.Password = passwordinput.LoadPdf(path, Password: password)
RasterSupport.IsLocked(RasterSupportType.Document)IronOcr.License.IsLicensed

Gängige Migrationsprobleme und Lösungen

Problem 1: Fehler bei der Auflösung des Lizenzdateipfads

LEADTOOLS: RasterSupport.SetLicense() löst die .LIC- und .LIC.KEY Dateipfade relativ zum Arbeitsverzeichnis auf, welches zwischen bin/Debug, bin/Release, Docker-Containern und IIS-Anwendungspools variiert. Ein häufiges Ausfallmuster ist ein Pfad, der in der Entwicklung funktioniert, aber "License file not found" in der Produktion wirft, weil sich das Arbeitsverzeichnis geändert hat.

Lösung: Löschen Sie beide Lizenzdateien und den SetLicense()-Aufruf vollständig. Ersetzen Sie dies durch eine einzelne Zeichenkettenzuweisung, die aus einer Umgebungsvariablen liest:

// Remove this:
// RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath));

// Replace with this:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE environment variable not set");
C#

Der String-Schlüssel verhält sich in jeder Umgebung identisch. Speichern Sie es im selben Geheimnismanager, der bereits für Datenbankverbindungszeichenfolgen verwendet wird.

Problem 2: Ausnahme "Motor nicht gestartet"

LEADTOOLS: Der Aufruf einer Erkennungsmethode vor Abschluss von engine.Startup() oder nachdem engine.Shutdown() aufgerufen wurde (z.B. in einem Entsorgen-vor-Verwenden-Rennzustand während des Herunterfahrens) wirft einen InvalidOperationException mit "Motor nicht gestartet." auf. Langlebige Dienstklassen müssen sich mit IsStarted-Prüfungen davor schützen.

Lösung: IronTesseract erfordert keinen Startaufruf und hat keinen gestartet/gestoppt-Zustand. Der IsStarted-Schutz und die gesamte Lebenszyklus-Dienstklasse kann gelöscht werden:

// Remove the guard:
// if (!_engine.IsStarted)
//     throw new InvalidOperationException("Engine not started");

// IronTesseract is always ready — just call Read()
var result = _ocr.Read(imagePath);
C#

Problem 3: Speicherakkumulation bei Rasterbildern in der Stapelverarbeitung

LEADTOOLS: Batch-Verarbeitung, die über PDF-Seiten oder Bilddateien iteriert, erstellt RasterImage-Instanzen in einer Schleife. Wenn ein Codepfad versäumt, eine RasterImage zu entsorgen — aufgrund einer ausgelösten Ausnahme vor dem Beenden des using-Blocks oder eines manuellen Entsorgungsmusters mit einem fehlenden Aufruf — sammeln sich die nicht freigegebenen Bilder im Speicher an. LEADTOOLS-Produktionscode enthält häufig GC.Collect() / GC.WaitForPendingFinalizers()-Aufrufe zwischen Batchen als Ausgleichsmechanismus.

Lösung: Entfernen Sie alle GC.Collect()-Aufrufe. OcrInput ist die einzige IDisposable in der IronOCR-Pipeline und ist für jede Batch-Operation mit einem Standard-using-Block abgegrenzt:

// Remove this pattern:
// GC.Collect();
// GC.WaitForPendingFinalizers();

// Replace with standard using scope:
foreach (var filePath in filePaths)
{
    using var input = new OcrInput();
    input.LoadImage(filePath);
    var text = _ocr.Read(input).Text;
    // input disposed here — no accumulation
}
C#

Weitere Hinweise zur Speicheroptimierung finden Sie im Blogbeitrag zur Reduzierung der Speicherbelegung .

Problem 4: DocumentWriterInstance-Optionen bleiben über Aufrufe hinweg erhalten

LEADTOOLS: engine.DocumentWriterInstance.SetOptions() ändert den Zustand der freigegebenen Motor-Schreiber-Instanz. Wenn ein Codepfad PdfDocumentOptions mit DocumentType = PdfDocumentType.PdfA setzt und ein nachfolgender Aufruf diese Optionen nicht vor dem Aufrufen von document.Save() zurücksetzt, bleibt das Ausgabeformat des vorherigen Aufrufs bestehen. Dies ist ein zustandsbehafteter Nebeneffekt der gemeinsam genutzten Engine-Instanz.

**Lösung:**IronOCR verfügt über keinen gemeinsamen Writer-Status. Jeder SaveAsSearchablePdf()-Aufruf ist unabhängig:

// Remove the options setup:
// var pdfOptions = new PdfDocumentOptions { ... };
// _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
// document.Save(outputPath, DocumentFormat.Pdf, null);

// Replace with:
result.SaveAsSearchablePdf(outputPath);
C#

Jeder Aufruf erzeugt eine Standard-PDF-Ausgabe mit einer Bildüberlagerung und einer durchsuchbaren Textebene. Es gibt keinen gemeinsamen Optionsstatus, der zwischen Anrufen zurückgesetzt werden könnte.

Problem 5: Falsches Paket – Fehlendes Modul zur Laufzeit

LEADTOOLS: Teams, die das Document Imaging SDK gekauft haben, könnten feststellen, dass Leadtools.Pdf-Typen nicht verfügbar sind oder dass verschlüsselte PDF-Seiten RasterException mit RasterExceptionCode.FeatureNotSupported auslösen. Dies geschieht, wenn das gekaufte Paket das PDF-Modul nicht enthält, und der Fehler tritt erst zur Laufzeit in der Produktionsumgebung auf.

**Lösung:**IronOCR beinhaltet alle Funktionen in jeder Lizenzstufe. Es gibt kein separates PDF-Modul, kein Add-on für verschlüsselte Dokumente und keinen sekundären Anbieter für einen genaueren Motor. Nach der Installation des einzelnen IronOcr-Pakets steht der vollständige Funktionsumfang ohne zusätzlichen Kauf zur Verfügung:

dotnet add package IronOcr

Problem 6: Zonenindex-Fehler nach Neuanordnung

LEADTOOLS: Zonenextraktion verwendet Positionsindizierung — page.Zones[0].Text, page.Zones[1].Text — die die Extraktionslogik an die Einfügereihenfolge in page.Zones.Add() bindet. Das Neuanordnen von Zonendefinitionen, um sie an ein geändertes Formularlayout anzupassen, führt stillschweigend zu einem Fehler bei der Datenextraktion, da alle nachfolgenden Indizes verschoben werden.

**Lösung:**IronOCR verwendet benannte Variablen mit CropRectangle pro Feld. Die Neuanordnung von Felddefinitionen hat keinen Einfluss auf die Extraktion, da jedes Feld unabhängig definiert ist:

// Each field is independent — reorder freely without breaking extraction
var invoiceNumber = ReadRegion(imagePath, 450, 80,  200, 30);
var invoiceDate   = ReadRegion(imagePath, 450, 115, 200, 30);
var vendorName    = ReadRegion(imagePath, 50,  150, 300, 40);
var totalAmount   = ReadRegion(imagePath, 450, 600, 200, 30);
C#

LEADTOOLS OCR-Migrations-Checkliste

Vor der Migration

Prüfen Sie den Quellcode, um alle LEADTOOLS-Nutzungen zu identifizieren, bevor Sie Änderungen vornehmen:

# Find all LEADTOOLS namespace imports
grep -rn "using Leadtools" --include="*.cs" .

# Find engine lifecycle calls
grep -rn "OcrEngineManager\|\.Startup(\|\.Shutdown()" --include="*.cs" .

# Find license file references
grep -rn "SetLicense\|LEADTOOLS\.LIC\|\.LIC\.KEY" --include="*.cs" .

# Find RasterCodecs usage
grep -rn "RasterCodecs\|_codecs\.Load\|GetInformation" --include="*.cs" .

# Find DocumentWriter usage
grep -rn "DocumentWriterInstance\|PdfDocumentOptions\|DocumentFormat\." --include="*.cs" .

# Find zone-based OCR
grep -rn "OcrZone\|page\.Zones\|LeadRect\|ZoneType" --include="*.cs" .

# Find GC workarounds to remove
grep -rn "GC\.Collect\|WaitForPendingFinalizers" --include="*.cs" .
SHELL

Notieren Sie, welches LEADTOOLS-Paket erworben wurde – OCR-Modul, PDF-Modul und Engine-Typ (LEAD vs. Tesseract vs. OmniPage) –, um sicherzustellen, dass bei der Validierung nach der Migration gleichwertige IronOCR Funktionen getestet werden.

Code-Migration

  1. Entfernen Sie alle LEADTOOLS-NuGet-Pakete: Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters, Leadtools.Pdf
  2. Installieren Sie das IronOcr NuGet-Paket
  3. Ersetzen Sie alle LEADTOOLS-using-Direktiven durch using IronOcr;
  4. Entfernen Sie die .LIC- und .LIC.KEY-Dateien aus dem Projekt und den Bereitstellungsartefakten
  5. Ersetzen Sie RasterSupport.SetLicense(licPath, keyContent) durch IronOcr.License.LicenseKey = "key" beim Anwendungsstart
  6. Löschen Sie alle IDisposable-Dienstklassen, die nur zur Verwaltung des IOcrEngine und RasterCodecs Lebenszyklus existieren
  7. Ersetzen Sie OcrEngineManager.CreateEngine() + engine.Startup() durch new IronTesseract()
  8. Ersetzen Sie _codecs.Load(imagePath) durch input.LoadImage(imagePath) innerhalb eines using var input = new OcrInput()-Blocks
  9. Ersetzen Sie mehrseitige TIFF-Seitenschleifen durch input.LoadImageFrames(tiffPath)
  10. Ersetzen Sie die PDF-Seiteniterationsschleife durch input.LoadPdf(pdfPath)
  11. Ersetzen Sie document.Pages.AddPage() + page.Recognize(null) + page.GetText(-1) durch ocr.Read(input).Text
  12. Ersetzen Sie OcrZone + page.Zones.Add()-Muster durch input.LoadImage(path, new CropRectangle(x, y, w, h))
  13. Ersetzen Sie PdfDocumentOptions + DocumentWriterInstance.SetOptions() + document.Save() durch result.SaveAsSearchablePdf(path)
  14. Ersetzen Sie Befehlsklassen für die Vorverarbeitung (DeskewCommand, DespeckleCommand, AutoBinarizeCommand) durch input.Deskew(), input.DeNoise(), input.Binarize() auf der OcrInput-Instanz
  15. Entfernen Sie alle GC.Collect() / GC.WaitForPendingFinalizers()-Aufrufe, die hinzugefügt wurden, um das Speichermanagement von LEADTOOLS auszugleichen

Nach der Migration

  • Überprüfen Sie anhand einer repräsentativen Auswahl von Bildern und PDFs, ob die erkannte Textausgabe mit der LEADTOOLS-Ausgabe übereinstimmt.
  • Bestätigen Sie, dass die Konfidenzwerte mit result.Confidence innerhalb der erwarteten Bereiche liegen
  • Der Test der Mehrbild-TIFF-Verarbeitung erzeugt die gleiche Seitenzahl wie die LEADTOOLS-Frame-Iterationsschleife.
  • Sicherstellen, dass die durchsuchbare PDF-Ausgabe in einem PDF-Reader (Adobe Acrobat oder vergleichbar) textdurchsuchbar ist
  • Testen Sie die zonenbasierte Feldextraktion anhand bekannter, korrekter Feldwerte aus Produktionsrechnungen oder Formularen.
  • Überprüfen Sie, dass die Entschlüsselung passwortgeschützter PDFs ohne das separate Leadtools.Pdf-Modul funktioniert
  • Führen Sie Batch-Verarbeitung unter Last aus und bestätigen Sie kein Speicherwachstum (alle GC.Collect() zuerst entfernen)
  • Docker- und CI/CD-Bereitstellung ohne Lizenzdateien testen – bestätigen, dass der Lizenzschlüssel als Zeichenkette korrekt aus der Umgebungsvariablen aufgelöst wird
  • Testen Sie parallele Verarbeitung mit Parallel.ForEach, um die Thread-Sicherheit zu überprüfen
  • Bestätigen Sie, dass strukturiertes Datenextraktion (result.Pages, page.Paragraphs, page.Words) die richtigen Koordinaten zurückgibt

Wichtigste Vorteile der Migration zu IronOCR

Bereitstellung wird zustandslos. Die LEADTOOLS .LIC- und .LIC.KEY-Dateien sind Artefakte, die jede Bereitstellungsumgebung mitführen muss. Container, die diese einbetten, legen Lizenzdaten im Image-Verlauf offen. Die Behälter, in denen sie montiert werden, erfordern eine Volumenkoordination. Nach der Migration zu IronOCR ist die Lizenz ein String in einer Umgebungsvariablen. Das Bereitstellungsartefakt ist eine Standard- NuGet Referenz. Keine Dateien, keine Pfade, keine Einbindungsstrategie. Die Docker-Bereitstellungsanleitung und die Azure-Bereitstellungsanleitung zeigen die vollständige Einrichtung für containerisierte Umgebungen.

Vier Pakete werden zu einem. Die Migration reduziert Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters und optional Leadtools.Pdf auf einen einzigen IronOcr-Verweis. Alle Funktionen – Vorverarbeitung, native PDF-Eingabe, durchsuchbare PDF-Ausgabe, Barcode-Lesung, Extraktion strukturierter Daten, Unterstützung von über 125 Sprachen – sind in diesem einen Paket enthalten. Der Funktionsumfang hängt nicht davon ab, welches Paket erworben wurde.

Batch-Verarbeitung eliminiert manuelles Speichermanagement. LEADTOOLS-Batch-Code führt defensive GC.Collect()-Aufrufe und explizite RasterImage-Entsorgung durch, um Speicheransammlungen bei Mehrfachdokumentläufen zu verhindern. IronOCR's OcrInput, abgegrenzt mit einem using-Block, verwaltet die Bereinigung automatisch. Threadsichere parallele Verarbeitung mit Parallel.ForEach — eine IronTesseract-Instanz pro Thread — liefert Multi-Core-Durchsatz ohne Synchronisationscode. Im Leitfaden zur Geschwindigkeitsoptimierung finden Sie Informationen zur Optimierung des Produktionsdurchsatzes.

Vorhersehbare Gesamtkosten. Die geschätzten Kosten für LEADTOOLS für ein fünfköpfiges Entwicklerteam belaufen sich im ersten Jahr auf 15.000 bis 40.000 US-Dollar, wobei die jährliche Wartung etwa 20 bis 25 % der Lizenzkosten beträgt, um Updates zu erhalten.IronOCR Professional kostet 2.999 US-Dollar und umfasst zehn Entwickler und zehn Bereitstellungsstandorte als einmalige, dauerhafte Lizenz. Updates für ein Jahr sind inklusive. Die weitere Nutzung nach Ablauf des Aktualisierungszeitraums erfordert keine zusätzlichen Zahlungen. Auf der IronOCR -Lizenzseite werden alle Stufenpreise direkt veröffentlicht, ohne vorherige Verkaufsberatung.

Strukturierte Daten ohne Zonen-Setup. Nach der Migration sind Wort-, Zeilen- und Absatzebenen-Daten mit Begrenzungsrahmenkoordinaten direkt auf OcrResult verfügbar — keine Zonendefinitionen erforderlich. Die fünfstufige Hierarchie (Pages, Paragraphs, Lines, Words, Characters) gibt jeweils Positionskoordinaten und elementweise Konfidenzwerte frei. Anwendungen, die eine LEADTOOLS-Zonenkonfiguration für die strukturierte Datenextraktion benötigten, erhalten umfangreichere Daten über eine einfachere API. Die Ergebnisseite der OCR-Texturierung fasst das vollständige Ausgabemodell zusammen.

Hinweis:: Adobe Acrobat, Kofax OmniPage, LEADTOOLS, und Tesseract sind eingetragene Warenzeichen ihrer jeweiligen Inhaber. Diese Website steht in keiner Verbindung mit, wird weder unterstützt noch gesponsert von Adobe Inc., Apryse, Google, Kofax oder LEAD Technologies. 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.

Verwandte Artikel

Key in blue circle

Holen Sie sich sofort Ihren kostenlosen 30-Tage-Testschlüssel.

Your trial license will be sent to your email address

Keine Einschränkungen. 100 % freigeschaltet. Keine Kreditkarte.

bullet_checkedIhr Testlizenzschlüssel wurde Ihnen per E-Mail gesendet.Keine Einschränkungen. 100 % freigeschaltet. Keine Kreditkarte.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Erhalten Sie Ihre unverbindliche Beratung
Füllen Sie das Formular unten aus oder senden Sie eine E-Mail an sales@ironsoftware.com
Ihre Daten werden immer vertraulich behandelt.
Von Millionen von Ingenieur*innen weltweit vertraut
Kundenlogos von Iron Software
Erhalten Sie sofort Ihren kostenlosen 30-Tage-Testschlüssel.
Ihr Testlizenzschlüssel wurde Ihnen per E-Mail gesendet.