Altbilgi içeriğine atla
VIDEOLAR

NET Maui'de OCR Nasıl Yapılır?

Bu kılavuz .NET geliştiricilerini LEADTOOLS OCR'dan IronOCR'a tam bir göç süreciyle yönlendirir. NuGet paketi değişiminden tam kod göçüne kadar her adımı kapsar ve LEADTOOLS'un başlangıç seremonisi, çoklu ad alanı yapısı ve dosya tabanlı lisans dağıtım modelinden en çok etkilenen desenler için öncesi ve sonrası örnekleri verir.

Neden LEADTOOLS OCR'dan Göç Etmeliyiz

LEADTOOLS OCR, kökeni 1990'a dayanan bir kurumsal görüntüleme platformunda bulunur ve API bu geçmişi yansıtır. Minimum çalışma yapılandırması dört NuGet paketi, dört ad alanı, bilinen bir yola dağıtılmış iki fiziksel lisans dosyası, motor öncesi başlatılan bir codec katmanı, üç seçenekten biri seçilen bir motor türü ve çalışma zamanında programın belleğe yüklenmesini sağlayan bir başlatma çağrısı gerektirir. Tüm bunlar, tek bir karakter tanınmadan önce çalışır. IronOCR'a geçiş yapan ekipler, o katmanların tamamını - bir paket, bir ad alanı, lisans anahtarı ayarlamak için bir satır - ortadan kaldırır.

Dosya Tabanlı Lisans Dağıtımı Kaplarda Bozulur. LEADTOOLS, uygulamayı çalıştıran her makinede belirli bir yolda okunabilen LEADTOOLS.LIC ve LEADTOOLS.LIC.KEY adlı iki fiziksel dosya gerektirir. Docker konteynerlerinde, bu dosyalar ya görüntüye yerleştirilmeli (katman geçmişinde onları açığa çıkararak) ya da çalıştırma sırasında monte edilmeli (her düzen ortamında hacim koordinasyonu gerektiren). Azure Functions ve AWS Lambda, iş çevresi olmadan lisans dosyası dağıtımı için mekanizma sunmaz. CI/CD hatları dosyaların başlangıç çağrısı tarafından kullanılan tam yolda bulunmasını gerektirir, aksi takdirde uygulama tek bir belge işlemeye başlamadan önce hata verir. IronOCR, her iki dosyayı bir ortam değişkenine, Kubernetes gizli bilgisine veya bir Azure Key Vault referansına uyacak bir dizeyle değiştirir.

Tek Bir Görev İçin Dört Paket. Çalışan bir LEADTOOLS OCR projesi, minimum olarak Leadtools, Leadtools.Ocr, Leadtools.Codecs ve Leadtools.Forms.DocumentWriters gerektirir. Şifre korumalı PDF desteği, satın alınan pakete dahil edilmeyebilecek ek bir Leadtools.Pdf modülü gerektirir. Her paketin mevcut, uyumlu ve aynı sürümde olması gerekir. IronOCR, tek bir NuGet paketi olarak gönderilir. Tüm yetenekler — yerel PDF girişi, aranabilir PDF çıktısı, önişleme, barkod okuma — dahildir.

Motor Yaşam Döngüsü Bir Bakım Alanı Oluşturur. LEADTOOLS, OCR motorunu IDisposable servis sınıfında kapsar, bu sadece idiomatik .NET nedenlerinden ötürü değil, Shutdown() çağrısının Dispose()'den önce yapılması gerektiğinden dolayıdır, aksi hâlde uygulama hataları oluşturur. LEADTOOLS toplu işlemcilerinin üretim uygulamalarında genellikle belge parçaları arasında GC.Collect() / GC.WaitForPendingFinalizers() çağrıları, biriken RasterImage örneklerini telafi etmek için bulunur.IronOCR standart using bloklarını kullanır. OcrInput, imha edilmesi gereken tek nesnedir.

Paket Karışıklığı Üretimde Yüzey Alır. LEADTOOLS fiyatlandırmasını açıkça yayınlamaz. Belge Görüntüleme SDK'sı — OCR'yi içeren sınıf — bir geliştirici başına yıllık 3.000–8.000 $ tahmini maliyetle çalışır. OCR modülünü PDF modülü olmadan satın alan ekipler, üretimde şifre korumalı belgeler üzerinde RasterSupport.IsLocked() doğru döndüğünde eksikliği keşfeder. OmniPage motoru doğruluk katmanı, LEADTOOLS satın alımının üzerine farklı bir Kofax lisans anlaşması gerektirir. IronOCR, her katmanda tüm özellikleri lisanslar. İkinci bir satıcı ilişkisi, şifrelenmiş belgeler için ayrı bir modül yoktur.

Başlangıç Maliyeti Soğuk Başlangıçları Etkiler. engine.Startup(), çalışma zamanı dosyalarını belleğe yükleyen engelleyici bir çağrıdır. Soğuk başlatma gecikmesinin önemli olduğu sunucusuz ortamlarda — Azure Functions, AWS Lambda — her türlü tanıma işi başlamadan önce 500–2000 ms'lik bir engelleyici başlangıç, bir yapısal sorun teşkil eder. IronOCR, tembel başlatma kullanır. IronTesseract örneği ilk kullanımda başlatılır ve aynı süreç içindeki sonraki çağrılar hiç başlangıç maliyeti ödemez.

Temel Sorun

LEADTOOLS dört ad alanı, dört NuGet paketi ve herhangi bir karakter tanınmadan önce bir başlangıç seremonisi gerektirir:

// 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
// 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
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports Leadtools.Forms.DocumentWriters

' LEADTOOLS: Four namespaces, four packages, six steps before recognition
RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath)) ' Step 1: two files on disk
Dim codecs As New RasterCodecs()                             ' Step 2: codec layer
Dim engine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) ' Step 3: engine factory
engine.Startup(codecs, Nothing, Nothing, runtimePath)        ' Step 4: blocking startup
' ... still need to create document, add page, call Recognize(), extract text
$vbLabelText   $csharpLabel
// IronOCR: One namespace, one package, one line
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read("document.jpg").Text;
// IronOCR: One namespace, one package, one line
using IronOcr;

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

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read("document.jpg").Text
$vbLabelText   $csharpLabel

IronOCR vs LEADTOOLS OCR: Özellik Karşılaştırması

