Przejdź do treści stopki
FILMY

Migracja z Asprise OCR do IronOCR

Ten przewodnik przeprowadza programistów .NET przez każdy etap zastępowaniaAsprise OCRprzez IronOCR. Obejmuje to wymianę pakietów mechanicznych, zmiany przestrzeni nazw oraz cztery wzorce migracji kodu, które stanowią większość zastosowań Asprise w produkcyjnych aplikacjach .NET. Docelowymi odbiorcami są programiści, którzy już podjęli decyzję o migracji i potrzebują konkretnego planu działania.

Dlaczego warto przejść z Asprise OCR

Asprise OCR został pierwotnie zaprojektowany jako produkt Java. Interfejs .NET stanowi nakładkę na silnik natywny pochodzący z Javy, a to pochodzenie kształtuje każdy aspekt działania biblioteki w środowisku .NET — od wdrażania, przez projekt API, po ograniczenia licencyjne.

Zaleznosc od JRE i natywnych bibliotek binarnych.Asprise OCRfor .NET wymaga obecnosci specyficznych dla platformy natywnych bibliotek binarnych (aocr.dll, aocr_x64.dll, libaocr.so, libaocr.dylib) na kazdym komputerze, na ktorym dziala aplikacja. Każdy plik binarny musi dokładnie odpowiadać platformie docelowej i architekturze procesora. 64-bitowy kontener Docker zbudowany z 32-bitowym DLL rzuca BadImageFormatException w czasie wykonywania. Wdrozenie na Linuxie brakujace libaocr.so z LD_LIBRARY_PATH rzuca DllNotFoundException. Żaden z tych błędów nie pojawia się w czasie kompilacji. Każdy nowy cel wdrożenia — nowy serwer, nowy obraz kontenera, agent CI — staje się ręcznym ćwiczeniem z pozyskiwania plików binarnych.

API stałej tekstowej z dzedzictwa Java. Asprise udostępnia stałe całkowite dla typu rozpoznawania i formatu wyjściowego: Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT, Ocr.OUTPUT_FORMAT_XML. Te stałe odpowiadają bezpośrednio interfejsowi API opartemu na liczbach całkowitych w pakiecie Java SDK. Programiści .NET nie otrzymują wskazówek IntelliSense dotyczących prawidłowych wartości stałych, nie mają zapewnionego bezpieczeństwa kompilacji w zakresie kombinacji argumentów ani obiektów wynikowych o silnym typowaniu. Pobieranie ustrukturyzowanych danych wymaga ręcznego parsowania ciągów XML.

Brak obsługi asynchronicznej bez obejść. Asprise nie udostępnia natywnego API asynchronicznego. Opakowanie synchronicznych wywołań Asprise w Task.Run w celu uniknięcia blokowania wątków ASP.NET powoduje presję na pulę wątków i nie rozwiązuje ograniczenia licencyjnego, które zabrania równoległego wykonywania w poziomach LITE i STANDARD. Wzory asynchroniczne w nowoczesnych aplikacjach .NET — usługi działające w tle, minimalne punkty końcowe API, Azure Functions — nie mają jednoznacznego odpowiednika w Asprise.

Przetwarzanie plików TIFF z wieloma ramkami wymaga ręcznego podziału. Asprise działa na pojedynczych plikach graficznych. Przetwarzanie wielostronicowego pliku TIFF wymaga zewnętrznego kodu do podzielenia klatek na pojedyncze pliki, a następnie przetworzenia każdego pliku w pętli. Żadne metadane klatek ani numeracja stron nie są przenoszone do pliku wyjściowego.

Ograniczenie dotyczące wątków blokuje wdrożenie produkcyjne. Licencje Lite (~299 USD) i STANDARD (~699 USD) ograniczają wykonanie do jednego wątku i jednego procesu. ASP.NET Core przetwarza wszystkie żądania HTTP w puli wątków. Każdy punkt końcowy API sieci Web, który wywołuje Asprise na tych warstwach, stanowi naruszenie licencji już od pierwszego równoczesnego żądania. Przejście na plan Enterprise usuwa to ograniczenie, ale wymaga skontaktowania się z działem sprzedaży, a cena nie jest podana — szacunki wahają się od 2000 do ponad 5000 USD w zależności od zakresu wdrożenia.

Obsluga formatu wyjsciowego wymaga analizy lancuchow tekstowych. Gdy określone jest OUTPUT_FORMAT_XML, Asprise zwraca surowy ciąg XML. Aplikacja jest odpowiedzialna za deseryalizację tego ciągu znaków, sprawdzenie jego struktury oraz wyodrębnienie słów i ich współrzędnych. Wyniki pewności dla poszczególnych słów są osadzone w atrybutach XML. Nie ma modelu obiektowego — tylko manipulacja ciągami znaków.

Podstawowy problem

Asprise wymaga konfiguracji natywnego pliku binarnego powiązanego z JRE przed wykonaniem pierwszego wywołania OCR.IronOCR nie wymaga niczego poza pakietem NuGet:

// Asprise: native binary must exist in PATH or application directory
// aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp();                              // Static init — touches native binary
Ocr ocr = new Ocr();
ocr.StartEngine("eng", Ocr.SPEED_FAST);  // Allocates native engine memory
string text = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT);
ocr.StopEngine();                         // Must call or native memory leaks
// Asprise: native binary must exist in PATH or application directory
// aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp();                              // Static init — touches native binary
Ocr ocr = new Ocr();
ocr.StartEngine("eng", Ocr.SPEED_FAST);  // Allocates native engine memory
string text = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT);
ocr.StopEngine();                         // Must call or native memory leaks
' Asprise: native binary must exist in PATH or application directory
' aocr_x64.dll missing → DllNotFoundException at runtime, not at build
Ocr.SetUp()                              ' Static init — touches native binary
Dim ocr As New Ocr()
ocr.StartEngine("eng", Ocr.SPEED_FAST)   ' Allocates native engine memory
Dim text As String = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
ocr.StopEngine()                         ' Must call or native memory leaks
$vbLabelText   $csharpLabel
// IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
string text = new IronTesseract().Read(imagePath).Text;
// IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
string text = new IronTesseract().Read(imagePath).Text;
' IronOCR: dotnet add package IronOcr — no binary sourcing, no lifecycle calls
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text
$vbLabelText   $csharpLabel

IronOCR a Asprise OCR: porównanie funkcji

Poniższa tabela przedstawia funkcje najbardziej istotne dla programistów rozważających tę migrację.

