Migracja z Charlesw Tesseract do IronOCR
Ten przewodnik wprowadza deweloperów .NET w proces migracji z pakietu NuGet charlesw/tesseract (Tesseract) do IronOCR. Migracja skupia się na jednym konkretnym problemie: modelu wdrażania natywnych binariów, który narzuca wraper charlesw i kodzie warunkowym platformy, który zmusza deweloperów do tworzenia. Zespoły, które miały trudności z DllNotFoundException w CI, zmagały się z Leptonica library paths na Linuxie, lub pisały bloki wykrywania systemu operacyjnego nie mające nic wspólnego z OCR, znajdą w tym przewodniku dokładne informacje o tym, co znika po zmianie.
Dlaczego warto przejść z Charlesw na Tesseract
Archiwizowany pakiet charlesw/tesseract powoduje problemy w nowych projektach nie ze względu na zły API, ale ponieważ wymaga modelu wdrażania, który został zaprojektowany na podstawie założeń nieaktualnych w nowoczesnej infrastrukturze .NET. Oto, co decyduje o wyborze migracji:
Natywne wdrażanie binarne na platformę. Pakiet NuGet Tesseract dostarcza platformowo-specyficzne natywne binaria: tesseract50.dll dla Windows x64, osobny build dla x86, libtesseract.so dla Linux x64. Te binaria muszą się znaleźć w poprawnej lokalizacji podczas działania, aby wywołania P/Invoke zakończyły się sukcesem. Na stacji roboczej programisty SDK kopiuje je automatycznie. W kontenerze Docker, agencie kompilacji ARM64 lub usłudze Azure App Service z niestandardowym katalogiem głównym aplikacji nie ma to miejsca. Każde nowe wdrożenie staje się sesją debugowania.
Leptonica jako ukryta zależność. Ładowanie obrazów w Tesseract jest obsługiwane przez bibliotekę Leptonica, która jest dostarczana jako osobny zestaw natywnych bibliotek DLL wraz z plikami binarnymi Tesseract. Na Windows leptonica-1.82.0.dll musi się znajdować w katalogu wyjściowym. W systemie Linux biblioteka współdzielona Leptonica musi być dołączona do pakietu lub zainstalowana jako pakiet systemowy. Obrazy Docker oparte na Debianie bez libleptonica-dev zawodzą przy Pix.LoadFromFile() z niewyjaśnionym wyjątkiem natywnym, a rozwiązanie tego wymaga znajomości systemowego pakietu rozwiązującego zależność.
Kod warunkowy platformy w logice aplikacji. Połączenie ładowania natywnego binariów i rozwiązywania ścieżki tessdata zmusza deweloperów do pisania sprawdzeń RuntimeInformation.IsOSPlatform(), wykrywania zmiennych środowiskowych w kontekstach kontenerowych i logiki budowania ścieżek zmieniającej się w zależności od celu. Żaden z tych kodów nie jest logiką OCR. Jest to infrastruktura wdrożeniowa, która istnieje wyłącznie dlatego, że zarządzanie plikami binarnymi pakietu jest niekompletne.
Zarchiwizowany pakiet bez ścieżki naprawy. Repozytorium zostało zarchiwizowane w 2021 roku. Gdy aktualizacja pakietu systemowego na hoście Linux zmienia Leptonica ABI lub gdy nowe środowisko uruchomieniowe .NET zmienia zachowanie ładowania natywnych plików binarnych, nie ma wersji, do której można by dokonać aktualizacji. Jedynymi opcjami są rozwidlenie natywnego potoku kompilacji lub wymiana biblioteki.
Tesseract 4.1.1 Engine Freeze. Pakiet zawiera Tesseract 4.1.1. Przepisany model LSTM w Tesseract 5 zapewnia znacznie wyższą dokładność w przypadku dokumentów o niskiej jakości. Ta aktualizacja nie jest dostępna w pakiecie charlesw — wymaga zmiany bibliotek.
Zarządzanie poziomem zaufania bez standardowego wzoru. Wraper charlesw wystawia page.GetMeanConfidence() jako liczbę zmiennoprzecinkową między 0 a 1, ale zastosowanie progów zaufania na poziomie słowa lub znaku wymaga wzorca iteratora z iter.GetConfidence(PageIteratorLevel.Word). Nie ma standardowego interfejsu API do filtrowania; każdy zespół wdraża własną logikę progową w inny sposób.
Podstawowy problem
Oprogramowanie Charlesw wymaga konfiguracji natywnego pliku binarnego specyficznego dla platformy, zanim będzie można uruchomić OCR:
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
Imports System
Imports System.Runtime.InteropServices
Imports Tesseract
' charlesw Tesseract: OS detection required just to find native DLLs
' DllNotFoundException on any platform where binaries do not resolve
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib")
End If
Dim engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath) ' Requires leptonica native DLL
Using page As Page = engine.Process(img)
Return page.GetText()
End Using
End Using
IronOCR nie posiada natywnej konfiguracji binarnej:
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
' IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text
IronOCR a Charlesw Tesseract: porównanie funkcji
Poniższa tabela przedstawia funkcje istotne dla zespołów oceniających tę migrację:
| Funkcja | Charlesw Tesseract | IronOCR |
|---|---|---|
| Status konserwacji | Archiwizowane (brak aktualizacji od 2021 r.) | Aktywnie utrzymywane |
| Wersja silnika Tesseract | 4.1.1 (zamrożone) | 5 (aktualne, zoptymalizowane) |
| Licencja | Apache 2.0 (bezpłatna) | Komercyjna ($999–$2,999 wieczysta) |
| Instalacja NuGet | Tesseract |
IronOcr |
| Natywne zarządzanie plikami binarnymi | Ręczne wdrażanie bibliotek DLL na poszczególnych platformach | W pakiecie, bez konfiguracji |
| Zależność od Leptonica | Wymaga leptonica-1.82.0.dll / libleptonica-dev |
Nie dotyczy (obsługiwane wewnętrznie) |
| Zarządzanie danymi Tessdata | Ręczne pobieranie i .csproj kopiowanie wpisów |
Pakiety językowe NuGet |
| Kod zależny od platformy | Wymagane do wdrożenia w wielu językach | Nie jest wymagane |
| Wdrożenie Docker | Wymaga jawnego tessdata COPY + Leptonica apt-get |
Tylko standardowe wymagania dotyczące kontenerów .NET Standard |
| Obsługa ARM64 | Niepotwierdzony wpis w archiwum | W pakiecie, zweryfikowane |
| Formaty obrazów | TIFF, PNG, BMP, JPG (za pośrednictwem Leptonica) | JPG, PNG, BMP, TIFF, GIF i inne |
| Wielostronicowy plik TIFF | Ręczna iteracja ramki | input.LoadImageFrames() |
| Natywne wprowadzanie plików PDF | Nie (wymaga biblioteki dodatkowej) | Tak |
| Wynik w formacie PDF z możliwością wyszukiwania | Nie | Tak (result.SaveAsSearchablePdf()) |
| Wbudowane przetwarzanie wstępne | None | Wyrównanie, Usuwanie szumów, Kontrast, Binaryzacja, Wyostrzanie, Skalowanie, Rozszerzanie, Erodowanie, Odwracanie |
| API filtrowania pewności | Ręczny iterator z GetConfidence() |
result.Confidence, word.Confidence |
| Wyniki uporządkowane | Wzorzec iteratora (ResultIterator) |
Bezpośrednie fragmenty (strony, akapity, wiersze, słowa) |
| Odczytywanie BarCode | Nie | Tak (podczas przetwarzania OCR) |
| OCR oparte na regionie | Nie | Tak (CropRectangle) |
| Bezpieczeństwo wątków | Odpowiedzialność dzwoniącego | Wbudowane |
| Ponad 125 pakietów językowych | Ręczne pobieranie plików tessdata | dotnet add package IronOcr.Languages.* |
| Wielopłatformowy .NET | Tak (.NET Standard 2.0) | Tak (.NET Framework 4.6.2+, .NET 5/6/7/8/9) |
| Częstotliwość wydawania poprawek bezpieczeństwa | Brak (archiwum) | Regularne wydania |
Szybki start: Migracja zCharlesw Tesseractdo IronOCR
Krok 1: Zastąp pakiet NuGet
Usuń pakiet charlesw Tesseract:
dotnet remove package Tesseract
dotnet remove package Tesseract
Zainstaluj IronOCR z NuGet:
dotnet add package IronOcr
Krok 2: Aktualizacja przestrzeni nazw
// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;
// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;
Imports IronOcr
Krok 3: Inicjalizacja licencji
Dodaj to wywołanie raz podczas uruchamiania aplikacji, przed wykonaniem jakichkolwiek operacji OCR:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Bezpłatna licencja próbna jest dostępna na stronie licencyjnej IronOCR. Wersja próbna usuwa znak wodny z wyników i zapewnia pełny dostęp do API.
Przykłady migracji kodu
Usuwanie konfiguracji natywnej ścieżki plików binarnych
Najczęstszym wzorcem inicjalizacji w projektach charlesw/tesseract jest klasa fabryczna lub pomocnicza, która tworzy ścieżkę tessdata i konfiguruje ładowanie bibliotek natywnych dla danego środowiska. Ten kod istnieje wyłącznie ze względu na model wdrażania opakowania.
Podejście Charlesw Tesseract:
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports Tesseract
Public Module OcrEngineFactory
Private Function GetTessDataPath() As String
' Different path per environment — all wrong until explicitly configured
If Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") = "true" Then
Return "/app/tessdata" ' Docker
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Return Path.Combine(AppContext.BaseDirectory, "tessdata") ' Linux bare metal
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.OSX) Then
Return "/usr/local/share/tessdata" ' macOS Homebrew install
End If
Return ".\tessdata" ' Windows dev machine
End Function
Public Function Create(Optional language As String = "eng") As TesseractEngine
' If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
' If tessdata folder is missing: TesseractException at engine construction
Return New TesseractEngine(GetTessDataPath(), language, EngineMode.Default)
End Function
End Module
' Call site
Using engine As TesseractEngine = OcrEngineFactory.Create()
Using img As Pix = Pix.LoadFromFile("invoice.jpg")
Using page As Page = engine.Process(img)
Console.WriteLine(page.GetText())
End Using
End Using
End Using
Podejście IronOCR:
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
' IronOCR: no factory, no path logic, no OS detection
' Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("invoice.jpg")
Console.WriteLine(result.Text)
Cała klasa OcrEngineFactory usuwa się. Logiczne ścieżki warunkowe platformy, kontrola DOTNET_RUNNING_IN_CONTAINER oraz zależność od Leptonica DLL znikają wraz z nią. Każde środowisko — stacja robocza programisty, agent CI, kontener Docker, maszyna wirtualna w chmurze — wykonuje te same dwie linijki kodu. Podręcznik konfiguracji IronTesseract opisuje opcje konfiguracyjne, które należy dostosować w przypadku konieczności zmiany ustawień domyślnych, jednak w większości przypadków nie są one wymagane.
Zastąpienie konwersji obrazu Leptonica
Wraper charlesw używa typu Pix Leptonica jako reprezentacji obrazu. Każdy kod, który zmienia obrazy przed OCR, musi przeprowadzić konwersję przez Pix, co wymaga załadowania i działania natywnego DLL Leptonica. Zastąpienie tego wzorca OcrInput całkowicie eliminuje zależność od Leptonica.
Podejście Charlesw Tesseract:
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
// Nie direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
// Nie direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
Imports System
Imports System.Drawing
Imports System.IO
Imports Tesseract
Public Class ImageProcessor
' Pix is Leptonica's image type — requires leptonica native DLL
' Converting from System.Drawing.Bitmap requires a temp file round-trip
Public Function ProcessInMemoryImage(bitmap As Bitmap) As String
' Nie direct Bitmap → Pix conversion; must write to temp file
Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png")
Try
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using pix As Pix = Pix.LoadFromFile(tempPath) ' Leptonica file I/O
Using page As Page = engine.Process(pix)
Return page.GetText()
End Using
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
End Function
End Class
Podejście IronOCR:
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}
Imports System.IO
' OcrInput accepts byte arrays and streams — no temp file, no Leptonica
Public Function ProcessInMemoryImage(imageBytes As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageBytes) ' Direct byte array loading
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
End Function
' Or from a stream — same pattern
Public Function ProcessFromStream(imageStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(imageStream)
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
End Function
Znikają operacje związane z plikami tymczasowymi. Żaden plik nie jest zapisywany na dysku, żaden DLL Leptonica nie jest wywoływany do konwersji i nie ma bloku finally do czyszczenia. Przewodnik po wczytywaniu obrazów image input guide i przewodnik po strumieniach stream input guide dokumentują wszystkie obsługiwane źródła wejścia, w tym ładowanie z adresów URL i plików mapowanych w pamięci.
Filtrowanie progu pewności
Wraper charlesw wystawia poziomy zaufania na dwóch poziomach: page.GetMeanConfidence() dla całej strony i iter.GetConfidence(PageIteratorLevel.Word) dla poszczególnych słów. Odfiltrowanie słów o niskim poziomie pewności z wyniku wymaga ręcznego zarządzania pętlą iteracyjną.IronOCR udostępnia poziom pewności bezpośrednio w obiektach wynikowych, dzięki czemu logika progowa staje się wyrażeniem LINQ.
Podejście Charlesw Tesseract:
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}
Imports System
Imports Tesseract
Public Class WordExtractor
Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Single = 0.8F) As List(Of String)
Dim highConfidenceWords As New List(Of String)()
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath)
Using page As Page = engine.Process(img)
' Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}")
Using iter As ResultIterator = page.GetIterator()
iter.Begin()
Do
If iter.IsAtBeginningOf(PageIteratorLevel.Word) Then
Dim wordText As String = iter.GetText(PageIteratorLevel.Word)?.Trim()
Dim wordConf As Single = iter.GetConfidence(PageIteratorLevel.Word) / 100.0F ' Returns 0-100
If Not String.IsNullOrEmpty(wordText) AndAlso wordConf >= minConfidence Then
highConfidenceWords.Add(wordText)
End If
End If
Loop While iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word)
End Using
End Using
End Using
End Using
Return highConfidenceWords
End Function
End Class
Podejście IronOCR:
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Double = 80.0) As List(Of String)
Dim result = New IronTesseract().Read(imagePath)
Console.WriteLine($"Page confidence: {result.Confidence}%")
' LINQ directly on the word collection — no iterator state management
Return result.Pages _
.SelectMany(Function(p) p.Lines) _
.SelectMany(Function(l) l.Words) _
.Where(Function(w) w.Confidence >= minConfidence AndAlso Not String.IsNullOrWhiteSpace(w.Text)) _
.Select(Function(w) w.Text) _
.ToList()
End Function
Maszyna stanów iteratora zniknęła. Wartości pewności w IronOCRsą konsekwentnie podawane w skali od 0 do 100, nie jest wymagane dzielenie przez 100. Przewodnik po wskaźnikach pewności obejmuje wzorce pewności w odniesieniu do poszczególnych słów, wierszy i stron. Przewodnik po wynikach wyszukiwania pokazuje, jak poruszać się po pełnej hierarchii wyników.
Przetwarzanie wielostronicowych plików TIFF w trybie wsadowym
Pliki TIFF zawierające wiele klatek są powszechne w procesach skanowania dokumentów. Oprogramowanie CharlesWrapper nie posiada wbudowanej obsługi wieloklatkowych plików TIFF; Każda klatka musi zostać wyodrębniona ręcznie przed przetworzeniem.IronOCR obsługuje natywnie wielo-ramkowe pliki TIFF za pomocą jednego wywołania ładowania.
Podejście Charlesw Tesseract:
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}
Imports System.Drawing
Imports System.Drawing.Imaging
Imports Tesseract
Imports System.IO
Imports System.Text
Public Function ProcessMultiFrameTiff(tiffPath As String) As String
Dim fullText As New StringBuilder()
Using tiffImage As Image = Image.FromFile(tiffPath)
Dim frameCount As Integer = tiffImage.GetFrameCount(FrameDimension.Page)
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
For i As Integer = 0 To frameCount - 1
tiffImage.SelectActiveFrame(FrameDimension.Page, i)
' Must save each frame as a temp file for Pix to load
Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png")
Try
tiffImage.Save(tempPath, Imaging.ImageFormat.Png)
Using pix As Pix = Pix.LoadFromFile(tempPath)
Using page As Page = engine.Process(pix)
fullText.AppendLine(page.GetText())
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
Next
End Using
End Using
Return fullText.ToString()
End Function
Podejście IronOCR:
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}
Imports System
Imports IronOcr
Public Class TiffProcessor
' LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
Public Function ProcessMultiFrameTiff(tiffPath As String) As String
Using input As New OcrInput()
input.LoadImageFrames(tiffPath) ' All frames loaded in one call
Dim result = New IronTesseract().Read(input)
' Pages maps directly to TIFF frames
For Each page In result.Pages
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words")
Next
Return result.Text
End Using
End Function
End Class
Pętla wyodrębniania plików tymczasowych oraz łańcuch usuwania na poziomie klatek zostały usunięte. Wykrywanie liczby klatek za pomocą FrameDimension.Page znika.IronOCR mapuje klatki TIFF na OcrResult.Pages, więc dostęp do tekstu dla każdej klatki nie wymaga dodatkowej logiki iteracyjnej. Przewodnik dotyczący plików wejściowych TIFF/GIF obejmuje dodatkowe opcje wyboru klatek i częściowego przetwarzania plików TIFF.
Generowanie plików PDF z możliwością wyszukiwania
Oprogramowanie CharlesW generuje wyłącznie dane tekstowe. Konwersja zeskanowanego dokumentu do przeszukiwalnego PDF — częsty wymóg dla systemów zarządzania dokumentami — wymaga wtórnej biblioteki PDF (IronPDF, PDFSharp lub podobnej), aby nałożyć wyodrębniony tekst na oryginalne strony obrazu.IronOCR tworzy pliki PDF z możliwością wyszukiwania za pomocą jednego wywołania metody, bez konieczności korzystania z dodatkowej biblioteki.
Podejście Charlesw Tesseract:
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
Imports Tesseract
Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
' Step 1: Extract text from image
Dim extractedText As String
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath)
Using page As Page = engine.Process(img)
extractedText = page.GetText()
End Using
End Using
End Using
' Step 2: Build a PDF with the image as background and text overlay
' Requires a separate PDF library (not shown — 50-100+ additional lines)
' The text layer must be positioned to match the original image layout
' Word-level coordinates from the iterator are needed for accurate alignment
Throw New NotImplementedException("Searchable PDF generation requires a separate PDF library. " & _
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.")
End Sub
Podejście IronOCR:
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
// Nie secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
// Nie secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}
' SaveAsSearchablePdf produces a PDF/A-compatible searchable document
' Nie secondary library, no text overlay code, no coordinate mapping
Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(imagePath)
result.SaveAsSearchablePdf(outputPdfPath)
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}")
End Sub
' Same API works for multi-page TIFF or existing PDF input
Public Sub MakePdfSearchable(scannedPdfPath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(scannedPdfPath)
result.SaveAsSearchablePdf(outputPdfPath)
End Sub
SaveAsSearchablePdf() osadza tekst OCR jako niewidzialną warstwę wyrównaną do rozpoznanych słów, sprawiając, że dokument jest w pełni przeszukiwalny bez zmiany jego wyglądu wizualnego. Przewodnik w formacie PDF z funkcją wyszukiwania obejmuje wybór zakresu stron i opcje kompresji. Przykład działającego kodu jest dostępny na stronie z przykładami w formacie PDF z możliwością wyszukiwania.
Charlesw TesseractAPI do IronOCR– dokumentacja API
| Charlesw Tesseract | Odpowiednik IronOCR |
|---|---|
new TesseractEngine(tessDataPath, "eng", EngineMode.Default) |
new IronTesseract() |
Pix.LoadFromFile(imagePath) |
input.LoadImage(imagePath) |
Pix.LoadFromMemory(bytes) |
input.LoadImage(imageBytes) |
engine.Process(pix) |
ocr.Read(input) |
page.GetText() |
result.Text |
page.GetMeanConfidence() |
result.Confidence (skala 0–100) |
page.GetIterator() |
result.Pages, result.Words (bezpośrednie kolekcje) |
iter.GetText(PageIteratorLevel.Word) |
word.Text |
iter.GetConfidence(PageIteratorLevel.Word) |
word.Confidence |
iter.TryGetBoundingBox(PageIteratorLevel.Word, out var b) |
word.X, word.Y, word.Width, word.Height |
iter.GetText(PageIteratorLevel.Para) |
paragraph.Text |
iter.IsAtBeginningOf(PageIteratorLevel.Block) |
page.Paragraphs (bezpośrednia iteracja) |
EngineMode.Default |
Automatyczne (domyślnie Tesseract 5 LSTM) |
EngineMode.TesseractOnly |
ocr.Configuration.PageSegmentationMode |
Ręczny plik .traineddata tessdata |
dotnet add package IronOcr.Languages.French |
TessDataPath stała + .csproj kopiowanie wpisów |
Nie dotyczy — w pakiecie |
Pix.LoadFromFile() przez Leptonica DLL |
input.LoadImage() — brak wymaganego natywnego DLL |
Metoda platformy GetTessDataPath() |
Nie dotyczy — usunięto |
leptonica-1.82.0.dll / libleptonica-dev |
Nie dotyczy — brak zależności od Leptonica |
| Ręczne wyodrębnianie ramek plików tymczasowych dla formatu TIFF | input.LoadImageFrames(tiffPath) |
| Brak możliwości wyszukiwania w pliku PDF | result.SaveAsSearchablePdf(outputPath) |
new TesseractEngine() na każdy wątek |
Jeden IronTesseract — bezpieczny dla wątków |
Typowe problemy związane z migracją i ich rozwiązania
Problem 1: Wyjątek DllNotFoundException dla plików binarnych Leptonica lub Tesseract
Charlesw Tesseract: System.DllNotFoundException: Unable to load DLL 'leptonica-1.82.0': The specified module could not be found. Ten wyjątek występuje, gdy natywny DLL Leptonica nie znajduje się w oczekiwanej lokalizacji. Jest to powszechnie spotykane w świeżych kontenerach Dockera, agentach CI, lub jakimkolwiek środowisku, gdzie folder runtimes/ pakietu NuGet nie został poprawnie skopiowany.
Rozwiązanie: Usuń pakiet Tesseract. Zainstaluj IronOcr.IronOCRłączy wewnętrznie wszystkie natywne pliki binarne i nie korzysta z P/Invoke do systemowego Leptonica. Wyjątek nie może wystąpić, ponieważ nie ma zewnętrznej zależności od Leptonica:
dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
Nie wymaga się apt-get install libleptonica-dev. Brak wpisów <CopyToOutputDirectory> dla natywnych DLLs.
Problem 2: Błędy ścieżki Tessdata po wdrożeniu
Charlesw Tesseract: Tesseract.TesseractException: Failed to initialise tesseract engine. Występuje to, gdy TessDataPath nie zostanie rozwiązany podczas działania. Kompiluje się bez błędu, ale zawodzi tylko podczas działania, a ścieżka błędu zależy od środowiska wdrażania.
Rozwiązanie: Koncepcja ścieżki tessdata nie istnieje w IronOCR. Usuń stałą, usuń CopyToOutputDirectory XML w .csproj, oraz usuń metodę fabryczną, która go buduje. Dane językowe są dystrybuowane jako pakiety NuGet:
# Replace this manual tessdata file management:
# tessdata/eng.traineddata (15 MB, manually downloaded)
# tessdata/fra.traineddata (15 MB, manually downloaded)
# .csproj <CopyToOutputDirectory> entry
# With NuGet packages:
dotnet add package IronOcr.Languages.French
# Replace this manual tessdata file management:
# tessdata/eng.traineddata (15 MB, manually downloaded)
# tessdata/fra.traineddata (15 MB, manually downloaded)
# .csproj <CopyToOutputDirectory> entry
# With NuGet packages:
dotnet add package IronOcr.Languages.French
Przewodnik dotyczący wielu języków pokazuje, jak skonfigurować rozpoznawanie wielu języków po dodaniu pakietów językowych.
Problem 3: Kompilacja kontenera kończy się niepowodzeniem po aktualizacji obrazu bazowego
Charlesw Tesseract: Plik Dockerfile zawiera apt-get install -y libleptonica-dev, aby spełnić natywną zależność Leptonica. Gdy obraz bazowy przechodzi z Debiana Bullseye na Bookworm lub gdy nazwa pakietu Leptonica zmienia się w różnych dystrybucjach, kompilacja kończy się niepowodzeniem z błędem apt. Naprawienie tego wymaga wiedzy na temat nazwy pakietu, której należy użyć w nowej dystrybucji.
Rozwiązanie: Całkowicie usuń linię Leptonica apt-get.IronOCR na Linux wymaga tylko standardowego pakietu libgdiplus, który każda aplikacja .NET używająca System.Drawing już potrzebuje:
# Before: Leptonica explicit install — breaks on base image updates
RUN apt-get update && apt-get install -y libleptonica-dev
# After: standard .NET Linux requirement only
RUN apt-get update && apt-get install -y libgdiplus
Przewodnik wdrażania Docker zawiera przetestowane szablony plików Dockerfile dla popularnych obrazów bazowych. Nie jest wymagany żaden kod infrastruktury specyficzny dla charlesw.
Problem 4: Wzorzec iteratora zatrzymuje się na pustych stronach lub stronach zawierających spacje
Charlesw Tesseract: ResultIterator zwraca null z iter.GetText() na niektórych segmentach strony, wymagając jawnych sprawdzeń null w całej pętli. Brak sprawdzenia null powoduje NullReferenceException na pustych stronach lub obrazach bez rozpoznawalnego tekstu.
Rozwiązanie: Zbiory wyników IronOCR nigdy nie są puste. Puste strony zwracają puste kolekcje. Sprawdź treść tekstu, a nie odwołania do wartości null:
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}
' Before: null checks required at every iterator level
Dim wordText = iter.GetText(PageIteratorLevel.Word)
If wordText IsNot Nothing AndAlso wordText.Trim().Length > 0 Then
results.Add(wordText.Trim())
End If
' After: collection is safe to enumerate; check content as needed
For Each word In result.Pages.SelectMany(Function(p) p.Lines).SelectMany(Function(l) l.Words)
If Not String.IsNullOrWhiteSpace(word.Text) Then
results.Add(word.Text)
End If
Next
Problem 5: Naruszenia bezpieczeństwa wątków pod obciążeniem
Charlesw Tesseract: TesseractEngine nie jest bezpieczny dla wątków. Współdzielenie jednej instancji między równoczesnymi żądaniami w aplikacji ASP.NET powoduje naruszenia dostępu lub uszkodzone wyniki. Standardowym rozwiązaniem jest utworzenie jednego silnika na wątek, ale nie wynika to wprost z API, a komunikaty o błędach w przypadku niepowodzenia są niejasnymi wyjątkami natywnymi.
Rozwiązanie: IronTesseract jest bezpieczny dla wątków. Jedna instancja może obsługiwać jednoczesne żądania, a dla maksymalnej przepustowości można utworzyć jedną instancję na wątek w Parallel.ForEach — oba wzorce działają bez modyfikacji:
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
' Thread-safe parallel processing — IronTesseract handles concurrent access
Dim results As New ConcurrentBag(Of String)()
Parallel.ForEach(imageFiles, Sub(imagePath)
Dim ocr As New IronTesseract()
Dim result = ocr.Read(imagePath)
results.Add(result.Text)
End Sub)
Przewodnik po asynchronicznym OCR obejmuje wzorce asynchroniczne dla kontrolerów ASP.NET Core, w których blokowanie wątków jest niedopuszczalne.
Problem 6: Brak pliku binarnego ARM64 w czasie wykonywania
Charlesw Tesseract: Na agentach CI AWS Graviton (Linux ARM64) lub Apple Silicon zarchiwizowany pakiet może nie zawierać natywnego pliku binarnego ARM64. Niepowodzenie to DllNotFoundException lub BadImageFormatException przy tworzeniu silnika — błąd w czasie działania na platformie, której pakiet nie wspiera.
Rozwiązanie:IronOCR dostarcza sprawdzone pliki binarne ARM64 zarówno dla systemu Linux, jak i macOS. Wdrażaj na ARM64 bez zmian w kodzie. Przewodnik wdrożeniowy dla systemu Linux oraz przewodnik wdrożeniowy dla systemu macOS potwierdzają obsługiwane identyfikatory środowiska uruchomieniowego.
Lista kontrolna migracji Charlesw Tesseract
Przed migracją
Przeprowadź audyt kodu źródłowego, aby zidentyfikować wszystkie wzorce, które ulegną zmianie:
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .
# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .
# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .
# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .
# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .
# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .
# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .
# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .
# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .
# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .
# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .
# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .
# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .
# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .
# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
Zwróć uwagę, na jakie środowiska wdrożeniowe jest skierowany projekt (Docker, Linux, ARM64, Azure, AWS) — są to środowiska, w których charlesw/tesseract wymaga najwięcej konfiguracji, którą eliminuje IronOCR.
Migracja kodu
- Uruchom
dotnet remove package Tesseract, aby odinstalować wraper charlesw - Uruchom
dotnet add package IronOcr, aby zainstalować IronOCR - Dodaj
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";podczas uruchamiania aplikacji - Zastąp wszystkie instrukcje
using Tesseract;instrukcjamiusing IronOcr; - Usuń stałą ścieżki tessdata oraz wszelkie metody, które tworzą ścieżkę dla danego środowiska
- Usuń wszystkie bloki
RuntimeInformation.IsOSPlatform()napisane do wyboru ścieżki tessdata - Usuń wpisy
<CopyToOutputDirectory>dla plików tessdata z wszystkich plików.csproj - Usuń pliki
.traineddatatessdata z kontroli źródła lub magazynów artefaktów wdrażania - Dodaj
dotnet add package IronOcr.Languages.*dla każdego języka wdrażanego wcześniej jako plik.traineddata - Zastąp łańcuchy
TesseractEngine+Pix.LoadFromFile()+engine.Process()przeznew IronTesseract().Read() - Zastąp wszystkie wywołania
Pix.LoadFromFile()iPix.LoadFromMemory()przezinput.LoadImage() - Zastąp wszystkie wywołania
page.GetText()przezresult.Text - Zastąp ekstrakcję słów/wierszy opartą na witeratorze bezpośrednim dostępem do kolekcji w
result.Pages - Zastąp logikę progów
iter.GetConfidence()przez LINQ naresult.Wordslubresult.Lines - Usuń
libleptonica-dev/leptonica-1.82.0.dllz plików Dockerfile i skryptów wdrażania
Po migracji
Po zakończeniu aktualizacji kodu sprawdź, czy:
- OCR działa poprawnie w systemie Windows bez żadnych błędów natywnych bibliotek DLL
- OCR działa pomyślnie w kontenerze Docker na Linux bez żadnych zmian
apt-getpozalibgdiplus - OCR generuje tekst na platformie ARM64, jeśli ta platforma znajduje się w macierzy wdrożeniowej
- Wielostronicowe pliki TIFF zwracają tekst ze wszystkich ramek, a nie tylko z pierwszej
- Filtrowanie według pewności zwraca ten sam logiczny zbiór słów o wysokim poziomie pewności, co poprzednia implementacja iteratora
- Dokumenty specyficzne dla danego języka (francuski, niemiećki itp.) są rozpoznawane poprawnie po zainstalowaniu pakietów NuGet dla danego języka
- Operacje równoległego OCR są wykonywane bez wyjątków i uszkodzonych wyników
- Generowany jest plik PDF z możliwością wyszukiwania, podczas gdy poprzednia implementacja zwracała wyłącznie tekst
- Kompilacje w ramach procesu CI/CD bez żadnych etapów pobierania danych tessdata ani poleceń instalacyjnych Leptonica
- Test sprawdzający na tym samym korpusie obrazów, który został użyty do walidacji poprzedniej implementacji
Kluczowe korzyści z migracji do IronOCR
Samodzielny model wdrażania. Po migracji zależność OCR jest w pełni opisana przez pojedyncze odwołanie do pakietu NuGet. Brak plików tessdata w kontroli źródła, brak wpisów CopyToOutputDirectory, brak kroków wdrażania natywnych DLLs, brak systemowych pakietów Leptonica. Pipelines CI/CD, które dotychczas wymagały zarządzania artefaktami w wielu krokach, są zredukowane do dotnet publish. Kod związany z wdrażaniem, który zgromadzono w celu obsługi opakowania charlesw, został trwałe usunięty.
Przenośność platformy bez logiki warunkowej. Ten sam plik binarny aplikacji działa na systemach Windows x64, Linux x64, Linux ARM64, macOS x64 i macOS ARM64 bez modyfikacji. Zespoły dodające cel wdrożeniowy ARM64 — czy to AWS Graviton, Apple Silicon CI, czy Raspberry Pi — nie piszą nowego kodu wykrywającego platformę. Przewodnik wdrożeniowy dla systemu Linux oraz przewodnik wdrożeniowy dla AWS potwierdzają sprawdzone konfiguracje.
Dokładność Tesseract 5 dzięki wbudowanemu przetwarzaniu wstępnemu. Przejście z Tesseract 4.1.1 na Tesseract 5 poprawia rozpoznawanie dokumentów o obniżonej jakości.IronOCR dodaje automatyczne przetwarzanie wstępne do aktualizacji silnika, stosując korekcję pochylenia, usuwanie szumów, normalizację kontrastu i binarizację przed przetworzeniem każdego obrazu przez silnik. Dokumenty, które wcześniej wymagały niestandardowego procesu przetwarzania wstępnego w celu osiągnięcia akceptowalnych progów dokładności, teraz osiągają te progi bez dodatkowego kodu. Przewodnik po korekcji jakości obrazu dokumentuje konkretne opcje przetwarzania wstępnego dla przypadków, które wymagają dostosowania wykraczającego poza ustawienia domyślne.
Bezpośrednia nawigacja wynikami zastępuje typowy wzorzec iteratora. Wzorzec iteratora charlesw — GetIterator(), Begin(), Next(), IsAtBeginningOf(), sprawdzanie null przez całość — jest zastępowany przez proste kolekcje. Słowa, wiersze, akapity i strony są właściwościami obiektu wynikowego. Filtrowanie oparte na pewności jest wyrażeniem LINQ. Kod, który wcześniej wyciągał dane na poziomie słów, wymagał 15–30 linii kodu do zarządzania iteratorami; Odpowiednik w IronOCR to 2–3 wiersze. Strona z wynikami OCR zawiera podsumowanie pełnego modelu wyników strukturalnych.
Wynikowy plik PDF przeszukiwalny bez dodatkowej biblioteki. result.SaveAsSearchablePdf() generuje PDF z warstwą tekstową wyrównaną do rozpoznanych słów, nie wymagając żadnej dodatkowej biblioteki PDF. Systemy zarządzania dokumentami, które przetwarzają pliki PDF z możliwością wyszukiwania, nie wymagają już oddzielnego etapu generowania plików PDF. Ten sam obiekt wynikowy, który dostarcza wyodrębniony tekst, zapisuje również plik z możliwością wyszukiwania, dzięki czemu przetwarzanie dokumentów opiera się na jednej bibliotece.
Aktywna konserwacja i obsługa poprawek bezpieczeństwa.IronOCR otrzymuje regularne aktualizacje uwzględniające ulepszenia modelu Tesseract 5, weryfikację zgodności środowiska uruchomieniowego .NET oraz obsługę poprawek bezpieczeństwa dla podstawowego silnika C++. Ta zależność nie wiąże się już z profilem ryzyka pakietu archiwalnego — przeglądy zgodności nie wykazują braków w ścieżce poprawek bezpieczeństwa. W miarę jak .NET 10 będzie stawał się ogólnodostępny do 2026 r., centrum dokumentacji IronOCR będzie odzwierciedlać aktualną kompatybilność bez konieczności stosowania obejść lub rozgałęzień.
Często Zadawane Pytania
Dlaczego warto przejść z charlesw/tesseract (opakowanie Tesseract dla .NET) na IronOCR?
Typowe czynniki motywujące to eliminacja złożoności interoperacyjności COM, zastąpienie zarządzania licencjami opartego na plikach, uniknięcie rozliczeń za stronę, umożliwienie wdrażania w Dockerze/kontenerach oraz przyjęcie natywnego dla NuGet przepływu pracy, który integruje się ze standardowymi narzędziami .NET.
Jakie są główne zmiany w kodzie podczas migracji z charlesw/tesseract (opakowanie Tesseract dla .NET) do IronOCR?
Zastąp sekwencje inicjalizacji charlesw/tesseract instancjonowaniem IronTesseract, usuń zarządzanie cyklem życia COM (jawne wzorce Create/Load/Close) i zaktualizuj nazwy właściwości wyników. W rezultacie znacznie zmniejsza się liczba powtarzających się linii kodu.
Jak zainstalować IronOCR, aby rozpocząć migrację?
Uruchom polecenie „Install-Package IronOcr” w konsoli menedżera pakietów lub „dotnet add package IronOcr” w interfejsie CLI. Pakiety językowe są oddzielnymi pakietami: na przykład „dotnet add package IronOcr.Languages.French” dla języka francuskiego.
Czy IronOCR dorównuje dokładnością OCR charlesw/tesseract (opakowanie Tesseract dla .NET) w przypadku standardowych dokumentów biznesowych?
IronOCR zapewnia wysoką dokładność w przypadku standardowych treści biznesowych, w tym faktur, umów, paragonów i formularzy wypełnionych na komputerze. Filtry przetwarzania wstępnego obrazu (prostowanie, usuwanie szumów, wzmacnianie kontrastu) dodatkowo poprawiają rozpoznawanie w przypadku pogorszonej jakości danych wejściowych.
W jaki sposób IronOCR obsługuje dane językowe, które charlesw/tesseract (opakowanie Tesseract dla .NET) instaluje oddzielnie?
Dane językowe w IronOCR są dystrybuowane jako pakiety NuGet. Polecenie „dotnet add package IronOcr.Languages.German” instaluje obsługę języka niemiećkiego. Nie wymaga to ręcznego umieszczania plików ani podawania ścieżek katalogów.
Czy migracja z charlesw/tesseract (opakowanie Tesseract dla .NET) do IronOCR wymaga zmian w infrastrukturze wdrożeniowej?
IronOCR wymaga mniej zmian w infrastrukturze niż charlesw/tesseract (opakowanie Tesseract dla .NET). Nie ma ścieżek do plików binarnych SDK, lokalizacji plików licencji ani konfiguracji serwerów licencyjnych. Pakiet NuGet zawiera kompletny silnik OCR, a klucz licencyjny jest ciągiem znaków ustawionym w kodzie aplikacji.
Jak skonfigurować licencjonowanie IronOCR po migracji?
W kodzie uruchamiającym aplikację przypisz IronOcr.License.LicenseKey = „YOUR-KEY”. W Dockerze lub Kubernetesie zapisz klucz jako zmienną środowiskową i odczytaj go podczas uruchamiania. Użyj License.IsValidLicense do sprawdzenia ważności przed przyjęciem ruchu.
Czy IronOCR może przetwarzać pliki PDF w taki sam sposób jak charlesw/tesseract?
Tak. IronOCR odczytuje zarówno natywne, jak i zeskanowane pliki PDF. Należy utworzyć instancję IronTesseract, wywołać ocr.Read(input), gdzie input jest ścieżką do pliku PDF lub obiektem OcrPdfInput, a następnie iterować strony OcrResult. Nie jest wymagany oddzielny proces renderowania plików PDF.
W jaki sposób IronOCR radzi sobie z wątkami podczas przetwarzania dużych ilości danych?
IronTesseract można bezpiecznie instancjonować dla każdego wątku. Uruchom jedną instancję na wątek w Parallel.ForEach lub puli zadań, uruchom OCR równolegle i usuń każdą instancję po zakończeniu. Nie jest wymagany żaden stan globalny ani blokowanie.
Jakie formaty wyjściowe obsługuje IronOCR po wyodrębnieniu tekstu?
IronOCR zwraca ustrukturyzowane wyniki, w tym tekst, współrzędne słów, wyniki pewności i strukturę strony. Opcje eksportu obejmują zwykły tekst, PDF z możliwością wyszukiwania oraz obiekty wyników ustrukturyzowanych do dalszego przetwarzania.
Czy ceny IronOCR są bardziej przewidywalne niż charlesw/tesseract (opakowanie Tesseract dla .NET) w przypadku skalowania obciążeń?
IronOCR stosuje licencję wieczystą z opłatą ryczałtową, bez opłat za stronę lub wolumen. Niezależnie od tego, czy przetwarzasz 10 000, czy 10 milionów stron, koszt licencji pozostaje stały. Opcje licencji wolumenowych i zespołowych znajdują się na stronie z cennikiem IronOCR.
Co stanie się z moimi istniejącymi testami po migracji z charlesw/tesseract (opakowanie Tesseract dla .NET) do IronOCR?
Testy sprawdzające wyodrębnioną treść tekstową powinny nadal przechodzić pomyślnie po migracji. Testy weryfikujące wzorce wywołań API lub cykl życia obiektów COM będą wymagały aktualizacji, aby odzwierciedlały prostszy model inicjalizacji i wyników IronOCR.