Aşağıdaki tablo, yetenekleri iki kütüphane arasında doğrudan eşleştirir.

Özellik LEADTOOLS OCR IronOCR
Gerekli NuGet paketleri Minimum 4 (daha fazlası PDF için) 1 (IronOcr)
Lisans mekanizması .LIC + .LIC.KEY dosya çifti Dize anahtarı
Lisans dağıtımı Her üretim makinesinde dosyalar Ortam değişkeni veya yapılandırma
Fiyatlandırma modeli $3,000–$15,000+/geliştirici/yıl (tahmini) $999–$2.999 tek seferlik süresiz
Motor başlangıcı Çalışma zamanı yoluyla manuel Startup() Otomatik, tembel
Motor kapanışı Shutdown() öncesinde manuel Dispose() Gerekli değil
Codec katmanı Tüm görüntü yüklemeleri için RasterCodecs gereklidir Gerekli değil
PDF girişi Sayfa bazında rasterleştirme döngüsü Yerel LoadPdf()
Şifre korumalı PDF Ayrı Leadtools.Pdf modülü gerektirir Yerleşik Password parametresi
Aranabilir PDF çıktısı DocumentWriter + PdfDocumentOptions + document.Save() result.SaveAsSearchablePdf()
Ön işlem Ayrı komut sınıfları (DeskewCommand, DespeckleCommand, vb.) OcrInput üzerinde yerleşik filtre yöntemleri
Çok sayfalı TIFF CodecsLoadByteOrder ile manuel çerçeve yinelemesi input.LoadImageFrames()
Yapısal çıktı Sayfa ve bölge seviyesi Koordinatlı sayfa, paragraf, satır, kelime, karakter
Güvenlik puanlaması OcrPageRecognizeStatus enum Yüzde olarak result.Confidence
Barkod okuma Ayrıca LEADTOOLS Barkod modülü Yerleşik (ReadBarCodes = true)
Thread güvenliği Dikkatli yönetim gerektirir Tam (her iş parçacığına bir IronTesseract)
Desteklenen diller 60–120 (motor bağımlı) 125'ten fazla NuGet dil paketleri üzerinden
Dil dağıtımı tessdata files or engine-bundled files Her dil için NuGet paketi
Çapraz platform Her platform için çalışma zamanı yapılandırması ile desteklenir Windows, Linux, macOS, Docker, Azure, AWS
Docker dağıtımı .KEY dosyaları monte edilmeli veya gömülmelidir Standart dotnet publish
Ticari destek Evet Evet

Hızlı Başlangıç: LEADTOOLS OCR'dan IronOCR'a Geçiş

Adım 1: NuGet Paketini Değiştirin

Tüm LEADTOOLS paketlerini kaldırın:

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
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

NuGet kullanarak IronOCR'u yükleyin:

dotnet add package IronOcr

Adım 2: Ad Alanlarını Güncelleyin

Tüm LEADTOOLS using direktiflerini tek bir IronOCR içe aktarması ile değiştirin:

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

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

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

Adım 3: Lisansa İzin Verin

Tüm RasterSupport.SetLicense() çağrılarını ve .LIC / .LIC.KEY dosya referanslarını kaldırın. Uygulama başlangıcında IronOCR lisans anahtarını ekleyin:

// 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");
// 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");
Imports System

' 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")
$vbLabelText   $csharpLabel

Lisans anahtarı, herhangi bir standart .NET sır yönetim deseni — appsettings.json, Azure Key Vault, AWS Secrets Manager veya bir Kubernetes sırrı içinde depolanabilir. Uygulama ikili dosyasıyla birlikte hiçbir dosya dağıtılmasına gerek yoktur.

Kod Göç Örnekleri

Motor Başlatma ve Kapatma Yaşam Döngüsü Kaldırma

LEADTOOLS, motor yaşam döngüsünün açıkça yönetilmesi gerektiğinden katı bir hizmet sınıfı örüntüsü zorunlu kılar. Yapıcı motoru başlatır, Dispose() onu doğru sırayla kapatır ve Shutdown()'yi Dispose()'den önce atlayan herhangi bir kod yolu bir çalışma zamanı hatası üretir.

LEADTOOLS OCR Yaklaşımı:

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();
    }
}
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();
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System
Imports System.IO

' Service class required purely to manage engine lifecycle
Public Class LeadtoolsOcrService
    Implements IDisposable

    Private _engine As IOcrEngine
    Private _codecs As RasterCodecs
    Private ReadOnly _runtimePath As String

    Public Sub New(licPath As String, keyPath As String, runtimePath As String)
        _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, Nothing, Nothing, _runtimePath)
    End Sub

    Public ReadOnly Property IsReady As Boolean
        Get
            Return If(_engine?.IsStarted, False)
        End Get
    End Property

    Public Function Process(imagePath As String) As String
        If Not IsReady Then
            Throw New InvalidOperationException("Engine not started")
        End If

        Using image = _codecs.Load(imagePath)
            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
        ' Order is mandatory: Shutdown before Dispose
        If _engine?.IsStarted = True Then
            _engine.Shutdown()
        End If

        _engine?.Dispose()
        _codecs?.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

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
}
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
}
Imports IronOcr

' No lifecycle management needed — the service class becomes trivial
Public Class OcrService
    Private ReadOnly _ocr As New IronTesseract()

    ' Always ready — no IsStarted check needed
    Public Function Process(imagePath As String) As String
        Return _ocr.Read(imagePath).Text
    End Function

    ' No Dispose() needed for the engine
    ' No Startup(), no Shutdown(), no codec layer
End Class
$vbLabelText   $csharpLabel

IronTesseract örneği ilk kullanımda başlatılır. Yapıcı argümanlar yok, çalışma zamanı yolu yok, Startup() çağrısı yok. Yukarıdaki servis sınıfının IDisposable'yı uygulaması gerekmiyor — motor durumsuzdur ve her Read() çağrısında kullanılan OcrInput nesneleri, standart using deseni ile kendi temizliğini gerçekleştirir. IronTesseract kurulum kılavuzu, üretim senaryoları için dil seçimi ve performans ayarlamalarını da içeren yapılandırma seçeneklerini kapsar.

Çok Kareli TIFF Yığın İşleme

LEADTOOLS, toplam çerçeve sayısını öğrenmek için kodeği sorgulayarak çok çerçeveli TIFF dosyalarını işler ve ardından her _codecs.Load() çağrısında belirgin lastPage parametreleri ile yineleme yapar. Her çerçeve resmi manuel olarak atılmalıdır aksi takdirde bellek birikir.