Funkcja Asprise OCR IronOCR
Główna platforma Java (starsza wersja) .NET natywne
Instalacja NuGet Wrapper + natywne biblioteki DLL platformy Pojedynczy pakiet (IronOcr)
Wymagany natywny plik binarny w czasie wykonywania Tak (biblioteka DLL dla każdej platformy) Nie
Styl API .NET Stałe liczbowe, zwracanie ciągów znaków Klasy i wyliczenia silnie typowane
IDisposable / using wzorzec Nie zaimplementowano Tak (OcrInput)
Asynchroniczne OCR Brak natywnej obsługi Tak (ReadAsync)
Wielowątkowość — poziom Lite/STANDARD Zabronione na mocy licencji Dopuszczalne
Wielowątkowość — wszystkie warstwy TYLKO DLA ENTERPRISE Wszystkie poziomy
Obsługa ASP.NET Core Web API Enterprise required Dowolny poziom
Funkcje Azure / AWS Lambda Enterprise required Dowolny poziom
Natywne wprowadzanie plików PDF Nie Tak
Wprowadzanie plików TIFF z wieloma ramkami Nie (ręczne dzielenie ramek) Tak (LoadImageFrames)
Tablica bajtów i dane wejściowe strumieniowe Ograniczone Tak
Wbudowane przetwarzanie wstępne obrazów Nie Tak (9+ filtrów)
Wynik w formacie PDF z możliwością wyszukiwania Nie Tak (SaveAsSearchablePdf)
Strukturalny model obiektowy wyników Nie (tylko ciąg znaków XML) Tak (strony, akapity, słowa, WORDy)
Wyniki pewności dla poszczególnych słów Nie (analiza atrybutów XML) Tak (result.Confidence)
Współrzędne pikseli w programie WORD Analiza atrybutów XML Właściwości silnie typowane
Liczba słów 20+ 125+
Wybór języka silnie typowanego Nie (kody łańcuchów) Tak (OcrLanguage enum)
Odczytywanie BarCode Tak (oddzielny typ rozpoznawania) Tak (flaga konfiguracyjna)
eksport hOCR Nie Tak
Wdrażanie wielopłatformowe Ręczny plik binarny dla każdej platformy NuGet obsługuje wszystkie platformy
Docker / Linux / macOS Ręczna konfiguracja LD_LIBRARY_PATH Działa od razu po uruchomieniu
Kompatybilność z platformą .NET Ograniczone (most Java) .NET Framework 4.6.2+, .NET 5–9
Cena podstawowa za korzystanie z serwera Enterprise (~2000 USD+) $999 (Lite, wszystkie funkcje)
Rodzaj licencji W przypadku poszczególnych poziomów prosimy o kontakt z działem sprzedaży w zakresie wersji Enterprise Na czas nieokreślony (jednorazowy zakup)

Szybki start: Migracja zAsprise OCRdo IronOCR

Krok 1: Zastąp pakiet NuGet

Usuń Asprise OCR:

dotnet remove package asprise-ocr-api
dotnet remove package asprise-ocr-api
SHELL

Zainstaluj IronOCR ze strony pakietu NuGet:

dotnet add package IronOcr

Krok 2: Aktualizacja przestrzeni nazw

Zamień przestrzenie nazw Asprise na przestrzeń nazw IronOCR:

// Before (Asprise)
using asprise.ocr;

// After (IronOCR)
using IronOcr;
// Before (Asprise)
using asprise.ocr;

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

Krok 3: Inicjalizacja licencji

Dodaj przypisanie klucza licencyjnego podczas startu aplikacji — w Program.cs przed jakimikolwiek wywolanami OCR, w Startup.Configure, lub w statycznym konstruktorze:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Bezpłatny klucz próbny jest dostępny na stronie licencyjnej IronOCR. Podczas tworzenia i testowania IronOCR działa bez klucza i umieszcza na wydrukach znak wodny wersji próbnej.

Przykłady migracji kodu

Konfiguracja ścieżki JRE i usunięcie inicjalizacji silnika

Aplikacje Asprise działające w systemach Linux lub macOS zazwyczaj zawierają kod startowy, który ustawia ścieżkę do środowiska JRE lub sprawdza obecność natywnych plików binarnych przed rozpoczęciem jakichkolwiek operacji OCR. Ta infrastruktura nie ma odpowiednika w IronOCR.

Podejście Asprise OCR:

// AppStartup.cs — native binary validation before accepting any requests
public static void InitializeOcr()
{
    // Validate native library is reachable before first use
    string nativePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
        ? Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll")
        : RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
            ? "/usr/lib/libaocr.so"
            : "/usr/local/lib/libaocr.dylib";

    if (!File.Exists(nativePath))
        throw new FileNotFoundException(
            $"Asprise native binary not found: {nativePath}. " +
            "Deploy the correct platform binary before starting.");

    // Static global init — must run before any Ocr instance is created
    Ocr.SetUp();
}
// AppStartup.cs — native binary validation before accepting any requests
public static void InitializeOcr()
{
    // Validate native library is reachable before first use
    string nativePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
        ? Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll")
        : RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
            ? "/usr/lib/libaocr.so"
            : "/usr/local/lib/libaocr.dylib";

    if (!File.Exists(nativePath))
        throw new FileNotFoundException(
            $"Asprise native binary not found: {nativePath}. " +
            "Deploy the correct platform binary before starting.");

    // Static global init — must run before any Ocr instance is created
    Ocr.SetUp();
}
Imports System
Imports System.IO
Imports System.Runtime.InteropServices

' AppStartup.vb — native binary validation before accepting any requests
Public Module AppStartup
    Public Sub InitializeOcr()
        ' Validate native library is reachable before first use
        Dim nativePath As String = If(RuntimeInformation.IsOSPlatform(OSPlatform.Windows),
                                      Path.Combine(AppContext.BaseDirectory, "aocr_x64.dll"),
                                      If(RuntimeInformation.IsOSPlatform(OSPlatform.Linux),
                                         "/usr/lib/libaocr.so",
                                         "/usr/local/lib/libaocr.dylib"))

        If Not File.Exists(nativePath) Then
            Throw New FileNotFoundException($"Asprise native binary not found: {nativePath}. " &
                                            "Deploy the correct platform binary before starting.")
        End If

        ' Static global init — must run before any Ocr instance is created
        Ocr.SetUp()
    End Sub
End Module
$vbLabelText   $csharpLabel

Podejście IronOCR:

// Program.cs — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// That is it. Nie binary validation, no path configuration, no SetUp() call.
// NuGet resolved the correct native runtime during package restore.
// Program.cs — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// That is it. Nie binary validation, no path configuration, no SetUp() call.
// NuGet resolved the correct native runtime during package restore.
' Program.vb — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

' That is it. Nie binary validation, no path configuration, no SetUp() call.
' NuGet resolved the correct native runtime during package restore.
$vbLabelText   $csharpLabel

Wzorzec Asprise ma zazwyczaj 15-30 linii w wielu plikach — walidator startowy, przelacznik platformy, wyjatek z wiadomoscia wdrozeniowa i wywolanie SetUp().IronOCR zastępuje to wszystko jednym zadaniem. Podręcznik konfiguracji IronTesseract obejmuje opcje konfiguracji wdrożenia dla środowisk wymagających niestandardowych ścieżek tessdata lub pracy w trybie offline.

Zastąpienie formatu wyjściowego XML obiektami wynikowymi o strukturze

Asprise generuje strukturalizowany wynik jako surowy ciąg XML, gdy jest określone OUTPUT_FORMAT_XML. Wyodrębnienie tekstu słowa, współrzędnych i poziomu pewności z tego ciągu wymaga kodu do parsowania XML.IronOCR zwraca graf obiektów typu.

Podejście Asprise OCR:

// Asprise: structured output is an XML string — must parse manually
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    string xmlOutput = ocr.Recognize(
        imagePath,
        Ocr.RECOGNIZE_TYPE_TEXT,
        Ocr.OUTPUT_FORMAT_XML);   // Returns raw XML, not an object

    // Parse the XML manually to extract words and coordinates
    var doc = System.Xml.Linq.XDocument.Parse(xmlOutput);
    var words = doc.Descendants("word")
        .Select(w => new
        {
            Text       = (string)w.Attribute("text"),
            Confidence = (float)w.Attribute("confidence"),
            X          = (int)w.Attribute("x"),
            Y          = (int)w.Attribute("y"),
        })
        .ToList();

    foreach (var word in words)
        Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}");
}
finally
{
    ocr.StopEngine();
}
// Asprise: structured output is an XML string — must parse manually
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    string xmlOutput = ocr.Recognize(
        imagePath,
        Ocr.RECOGNIZE_TYPE_TEXT,
        Ocr.OUTPUT_FORMAT_XML);   // Returns raw XML, not an object

    // Parse the XML manually to extract words and coordinates
    var doc = System.Xml.Linq.XDocument.Parse(xmlOutput);
    var words = doc.Descendants("word")
        .Select(w => new
        {
            Text       = (string)w.Attribute("text"),
            Confidence = (float)w.Attribute("confidence"),
            X          = (int)w.Attribute("x"),
            Y          = (int)w.Attribute("y"),
        })
        .ToList();

    foreach (var word in words)
        Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}");
}
finally
{
    ocr.StopEngine();
}
Imports System.Xml.Linq

' Asprise: structured output is an XML string — must parse manually
Ocr.SetUp()
Dim ocr As New Ocr()
Try
    ocr.StartEngine("eng", Ocr.SPEED_FAST)
    Dim xmlOutput As String = ocr.Recognize(imagePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_XML) ' Returns raw XML, not an object

    ' Parse the XML manually to extract words and coordinates
    Dim doc As XDocument = XDocument.Parse(xmlOutput)
    Dim words = doc.Descendants("word") _
        .Select(Function(w) New With {
            .Text = CStr(w.Attribute("text")),
            .Confidence = CSng(w.Attribute("confidence")),
            .X = CInt(w.Attribute("x")),
            .Y = CInt(w.Attribute("y"))
        }) _
        .ToList()

    For Each word In words
        Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence}")
Next
Finally
    ocr.StopEngine()
End Try
$vbLabelText   $csharpLabel

Podejście IronOCR:

// IronOCR: structured result is a typed object — no XML parsing
var result = new IronTesseract().Read(imagePath);

foreach (var page in result.Pages)
{
    foreach (var paragraph in page.Paragraphs)
    {
        foreach (var word in paragraph.Words)
        {
            Console.WriteLine(
                $"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%");
        }
    }
}
// IronOCR: structured result is a typed object — no XML parsing
var result = new IronTesseract().Read(imagePath);

foreach (var page in result.Pages)
{
    foreach (var paragraph in page.Paragraphs)
    {
        foreach (var word in paragraph.Words)
        {
            Console.WriteLine(
                $"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%");
        }
    }
}
Imports IronOcr

' IronOCR: structured result is a typed object — no XML parsing
Dim result = New IronTesseract().Read(imagePath)

For Each page In result.Pages
    For Each paragraph In page.Paragraphs
        For Each word In paragraph.Words
            Console.WriteLine($"{word.Text} @ ({word.X},{word.Y}) conf={word.Confidence:F1}%")
        Next
    Next
Next
$vbLabelText   $csharpLabel

Bez deseryzacji XML, bez rzutowania atrybutów, bez założeń dotyczących schematów. Model obiektowy OcrResult udostępnia strony, akapity, linie, słowa i znaki z właściwościami typowanymi. Przewodnik po wynikach odczytu obejmuje pełną hierarchię i układ współrzędnych, w tym sposób filtrowania według progu pewności dla zautomatyzowanych przepływów pracy.

Przetwarzanie plików TIFF z wieloma ramkami

Asprise akceptuje pojedyncze pliki graficzne. Plik TIFF zawierający wiele klatek — powszechnie stosowany w procesach skanowania dokumentów — musi zostać podzielony na osobne pliki klatek, zanim Asprise będzie mógł go przetworzyć.IronOCR akceptuje wielowarstwowe TIFFy bezpośrednio przez LoadImageFrames.

Podejście Asprise OCR:

// Asprise: no multi-frame TIFF support — split frames externally first
// Using an external imaging library (e.g., System.Drawing or Magick.NET)
var frameFiles = new List<string>();
using (var tiff = System.Drawing.Image.FromFile("scanned-batch.tiff"))
{
    int frameCount = tiff.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
    for (int i = 0; i < frameCount; i++)
    {
        tiff.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
        string framePath = $"frame_{i}.png";
        tiff.Save(framePath);
        frameFiles.Add(framePath);
    }
}

// Now process each frame individually — sequential on LITE/STANDARD
var allText = new System.Text.StringBuilder();
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    foreach (var framePath in frameFiles)
    {
        string pageText = ocr.Recognize(
            framePath,
            Ocr.RECOGNIZE_TYPE_TEXT,
            Ocr.OUTPUT_FORMAT_PLAINTEXT);
        allText.AppendLine(pageText);
    }
}
finally
{
    ocr.StopEngine();
    // Clean up temporary frame files
    foreach (var f in frameFiles)
        File.Delete(f);
}
Console.WriteLine(allText.ToString());
// Asprise: no multi-frame TIFF support — split frames externally first
// Using an external imaging library (e.g., System.Drawing or Magick.NET)
var frameFiles = new List<string>();
using (var tiff = System.Drawing.Image.FromFile("scanned-batch.tiff"))
{
    int frameCount = tiff.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
    for (int i = 0; i < frameCount; i++)
    {
        tiff.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
        string framePath = $"frame_{i}.png";
        tiff.Save(framePath);
        frameFiles.Add(framePath);
    }
}

// Now process each frame individually — sequential on LITE/STANDARD
var allText = new System.Text.StringBuilder();
Ocr.SetUp();
Ocr ocr = new Ocr();
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    foreach (var framePath in frameFiles)
    {
        string pageText = ocr.Recognize(
            framePath,
            Ocr.RECOGNIZE_TYPE_TEXT,
            Ocr.OUTPUT_FORMAT_PLAINTEXT);
        allText.AppendLine(pageText);
    }
}
finally
{
    ocr.StopEngine();
    // Clean up temporary frame files
    foreach (var f in frameFiles)
        File.Delete(f);
}
Console.WriteLine(allText.ToString());
Imports System.Drawing
Imports System.Text
Imports System.IO

' Asprise: no multi-frame TIFF support — split frames externally first
' Using an external imaging library (e.g., System.Drawing or Magick.NET)
Dim frameFiles As New List(Of String)()
Using tiff As Image = Image.FromFile("scanned-batch.tiff")
    Dim frameCount As Integer = tiff.GetFrameCount(Imaging.FrameDimension.Page)
    For i As Integer = 0 To frameCount - 1
        tiff.SelectActiveFrame(Imaging.FrameDimension.Page, i)
        Dim framePath As String = $"frame_{i}.png"
        tiff.Save(framePath)
        frameFiles.Add(framePath)
    Next
