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
// 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
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
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
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")
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
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
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
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
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
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
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
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
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
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
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"))
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);
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
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)
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)
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" .
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
- Tüm LEADTOOLS NuGet paketlerini kaldırın:
Leadtools,Leadtools.Ocr,Leadtools.Codecs,Leadtools.Forms.DocumentWriters,Leadtools.Pdf IronOcrNuGet paketini yükleyin- Tüm LEADTOOLS
usingdirektifleriniusing IronOcr;ile değiştirin .LICve.LIC.KEYdosyalarını projeden ve dağıtım ürünlerinden kaldırın- Uygulama başlatıldığında
RasterSupport.SetLicense(licPath, keyContent)'üIronOcr.License.LicenseKey = "key"ile değiştirin - Sadece
IOcrEngineveRasterCodecsyaşam döngüsünü yönetmek için var olan tümIDisposableservis sınıflarını silin OcrEngineManager.CreateEngine()+engine.Startup()yerinenew IronTesseract()kullanın_codecs.Load(imagePath)'ı, birusing var input = new OcrInput()bloğu içindeinput.LoadImage(imagePath)ile değiştirin- Çok çerçeveli TIFF sayfa döngülerini
input.LoadImageFrames(tiffPath)ile değiştirin - PDF sayfa döngüsü yinelemesini
input.LoadPdf(pdfPath)ile değiştirin document.Pages.AddPage()+page.Recognize(null)+page.GetText(-1)yerineocr.Read(input).TextkullanınOcrZone+page.Zones.Add()kalıplarınıinput.LoadImage(path, new CropRectangle(x, y, w, h))ile değiştirinPdfDocumentOptions+DocumentWriterInstance.SetOptions()+document.Save()yerineresult.SaveAsSearchablePdf(path)kullanın- Ön işlem komut sınıflarını (
DeskewCommand,DespeckleCommand,AutoBinarizeCommand)input.Deskew(),input.DeNoise(),input.Binarize()ileOcrInputörneğinde değiştirin - 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.Confidencekullanarak 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.Pdfmodü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.ForEachile 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.
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.