LEADTOOLS OCR Yaklaşımı:

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;
    }
}
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;
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System.IO

Public Class LeadtoolsTiffBatchService
    Private ReadOnly _engine As IOcrEngine
    Private ReadOnly _codecs As RasterCodecs

    Public Function ProcessMultiFrameTiff(tiffPath As String) As List(Of String)
        Dim pageTexts As New List(Of String)()

        ' Must query page count before iterating
        Dim info = _codecs.GetInformation(tiffPath, True)
        Dim frameCount As Integer = info.TotalPages

        Using document = _engine.DocumentManager.CreateDocument()
            For frameNum As Integer = 1 To frameCount
                ' Load one frame at a time — must specify firstPage/lastPage
                Using frameImage = _codecs.Load(tiffPath, 0, CodecsLoadByteOrder.BgrOrGray, frameNum, frameNum)
                    Dim page = document.Pages.AddPage(frameImage, Nothing)
                    page.Recognize(Nothing)
                    pageTexts.Add(page.GetText(-1))

                    ' GC pressure accumulates if disposal is missed on any frame
                End Using
            Next
        End Using

        Return pageTexts
    End Function

    Public Function ProcessTiffDirectory(directoryPath As String) As Dictionary(Of String, List(Of String))
        Dim results As New Dictionary(Of String, List(Of String))()

        For Each tiffFile In Directory.GetFiles(directoryPath, "*.tiff")
            results(tiffFile) = ProcessMultiFrameTiff(tiffFile)

            ' Manual GC between files to prevent memory growth
            GC.Collect()
            GC.WaitForPendingFinalizers()
        Next

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

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

Public Class TiffBatchService
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ProcessMultiFrameTiff(tiffPath As String) As List(Of String)
        Using input As New OcrInput()
            input.LoadImageFrames(tiffPath) ' All frames loaded automatically

            Dim result = _ocr.Read(input)

            ' Per-frame text available through result.Pages
            Return result.Pages.Select(Function(p) p.Text).ToList()
        End Using
    End Function

    Public Function ProcessTiffDirectory(directoryPath As String) As Dictionary(Of String, List(Of String))
        Dim results As New Dictionary(Of String, List(Of String))()

        For Each tiffFile In Directory.GetFiles(directoryPath, "*.tiff")
            results(tiffFile) = ProcessMultiFrameTiff(tiffFile)
        Next

        Return results
    End Function

    ' Parallel processing across files — thread-safe out of the box
    Public Function ProcessTiffDirectoryParallel(directoryPath As String) As Dictionary(Of String, List(Of String))
        Dim concurrentResults As New ConcurrentDictionary(Of String, List(Of String))()
        Dim tiffFiles = Directory.GetFiles(directoryPath, "*.tiff")

        Parallel.ForEach(tiffFiles, Sub(tiffFile)
                                        Using input As New OcrInput()
                                            input.LoadImageFrames(tiffFile)
                                            Dim result = New IronTesseract().Read(input)
                                            concurrentResults(tiffFile) = result.Pages.Select(Function(p) p.Text).ToList()
                                        End Using
                                    End Sub)

        Return New Dictionary(Of String, List(Of String))(concurrentResults)
    End Function
End Class
$vbLabelText   $csharpLabel

LoadImageFrames(), tek bir çağrıda TIFF'ten tüm çerçeveleri okur. Çerçeve sayısı sorgusu, döngü, açıkça çerçeve başına atama yok. Paralel sürüm, iş parçacığı başına bir IronTesseract örneği oluşturur, bu doğru bir desendir — tam iş parçacığı modeli için çok iş parçacığı kullanımı örneğine bakın. TIFF'ye özel giriş seçenekleri için TIFF ve GIF giriş kılavuzu, çerçeve seçimini ve çoklu format işleme koşullarını kapsar.

Belge Yazar Hat İş Simplifikasyonu

LEADTOOLS aranabilir PDF oluşturma, motor üzerinde bir DocumentWriter örneğini yapılandırmayı, çıktı türü ve örtüşme ayarları ile bir PdfDocumentOptions nesnesi oluşturmayı, seçenekleri SetOptions() aracılığıyla uygulamayı ve ardından document.Save() ile format enum'u çağırmayı gerektirir. Bu adımların her biri ayrı bir nesne ve ayrı bir API çağrısıdır.

LEADTOOLS OCR Yaklaşımı:

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);
    }
}
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);
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports Leadtools.Forms.DocumentWriters

Public Class LeadtoolsDocumentWriterService
    Private ReadOnly _engine As IOcrEngine
    Private ReadOnly _codecs As RasterCodecs

    Public Sub CreateSearchablePdfFromImages(imagePaths As String(), outputPath As String)
        Using document = _engine.DocumentManager.CreateDocument()

            For Each imagePath In imagePaths
                Using image = _codecs.Load(imagePath)
                    Dim page = document.Pages.AddPage(image, Nothing)
                    page.Recognize(Nothing)
                End Using
            Next

            ' DocumentWriter configuration — four properties to set before save
            Dim pdfOptions As New PdfDocumentOptions With {
                .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, Nothing)
        End Using
    End Sub

    Public Sub CreateSearchablePdfFromPdf(inputPdfPath As String, outputPath As String)
        Dim pdfInfo = _codecs.GetInformation(inputPdfPath, True)
        Using document = _engine.DocumentManager.CreateDocument()

            For i As Integer = 1 To pdfInfo.TotalPages
                Using pageImage = _codecs.Load(inputPdfPath, 0, CodecsLoadByteOrder.BgrOrGray, i, i)
                    Dim page = document.Pages.AddPage(pageImage, Nothing)
                    page.Recognize(Nothing)
                End Using
            Next

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

            _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions)
            document.Save(outputPath, DocumentFormat.Pdf, Nothing)
        End Using
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

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