End Using

' Now process each frame individually — sequential on LITE/STANDARD
Dim allText As New StringBuilder()
Ocr.SetUp()
Dim ocr As New Ocr()
Try
    ocr.StartEngine("eng", Ocr.SPEED_FAST)
    For Each framePath As String In frameFiles
        Dim pageText As String = ocr.Recognize(framePath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
        allText.AppendLine(pageText)
    Next
Finally
    ocr.StopEngine()
    ' Clean up temporary frame files
    For Each f As String In frameFiles
        File.Delete(f)
    Next
End Try
Console.WriteLine(allText.ToString())
$vbLabelText   $csharpLabel

Podejście IronOCR:

// IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");  // All frames, one call

var result = new IronTesseract().Read(input);

// Access each page independently with its page number
foreach (var page in result.Pages)
    Console.WriteLine($"Page {page.PageNumber}: {page.Text}");
// IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");  // All frames, one call

var result = new IronTesseract().Read(input);

// Access each page independently with its page number
foreach (var page in result.Pages)
    Console.WriteLine($"Page {page.PageNumber}: {page.Text}");
Imports IronOcr

' IronOCR: multi-frame TIFF loads directly — no frame splitting, no temp files
Using input As New OcrInput()
    input.LoadImageFrames("scanned-batch.tiff") ' All frames, one call

    Dim result = New IronTesseract().Read(input)

    ' Access each page independently with its page number
    For Each page In result.Pages
        Console.WriteLine($"Page {page.PageNumber}: {page.Text}")
    Next
End Using
$vbLabelText   $csharpLabel

Podejście Asprise wymaga zewnętrznej zależności od obrazówania, zarządzania plikami tymczasowymi, ręcznego czyszczenia oraz sekwencyjnego przetwarzania poszczególnych klatek.IronOCR przetwarza wszystkie ramki w jednym przebiegu. Przewodnik dotyczący plików wejściowych TIFF i GIF obejmuje wybór zakresu klatek w przypadku dużych plików TIFF, w których potrzebne są tylko określone strony.

Generowanie plików PDF z możliwością wyszukiwania

Asprise nie oferuje możliwości generowania plików PDF z funkcją wyszukiwania w żadnym poziomie licencji. Utworzenie pliku PDF z osadzonym tekstem OCR ze skanowanego dokumentu wymaga zewnętrznej biblioteki PDF, oddzielnego przetwarzania OCR w celu uzyskania pozycji tekstu oraz ręcznego nakładania warstw.IronOCR tworzy pliki PDF z możliwością wyszukiwania bezpośrednio na podstawie wyników rozpoznawania.

Podejście Asprise OCR:

// Asprise: no searchable PDF output — external PDF library required
// Step 1: OCR the document to get text
Ocr.SetUp();
Ocr ocr = new Ocr();
string recognizedText;
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    recognizedText = ocr.Recognize(
        "scanned-contract.jpg",
        Ocr.RECOGNIZE_TYPE_TEXT,
        Ocr.OUTPUT_FORMAT_PLAINTEXT);   // Only plain text — no position data
}
finally
{
    ocr.StopEngine();
}

// Step 2: Use an external PDF library to embed text over the image
// (iTextSharp, PdfSharp, or similar — adds another dependency and license)
// Text positioning requires coordinate data Asprise cannot provide in plain text mode
// ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone");
// Asprise: no searchable PDF output — external PDF library required
// Step 1: OCR the document to get text
Ocr.SetUp();
Ocr ocr = new Ocr();
string recognizedText;
try
{
    ocr.StartEngine("eng", Ocr.SPEED_FAST);
    recognizedText = ocr.Recognize(
        "scanned-contract.jpg",
        Ocr.RECOGNIZE_TYPE_TEXT,
        Ocr.OUTPUT_FORMAT_PLAINTEXT);   // Only plain text — no position data
}
finally
{
    ocr.StopEngine();
}

// Step 2: Use an external PDF library to embed text over the image
// (iTextSharp, PdfSharp, or similar — adds another dependency and license)
// Text positioning requires coordinate data Asprise cannot provide in plain text mode
// ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone");
' Asprise: no searchable PDF output — external PDF library required
' Step 1: OCR the document to get text
Ocr.SetUp()
Dim ocr As New Ocr()
Dim recognizedText As String
Try
    ocr.StartEngine("eng", Ocr.SPEED_FAST)
    recognizedText = ocr.Recognize( _
        "scanned-contract.jpg", _
        Ocr.RECOGNIZE_TYPE_TEXT, _
        Ocr.OUTPUT_FORMAT_PLAINTEXT)   ' Only plain text — no position data
Finally
    ocr.StopEngine()
End Try

' Step 2: Use an external PDF library to embed text over the image
' (iTextSharp, PdfSharp, or similar — adds another dependency and license)
' Text positioning requires coordinate data Asprise cannot provide in plain text mode
' ... 40-80 lines of PDF construction code
Console.WriteLine("Searchable PDF: not achievable with Asprise alone")
$vbLabelText   $csharpLabel

Podejście IronOCR:

// IronOCR: searchable PDF in two lines — no external PDF library
var result = new IronTesseract().Read("scanned-contract.jpg");
result.SaveAsSearchablePdf("searchable-contract.pdf");

// Batch: convert a folder of scanned images to searchable PDFs
foreach (var imagePath in Directory.GetFiles("scans", "*.jpg"))
{
    var batchResult = new IronTesseract().Read(imagePath);
    string outputPath = Path.ChangeExtension(imagePath, ".searchable.pdf");
    batchResult.SaveAsSearchablePdf(outputPath);
    Console.WriteLine($"Converted: {outputPath}");
}
// IronOCR: searchable PDF in two lines — no external PDF library
var result = new IronTesseract().Read("scanned-contract.jpg");
result.SaveAsSearchablePdf("searchable-contract.pdf");

// Batch: convert a folder of scanned images to searchable PDFs
foreach (var imagePath in Directory.GetFiles("scans", "*.jpg"))
{
    var batchResult = new IronTesseract().Read(imagePath);
    string outputPath = Path.ChangeExtension(imagePath, ".searchable.pdf");
    batchResult.SaveAsSearchablePdf(outputPath);
    Console.WriteLine($"Converted: {outputPath}");
}
Imports System.IO
Imports IronOcr

' IronOCR: searchable PDF in two lines — no external PDF library
Dim result = New IronTesseract().Read("scanned-contract.jpg")
result.SaveAsSearchablePdf("searchable-contract.pdf")

' Batch: convert a folder of scanned images to searchable PDFs
For Each imagePath In Directory.GetFiles("scans", "*.jpg")
    Dim batchResult = New IronTesseract().Read(imagePath)
    Dim outputPath As String = Path.ChangeExtension(imagePath, ".searchable.pdf")
    batchResult.SaveAsSearchablePdf(outputPath)
    Console.WriteLine($"Converted: {outputPath}")
Next
$vbLabelText   $csharpLabel

