Asprise OCR에서 IronOCR로 마이그레이션하기
이 가이드는 .NET 개발자가 Asprise OCR을 IronOCR 로 교체하는 모든 단계를 안내합니다. 이 문서에서는 프로덕션 .NET 애플리케이션에서 Asprise 사용의 대부분을 차지하는 기계적 패키지 교체, 네임스페이스 변경 및 네 가지 코드 마이그레이션 패턴을 다룹니다. 이미 마이그레이션을 결정하고 구체적인 실행 계획이 필요한 개발자가 이 책의 주요 대상 독자입니다.
Asprise OCR에서 마이그레이션해야 하는 이유는 무엇일까요?
Asprise OCR은 원래 Java 제품으로 설계되었습니다. .NET 인터페이스는 Java 기반 네이티브 엔진을 감싸는 래퍼이며, 이러한 기원은 배포부터 API 설계, 라이선스 제약 조건에 이르기까지 라이브러리의 .NET 환경에서의 모든 동작에 영향을 미칩니다.
JRE 및 네이티브 바이너리 종속성. Asprise OCRfor .NET은 모든 기기에서 응용 프로그램이 실행될 때 플랫폼별 네이티브 바이너리(aocr.dll, aocr_x64.dll, libaocr.so, libaocr.dylib)가 필요합니다. 각 바이너리 파일은 대상 플랫폼 및 프로세스 아키텍처와 정확히 일치해야 합니다. 32비트 DLL로 구축된 64비트 Docker 컨테이너는 실행 시 BadImageFormatException를 던집니다. libaocr.so에서 LD_LIBRARY_PATH를 누락한 Linux 배포는 DllNotFoundException를 던집니다. 빌드 시점에는 두 오류 모두 발생하지 않습니다. 새로운 배포 대상(새로운 서버, 새로운 컨테이너 이미지, CI 에이전트)이 추가될 때마다 수동으로 바이너리 파일을 추출해야 합니다.
Java Heritage 출신의 String-Constant API. Asprise는 인식 유형 및 출력 형식용 정수 상수를 공개합니다: Ocr.RECOGNIZE_TYPE_TEXT, Ocr.OUTPUT_FORMAT_PLAINTEXT, Ocr.OUTPUT_FORMAT_XML. 이 상수들은 Java SDK의 정수 기반 API에 직접적으로 대응됩니다. .NET 개발자는 유효한 상수 값에 대한 IntelliSense 안내를 받지 못하고, 인자 조합에 대한 컴파일 시간 안전성도 보장되지 않으며, 강력한 형식의 결과 객체도 제공받지 못합니다. 구조화된 출력을 추출하려면 XML 문자열을 수동으로 구문 분석해야 합니다.
별도의 해결 방법 없이는 비동기 기능을 지원하지 않습니다. Asprise는 네이티브 비동기 API를 제공하지 않습니다. ASPRISE의 동기 호출을 Task.Run로 래핑하여 ASP.NET 스레드를 차단하지 않도록 하여 스레드 풀 압력을 발생시키고 LITE 및 STANDARD 계층에서 동시 실행을 금지하는 라이센스 제한을 해결하지 않습니다. 최신 .NET 애플리케이션의 비동기 패턴(백그라운드 서비스, 최소 API 엔드포인트, Azure Functions)은 Azure에서 깔끔하게 구현할 수 있는 방법이 없습니다.
다중 프레임 TIFF 처리에는 수동 분할이 필요합니다. Asprise는 단일 이미지 파일에서 작동합니다. 여러 페이지로 구성된 TIFF 파일을 처리하려면 외부 코드를 사용하여 프레임을 개별 파일로 분할한 다음 루프를 통해 각 파일을 처리해야 합니다. 프레임 메타데이터나 페이지 번호는 출력에 포함되지 않습니다.
스레드 제한으로 인해 프로덕션 배포가 차단됩니다. Lite (~$299) 및 STANDARD(~$699) 라이선스는 계약상 실행을 단일 스레드 및 단일 프로세스로 제한합니다. ASP.NET Core 스레드 풀에서 모든 HTTP 요청을 처리합니다. 해당 등급에서 Asprise를 호출하는 모든 웹 API 엔드포인트는 첫 번째 동시 요청부터 라이선스 위반이 됩니다. Enterprise 등급으로 업그레이드하면 이러한 제한이 해제되지만, 정식 가격이 공개되지 않았으며 배포 범위에 따라 2,000달러에서 5,000달러 이상으로 예상되므로 영업팀에 문의해야 합니다.
출력 형식 처리는 문자열 구문 분석이 필요합니다. OUTPUT_FORMAT_XML이 지정된 경우 Asprise는 원시 XML 문자열을 반환합니다. 해당 애플리케이션은 문자열을 역직렬화하고, 구조를 검증하고, 단어와 그 위치를 추출하는 역할을 담당합니다. 단어별 신뢰도 점수는 XML 속성에 포함되어 있습니다. 객체 모델은 없고, 문자열 조작만 가능합니다.
근본적인 문제
Asprise는 첫 번째 OCR 호출을 실행하기 전에 JRE와 관련된 네이티브 바이너리 구성을 필요로 합니다.IronOCR 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
// 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
IronOCR과 Asprise OCR: 기능 비교
아래 표는 이번 마이그레이션을 평가하는 개발자에게 가장 중요한 기능들을 다룹니다.
| 기능 | Asprise OCR | IronOCR |
|---|---|---|
| 주요 플랫폼 | 자바(레거시) | .NET 네이티브 |
| NuGet 설치 | 래퍼 + 플랫폼 네이티브 DLL | 단일 패키지 (IronOcr) |
| 런타임에 네이티브 바이너리가 필요합니다. | 예 (플랫폼별 DLL) | 아니요 |
| .NET API 스타일 | 정수 상수, 문자열 반환 | 강력한 형식의 클래스와 열거형 |
IDisposable / using 패턴 |
구현되지 않음 | 예 (OcrInput) |
| 비동기 OCR | 네이티브 지원 없음 | 예 (ReadAsync) |
| 멀티스레딩 — Lite/스탠다드 등급 | 라이선스에 의해 금지됨 | 허용됨 |
| 멀티스레딩 - 모든 계층 | Enterprise 전용 | 모든 등급 |
| ASP.NET Core 웹 API 지원 | Enterprise 필수 | 모든 등급 |
| Azure Functions / AWS 람다 | Enterprise 필수 | 모든 등급 |
| 네이티브 PDF 입력 | 아니요 | 예 |
| 다중 프레임 TIFF 입력 | 아니요 (수동 프레임 분할) | 예 (LoadImageFrames) |
| 바이트 배열 및 스트림 입력 | 제한적 | 예 |
| 내장 이미지 전처리 기능 | 아니요 | 예 (9개 이상의 필터) |
| 검색 가능한 PDF 출력 | 아니요 | 예 (SaveAsSearchablePdf) |
| 구조화된 결과 객체 모델 | 아니요 (XML 문자열만 해당) | 예 (페이지, 단락, 단어, 문자) |
| 단어별 신뢰도 점수 | 아니요 (XML 속성 구문 분석) | 예 (result.Confidence) |
| 단어 픽셀 좌표 | XML 속성 구문 분석 | 강력한 유형의 속성 |
| 언어 개수 | 20세 이상 | 125+ |
| 강력한 유형의 언어 선택 | 아니요 (문자열 코드) | 예 (OcrLanguage enum) |
| 바코드 판독 | 예 (별도 인식 유형) | 예 (구성 플래그) |
| hOCR 내보내기 | 아니요 | 예 |
| 크로스 플랫폼 배포 | 플랫폼별 수동 바이너리 | NuGet 모든 플랫폼을 지원합니다. |
| Docker / Linux / macOS | 수동 LD_LIBRARY_PATH 구성 |
별도의 설정 없이 바로 사용 가능합니다. |
| .NET 호환성 | 제한된(자바 브리지) | .NET Framework 4.6.2 이상, .NET 5~9 |
| 서버 사용료 | Enterprise (~2,000달러 이상) | $999 (Lite, 모든 기능) |
| 라이선스 유형 | 등급별 문의 사항은 Enterprise 에 연락하십시오. | 영구(일회성 구매) |
빠른 시작: Asprise OCR에서IronOCR로 마이그레이션
1단계: NuGet 패키지 교체
Asprise OCR 제거:
dotnet remove package asprise-ocr-api
dotnet remove package asprise-ocr-api
NuGet 패키지 페이지 에서IronOCR설치하세요.
dotnet add package IronOcr
단계 2: 네임스페이스 업데이트
Asprise 네임스페이스를IronOCR네임스페이스로 교체합니다:
// Before (Asprise)
using asprise.ocr;
// After (IronOCR)
using IronOcr;
// Before (Asprise)
using asprise.ocr;
// After (IronOCR)
using IronOcr;
Imports IronOcr
단계 3: 라이선스 초기화
OCR 호출 전에, Program.cs, Startup.Configure 또는 정적 생성자에 라이센스 키 할당을 애플리케이션 시작 시 추가하십시오.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
IronOCR 라이선스 페이지 에서 무료 평가판 키를 다운로드할 수 있습니다. 개발 및 평가 단계에서IronOCR키 없이 실행되며 출력물에 시험용 워터마크를 삽입합니다.
코드 마이그레이션 예제
JRE 경로 구성 및 엔진 초기화 제거
Linux 또는 macOS에서 실행되는 Asprise 애플리케이션은 일반적으로 OCR 작업이 시작되기 전에 JRE 경로를 설정하거나 네이티브 바이너리 존재 여부를 확인하는 시작 코드를 포함합니다.IronOCR에는 이와 동등한 인프라가 없습니다.
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
IronOCR 접근 방식:
// Program.cs — license key assignment is the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// That is it. 아니요 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. 아니요 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. 아니요 binary validation, no path configuration, no SetUp() call.
' NuGet resolved the correct native runtime during package restore.
Asprise 패턴은 보통 여러 파일에 걸쳐 15-30줄의 시작 검증자, 플랫폼 전환, 배포 메시지가 있는 예외, 그리고 SetUp() 호출로 구성됩니다.IronOCR이 모든 것을 하나의 할당으로 대체합니다. IronTesseract 설정 가이드 에서는 사용자 지정 테스데이터 경로 또는 오프라인 작동이 필요한 환경에 대한 배포 구성 옵션을 다룹니다.
XML 출력 형식을 구조화된 결과 객체로 대체
Asprise는 OUTPUT_FORMAT_XML이 지정되면 구조화된 출력을 원시 XML 문자열로 제공합니다. 해당 문자열에서 단어 텍스트, 좌표 및 신뢰도를 추출하려면 XML 파싱 코드가 필요합니다.IronOCR타입이 지정된 객체 그래프를 반환합니다.
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
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
XML 역직렬화, 속성 형변환, 스키마 가정이 필요 없습니다. OcrResult 객체 모델은 페이지, 단락, 행, 단어 및 문자를 유형화된 속성으로 노출합니다. 판독 결과 가이드는 자동화된 워크플로우에서 신뢰도 임계값으로 필터링하는 방법을 포함하여 전체 계층 구조 및 좌표계를 다룹니다.
다중 프레임 TIFF 처리
Asprise는 단일 이미지 파일을 허용합니다. 문서 스캔 워크플로에서 흔히 사용되는 멀티프레임 TIFF 파일은 Asprise에서 처리하기 전에 개별 프레임 파일로 분할해야 합니다. IronOCR는 멀티 프레임 TIFF를 LoadImageFrames을 통해 직접 허용합니다.
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())
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
Asprise 방식은 외부 이미지 처리 종속성, 임시 파일 관리, 수동 정리 및 프레임별 순차적 처리를 필요로 합니다.IronOCR모든 프레임을 한 번에 처리합니다. TIFF 및 GIF 입력 가이드 에서는 특정 페이지만 필요한 대용량 TIFF 파일의 프레임 범위 선택에 대해 설명합니다.
검색 가능한 PDF 생성
Asprise는 어떤 라이선스 등급에서도 검색 가능한 PDF 출력 기능을 제공하지 않습니다. 스캔한 문서에서 OCR로 인식한 텍스트가 포함된 PDF를 생성하려면 외부 PDF 라이브러리, 텍스트 위치를 추출하기 위한 별도의 OCR 과정, 그리고 수동 오버레이 구성이 필요합니다.IronOCR인식 결과에서 바로 검색 가능한 PDF 파일을 생성합니다.
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")
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
검색 가능한 PDF 파일에는 원본 이미지가 시각적 레이어로 포함되어 있고, OCR로 인식된 텍스트가 정확한 좌표에 보이지 않게 겹쳐져 있습니다. 이는 보관 및 규정 준수 워크플로의 표준 형식입니다. 검색 가능한 PDF 사용 설명서 와 검색 가능한 PDF 예시를 참조하여 장기 보관을 위한 PDF/A 출력 옵션을 확인하세요.
웹 애플리케이션에서의 비동기 OCR
Asprise에는 비동기 API가 없습니다. 개발자는 동기 호출을 Task.Run로 래핑하여 비동기 .NET 응용 프로그램에 통합하는데, 이는 스레드 풀 스레드를 사용하며 차단을 제거하지 않습니다.IronOCR네이티브 비동기 경로를 제공합니다.
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
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
IronOCR 버전은 임시 파일 쓰기, Task.Run 래퍼 및 스레드 차단 동작을 제거합니다. 여러 동시 요청은 각각 자체 IronTesseract 인스턴스를 생성합니다 — 클래스는 상태 비저장이며 각 인스턴스는 독립적입니다. async OCR 가이드는 ReadAsync 패턴과 장기 실행 배치 작업의 취소 토큰 지원을 포함합니다.
Asprise OCRAPI와IronOCR매핑 참조
| Asprise OCR | IronOCR에 상응하는 |
|---|---|
asprise.ocr 네임스페이스 |
IronOcr 네임스페이스 |
Ocr.SetUp() |
필요하지 않음 |
new Ocr() |
new IronTesseract() |
ocr.StartEngine("eng", Ocr.SPEED_FAST) |
필요하지 않음 |
ocr.StartEngine("eng+fra", speed) |
ocr.Language = OcrLanguage.English + OcrLanguage.French |
ocr.Recognize(path, type, format) |
ocr.Read(path) 또는 ocr.Read(input) |
Ocr.RECOGNIZE_TYPE_TEXT |
기본 동작 |
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 |
ocr.Configuration.TesseractEngineMode 튜닝 |
Ocr.SPEED_FAST |
기본 설정 |
Ocr.SPEED_SLOW |
더욱 정확한 구성 설정 |
ocr.StopEngine() |
필요하지 않음 — OcrInput은 IDisposable 입니다. |
result.StartsWith("ERROR:") 확인 |
표준 .NET 예외 처리 (try/catch) |
| 플랫폼 네이티브 DLL(aocr_x64.dll) | NuGet 런타임 패키지(자동) |
| 스트림 입력용 수동 임시 파일 | input.LoadImage(stream) 직접 |
| 다중 프레임 TIFF용 외부 라이브러리 | input.LoadImageFrames(path) |
| 검색 가능한 PDF용 외부 라이브러리 | result.SaveAsSearchablePdf(path) |
일반적인 마이그레이션 문제와 해결책
문제 1: 네이티브 바이너리 제거 후 DllNotFoundException 발생
Asprise OCR: Asprise NuGet 패키지를 제거하지만 프로젝트 파일 복사 규칙, Docker COPY 명령 또는 배포 스크립트에 남아 있는 네이티브 바이너리 참조는 존재하지 않는 바이너리를 가리키는 구성을 통해 DllNotFoundException가 다시 나타나게 할 수 있습니다.
해결책: 배포 아티팩트를 검색하여 aocr, libaocr 또는 LD_LIBRARY_PATH 설정에 대한 참조를 찾아 제거합니다.IronOCR별도의 구성 요구 사항이 없습니다. 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
크로스 플랫폼 배포를 위해 Docker 배포 가이드에서는 Linux 컨테이너에서IronOCR하기 위한 기본 이미지 요구 사항을 다룹니다.
문제 2: Ocr.SetUp() 제거 누락으로 인한 시작 실패
Asprise OCR: Ocr.SetUp()는 전역 네이티브 초기화를 수행합니다. 몇몇 코드베이스는 이를 정적 생성자나 Startup.Configure에 호출합니다. 이전 후에 Asprise 네임스페이스를 제거하면 컴파일 에러가 없지만, SetUp()가 예외를 억제하는 try/catch로 래핑되어 있으면 초기화 없이 코드가 조용히 컴파일되고 실행될 수 있습니다.
해결책: 모든 SetUp() 호출을 검색하여 초기화 블록 전체를 제거합니다. 해당 시작 후크를IronOCR라이선스 키 할당으로 교체하십시오.
grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
grep -rn "Ocr.SetUp\|StartEngine\|StopEngine" --include="*.cs" .
// 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";
문제 3: XML 출력 구문 분석 코드에 대한 직접적인 대체 방법이 없음
Asprise OCR: OUTPUT_FORMAT_XML 문자열을 XDocument, XmlReader 또는 정규식 패턴으로 구문 분석하는 코드가 IronOCR에서는 이에 상응하는 XML 구조가 없습니다. Asprise에서 생성하는 XML 스키마는 IronOCR의 객체 모델과 직접적으로 일치하지 않습니다.
해결책: XML 구문 분석 코드를 OcrResult에서 직접 속성 액세스로 교체합니다. 매핑은 다음과 같습니다.
// 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})
읽기 결과 가이드는 경계 상자를 포함한 문자 수준 데이터를 비롯한 전체 객체 계층 구조를 다룹니다.
문제 4: Task.Run 래퍼로 인한 스레드 풀 고갈
Asprise OCR: Task.Run에 Asprise를 래핑한 고율 동시 웹 애플리케이션은 OCR 볼륨 급증 시 스레드 풀을 소진할 수 있습니다. 각 대기열의 Task.Run는 OCR 작업 전체 기간 동안 스레드 풀 스레드를 잡고 있습니다.
해결 방법: Task.Run(() => { asprise...를 대체합니다. })패턴은IronOCR의 네이티브 비동기 호출을 사용합니다. 각IronTesseract` 인스턴스는 독립적입니다 — 요청별로 하나씩 생성합니다.
// 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
문제 5: 문자열 기반 언어 코드 유효성 검사
Asprise OCR: 언어 코드는 문자열로 전달됩니다 ("eng", "fra", "eng+fra"). 런타임에 이러한 문자열을 검증하는 애플리케이션 — 하드 코딩된 목록과 확인하거나 구성에서 읽는 방식 — 문자열 형식이 OcrLanguage enum으로 변경될 때 업데이트가 필요합니다.
해결책: 언어 문자열 매개변수를 OcrLanguage enum 값으로 교체합니다. 구성 기반 언어 선택은 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)
다중 언어 가이드는 모든 유효한 OcrLanguage 열거형 값과 해당하는 NuGet 언어 팩 패키지를 나열합니다.
이슈 6: 라이선스 등급 확인 로직이 더 이상 필요하지 않습니다.
Asprise OCR: 일부 프로덕션 코드베이스에는 Asprise 라이선스 등급을 감지하고 Enterprise 등급 미만으로 실행될 때 OCR 작업을 직렬화하는 런타임 검사가 포함되어 있습니다. 이러한 보호 조치는 라이선스 위반을 방지하지만 복잡성을 증가시키고 처리량을 감소시킵니다.
해결 방법: 모든 계층 감지 및 직렬화 보호 기능을 제거합니다.IronOCR어떤 등급에서도 스레드 제한이 없습니다. Asprise 호출을 직렬화하는 데 사용되는 ConcurrentQueue, SemaphoreSlim 또는 단일 스레드 디스패처 패턴은 마이그레이션 후 필요 없습니다:
// 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)
Asprise OCR마이그레이션 체크리스트
사전 마이그레이션
교체 코드를 작성하기 전에 코드베이스에서 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" .
결과를 목록화하세요:
asprise.ocr를 가져오는 모든 파일 수 — 이들은 모두 네임스페이스 업데이트가 필요합니다- 모든
StartEngine호출 사이트 나열 — 각각Read호출로 변환됩니다 - XML 출력 구문 분석 코드 식별 - 각 블록은 객체 모델 교체가 필요합니다.
- 라이선스 등급 보호 장치 또는 직렬화 래퍼가 있는지 확인하십시오. 이러한 항목은 제거할 수 있습니다.
- 네이티브 바이너리 배포 스크립트 및 컨테이너 구성을 찾습니다.
코드 마이그레이션
- 모든 프로젝트에서
asprise-ocr-apiNuGet 패키지를 제거합니다 - OCR을 수행하는 각 프로젝트에
IronOcrNuGet 패키지를 설치합니다 - 모든 파일에서
using asprise.ocr을using IronOcr로 교체합니다 - 애플리케이션 시작 시
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"를 추가합니다. - 모든 시작 및 초기화 코드에서
Ocr.SetUp()호출을 제거합니다 - 모든
Ocr.StartEngine/Recognize/StopEngine블록을new IronTesseract().Read(path).Text으로 교체합니다 OUTPUT_FORMAT_XML구문 분석 블록을result.Pages객체 탐색으로 교체합니다OUTPUT_FORMAT_PDF대체 방식을result.SaveAsSearchablePdf(path)으로 교체합니다- 멀티 프레임 TIFF 분할 코드를
input.LoadImageFrames(tiffPath)으로 교체합니다 - 스트림 기반
Task.Run래퍼를await ocr.ReadAsync(input)으로 교체합니다 - Asprise의 동시 사용을 보호하던
SemaphoreSlim또는 직렬화 가드를 제거합니다 .csproj파일 및 Dockerfiles에서 네이티브 바이너리 복사 지시를 제거합니다- 환경 구성 및 CI 스크립트에서
LD_LIBRARY_PATH설정을 제거합니다 - 문자열 언어 코드를 (
"eng","eng+fra")OcrLanguageenum 값으로 교체합니다 result.StartsWith("ERROR:")검사를try/catch블록으로 교체합니다
마이그레이션 이후
dotnet build이 네이티브 라이브러리 누락에 대한 경고가 없이 완료되는지 확인합니다- 모든 대상 환경(Windows, Linux, Docker)에서 시작 시
DllNotFoundException또는BadImageFormatException가 발생하지 않는지 확인합니다 - 대표 이미지에 대해 OCR을 실행하고 텍스트 출력 결과가 마이그레이션 전 기준선과 일치하는지 확인합니다.
- 다중 프레임 TIFF 처리 기능을 테스트하고 모든 페이지가 올바른 페이지 번호와 함께 반환되는지 확인합니다.
- 검색 가능한 PDF를 생성하고 PDF 뷰어에서 텍스트를 선택하고 검색할 수 있는지 확인합니다.
- OCR을 호출하는 모든 API 엔드포인트에 동시에 HTTP 요청을 보내고 모든 요청이 오류 없이 완료되었는지 확인합니다.
- 동시 부하 상황에서 비동기 엔드포인트가 교착 상태 없이 결과를 반환하는지 확인합니다.
- 구조화된 데이터 추출(단어 좌표 및 신뢰도)이 알려진 문서에서 올바른 결과를 생성하는지 확인합니다.
- 애플리케이션 메모리 사용량을 시간에 따라 확인하여 네이티브 메모리 누수가 없는지 확인합니다 (이전에
StopEngine()호출을 놓쳐서 발생한 것들) - Linux 환경 또는 Docker 컨테이너에서 애플리케이션을 실행하여 바이너리 구성 없이 크로스 플랫폼 배포가 제대로 작동하는지 확인하십시오.
IronOCR로 마이그레이션할 때의 주요 이점
배포 과정이 단일 NuGet 참조로 간소화됩니다. 마이그레이션 후 개발 워크스테이션, 스테이징 서버, Linux 컨테이너, CI 에이전트 등 모든 배포 대상에서 동일한 패키지를 동일한 명령으로 설치합니다. 플랫폼 감지 로직, 아키텍처별 바이너리 소싱, 런타임 경로 구성은 없습니다. 이전에 수동 네이티브 바이너리 COPY 지시가 필요했던 Docker 이미지가 이제는 dotnet restore만 필요합니다. Linux 배포 가이드 와 Azure 배포 가이드 에는 해당되는 경우 환경별 참고 사항이 포함되어 있습니다.
모든 라이선스 계층은 서버 등급 배포를 잠금 해제합니다. $999 Lite 라이선스는 ASP.NET Core 웹 API, Windows 서비스, Azure Functions, AWS Lambda, 그리고 기타 모든 멀티 스레드 .NET 작업을 지원합니다. Asprise에서 2,000달러~5,000달러 이상을 받고 제공하는 Enterprise급 스레딩 기능이 모든IronOCR등급에 포함되어 있습니다. Asprise Enterprise 에서IronOCR Lite 로 마이그레이션하는 팀은 OCR 라이선스 비용을 절감하는 동시에 Enterprise 제공하지 않았던 기능(네이티브 PDF, 구조화된 출력, 검색 가능한 PDF 생성 및 125개 언어 지원)을 활용할 수 있습니다.
구조화된 OCR 결과는 XML 문자열 구문 분석을 대체합니다. OcrResult 객체 모델은 완전한 문서 계층 구조를 노출합니다: 페이지, 단락, 행, 단어, 그리고 문자, 각 픽셀 정확한 경계 상자 좌표 및 신뢰 점수와 함께. 이전에는 XDocument 또는 정규식을 사용하여 Asprise XML 문자열을 구문 분석했던 코드가 이제 직접 속성에 접근하는 방식으로 변경되었습니다. OCR 결과 기능 페이지에서는 좌표계와 자동 품질 검사를 위한 신뢰도별 결과 필터링 방법을 다룹니다.
내장 전처리는 외부 이미징 종속성을 제거합니다. OcrInput을 통해 제공되는 전처리 파이프라인 — Deskew, DeNoise, Contrast, Binarize, Sharpen, Dilate, Erode, Scale, Invert, 그리고 DeepCleanBackgroundNoise —는 Asprise 통합이 필요로 하는 외부 이미징 라이브러리를 제거합니다. 이 종속성을 제거함으로써 라이선스 문제가 해결되고, 빌드 크기가 줄어들며, OCR 구성을 같은 코드 파일에 바로 인접한 전처리 구성에 배치할 수 있습니다. 전처리 기능 페이지와 영상 품질 수정 가이드는 각 필터를 언제 적용해야 하는지와 저품질 스캔에서 각각이 제공하는 측정 가능한 정확성 향상을 다룹니다.
네이티브 비동기 및 진정한 병렬 처리로 처리량을 개선합니다. ReadAsync은 스레드 풀 차단 없이 표준 async/await 패턴에 통합됩니다. Parallel.ForEach 또는 PLINQ와의 병렬 배치 처리는 사용 가능한 코어 수에 따라 선형적으로 확장됩니다. Asprise Lite/STANDARD에서 순차적으로 실행하도록 강제한 문서 배치(문서 100개를 각각 2초씩 처리하면 3분 이상 소요)가IronOCR사용하는 8코어 컴퓨터에서는 약 25초 만에 실행됩니다. 멀티스레딩 예제는 병렬 처리량 패턴을 보여주며, ConcurrentBag을 사용하여 스레드 안전한 결과 수집을 수행하는 방법을 설명합니다.
이진 배포 없는 125개 이상의 언어. 언어 팩은 NuGet 패키지로 설치됩니다 — dotnet add package IronOcr.Languages.Arabic, dotnet add package IronOcr.Languages.Japanese — 그리고 다른 종속성과 같이 애플리케이션과 함께 배포됩니다. 수동으로 tessdata 폴더를 만들 필요도 없고, 언어 바이너리 파일을 찾을 필요도 없으며, 대상 시스템에서 경로를 구성할 필요도 없습니다. 언어 목록 에는 사용 가능한 125개 이상의 언어 팩이 모두 나열되어 있습니다.
자주 묻는 질문
Asprise OCR SDK에서 IronOCR로 마이그레이션해야 하는 이유는 무엇인가요?
일반적인 동인으로는 COM 상호 운용의 복잡성 제거, 파일 기반 라이선스 관리 대체, 페이지당 과금 방지, Docker/컨테이너 배포 활성화, 표준 .NET 툴링과 통합되는 NuGet 네이티브 워크플로 채택 등이 있습니다.
Asprise OCR SDK에서 IronOCR로 마이그레이션할 때 주요 코드 변경 사항은 무엇인가요?
Asprise OCR 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리(명시적 생성/로드/폐쇄 패턴)를 제거하며, 결과 속성 이름을 업데이트합니다. 그 결과 상용구 줄이 현저히 줄어듭니다.
마이그레이션을 시작하려면 IronOCR을 어떻게 설치하나요?
패키지 관리자 콘솔에서 '설치-패키지 IronOcr'을 실행하거나 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행하세요. 언어 팩은 별도의 패키지입니다: 예를 들어 프랑스어의 경우 '닷넷 추가 패키지 IronOcr.Languages.French'를 실행합니다.
IronOCR은 표준 비즈니스 문서용 Asprise OCR SDK의 OCR 정확도와 일치하나요?
IronOCR은 송장, 계약서, 영수증, 타이핑된 양식 등 표준 비즈니스 콘텐츠에 대해 높은 정확도를 달성합니다. 이미지 전처리 필터(데스큐, 노이즈 제거, 대비 향상)는 품질이 저하된 입력에 대한 인식률을 더욱 향상시킵니다.
IronOCR은 Asprise OCR SDK가 별도로 설치하는 언어 데이터를 어떻게 처리하나요?
IronOCR의 언어 데이터는 NuGet 패키지로 배포됩니다. '닷넷 추가 패키지 IronOcr.Languages.German'은 독일어 지원을 설치합니다. 수동 파일 배치나 디렉터리 경로는 필요하지 않습니다.
Asprise OCR SDK에서 IronOCR로 마이그레이션하려면 배포 인프라를 변경해야 하나요?
IronOCR은 Asprise OCR SDK보다 인프라 변경이 더 적게 필요합니다. SDK 바이너리 경로, 라이선스 파일 배치 또는 라이선스 서버 구성이 필요하지 않습니다. NuGet 패키지에는 완전한 OCR 엔진이 포함되어 있으며 라이선스 키는 애플리케이션 코드에 설정된 문자열입니다.
마이그레이션 후 IronOCR 라이선싱은 어떻게 구성하나요?
애플리케이션 시작 코드에 IronOcr.License.LicenseKey = "YOUR-KEY"를 할당하세요. Docker 또는 Kubernetes에서 키를 환경 변수로 저장하고 시작 시 키를 읽습니다. 트래픽을 수락하기 전에 License.IsValidLicense를 사용하여 유효성을 검사하세요.
IronOCR은 Asprise OCR과 동일한 방식으로 PDF를 처리할 수 있나요?
예. IronOCR은 원본 및 스캔한 PDF를 모두 읽습니다. IronTesseract를 인스턴스화하고, 입력이 PDF 경로 또는 OcrPdfInput인 경우 ocr.Read(input)를 호출하고, OcrResult 페이지를 반복하면 됩니다. 별도의 PDF 렌더링 파이프라인이 필요하지 않습니다.
IronOCR은 대량 처리에서 스레딩을 어떻게 처리하나요?
IronTesseract는 스레드별로 인스턴스화해도 안전합니다. Parallel.ForEach 또는 Task 풀에서 스레드당 하나의 인스턴스를 스핀업하고, OCR을 동시에 실행하고, 완료되면 각 인스턴스를 폐기하면 됩니다. 전역 상태나 잠금이 필요하지 않습니다.
IronOCR은 텍스트 추출 후 어떤 출력 형식을 지원하나요?
IronOCR은 텍스트, 단어 좌표, 신뢰도 점수, 페이지 구조를 포함한 구조화된 결과를 반환합니다. 내보내기 옵션에는 일반 텍스트, 검색 가능한 PDF, 다운스트림 처리를 위한 구조화된 결과 개체가 포함됩니다.
워크로드 확장을 위해 IronOCR 가격이 Asprise OCR SDK보다 더 예측 가능한가요?
IronOCR은 페이지당 또는 볼륨당 요금이 없는 정액제 영구 라이선스를 사용합니다. 10,000페이지를 처리하든 1,000만 페이지를 처리하든 라이선스 비용은 일정하게 유지됩니다. 볼륨 및 팀 라이선스 옵션은 IronOCR 가격 페이지에서 확인할 수 있습니다.
Asprise OCR SDK에서 IronOCR로 마이그레이션한 후 기존 테스트는 어떻게 되나요?
추출된 텍스트 콘텐츠에 대해 어설트하는 테스트는 마이그레이션 후에도 계속 통과해야 합니다. API 호출 패턴 또는 COM 개체 수명 주기의 유효성을 검사하는 테스트는 IronOCR의 더 간단한 초기화 및 결과 모델을 반영하도록 업데이트해야 합니다.