Public Class SearchablePdfService
    Private ReadOnly _ocr As New IronTesseract()

    Public Sub CreateSearchablePdfFromImages(imagePaths As String(), outputPath As String)
        Using input As New OcrInput()
            For Each imagePath In imagePaths
                input.LoadImage(imagePath)
            Next

            Dim result = _ocr.Read(input)
            result.SaveAsSearchablePdf(outputPath) ' DocumentWriter pipeline: gone
        End Using
    End Sub

    Public Sub CreateSearchablePdfFromPdf(inputPdfPath As String, outputPath As String)
        Using input As New OcrInput()
            input.LoadPdf(inputPdfPath)

            Dim result = _ocr.Read(input)
            result.SaveAsSearchablePdf(outputPath)
        End Using
    End Sub

    ' Get bytes directly — useful for streaming responses in ASP.NET
    Public Function CreateSearchablePdfBytes(inputPdfPath As String) As Byte()
        Using input As New OcrInput()
            input.LoadPdf(inputPdfPath)
            Return _ocr.Read(input).SaveAsSearchablePdfBytes()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

SaveAsSearchablePdf(), tüm PdfDocumentOptions + SetOptions() + document.Save() zincirini değiştirir. Resim üstü metin katmanı davranışı otomatik olarak yapılır. Tam aranabilir PDF çıktı dokümantasyonu için aranabilir PDF nasıl yapılır kılavuzu çıktı seçeneklerini kapsar ve aranabilir PDF örneği ASP.NET yanıt akışlarına entegrasyonu gösterir.

Çok Bölgeli Alan Çıkarma Göçü

LEADTOOLS bölge tabanlı OCR, OcrZone nesneleri ile LeadRect sınırları, OcrZoneType ve OcrZoneCharacterFilters özelliklerini kullanır. Birden fazla bölge tek bir sayfaya eklenir ve bir page.Recognize() çağrısında tanınır, ardından bölge indeksi ile çıkarılır. Bölge dizini ekleme sırasını eşleştirir, bu da çıkarma döngüsünün bu sıralamayı koruması gerektiği anlamına gelir.

LEADTOOLS OCR Yaklaşımı:

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; }
}
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; }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs

Public Class LeadtoolsFormFieldExtractor
    Private ReadOnly _engine As IOcrEngine
    Private ReadOnly _codecs As RasterCodecs

    ' Invoice field extraction using named zones
    Public Function ExtractInvoiceFields(invoicePath As String) As InvoiceFields
        Using image = _codecs.Load(invoicePath)
            Using document = _engine.DocumentManager.CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing)

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

                ' Zone definitions — index order matters for extraction
                Dim zoneDefinitions = New() {
                    New With {.Name = "InvoiceNumber", .X = 450, .Y = 80, .W = 200, .H = 30},
                    New With {.Name = "InvoiceDate", .X = 450, .Y = 115, .W = 200, .H = 30},
                    New With {.Name = "VendorName", .X = 50, .Y = 150, .W = 300, .H = 40},
                    New With {.Name = "TotalAmount", .X = 450, .Y = 600, .W = 200, .H = 30}
                }

                For Each def In zoneDefinitions
                    Dim zone = New OcrZone With {
                        .Bounds = New LeadRect(def.X, def.Y, def.W, def.H),
                        .ZoneType = OcrZoneType.Text,
                        .CharacterFilters = OcrZoneCharacterFilters.None,
                        .RecognitionModule = OcrZoneRecognitionModule.Auto
                    }
                    page.Zones.Add(zone)
                Next

                page.Recognize(Nothing)

                ' Extract by index — must match insertion order exactly
                Return New InvoiceFields With {
                    .InvoiceNumber = page.Zones(0).Text?.Trim(),
                    .InvoiceDate = page.Zones(1).Text?.Trim(),
                    .VendorName = page.Zones(2).Text?.Trim(),
                    .TotalAmount = page.Zones(3).Text?.Trim()
                }
            End Using
        End Using
    End Function
End Class

Public Class InvoiceFields
    Public Property InvoiceNumber As String
    Public Property InvoiceDate As String
    Public Property VendorName As String
    Public Property TotalAmount As String
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

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

Public Class FormFieldExtractor
    Private ReadOnly _ocr As New IronTesseract()

    ' Each field gets its own CropRectangle-scoped Read() call
    ' No zone index management, no zone ordering dependency
    Public Function ExtractInvoiceFields(invoicePath As String) As InvoiceFields
        Return New InvoiceFields With {
            .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)
        }
    End Function

    Private Function ReadRegion(imagePath As String, x As Integer, y As Integer, width As Integer, height As Integer) As String
        Using input As New OcrInput()
            input.LoadImage(imagePath, New CropRectangle(x, y, width, height))
            Return _ocr.Read(input).Text.Trim()
        End Using
    End Function

    ' Batch: extract the same field from many invoices in parallel
    Public Function ExtractInvoiceNumbersBatch(invoicePaths As String()) As Dictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        Parallel.ForEach(invoicePaths, Sub(invoicePath)
                                           Using input As New OcrInput()
                                               input.LoadImage(invoicePath, New CropRectangle(450, 80, 200, 30))
                                               results(invoicePath) = New IronTesseract().Read(input).Text.Trim()
                                           End Using
                                       End Sub)

        Return New Dictionary(Of String, String)(results)
    End Function
End Class
$vbLabelText   $csharpLabel

CropRectangle doğrudan LoadImage()'ya geçirildiğinde, tüm OcrZone kurulumunu değiştirir. İzlenecek bir bölge indeksi, gerekli page.Zones.Clear() çağrısı veya tanıma durumu kontrolü yoktur. bölge tabanlı OCR kılavuzu tekli ve çoklu bölge ayıklama örneklerini kapsar. Tam bir fatura alan çıkarma öğreticisi için fatura OCR öğreticisine bakın.

Sözel Koordinatlarla Yapılandırılmış Veri Çıkarma

LEADTOOLS yapılandırılmış çıktı, sayfa ve bölge seviyesinde çalışır. Bağımsız kelime düzeyinde veri elde etmek için geliştirici, tanınmış bir bölgeden OcrWord nesnelerine erişir. API tanıma sonrası bölge koleksiyonu üzerinde çalışmayı ve her bir bölge için kelime listesi yinelemeyi gerektirir.

LEADTOOLS OCR Yaklaşımı:

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; }
}
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; }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs

Public Class LeadtoolsStructuredExtractor
    Private ReadOnly _engine As IOcrEngine
    Private ReadOnly _codecs As RasterCodecs

    Public Function ExtractWordsWithLocations(imagePath As String) As List(Of WordLocation)
        Dim wordLocations As New List(Of WordLocation)()

        Using image = _codecs.Load(imagePath)
            Using document = _engine.DocumentManager.CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing)
                page.Recognize(Nothing)

                ' Access words through the zone collection
                For Each zone As OcrZone In page.Zones
                    For Each word As OcrWord In zone.Words
                        wordLocations.Add(New WordLocation With {
                            .Text = word.Value,
                            .X = word.Bounds.X,
                            .Y = word.Bounds.Y,
                            .Width = word.Bounds.Width,
                            .Height = word.Bounds.Height,
                            .Confidence = word.Confidence
                        })
                    Next
                Next
            End Using
        End Using

        Return wordLocations
    End Function
End Class

Public Class WordLocation
    Public Property Text As String
    Public Property X As Integer
    Public Property Y As Integer
    Public Property Width As Integer
    Public Property Height As Integer
    Public Property Confidence As Integer
End Class
$vbLabelText   $csharpLabel

IronOCR Yaklaşımı:

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

Public Class StructuredExtractor
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ExtractWordsWithLocations(imagePath As String) As List(Of WordLocation)
        Dim result = _ocr.Read(imagePath)

        ' Five-level hierarchy: Pages > Paragraphs > Lines > Words > Characters
        Return result.Pages _
            .SelectMany(Function(page) page.Paragraphs) _
            .SelectMany(Function(para) para.Lines) _
            .SelectMany(Function(line) line.Words) _
            .Select(Function(word) New WordLocation With {
                .Text = word.Text,
                .X = word.X,
                .Y = word.Y,
                .Width = word.Width,
                .Height = word.Height,
                .Confidence = CInt(word.Confidence)
            }) _
            .ToList()
    End Function

    ' Paragraph-level extraction with position data
    Public Sub PrintDocumentStructure(imagePath As String)
        Dim result = _ocr.Read(imagePath)
        Console.WriteLine($"Document confidence: {result.Confidence}%")

        For Each page In result.Pages
            Console.WriteLine($"Page {page.PageNumber}:")
            For Each paragraph In page.Paragraphs
                Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):")
                Console.WriteLine($"  {paragraph.Text}")
            Next
        Next
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR'un sonuç hiyerarşisi, Pages'den Paragraphs, Lines, Words ve Characters aracılığıyla aşağı iner. Her seviye, X, Y, Width, Height, Text ve Confidence'yi ortaya çıkarır. LEADTOOLS bölge tabanlı erişim örüntüsü yok olur — kelime verisine ulaşmak için bölge yinelemeye gerek yoktur. sonuçları okuma nasıl yapılır kılavuzu, koordinat erişim örüntüleriyle birlikte tam çıktı modelini kapsar. OcrResult API referansı, sonuç hiyerarşisindeki her özelliği belgeler.

LEADTOOLS OCRAPI'sinden IronOCR Haritalama Referansı

LEADTOOLS OCR IronOCR
RasterSupport.SetLicense(licPath, keyContent) IronOcr.License.LicenseKey = "key"
new RasterCodecs() Gerekli değil
OcrEngineManager.CreateEngine(OcrEngineType.LEAD) new IronTesseract()
engine.Startup(codecs, null, null, runtimePath) Gerekli değil
engine.IsStarted Gerekli değil (her zaman hazır)
engine.Shutdown() Gerekli değil
engine.Dispose() Gerekli değil
_codecs.Load(imagePath) input.LoadImage(imagePath)
_codecs.Load(path, 0, BgrOrGray, page, page) input.LoadPdf(path) veya input.LoadImageFrames(path)
_codecs.GetInformation(path, true).TotalPages Gerekli değil — otomatik
engine.DocumentManager.CreateDocument() Gerekli değil
document.Pages.AddPage(image, null) input.LoadImage(imagePath)
page.Recognize(null) ocr.Read(input) (tanıma kısmı Read())
page.GetText(-1) result.Text
page.RecognizeStatus result.Confidence (yüzde)
OcrZone { Bounds = new LeadRect(x, y, w, h) } new CropRectangle(x, y, w, h)
page.Zones.Clear() Gerekli değil
page.Zones.Add(zone) input.LoadImage(path, cropRect)
zone.Words / word.Bounds result.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 } SaveAsSearchablePdf() tarafından otomatik olarak ele alınır
engine.DocumentWriterInstance.SetOptions(format, opts) Gerekli değil
document.Save(path, DocumentFormat.Pdf, null) result.SaveAsSearchablePdf(path)
_codecs.Options.Pdf.Load.Password = password input.LoadPdf(path, Password: password)
RasterSupport.IsLocked(RasterSupportType.Document) IronOcr.License.IsLicensed

Yaygın Göç Sorunları ve Çözümleri

Sorun 1: Lisans Dosya Yolu Çözümleme Hataları

LEADTOOLS: RasterSupport.SetLicense(), .LIC ve .LIC.KEY dosya yollarını çalışma dizinine göre çözer, bu da bin/Debug, bin/Release, Docker konteynerleri ve IIS uygulama havuzları arasında farklılık gösterir. Yaygın bir başarısızlık modu, geliştirme sırasında çalışan ancak üretimde "License file not found" fırlatan bir yoldur, çünkü çalışma dizini değişmiştir.

Çözüm: Her iki lisans dosyasını ve SetLicense() çağrısını tamamen silin. Bir ortam değişkeninden okunan tek bir dize ataması ile değiştirin:

// 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");
// 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");
' Remove this:
' RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath))

' Replace with this:
IronOcr.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONOCR_LICENSE"), Throw New InvalidOperationException("IRONOCR_LICENSE environment variable not set"))
$vbLabelText   $csharpLabel

Dize anahtarı, her ortamda aynı şekilde davranır. Bunu, veritabanı bağlantı dizgeleri için zaten kullanılan aynı gizli yöneticiye depolayın.

Sorun 2: Motor Başlatılmadı İstisnası

LEADTOOLS: engine.Startup() tamamlanmadan önce veya engine.Shutdown() çağrıldıktan sonra (örneğin, kapatma sırasında kullanımdan önce yok etmek yarışı durumu), bir InvalidOperationException "Motor başlatılmadı." ile fırlatır. Uzun ömürlü servis sınıfları, IsStarted kontrolleri ile buna karşı koruma sağlamalıdır.

Çözüm: IronTesseract, başlangıç çağrısı gerektirmez ve başlatılmış/durdurulmuş bir durumu yoktur. IsStarted koruması ve tüm yaşam döngüsü servis sınıfı silinebilir:

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