PDF z funkcją wyszukiwania zawiera oryginalny obraz jako warstwę wizualną z nałożonym niewidocznym tekstem OCR w odpowiednich współrzędnych — jest to standardowy format dla procesów archiwizacji i zapewnienia zgodności. Zobacz przewodnik w formacie PDF z funkcją wyszukiwania oraz przykład w formacie PDF z funkcją wyszukiwania, aby zapoznać się z opcjami, w tym wyjściem w formacie PDF/A do długoterminowej archiwizacji.

Asynchroniczne OCR w aplikacjach internetowych

Asprise nie posiada asynchronicznego interfejsu API. Programiści integrują go z asynchronicznymi aplikacjami .NET, opakowując synchroniczne wywołania w Task.Run, co pochłania wątki puli wątków i nie eliminuje blokowania.IronOCR zapewnia natywną ścieżkę asynchroniczną.

Podejście Asprise OCR:

// Asprise: no async API — must offload to Task.Run
// This blocks a thread pool thread during the entire OCR operation
// On LITE/STANDARD, concurrent Task.Run calls = license violation
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
    string tempPath = Path.GetTempFileName();
    await using (var fs = new FileStream(tempPath, FileMode.Create))
        await fileStream.CopyToAsync(fs);

    // Task.Run wraps synchronous Asprise — occupies a thread pool thread
    // Two concurrent requests still violate LITE/STANDARD license
    return await Task.Run(() =>
    {
        Ocr ocr = new Ocr();
        try
        {
            ocr.StartEngine("eng", Ocr.SPEED_FAST);
            return ocr.Recognize(
                tempPath,
                Ocr.RECOGNIZE_TYPE_TEXT,
                Ocr.OUTPUT_FORMAT_PLAINTEXT);
        }
        finally
        {
            ocr.StopEngine();
            File.Delete(tempPath);
        }
    });
}
// Asprise: no async API — must offload to Task.Run
// This blocks a thread pool thread during the entire OCR operation
// On LITE/STANDARD, concurrent Task.Run calls = license violation
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
    string tempPath = Path.GetTempFileName();
    await using (var fs = new FileStream(tempPath, FileMode.Create))
        await fileStream.CopyToAsync(fs);

    // Task.Run wraps synchronous Asprise — occupies a thread pool thread
    // Two concurrent requests still violate LITE/STANDARD license
    return await Task.Run(() =>
    {
        Ocr ocr = new Ocr();
        try
        {
            ocr.StartEngine("eng", Ocr.SPEED_FAST);
            return ocr.Recognize(
                tempPath,
                Ocr.RECOGNIZE_TYPE_TEXT,
                Ocr.OUTPUT_FORMAT_PLAINTEXT);
        }
        finally
        {
            ocr.StopEngine();
            File.Delete(tempPath);
        }
    });
}
Imports System.IO
Imports System.Threading.Tasks

' Asprise: no async API — must offload to Task.Run
' This blocks a thread pool thread during the entire OCR operation
' On LITE/STANDARD, concurrent Task.Run calls = license violation
Public Async Function ProcessUploadAsync(fileStream As Stream, fileName As String) As Task(Of String)
    Dim tempPath As String = Path.GetTempFileName()
    Await Using fs As New FileStream(tempPath, FileMode.Create)
        Await fileStream.CopyToAsync(fs)
    End Using

    ' Task.Run wraps synchronous Asprise — occupies a thread pool thread
    ' Two concurrent requests still violate LITE/STANDARD license
    Return Await Task.Run(Function()
                              Dim ocr As New Ocr()
                              Try
                                  ocr.StartEngine("eng", Ocr.SPEED_FAST)
                                  Return ocr.Recognize(tempPath, Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT)
                              Finally
                                  ocr.StopEngine()
                                  File.Delete(tempPath)
                              End Try
                          End Function)
End Function
$vbLabelText   $csharpLabel

Podejście IronOCR:

// IronOCR: native async, concurrent requests permitted on all tiers
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
    using var input = new OcrInput();
    input.LoadImage(fileStream);       // Stream input directly — no temp file

    var ocr = new IronTesseract();
    var result = await ocr.ReadAsync(input);
    return result.Text;
}
// IronOCR: native async, concurrent requests permitted on all tiers
public async Task<string> ProcessUploadAsync(Stream fileStream, string fileName)
{
    using var input = new OcrInput();
    input.LoadImage(fileStream);       // Stream input directly — no temp file

    var ocr = new IronTesseract();
    var result = await ocr.ReadAsync(input);
    return result.Text;
}
Imports System.IO
Imports System.Threading.Tasks