// IronTesseract is always ready — just call Read()
var result = _ocr.Read(imagePath);
// Remove the guard:
// if (!_engine.IsStarted)
//     throw new InvalidOperationException("Engine not started");

// IronTesseract is always ready — just call Read()
var result = _ocr.Read(imagePath);
$vbLabelText   $csharpLabel

Sorun 3: Batch İşlemde RasterImage Bellek Birikimi

LEADTOOLS: PDF sayfaları veya görüntü dosyaları üzerinde yineleyerek gerçekleştirilen toplu işlem, bir döngü içinde RasterImage örnekleri oluşturur. Herhangi bir kod yolu, using bloğundan çıkmadan önce atılan bir istisna nedeniyle veya eksik bir çağrı ile manuel bir imha deseni nedeniyle bir RasterImage'yi imha etmezse, serbest bırakılmamış görüntüler bellekte birikir. LEADTOOLS üretim kodu, toplu işlemeler arasında GC.Collect() / GC.WaitForPendingFinalizers() çağrılarını telafi edici bir mekanizma olarak yaygın bir şekilde içerir.

Çözüm: Tüm GC.Collect() çağrılarını kaldırın. OcrInput,IronOCR işlem hattında tek IDisposable'dir ve standart using bloğu ile her toplu işlem için kapsamlanmıştır.

// 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
}
// 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
}
' Remove this pattern:
' GC.Collect()
' GC.WaitForPendingFinalizers()

' Replace with standard using scope:
For Each filePath In filePaths
    Using input As New OcrInput()
        input.LoadImage(filePath)
        Dim text = _ocr.Read(input).Text
        ' input disposed here — no accumulation
    End Using
Next
$vbLabelText   $csharpLabel

Ek bellek optimizasyonu kılavuzu için müşteri bellek tahsisi azaltımı blog yazısına başvurun.

Sorun 4: DocumentWriterInstance Seçenekleri Çağrılar Arasında Kalıcı

LEADTOOLS: engine.DocumentWriterInstance.SetOptions(), paylaşılan motor yazar örneğinde durumu değiştirir. Bir kod yolu PdfDocumentOptions'yı DocumentType = PdfDocumentType.PdfA ile ayarlarsa ve müteakip çağrı bu seçenekleri document.Save()'dan önce sıfırlamazsa, önceki çağrının çıktı formatı kalır. Bu, paylaşılan motor örneğinde duruma dayalı yan etkidir.

Çözüm: IronOCR, paylaşılan yazıcı durumu yoktur. Her SaveAsSearchablePdf() çağrısı bağımsızdır:

// 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);
// 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);
' Remove the options setup:
' Dim pdfOptions As New PdfDocumentOptions With { ... }
' _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions)
' document.Save(outputPath, DocumentFormat.Pdf, Nothing)

' Replace with:
result.SaveAsSearchablePdf(outputPath)
$vbLabelText   $csharpLabel

Her çağrı, bir görüntü kaplaması ve aranabilir bir metin katmanı ile standart PDF çıktısı üretir. Çağrılar arasında sıfırlanması gereken paylaşılan seçenek durumu yoktur.

Sorun 5: Yanlış Paket — Çalışma Zamanında Eksik Modül

LEADTOOLS: Document Imaging SDK'sını satın alan ekipler, Leadtools.Pdf türlerinin kullanılamayabileceğini veya şifreli PDF sayfalarının RasterException ile RasterExceptionCode.FeatureNotSupported fırlatabileceğini görebilir. Bu, satın alınan paketin PDF modülünü içermediğinde olur ve hata yalnızca üretimde çalışma zamanında ortaya çıkar.

Çözüm: IronOCR, her lisans katmanında tüm özellikleri içerir. Ayrı bir PDF modülü, şifreli belgeler için bir eklenti veya daha yüksek doğruluklu bir motor için ikinci bir satıcı bulunmamaktadır. Tek IronOcr paketi yüklendikten sonra, tam özellik seti herhangi bir ek satın alma gerektirmeden kullanılabilir durumdadır.

dotnet add package IronOcr

Sorun 6: Boylam İndeksi Yeniden Sıralama Sonrası Uyumsuzluk

LEADTOOLS: Bölge çıkarımı, çıkarım mantığını page.Zones.Add()'deki yerleştirme sırasına bağlayan pozisyonel indeksleme — page.Zones[0].Text, page.Zones[1].Text — kullanır. Bölge tanımlarını otomatik güncellemeyi ifade eden ya da yeniden sıralamak, ardından gelen tüm indeksleri yerleştirerek sessizce kırar.

Çözüm: IronOCR, alan başına CropRectangle ile adlandırılmış değişkenler kullanır. Alan tanımlarının yeniden sıralanması, çıkarma sırasında hiçbir etkiye sahip değildir çünkü her alan bağımsız olarak kapsamlanmıştır:

// 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);
// 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);
' Each field is independent — reorder freely without breaking extraction
Dim invoiceNumber = ReadRegion(imagePath, 450, 80, 200, 30)
Dim invoiceDate = ReadRegion(imagePath, 450, 115, 200, 30)
Dim vendorName = ReadRegion(imagePath, 50, 150, 300, 40)
Dim totalAmount = ReadRegion(imagePath, 450, 600, 200, 30)
$vbLabelText   $csharpLabel

LEADTOOLS OCRGöç Kontrol Listesi

Öncesi-Geçiş

Değişiklik yapmadan önce tüm LEADTOOLS kullanımını belirlemek için kod tabanını denetleyin:

# 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" .
# 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

Satın alınan LEADTOOLS paketinin — OCR modülü, PDF modülü ve motor türü (LEAD vs Tesseract vs OmniPage) — hangi olduğunu not edin, böylece eşdeğer IronOCR özellikleri göç sonrası doğrulama sırasında test edilir.

Kod Geçişi

  1. Tüm LEADTOOLS NuGet paketlerini kaldırın: Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters, Leadtools.Pdf
  2. IronOcr NuGet paketini yükleyin
  3. Tüm LEADTOOLS using direktiflerini using IronOcr; ile değiştirin
  4. .LIC ve .LIC.KEY dosyalarını projeden ve dağıtım ürünlerinden kaldırın
  5. Uygulama başlatıldığında RasterSupport.SetLicense(licPath, keyContent)IronOcr.License.LicenseKey = "key" ile değiştirin
  6. Sadece IOcrEngine ve RasterCodecs yaşam döngüsünü yönetmek için var olan tüm IDisposable servis sınıflarını silin
  7. OcrEngineManager.CreateEngine() + engine.Startup() yerine new IronTesseract() kullanın
  8. _codecs.Load(imagePath)'ı, bir using var input = new OcrInput() bloğu içinde input.LoadImage(imagePath) ile değiştirin
  9. Çok çerçeveli TIFF sayfa döngülerini input.LoadImageFrames(tiffPath) ile değiştirin
  10. PDF sayfa döngüsü yinelemesini input.LoadPdf(pdfPath) ile değiştirin
  11. document.Pages.AddPage() + page.Recognize(null) + page.GetText(-1) yerine ocr.Read(input).Text kullanın
  12. OcrZone + page.Zones.Add() kalıplarını input.LoadImage(path, new CropRectangle(x, y, w, h)) ile değiştirin
  13. PdfDocumentOptions + DocumentWriterInstance.SetOptions() + document.Save() yerine result.SaveAsSearchablePdf(path) kullanın
  14. Ön işlem komut sınıflarını (DeskewCommand, DespeckleCommand, AutoBinarizeCommand) input.Deskew(), input.DeNoise(), input.Binarize() ile OcrInput örneğinde değiştirin
  15. LEADTOOLS bellek yönetimini telafi etmek için eklenen tüm GC.Collect() / GC.WaitForPendingFinalizers() çağrılarını kaldırın

Geçiş Sonrası

  • Tanınan metin çıktısının, temsilci bir görüntü ve PDF örneği üzerinde LEADTOOLS çıktısıyla eşleştiğini doğrulayın
  • result.Confidence kullanarak güven puanlarının beklenen aralıklarda olduğundan emin olun
  • Çok kareli TIFF işleme, LEADTOOLS çerçeve yineleme döngüsü ile aynı sayıda sayfa ürettiğini test edin
  • Aranabilir PDF çıktısının, bir PDF okuyucusunda (Adobe Acrobat veya dengi) metin aranabilir olduğunu onaylayın
  • Üretim faturalarından veya formlarından bilinen iyi alan değerlerine karşı alan tabanlı çıkarımı test edin
  • Ayrı Leadtools.Pdf modülü olmadan şifre korumalı PDF şifresinin çözüldüğünü doğrulayın
  • Yük altında toplu işlemeyi çalıştırın ve bellek artışı olmadığını doğrulayın (önce tüm GC.Collect() kaldırın)
  • Lisans dosyası olmadan Docker ve CI/CD dağıtımını test edin — lisans anahtarının ortam değişkeninden doğru şekilde çözümlendiğini doğrulayın
  • İş parçacığı güvenliğini doğrulamak için Parallel.ForEach ile paralel işlemeyi test edin
  • Yapılandırılmış veri çıkarımının (result.Pages, page.Paragraphs, page.Words) doğru koordinatları döndürdüğünü doğrulayın

IronOCR'a Geçişin Ana Faydaları

Dağıtım Durumsuz Hale Gelir. LEADTOOLS .LIC ve .LIC.KEY dosyaları, her dağıtım ortamının taşıması gereken artefaktlardır. Onları içeren kapsayıcılar lisans verilerini imaj geçmişinde açığa çıkarır. Onları monte eden kapsayıcılar, hacim koordinasyonu gerektirir. IronOCR'ye göçten sonra, lisans bir ortam değişkeninde bir dizgedir. Dağıtım eseri, bir standart NuGet referansıdır. Dosya yoktur, yol yoktur, montaj stratejisi yoktur. Docker dağıtım kılavuzu ve Azure dağıtım kılavuzu, kapsayıcılaştırılmış ortamlar için tamamlanmış ayarı gösterir.

Dört Paket Bir Olur. Geçiş Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters ve isteğe bağlı olarak Leadtools.Pdf'yı tek bir IronOcr referansına indirir. Tüm yetenekler — işlem öncesi, yerel PDF girişi, aranabilir PDF çıktısı, barkod okuma, yapılandırılmış veri çıkarma, 125+ dil desteği — tek pakette yer alır. Özellik seti, hangi paketin satın alındığına bağlı değildir.

Toplu İşlem Elle Bellek Yönetimini Ortadan Kaldırır. LEADTOOLS toplu kodu, çok belgeli işlemler sırasında bellek birikimini önlemek için defansif GC.Collect() çağrılarını ve açık RasterImage imhasını taşır. IronOCR'un OcrInput'ü, bir using bloğu ile kapsamlanmış, temizlemeyi otomatik olarak gerçekleştirir. Paralel iş parçacığı güvenli işleme Parallel.ForEach ile — iş parçacığı başına bir IronTesseract örneği — senkronizasyon kodu olmadan çok çekirdekli verim sağlar. Üretim throughput ayarı için hız optimizasyonu kılavuzuna bakın.

Öngörülebilir Toplam Maliyet. LEADTOOLS'un beş geliştiricili bir ekip için tahmini maliyeti, ilk yılda 15.000–40.000 $ arasında koşar ve lisans maliyetinin %20-25'i oranında yıllık bakım gerektirir.IronOCR Professional $2,999'de on geliştirici ve on dağıtım konumunu kapsar ve bir kerelik süresiz bir satın almadır. Bir yıl güncellemeler dahildir. Güncelleme döneminden sonra devam eden kullanım için ek ödeme gerekmemektedir. IronOCR lisans sayfası, tüm katman fiyatlarını doğrudan yayınlar, satış danışmanlığı olmadan.

Bölge Kurulumu Olmadan Yapılandırılmış Veri. Geçişten sonra OcrResult üzerinde doğrudan sınırlayıcı kutu koordinatları ile kelime seviyesi, satır seviyesi ve paragraf seviyesi veri elde edilebilir duruma gelir — bölge tanımları gerekmez. Beş seviyeli hiyerarşi (Pages, Paragraphs, Lines, Words, Characters) her biri konum koordinatlarını ve eleman bazlı güven puanlarını sunar. Yapısal çıkarım elde etmek için LEADTOOLS bölge yapılandırmasına ihtiyaç duyan uygulamalar, daha basit bir API'den daha zengin veri elde ederler. OCR sonuçları özellik sayfası, tam çıktı modelini özetler.