' IronOCR: native async, concurrent requests permitted on all tiers
Public Async Function ProcessUploadAsync(fileStream As Stream, fileName As String) As Task(Of String)
    Using input As New OcrInput()
        input.LoadImage(fileStream) ' Stream input directly — no temp file

        Dim ocr As New IronTesseract()
        Dim result = Await ocr.ReadAsync(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

Wersja IronOCR eliminuje zapis do pliku tymczasowego, wrapper Task.Run i zachowanie blokujące wątek. Wiele równoczesnych żądań tworzy własną instancję IronTesseract — klasa jest bezstanowa i każda instancja jest niezależna. Przewodnik po asynchronicznym OCR obejmuje wzorce ReadAsync i obsługę tokenów anulowania dla długotrwałych operacji wsadowych w usługach hostowanych.

Asprise OCRAPI do IronOCR– dokumentacja API dla mapowania

Asprise OCR Odpowiednik IronOCR
asprise.ocr przestrzeń nazw IronOcr przestrzeń nazw
Ocr.SetUp() Nie jest wymagane
new Ocr() new IronTesseract()
ocr.StartEngine("eng", Ocr.SPEED_FAST) Nie jest wymagane
ocr.StartEngine("eng+fra", speed) ocr.Language = OcrLanguage.English + OcrLanguage.French
ocr.Recognize(path, type, format) ocr.Read(path) lub ocr.Read(input)
Ocr.RECOGNIZE_TYPE_TEXT Domyślne zachowanie
Ocr.RECOGNIZE_TYPE_BARCODE ocr.Configuration.ReadBarCodes = true
Ocr.RECOGNIZE_TYPE_ALL ocr.Configuration.ReadBarCodes = true
Ocr.OUTPUT_FORMAT_PLAINTEXT result.Text
Ocr.OUTPUT_FORMAT_XML result.Pages / result.Pages[n].Words
Ocr.OUTPUT_FORMAT_PDF result.SaveAsSearchablePdf(path)
Ocr.SPEED_FASTEST strojenie ocr.Configuration.TesseractEngineMode
Ocr.SPEED_FAST Konfiguracja domyślna
Ocr.SPEED_SLOW Ustawienia konfiguracyjne zapewniające wyższą dokładność
ocr.StopEngine() Nie wymagane — OcrInput to IDisposable
sprawdzenie result.StartsWith("ERROR:") Standardowa obsluga wyjatkow .NET (try/catch)
Natywna biblioteka DLL platformy (aocr_x64.dll) Pakiet uruchomieniowy NuGet (automatyczny)
Ręczny plik tymczasowy dla wejścia strumieniowego bezposrednio input.LoadImage(stream)
Zewnętrzna biblioteka do obsługi plików TIFF z wieloma ramkami input.LoadImageFrames(path)
Zewnętrzna biblioteka do przeszukiwania plików PDF result.SaveAsSearchablePdf(path)

Typowe problemy związane z migracją i ich rozwiązania

Problem 1: Wyjątek DllNotFoundException po usunięciu natywnych plików binarnych

Asprise OCR: Usunięcie pakietu NuGet Asprise, ale pozostawienie natywnych odniesień do bibliotek binarnych (w zasadach kopiowania plików projektowych, instrukcjach Docker COPY lub skryptach wdrażania) może spowodować ponowne pojawienie się DllNotFoundException z nieaktualnej konfiguracji wskazującej na nieistniejącą bibliotekę binarną.

Rozwiazanie: Przeszukaj artefakty wdrozeniowe pod katem wszelkich odniesien do ustawień aocr, libaocr lub LD_LIBRARY_PATH i usuń je.IronOCR nie ma żadnych wymagań dotyczących konfiguracji. W pliku Dockerfile:

# Remove: COPY aocr_x64.dll /app/
# Remove: ENV LD_LIBRARY_PATH=/app
# IronOCR: nothing to add — NuGet handles native runtime packaging
RUN dotnet restore
RUN dotnet publish -c Release -o /app/publish

W przypadku wdrażania wielopłatformowego przewodnik wdrażania Docker zawiera wymagania dotyczące obrazu bazowego dla IronOCR w kontenerach Linux.

Problem 2: Brakaca usuniecia Ocr.SetUp() przerywa start

Asprise OCR: Ocr.SetUp() wykonuje globalna inicjalizacje natywna. Niektóre bazy kodu wywołują ją w statycznym konstruktorze lub Startup.Configure. Po migracji, usuniecie przestrzeni nazw Asprise usuwa blad kompilacji, ale jesli SetUp() jest opakowany w try/catch, ktory tlumi wyjatek, kod moze kompilowac sie i dzialac cicho, bez inicjalizacji czegokolwiek.

Rozwiazanie: Przeszukaj wszystkie wywolania SetUp() i usun caly blok inicjalizacyjny. Zastąp odpowiedni hook startowy przypisaniem klucza licencyjnego IronOCR:

grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
SHELL
// Remove all occurrences of the engine lifecycle pattern:
// Ocr.SetUp();
// ocr.StartEngine(...);
// ocr.StopEngine();

// Replace application startup initialization with:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Remove all occurrences of the engine lifecycle pattern:
// Ocr.SetUp();
// ocr.StartEngine(...);
// ocr.StopEngine();

// Replace application startup initialization with:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
$vbLabelText   $csharpLabel

Problem 3: Kod parsujący dane wyjściowe XML nie ma bezpośredniego zamiennika

Asprise OCR: Kod, który analizuje ciągi OUTPUT_FORMAT_XML za pomocą XDocument, XmlReader lub wzorców regex, nie ma równoważnej struktury XML w IronOCR. Schemat XML generowany przez Asprise nie odpowiada bezpośrednio modelowi obiektowemu IronOCR.

Rozwiazanie: Zamień kod analizy XML na bezpośredni dostęp do właściwości na OcrResult. Mapowanie wygląda następująco:

// Asprise XML parsing (remove)
var words = XDocument.Parse(xmlOutput)
    .Descendants("word")
    .Select(w => new { Text = (string)w.Attribute("text"), X = (int)w.Attribute("x") });

//IronOCR object model (replace with)
var result = new IronTesseract().Read(imagePath);
var words = result.Pages
    .SelectMany(p => p.Paragraphs)
    .SelectMany(para => para.Words)
    .Select(w => new { w.Text, w.X });
// Asprise XML parsing (remove)
var words = XDocument.Parse(xmlOutput)
    .Descendants("word")
    .Select(w => new { Text = (string)w.Attribute("text"), X = (int)w.Attribute("x") });

//IronOCR object model (replace with)
var result = new IronTesseract().Read(imagePath);
var words = result.Pages
    .SelectMany(p => p.Paragraphs)
    .SelectMany(para => para.Words)
    .Select(w => new { w.Text, w.X });
Imports System.Xml.Linq
Imports IronOcr

' Asprise XML parsing (remove)
Dim words = XDocument.Parse(xmlOutput) _
    .Descendants("word") _
    .Select(Function(w) New With {Key .Text = CType(w.Attribute("text"), String), Key .X = CType(w.Attribute("x"), Integer)})

' IronOCR object model (replace with)
Dim result = New IronTesseract().Read(imagePath)
Dim words = result.Pages _
    .SelectMany(Function(p) p.Paragraphs) _
    .SelectMany(Function(para) para.Words) _
    .Select(Function(w) New With {w.Text, w.X})
$vbLabelText   $csharpLabel

Przewodnik po wynikach odczytu obejmuje pełną hierarchię obiektów, w tym dane na poziomie znaków wraz z ramkami ograniczającymi.

Problem 4: Owijki Task.Run powodujące wyczerpanie puli wątków

Asprise OCR: Aplikacje sieciowe o wysokiej konkurencyjności opakowujące Asprise w Task.Run mogą zużywać pulę wątków, gdy wolumen OCR gwałtownie wzrasta. Każdy zakolejkowany Task.Run zajmuje wątek puli wątków na cały czas trwania operacji OCR.

Rozwiązanie: Zastąp Task.Run(() =&gt; { asprise... }) z natywnymi wywołaniami asynchronicznymi IronOCR. Każda instancja IronTesseract jest niezależna — stwórz jedną na każde żądanie:

// Remove: await Task.Run(() => { ocr.Recognize(...) });

// Replace with:
using var input = new OcrInput();
input.LoadImage(stream);
var result = await new IronTesseract().ReadAsync(input);
return result.Text;
// Remove: await Task.Run(() => { ocr.Recognize(...) });

// Replace with:
using var input = new OcrInput();
input.LoadImage(stream);
var result = await new IronTesseract().ReadAsync(input);
return result.Text;
Imports IronTesseract

Using input As New OcrInput()
    input.LoadImage(stream)
    Dim result = Await (New IronTesseract()).ReadAsync(input)
    Return result.Text
End Using
$vbLabelText   $csharpLabel

Problem 5: Walidacja kodu językowego oparta na ciągach znaków

Asprise OCR: Kody języków są przekazywane jako ciągi ("eng", "fra", "eng+fra"). Aplikacje, które weryfikują te ciągi w czasie pracy — sprawdzając w porównaniu do zakodowanej na sztywno listy, odczytując z konfiguracji — potrzebują aktualizacji, gdy format ciągu zostaje zmieniony na enum OcrLanguage.

Rozwiazanie: Zamień parametry języka w postaci ciągu na wartości enum OcrLanguage. Wybór języka oparty na konfiguracji mapuje się czysto na Enum.Parse:

// Asprise string-based (remove)
string language = config["OcrLanguage"];  // e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST);

//IronOCR enum-based (replace with)
// For single language from config:
var ocr = new IronTesseract();
ocr.Language = Enum.Parse<OcrLanguage>(config["OcrLanguage"]);  // e.g. "English"
var result = ocr.Read(input);
// Asprise string-based (remove)
string language = config["OcrLanguage"];  // e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST);

//IronOCR enum-based (replace with)
// For single language from config:
var ocr = new IronTesseract();
ocr.Language = Enum.Parse<OcrLanguage>(config["OcrLanguage"]);  // e.g. "English"
var result = ocr.Read(input);
Imports System
Imports IronOcr

' Asprise string-based (remove)
Dim language As String = config("OcrLanguage")  ' e.g. "eng+fra"
ocr.StartEngine(language, Ocr.SPEED_FAST)

' IronOCR enum-based (replace with)
' For single language from config:
Dim ocr As New IronTesseract()
ocr.Language = [Enum].Parse(Of OcrLanguage)(config("OcrLanguage"))  ' e.g. "English"
Dim result = ocr.Read(input)
$vbLabelText   $csharpLabel

Przewodnik po wielu językach zawiera listę wszystkich prawidłowych wartości enum OcrLanguage i odpowiadających im pakietów językowych NuGet.

Problem 6: Logika sprawdzania poziomu licencji nie jest już potrzebna

Asprise OCR: Niektóre produkcyjne bazy kodu zawierają kontrole środowiska uruchomieniowego, które wykrywają poziom licencji Asprise i sekwencjonują pracę OCR w przypadku działania poniżej poziomu ENTERPRISE. Te zabezpieczenia zapobiegają naruszeniom licencji, ale zwiększają złożoność i zmniejszają przepustowość.

Rozwiązanie: Usuń wszystkie zabezpieczenia wykrywania warstw i serializacji.IronOCR nie ma żadnych ograniczeń dotyczących wątków na żadnym poziomie. Wzorce ConcurrentQueue, SemaphoreSlim, lub jednowatkowego dyspozytora wykorzystywane do szeregowania wywołań Asprise nie maja sensu po migracji:

// Remove: SemaphoreSlim _ocrLock = new SemaphoreSlim(1, 1);
// Remove: await _ocrLock.WaitAsync(); ... _ocrLock.Release();

// IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, path =>
{
    var text = new IronTesseract().Read(path).Text;
    results[path] = text;
});
// Remove: SemaphoreSlim _ocrLock = new SemaphoreSlim(1, 1);
// Remove: await _ocrLock.WaitAsync(); ... _ocrLock.Release();

// IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, path =>
{
    var text = new IronTesseract().Read(path).Text;
    results[path] = text;
});
Imports System.Threading.Tasks

' IronOCR: direct concurrent access, no guards needed
Parallel.ForEach(documentPaths, Sub(path)
    Dim text = (New IronTesseract()).Read(path).Text
    results(path) = text
End Sub)
$vbLabelText   $csharpLabel

Lista kontrolna migracji Asprise OCR

Przed migracją

Przed napisaniem jakiegokolwiek kodu zastępczego należy sprawdzić kod źródłowy pod kątem wszystkich miejsc użycia Asprise:

# Find all files importing asprise namespace
grep -rn "using asprise" --include="*.cs" .

# Find all engine lifecycle calls
grep -rn "SetUp\|StartEngine\|StopEngine" --include="*.cs" .

# Find all integer constant references
grep -rn "RECOGNIZE_TYPE\|OUTPUT_FORMAT\|SPEED_FAST\|SPEED_SLOW" --include="*.cs" .

# Find native binary references in project files and deployment scripts
grep -rn "aocr\|libaocr" --include="*.csproj" --include="Dockerfile" --include="*.yml" .

# Find XML output parsing code
grep -rn "OUTPUT_FORMAT_XML\|XDocument.Parse\|Descendants.*word" --include="*.cs" .

# Find Task.Run wrappers around OCR calls
grep -rn "Task.Run.*ocr\|Task.Run.*Recognize" --include="*.cs" .
# Find all files importing asprise namespace
grep -rn "using asprise" --include="*.cs" .

# Find all engine lifecycle calls
grep -rn "SetUp\|StartEngine\|StopEngine" --include="*.cs" .

# Find all integer constant references
grep -rn "RECOGNIZE_TYPE\|OUTPUT_FORMAT\|SPEED_FAST\|SPEED_SLOW" --include="*.cs" .

# Find native binary references in project files and deployment scripts
grep -rn "aocr\|libaocr" --include="*.csproj" --include="Dockerfile" --include="*.yml" .

# Find XML output parsing code
grep -rn "OUTPUT_FORMAT_XML\|XDocument.Parse\|Descendants.*word" --include="*.cs" .

# Find Task.Run wrappers around OCR calls
grep -rn "Task.Run.*ocr\|Task.Run.*Recognize" --include="*.cs" .
SHELL

Podsumowanie wyników:

  • Policz pliki importujące asprise.ocr — wszystkie muszą zostać uaktualnione przestrzenie nazw
  • Wymień każde miejsce wywołania StartEngine — każde z nich staje sie wywołaniem Read
  • Zidentyfikuj kod parsujący dane wyjściowe XML — każdy blok wymaga zastąpienia modelu obiektowego
  • Zwróć uwagę na wszelkie zabezpieczenia poziomów licencji lub opakowania serializacji — można je usunąć
  • Zlokalizuj natywne skrypty wdrażania plików binarnych i konfigurację kontenerów

Migracja kodu

  1. Usuń pakiet NuGet asprise-ocr-api ze wszystkich projektów
  2. Zainstaluj pakiet NuGet IronOcr w każdym projekcie, który wykonuje OCR
  3. Zamień using asprise.ocr na using IronOcr we wszystkich plikach
  4. Dodaj IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" przy starcie aplikacji
  5. Usuń wywołania Ocr.SetUp() z całego kodu startowego i inicjującego
  6. Zamień każdy blok Ocr.StartEngine / Recognize / StopEngine na new IronTesseract().Read(path).Text
  7. Zamień bloki analizy OUTPUT_FORMAT_XML na przejście obiektowe result.Pages
  8. Zamień obejścia OUTPUT_FORMAT_PDF na result.SaveAsSearchablePdf(path)
  9. Zamień kod dzielący wielowarstwowe TIFFy na input.LoadImageFrames(tiffPath)
  10. Zamień opakowania oparte na strumieniach Task.Run na await ocr.ReadAsync(input)
  11. Usuń SemaphoreSlim lub zabezpieczenia serializacji, które chroniły Asprise przed równoczesnym użyciem
  12. Usuń instrukcje kopiowania natywnych bibliotek z plików .csproj i Dockerfiles
  13. Usuń ustawienia LD_LIBRARY_PATH z konfiguracji środowiska i skryptów CI
  14. Zamień kody języków w postaci tekstowej ("eng", "eng+fra") na wartości enum OcrLanguage
  15. Zamień sprawdzenia result.StartsWith("ERROR:") na bloki try/catch