Lütfen dikkate alınAdobe Acrobat, Kofax OmniPage, LEADTOOLS ve Tesseract kendi sahiplerinin tescilli ticari markalarıdır. Bu site, Adobe Inc., Apryse, Google, Kofax veya LEAD Technologies tarafından bağlı, onaylanmış veya desteklenmemektedir. Tüm ürün adları, logolar ve markalar kendi sahiplerine aittir. Karşılaştırmalar, yalnızca bilgilendirme amaçlıdır ve yazı sırasında halka açık bilgilerle alakalı olarak yansıtılmaktadır.

Sıkça Sorulan Sorular

LEADTOOLS OCR'den IronOCR'ye neden geçmeliyim?

Yaygın geçiş nedenleri arasında COM ara bağlamının karmaşıklığını ortadan kaldırmak, dosya tabanlı lisans yönetimini değiştirmek, sayfa başına fatura düzenlemekten kaçınmak, Docker/kapsayıcı dağıtımını etkinleştirmek ve standart .NET araçlarıyla entegre olan bir NuGet doğal iş akışı benimsemek yer almaktadır.

LEADTOOLS OCR'den IronOCR'ye geçişteki ana kod değişiklikleri nelerdir?

LEADTOOLS OCR başlangıç dizilerini IronTesseract örneği ile değiştirin, COM yaşam döngüsü yönetimini (açık Create/Load/Close desenleri) kaldırın ve sonuç özellik adlarını güncelleyin. Sonuç, önemli ölçüde daha az boilerplate satırıdır.

Geçişi başlatmak için IronOCR'u nasıl kurarım?

Paket Yöneticisi Konsolunda 'Install-Package IronOcr' veya CLI'da 'dotnet add package IronOcr' çalıştırın. Dil paketleri ayrı paketlerdir: Örneğin, Fransızca için 'dotnet add package IronOcr.Languages.French'.

IronOCR, LEADTOOLS OCR'in standart iş belgeleri için OCR doğruluğunu karşılıyor mu?

IronOCR, faturalar, sözleşmeler, makbuzlar ve yazılı formlar dahil olmak üzere standart işletme içerikleri için yüksek doğruluğa ulaşır. Görüntü ön işleme filtreleri (dengelemeyi düzeltme, gürültü kaldırma, kontrast artırma) bozulmuş girdiler üzerindeki tanımayı daha da iyileştirir.

IronOCR, LEADTOOLS OCR'in ayrı kurduğu dil verilerini nasıl yönetiyor?

IronOCR'daki dil verileri, NuGet paketleri olarak dağıtılır. 'dotnet add package IronOcr.Languages.German' komutuyla Almanca desteği yüklenir. Herhangi bir manuel dosya yerleştirme veya dizin yolu gerekmez.

LEADTOOLS OCR'den IronOCR'ye geçiş, dağıtım altyapısında değişiklik gerektiriyor mu?

IronOCR, LEADTOOLS OCR'den daha az altyapı değişikliği gerektirir. SDK ikili yolları, lisans dosyası yerleşimleri veya lisans sunucu yapılandırmaları yoktur. NuGet paketi, tam OCR motorunu içerir ve lisans anahtarı uygulama kodunda belirlenmiş bir dizgedir.

Geçişten sonra IronOCR lisanslamasını nasıl yapılandırırım?

Uygulama başlangıç ​​kodunda IronOcr.License.LicenseKey = "SİZİN-ANAHTARINIZ" atayın. Docker veya Kubernetes'te, anahtarı bir ortam değişkeni olarak saklayın ve başlangıçta okuyun. Trafiği kabul etmeden önce doğrulamak için License.IsValidLicense kullanın.

IronOCR, PDF'leri LEADTOOLS OCR gibi işleyebilir mi?

Evet. IronOCR hem yerel hem de taranmış PDF'leri okur. Bir PDF yolu veya OcrPdfInput olan girdiye ocr.Read(input) çağrısı yapmak için IronTesseract örneği çağırın ve OcrResult sayfalarını yineleyin. Ayrı bir PDF işleme hattı gerekmez.

IronOCR, yüksek hacim işleme sırasında iş parçacığı nasıl ele alır?

IronTesseract, iş parçacığı başına örnek olacak şekilde güvenlidir. Paralel.ForEach veya Görev havuzunda her iş parçacığı için bir örnek oluşturun, OCR'u eşzamanlı olarak çalıştırın ve her örneği iş tamamlandığında bırakın. Küresel durum veya kilitleme gerekmez.

IronOCR metin çıktıktan sonra hangi çıktıları destekler?

IronOCR, metin, kelime koordinatları, güven skorları ve sayfa yapısını içeren yapılandırılmış sonuçlar döndürür. Dışa aktarma seçenekleri düz metin, aranabilir PDF ve aşağı akış işlemesi için yapılandırılmış sonuç nesneleri içerir.

IronOCR'ın fiyatlandırması, ölçeklendirme iş yükleri için LEADTOOLS OCR'den daha öngörülebilir mi?

IronOCR, sayfa başına veya hacim ücretlendirmesi olmadan düz oranlı sürekli lisanslama kullanır. 10.000 veya 10 milyon sayfa işleseniz de lisans maliyeti sabit kalır. Hacim ve ekip lisanslama seçenekleri IronOCR fiyatlandırma sayfasındadır.

LEADTOOLS OCR'den IronOCR'ye geçtikten sonra mevcut testlerime ne olacak?

Çıkarılmış metin içeriğini doğrulayan testler, geçişten sonra çalışmaya devam etmelidir. API çağrı şablonlarını veya COM nesne yaşam döngüsünü doğrulayan testler, IronOCR'un daha basit başlatma ve sonuç modelini yansıtacak şekilde güncellenmelidir.

Curtis Chau
Teknik Yazar

Curtis Chau, Bilgisayar Bilimleri alanında Lisans Derecesine (Carleton Üniversitesi) sahip ve Node.js, TypeScript, JavaScript ve React konularında uzmanlaşmış ön uç geliştirmeyle ilgileniyor. Sezgisel ve estetik açıdan hoş kullanıcı arayüzleri oluşturma tutkunu, Curtis modern çerçevelerle çalışmayı ve iyi yapı...

Daha Fazla Oku

Iron Destek Ekibi

Haftada 5 gün, 24 saat çevrimiçiyiz.
Sohbet
E-posta
Beni Ara