Po migracji

  • Zweryfikuj, czy dotnet build kończy się bez ostrzeżeń o brakujących bibliotekach natywnych
  • Potwierdź, że żadne DllNotFoundException lub BadImageFormatException nie występują na starcie we wszystkich docelowych środowiskach (Windows, Linux, Docker)
  • Uruchom OCR na reprezentatywnym obrazie i sprawdź, czy wynik tekstowy odpowiada punktowi odniesienia sprzed migracji
  • Przetestuj przetwarzanie plików TIFF z wieloma ramkami i sprawdź, czy wszystkie strony są zwracane z prawidłowymi numerami stron
  • Utwórz plik PDF z możliwością wyszukiwania i sprawdź, czy tekst można zaznaczyć i przeszukiwać w przeglądarce plików PDF
  • Wysyłaj równoległe żądania HTTP do dowolnego punktu końcowego API, który wywołuje OCR, i upewnij się, że wszystkie żądania zakończą się bez błędów
  • Sprawdź, czy asynchroniczne punkty końcowe zwracają wyniki bez blokowania się przy obciążeniu równoległym
  • Sprawdź, czy wyodrębnianie danych ustrukturyzowanych (współrzędne słów i poziom pewności) daje poprawny wynik na znanym dokumencie
  • Sprawdź użycie pamięci aplikacji w czasie, aby potwierdzić brak wycieków pamięci natywnej (wcześniej powodowane przez pominięte wywołania StopEngine())
  • Uruchom aplikację w systemie Linux lub w kontenerze Docker, aby sprawdzić, czy wdrożenie międzyplatformowe działa bez konfiguracji plików binarnych

Kluczowe korzyści z migracji do IronOCR

Wdrożenie sprowadza się do jednego odwołania NuGet. Po migracji każdy cel wdrożenia — stacje robocze programistów, serwery stagingowe, kontenery Linux, agenci CI — instaluje ten sam pakiet za pomocą tego samego polecenia. Nie ma logiki wykrywania platformy, pozyskiwania plików binarnych specyficznych dla architektury ani konfiguracji ścieżki uruchomieniowej. Obraz Docker, który wcześniej wymagał ręcznych instrukcji kopiowania natywnych bibliotek binarnych, teraz wymaga tylko dotnet restore. Przewodnik wdrażania w systemie Linux oraz przewodnik wdrażania w Azure zawierają uwagi dotyczące konkretnego środowiska, tam gdzie ma to zastosowanie.

Wszystkie poziomy licencji odblokowują wdrożenie klasy serwerowej. Licencja $999 Lite obsługuje ASP.NET Core Web APIs, usługi Windows, funkcje Azure, AWS Lambda i każdą inną wielowątkową roboczosc .NET. Funkcja wielowątkowości na poziomie Enterprise, za którą firma Asprise pobiera opłatę w wysokości 2000–5000 USD+, jest dostępna na każdym poziomie IronOCR. Zespoły przechodzące z Asprise ENTERPRISE na IronOCR Lite obniżają koszty licencji OCR, zyskując jednocześnie funkcje, których ENTERPRISE nie oferowało — natywny format PDF, uporządkowany wynik, generowanie plików PDF z możliwością wyszukiwania oraz obsługę 125 języków.

Strukturalne wyniki OCR zastepuja analize ciagow XML. Model obiektowy OcrResult udostępnia pełną hierarchię dokumentów: strony, akapity, linie, słowa i znaki, każdy z dokładną do piksela współrzędną ramki ograniczającej i wynikiem pewnosci. Kod, który wcześniej analizował ciągi XML Asprise za pomocą XDocument lub wyrażeń regularnych, staje się bezpośrednim dostępem do właściwości. Strona poświęcona wynikom OCR obejmuje systemy współrzędnych oraz sposób filtrowania wyników według poziomu pewności w celu automatycznej kontroli jakości.

Wbudowane przetwarzanie wstępne usuwa zależności od zewnętrznych bibliotek obrazów. Przetwarzanie wstępne dostępne przez OcrInputDeskew, DeNoise, Contrast, Binarize, Sharpen, Dilate, Erode, Scale, Invert i DeepCleanBackgroundNoise — eliminuje zewnętrzną bibliotekę obrazów, której wymagają integracje z Asprise. Usunięcie tej zależności usuwa troskę o licencjonowanie, zmniejsza ślad budowy i umieszcza konfigurację przetwarzania wstępnego bezpośrednio obok konfiguracji OCR w tym samym pliku kodu. Strona funkcji przetwarzania wstępnego i przewodnik korygowania jakości obrazu zawierają kiedy zastosować każdy filtr i wymierne korzyści w dokładności, jakie każdy zapewnia na skanach niskiej jakości.

Natywny asynchroniczny i prawdziwy równoległość poprawiają przepustowość. ReadAsync integruje się w standardowy wzorzec async/await bez blokowania puli wątków. Równoległe przetwarzanie wsadowe z Parallel.ForEach lub PLINQ skaluje liniowo z dostępnymi rdzeniami. Partia dokumentów, którą Asprise Lite/Standard zmuszony jest przetwarzać sekwencyjnie — 100 dokumentów po 2 sekundy każdy zajmuje ponad 3 minuty — na komputerze z 8 rdzeniami i IronOCR przetwarzana jest w około 25 sekund. Przykład wielowątkowości demonstruje wzorce równoległej przepustowości i pokazuje, jak używać ConcurrentBag do bezpiecznego dla wątków zbierania wyników.

125+ języków bez dystrybucji binarnej. Pakiety językowe instalują się jako pakiety NuGet — dotnet add package IronOcr.Languages.Arabic, dotnet add package IronOcr.Languages.Japanese — i wdrażają się z aplikacją jak każda inna zależność. Nie ma ręcznego folderu tessdata do wypełnienia, nie ma pliku binarnego języka do zlokalizowania i nie jest wymagana konfiguracja ścieżki na komputerze docelowym. Indeks języków zawiera listę wszystkich ponad 125 dostępnych pakietów językowych.

Zwróć uwagęAsprise OCR, PDFSharp, Tesseract i iText są zarejestrowanymi znakami towarowymi ich odpowiednich właścicieli. Ta strona nie jest związana z, wspierana ani sponsorowana przez Asprise, Google, empira Software GmbH ani iText Group. Wszystkie nazwy produktów, loga i marki są własnością ich odpowiednich właścicieli. Porównania mają charakter wyłącznie informacyjny i odzwierciedlają informacje dostępne publicznie w momencie pisania.

Często Zadawane Pytania

Dlaczego warto przejść z Asprise OCR SDK 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 Asprise OCR SDK do IronOCR?

Zastąp sekwencje inicjalizacji Asprise OCR 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 bibliotece Asprise OCR SDK 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 Asprise OCR SDK 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 Asprise OCR SDK do IronOCR wymaga zmian w infrastrukturze wdrożeniowej?

IronOCR wymaga mniej zmian w infrastrukturze niż Asprise OCR SDK. Nie ma ścieżek binarnych SDK, lokalizacji plików licencyjnych 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 Asprise OCR?

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ż Asprise OCR SDK 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 Asprise OCR SDK 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.

Kannaopat Udonpant
Inżynier oprogramowania
Zanim stał się inżynierem oprogramowania, Kannapat ukończył doktorat z zasobów środowiskowych na Uniwersytecie Hokkaido w Japonii. W czasie studiowania, Kannapat również został członkiem Laboratorium Robotyki Pojazdów, które jest częścią Wydziału Inżynierii Bioprodukcji. W 2022 roku wykorzystał swoje umiejętności w ...
Czytaj więcej

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie