Tesseract.NET SDK에서 IronOCR로 마이그레이션하기
.NET 개발자를 위한 이 가이드는Tesseract.NET SDK(Tesseract.Net.SDK, 네임스페이스 Patagames.Ocr)에서 IronOCR로의 구체적인 마이그레이션을 안내합니다. 특히 .NET Framework 시대의 초기화 패턴, 레거시 디스포절 관용구, 동기식 전용 파이프라인을 현재 .NET 8, Linux 컨테이너, 비동기 우선 웹 프레임워크 환경에서 운영하는 팀에 중점을 둡니다. OCR 서비스가 net472에 대해 컴파일되고 있어 누군가 <TargetFramework>net8.0</TargetFramework>을 .csproj에 추가할 때 중단된다면, 이 가이드는 여러분을 위한 것입니다.
Tesseract.NET SDK에서 마이그레이션해야 하는 이유
Patagames SDK는 .NET Framework 4.5가 배포 기준이었고 Windows Server가 유일한 대상 환경이었을 때 실질적인 가치를 제공했습니다. 그 맥락이 바뀌었습니다. 현재 대부분의 조직은 서비스를 컨테이너화하고, Linux 러너에서 CI를 실행하며, .NET 6, 8 또는 9를 표준으로 채택하고 있습니다. Tesseract.NET SDK는 이러한 추세를 따라가지 못하고 있습니다.
.NET Framework 4.5에 대한 하드 제한. 패키지는 net20에서 net45까지 대상으로 합니다. 이는 netstandard 또는 net6.0 어셈블리를 생성하지 않습니다. Tesseract.Net.SDK을 포함하는 프로젝트 파일은 <TargetFramework>net8.0</TargetFramework>을 설정할 수 없습니다. 나머지 코드베이스가 스프린트 내에서 완료하는 .NET 업그레이드가 OCR 레이어에서 무기한으로 중단됩니다.
컨테이너 경로는 없습니다. 이 SDK는 Windows 전용 P/Invoke 호출을 통해 Windows 네이티브 바이너리로 전달됩니다. 모든 Linux 기반 이미지에서 — mcr.microsoft.com/dotnet/aspnet:8.0, ubuntu:22.04, alpine:3.19 — 애플리케이션은 단일 문서를 처리하기 전에 DllNotFoundException를 던집니다. Windows 컨테이너는 임시 해결책으로 존재하지만, 이미지 크기가 더 크고 별도의 라이선스 비용이 발생하며, 기본적으로 Linux 노드 풀을 사용하는 대부분의 관리형 Kubernetes 서비스와 호환되지 않습니다.
동기식 API만이 ASP.NET Core 파이프라인을 차단합니다. OcrApi.GetTextFromImage() 메서드는 동기식입니다. .NET Core에서 요청 스레드에서 차단형 동기 작업을 호출하면 부하 상태에서 처리량이 저하되고 스레드 풀 고갈의 위험이 있습니다. IronOCR는 비차단 통합을 위한 ReadAsync()을 제공합니다. 패턴에 대해서는 비동기 OCR 가이드를 참조하십시오.
요청당 엔진 생성은 메모리를 소모합니다. .NET Framework 코드는 일반적으로 메서드 호출당 또는 요청당 하나의 OcrApi 인스턴스를 생성하고 종료 시 이를 폐기합니다. 이는 .NET Framework 라이프사이클 관리의 관례적인 방식입니다. 이는 또한 비용이 많이 듭니다: 각 Init()는 40~100MB의 언어 데이터를 로드합니다. 동시 요청 10건이 동일한 언어 모델을 10회 로드합니다. IronOCR의 IronTesseract는 스레드 안전합니다 — 하나의 인스턴스가 애플리케이션 수명 동안 살아있으며, 모든 동시 호출자가 단일 언어 모델 로드에서 서비스를 제공합니다.
구식 처리 방식은 위험을 누적시킵니다. SDK를 올바르게 사용하려면 using (var api = OcrApi.Create()) { ... } statement that predates using var 선언. C# 8.0 이전에 작성된 코드베이스는 종종 try/finally 폐기 패턴을 포함하거나, 버그 케이스에서는 전혀 폐기되지 않습니다. 이러한 패턴은 .NET Framework에서 컴파일되고 실행되지만, 현대적인 리팩토링을 방해하는 기술적 부채를 안고 있습니다.
비동기 없음, DI 없음, 현대적인 시작 없음. SDK에는 의존성 주입 통합, 호스팅 서비스 수명 또는 IOptions<t> 구성의 개념이 없습니다. 이를 ASP.NET Core 애플리케이션에 통합하려면 수동으로 서비스를 등록해야 하며, 요청마다 인스턴스를 생성하는 것을 주의 깊게 피해야 합니다. IronOCR은 표준 DI 컨테이너 내에서 싱글톤 서비스로 원활하게 통합됩니다.
근본적인 문제
// Tesseract.NET SDK: .NET Framework 4.5 ceiling — will not compile on net8.0
// Every project referencing this package is locked below the upgrade line
using Patagames.Ocr; // Patagames.Ocr targets net45; no netstandard or net8 assembly
public class OcrService
{
public string ProcessDocument(string imagePath)
{
// Synchronous-only — blocks ASP.NET Core request threads
// 아니요 DI support — must be instantiated manually each time
using (var api = OcrApi.Create()) // C# 1.0 using statement, 40-100MB load per call
{
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
// Project cannot target net6.0, net8.0, or any Linux container base image
}
}
// IronOCR: same logic, any runtime from net462 to net9.0, any platform
using IronOcr; // Single NuGet, supports .NET Framework 4.6.2+, .NET 5/6/7/8/9
// Register once as singleton — load language model once, share across all requests
// Call ReadAsync() in ASP.NET Core for non-blocking operation
var ocr = new IronTesseract();
var result = await ocr.ReadAsync("document.jpg"); // Async-first, no thread blocking
Console.WriteLine(result.Text);
IronOCR대 Tesseract.NET SDK: 기능 비교
아래 표는 .NET 현대화 마이그레이션과 직접적으로 관련된 기능을 정리한 것입니다.
| 기능 | Tesseract.NET SDK | IronOCR |
|---|---|---|
| .NET Framework 2.0~4.5 | 예 | 아니요 |
| .NET Framework 4.6.2-4.8 | 아니요 | 예 |
| .NET Core 2.x / 3.x | 아니요 | 예 |
| .NET 5 | 아니요 | 예 |
| .NET 6 | 아니요 | 예 |
| .NET 7 | 아니요 | 예 |
| .NET 8 | 아니요 | 예 |
| .NET 9 | 아니요 | 예 |
| Windows 배포 | 예 | 예 |
| Linux 배포 | 아니요 | 예 |
| macOS 배포 | 아니요 | 예 |
| Docker Linux 컨테이너 | 아니요 | 예 |
| Azure 앱 서비스(리눅스) | 아니요 | 예 |
| AWS 람다 | 아니요 | 예 |
Async API (ReadAsync) | 아니요 | 예 |
| 스레드 안전 단일 인스턴스 | 아니요 | 예 |
| ASP.NET Core DI 통합 | 수동 | 싱글톤 서비스 |
| 네이티브 PDF 입력 | 아니요 | 예 |
| 내장 전처리 기능 | 아니요 | 예 |
| 검색 가능한 PDF 출력 | 아니요 | 예 |
| 구조화된 데이터(WORD, 줄, 단락) | 아니요 | 예 |
| 상업적 지원 / 서비스 수준 계약(SLA) | 아니요 (개별 개발자) | 예 |
| 영구 라이선스 가격 | ~$20–50 (개발자 1명) | From $999 |
빠른 시작: Tesseract.NET SDK에서 IronOCR로의 마이그레이션
1단계: NuGet 패키지 교체
Tesseract.NET SDK 제거:
dotnet remove package Tesseract.Net.SDK
PdfiumViewer나 이와 유사한 PDF 렌더링 라이브러리가 SDK에 PDF 페이지를 전달하기 위한 목적으로만 설치된 경우, 해당 라이브러리도 제거하십시오. IronOCR은 PDF를 기본적으로 직접 읽을 수 있습니다:
dotnet remove package PdfiumViewer
NuGet 에서IronOCR설치하세요.
단계 2: 네임스페이스 업데이트
// Before (Tesseract.NET SDK)
using Patagames.Ocr;
using Patagames.Ocr.Enums;
// After (IronOCR)
using IronOcr;
단계 3: 라이선스 초기화
애플리케이션 시작 시 한 번 라이선스 키 호출을 추가하십시오 — Program.cs, Startup.cs, 또는 애플리케이션 호스트 빌더에서:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"워터마크 없이 평가해 볼 수 있는 무료 체험판 라이선스가 제공됩니다.
코드 마이그레이션 예제
.NET Framework 시작 패턴에서 Modern Host Builder로
.NET Framework 애플리케이션은 일반적으로 학습 엔진을 정적 생성자, Application_Start 이벤트 또는 Global.asax 핸들러에서 초기화합니다. 일반 호스트 모델(Generic Host Model) 기반으로 구축된 .NET 6+ 애플리케이션에는 이러한 기능이 존재하지 않습니다.
Tesseract.NET SDK 접근 방식:
// Global.asax.cs — .NET Framework MVC application
// OcrApi lifecycle managed manually; no DI container involved
public class MvcApplication : System.Web.HttpApplication
{
// Static field — one engine for the app lifetime
// But: NOT thread-safe; concurrent requests share a single OcrApi instance
private static OcrApi _globalApi;
protected void Application_Start()
{
// Initialize OCR engine on app startup
// Path to tessdata hardcoded for deployment environment
_globalApi = OcrApi.Create();
_globalApi.Init(Languages.English);
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
protected void Application_End()
{
// Must manually dispose on shutdown
_globalApi?.Dispose();
}
}
IronOCR 접근 방식:
// Program.cs — .NET 8ASP.NET Core application
// IronTesseract는 나사산에 안전합니다. register as singleton, inject where needed
var builder = WebApplication.CreateBuilder(args);
IronOcr.License.LicenseKey = builder.Configuration["IronOcr:LicenseKey"];
// Register as singleton — one instance, thread-safe, shared across all requests
builder.Services.AddSingleton<IronTesseract>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Global.asax 패턴은 완전히 사라집니다. IronTesseract은 표준 싱글톤 서비스로 등록되며, 생성자를 통해 컨트롤러 및 서비스에 주입됩니다. 언어 모델은 처음 사용할 때 한 번 로드되며, 애플리케이션이 실행되는 동안 메모리에 유지됩니다. IronTesseract 설정 가이드에는 등록 시 언어 선택 및 엔진 모드를 포함한 구성 옵션이 설명되어 있습니다.
레거시 폐기 패턴 현대화
.NET Framework 2.0 코드는 using (var x = ...) { } 블록 문을 사용합니다. C# 8.0은 폐기를 둘러싼 블록으로 스코프 하는 using var 선언을 도입했습니다. 오래된 코드베이스도 try/finally 폐기 보호를 가지고 있는데, 이는 모든 시나리오에서 using 문을 믿지 않았을 때 작성된 것입니다. 이 모든 패턴은 .NET Framework용으로 작성된 코드를 나타내며, 마이그레이션 과정에서 현대화되어야 합니다.
Tesseract.NET SDK 접근 방식:
// .NET Framework 4.x disposal patterns — three variants encountered in production
public class LegacyOcrProcessor
{
// Pattern 1: try/finally guard (pre-C# 2.0 style, still common in legacy code)
public string ProcessWithTryFinally(string imagePath)
{
OcrApi api = null;
try
{
api = OcrApi.Create();
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
finally
{
if (api != null)
api.Dispose(); //수동null check required
}
}
// Pattern 2: nested using blocks — one for engine, one for image object
public string ProcessWithNestedUsing(string imagePath)
{
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var img = OcrImage.FromFile(imagePath))
{
api.SetImage(img);
return api.GetText();
} // img disposed here
} // api disposed here — nested indentation grows with each resource
}
// Pattern 3: missing disposal — memory leak, common in older service code
public string ProcessUnsafe(string imagePath)
{
var api = OcrApi.Create(); // WARNING: never disposed
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
}
IronOCR 접근 방식:
// Modern C# 8.0+ disposal — flat, readable, no nesting
public class ModernOcrProcessor
{
private readonly IronTesseract _ocr; // Injected singleton, never disposed per-request
public ModernOcrProcessor(IronTesseract ocr) => _ocr = ocr;
// Pattern 1: using var declaration — scoped to method, no nesting
public string ProcessDocument(string imagePath)
{
using var input = new OcrInput(); // OcrInput is the disposable resource, not the engine
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
} // input disposed here automatically — no nesting, no try/finally
// Pattern 2: multiple inputs in one scope — still flat
public string ProcessMultipleInputs(string imagePath, string pdfPath)
{
using var imageInput = new OcrInput();
imageInput.LoadImage(imagePath);
using var pdfInput = new OcrInput();
pdfInput.LoadPdf(pdfPath);
var imageText = _ocr.Read(imageInput).Text;
var pdfText = _ocr.Read(pdfInput).Text;
return $"{imageText}\n{pdfText}";
} // both inputs disposed here — zero nesting
}
OcrInput은 IronOCR에서 유일한 폐기 가능한 리소스입니다. 엔진 자체(IronTesseract)는 요청당 폐기되지 않으며 — 싱글톤입니다. 이로 인해 요청당 OcrApi.Create() + api.Init() 이 부과하던 40~100MB 언어 모델 리로드가 제거됩니다. 이미지 입력 가이드는 스트림, 바이트 배열, URL을 포함한 모든 OcrInput 로딩 방법을 다룹니다.
ASP.NET Core 컨트롤러용 Async Integration
Tesseract.NET SDK에는 비동기 API가 없습니다. 모든 호출은 동기식입니다. .NET Core에서 비동기 컨트롤러 액션 내에서 동기식 차단 작업을 호출하면 부하가 걸렸을 때 스레드 풀 고갈 위험이 있습니다. 일반적인 해결책 — 동기 호출을 Task.Run()으로 래핑 — 은 차단 작업을 스레드 풀 스레드에 오프로드하지만 스레드 소비를 제거하지는 않습니다. IronOCR의 ReadAsync()은 진정한 비동기 I/O 통합을 제공합니다.
Tesseract.NET SDK 접근 방식:
// ASP.NET Core controller — forced workaround for synchronous OCR API
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Must copy upload to temp file — OcrApi does not accept streams directly
var tempPath = Path.GetTempFileName();
await using (var stream = System.IO.File.OpenWrite(tempPath))
await file.CopyToAsync(stream);
string text;
try
{
// Task.Run wraps synchronous call — still consumes a thread-pool thread
// Does NOT free the calling thread during OCR processing
text = await Task.Run(() =>
{
using (var api = OcrApi.Create()) // 40-100MB load per request
{
api.Init(Languages.English);
return api.GetTextFromImage(tempPath); // synchronous, blocking
}
});
}
finally
{
System.IO.File.Delete(tempPath); //수동temp file cleanup
}
return Ok(new { text });
}
}
IronOCR 접근 방식:
// ASP.NET Core controller — genuine async OCR, no temp files, no thread blocking
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
private readonly IronTesseract _ocr; // Singleton injected via DI
public OcrController(IronTesseract ocr) => _ocr = ocr;
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Load stream directly — no temp file needed
using var input = new OcrInput();
input.LoadImage(file.OpenReadStream()); // Stream input, no disk write
// ReadAsync — genuinely non-blocking, integrates with ASP.NET Core pipeline
var result = await _ocr.ReadAsync(input);
return Ok(new
{
text = result.Text,
confidence = result.Confidence
});
}
}
임시 파일 왕복 과정이 사라집니다. Task.Run 래퍼가 사라집니다. 요청당 OcrApi.Create()와 그 후 40~100MB 로드가 사라집니다. 비동기 OCR 사용법 및 스트림 입력 가이드에는 취소 토큰 지원을 포함한 전체 비동기 파이프라인이 설명되어 있습니다.
다중 프레임 TIFF 처리
1단계 비교 기사에서는 기본적인 이미지 및 PDF 처리 기능을 다루었습니다. 다중 프레임 TIFF는 문서 보관, 팩스 시스템 및 의료 영상 처리 파이프라인에서 흔히 볼 수 있는 독특한 시나리오입니다. Tesseract.NET SDK는 System.Drawing.Bitmap을 사용하여 수동으로 TIFF 프레임을 반복하고, 각 프레임을 임시 PNG 파일로 추출하며, 임시 파일에서 OCR을 실행하고 정리해야 합니다. 이 패턴은 대용량 문서에서 메모리 부족 오류를 피하기 위해 명시적인 GC 호출을 강제합니다.
Tesseract.NET SDK 접근 방식:
// Multi-frame TIFF: manual frame extraction to temp files + forced GC
using System.Drawing;
using System.Drawing.Imaging;
using Patagames.Ocr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var pageTexts = new List<string>();
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var bitmap = new Bitmap(tiffPath))
{
var dimension = new FrameDimension(bitmap.FrameDimensionsList[0]);
int frameCount = bitmap.GetFrameCount(dimension);
for (int i = 0; i < frameCount; i++)
{
bitmap.SelectActiveFrame(dimension, i);
// Must write each frame to a temp file — no in-memory path
var tempPath = Path.GetTempFileName() + ".png";
bitmap.Save(tempPath, ImageFormat.Png);
try
{
pageTexts.Add(api.GetTextFromImage(tempPath));
}
finally
{
File.Delete(tempPath); //수동cleanup on every frame
}
// Force GC every 10 frames — workaround for memory pressure
// Slows processing; indicates memory management is manual
if (i % 10 == 0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}
return pageTexts;
}
IronOCR 접근 방식:
// Multi-frame TIFF: one method call, no temp files, no manual GC
using IronOcr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // Loads all frames natively — no temp files
var result = ocr.Read(input);
// Pages map directly to TIFF frames
return result.Pages.Select(page => page.Text).ToList();
}
30줄이 8줄로 압축되었습니다. 임시 파일도 없고, Bitmap 프레임 반복도 없으며, GC.Collect() 호출도 없습니다. LoadImageFrames은 중간 파일을 기록하지 않고 대형 다중 프레임 TIFF를 처리합니다. TIFF 및 GIF 입력 가이드에는 대규모 문서에 대한 선택적 프레임 로딩(인덱스 범위별) 및 진행 상황 콜백에 대한 내용이 포함되어 있습니다.
Docker 컨테이너 배포 준비
개발자의 Windows 컴퓨터에서 실행되는Tesseract.NET SDK코드는 기본 이미지가 Linux일 때 Docker 빌드 또는 실행 단계에서 실패합니다. 이 수정 사항은 Dockerfile을 조정하는 것이 아닙니다. 네이티브 바이너리는 Windows 전용이며 Linux에서는 전혀 로드할 수 없습니다. IronOCR의 Linux 지원은 Dockerfile에 소량의 apt-get 추가 및 애플리케이션 코드의 그 외에는 필요하지 않습니다.
Tesseract.NET SDK 접근 방식:
# Dockerfile attempt — fails at runtime on Linux base image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# This base image is Linux (Debian) by default
# Tesseract.Net.SDK's Windows native DLLs cannot load here
# Application throws DllNotFoundException on first OCR call
WORKDIR /app
COPY --from=build /app/publish .
# Even copying the Windows tessdata folder has no effect —
# the P/Invoke DLL cannot be loaded regardless of file placement
COPY tessdata/ ./tessdata/
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Runtime error: DllNotFoundException: Unable to load DLL 'libtesseract'
# 아니요 fix available within Tesseract.Net.SDK — requires replacing the library
IronOCR 접근 방식:
# Dockerfile forIronOCR on Linux — add one apt-get line, nothing else changes
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Required system dependency forIronOCR on Debian/Ubuntu base images
RUN apt-get update && apt-get install -y libgdiplus \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# 아니요 tessdata folder — language data is bundled with the IronOcr NuGet packages
# 아니요 platform check code —IronOCR runs identically on Windows and Linux
ENTRYPOINT ["dotnet", "MyApp.dll"]
하나의 apt-get 라인. tessdata 폴더는 없습니다. 애플리케이션에는 플랫폼에 의존적인 코드가 포함되어 있지 않습니다. 개발자의 Windows 컴퓨터에서 실행되는 것과 동일한 애플리케이션 바이너리가 이 Linux 컨테이너에서도 변경 없이 실행됩니다. Docker 배포 가이드는 Alpine 기반 이미지(이는 apk 대신 apt-get을 사용), 다중 단계 빌드 최적화 및 라이선스 키에 대한 환경 변수 구성을 다룹니다. Linux 배포 가이드는 베어메탈 Linux 및 WSL2 시나리오를 다룹니다.
Tesseract.NET SDKAPI와IronOCR매핑 참조
| Tesseract.NET SDK | IronOCR에 상응하는 | 노트 |
|---|---|---|
Install-Package Tesseract.Net.SDK | dotnet add package IronOcr | IronOCR은 .NET Framework 4.6.2 이상 및 .NET 5–9를 지원합니다. |
using Patagames.Ocr; | using IronOcr; | 단일 네임스페이스 |
using Patagames.Ocr.Enums; | (not needed) | 열거형은 IronOcr 네임스페이스에 있습니다 |
OcrApi.Create() | new IronTesseract() | IronTesseract는 나사산에 안전합니다. 싱글톤으로 사용 |
api.Init(Languages.English) | ocr.Language = OcrLanguage.English | 메서드 호출이 아닌 속성 할당 |
api.Init(Languages.English | Languages.German) | ocr.Language = OcrLanguage.English + OcrLanguage.German | 연산자 +, 비트 OR가 아님 |
api.GetTextFromImage(path) | ocr.Read("path.jpg").Text | OcrInput를 통해 직접 또는 우회 |
api.GetTextFromImage(path) (비동기) | await ocr.ReadAsync(input) | 진정한 비동기 — Task.Run 래퍼가 필요하지 않음 |
OcrImage.FromFile(path) | input.LoadImage(path) | OcrInput이 OcrImage을(를) 대체 |
OcrImage.FromBitmap(bitmap) | input.LoadImage(bitmap) | |
new MemoryStream(bytes) → OcrImage.FromBitmap | input.LoadImage(bytes) | 바이트 배열 직접 지원 |
api.SetImage(img); api.GetText() | ocr.Read(input).Text | OcrInput이 Read에 전달됨 |
api.GetMeanConfidence() | result.Confidence | 백분율을 반환합니다; also available per-word |
api.SetRectangle(x, y, w, h) | input.LoadImage(path, new CropRectangle(x, y, w, h)) | CropRectangle을 통한 지역 기반 OCR |
api.SetVariable("tessedit_char_whitelist", x) | ocr.Configuration.WhiteListCharacters = x | |
api.SetVariable("tessedit_char_blacklist", x) | ocr.Configuration.BlackListCharacters = x | |
| 비트맵 프레임 반복 처리 + 임시 파일 | input.LoadImageFrames(tiffPath) | 네이티브 멀티 프레임 TIFF 지원 |
| (synchronous only) | result.SaveAsSearchablePdf("out.pdf") | Tesseract.NET SDK에는 이에 상응하는 기능이 없습니다. |
| (no structured output) | result.Pages, result.Words, result.Lines | 단어 수준 좌표 및 신뢰도 |
GC.Collect() 해결책 | (not needed) | IronOCR은 내부적으로 메모리를 관리합니다 |
플랫폼 검사: IsOSPlatform(Windows) | (remove entirely) | IronOCR은 크로스 플랫폼입니다 |
| Tessdata 폴더 관리 | (remove entirely) | NuGet 패키지에 포함된 언어 |
일반적인 마이그레이션 문제와 해결책
문제 1: 프로젝트 대상 프레임워크 충돌
Tesseract.NET SDK: Tesseract.Net.SDK을 제거하고 IronOcr을 추가한 후에도 프로젝트는 여전히 옛 요구에서 net45 또는 net472을 대상으로 합니다. IronOCR는 net462 및 그 이후를 지원하므로 net45 프로젝트는 패키지가 깔끔하게 복원되기 전에 대상 프레임워크를 업데이트해야 합니다.
해결책: IronOCR을 추가하기 전에 <TargetFramework>을 .csproj 파일에서 업데이트하십시오. 단계적 마이그레이션 과정에서 기존 런타임과 새로운 런타임을 모두 지원해야 하는 경우, 다중 타겟팅을 사용하십시오:
<!-- Single modern target (preferred) -->
<TargetFramework>net8.0</TargetFramework>
<!-- Multi-targeting during phased migration — supports both simultaneously -->
<TargetFrameworks>net462;net8.0</TargetFrameworks>
IronOCR은 각 대상에 맞는 올바른 어셈블리를 자동으로 식별합니다. 같은 dotnet add package IronOcr 명령이 둘 다에 대해 작동합니다. .NET OCR 라이브러리 페이지에는 지원되는 모든 대상 프레임워크가 나열되어 있습니다.
이슈 2: 정적 OcrApi 필드가 DI 싱글톤으로 대체됨
Tesseract.NET SDK: 레거시 코드는 싱글 OcrApi 인스턴스를 정적 필드로 등록합니다 (예: Global.asax, 정적 서비스 로케이터, 또는 싱글톤 래퍼 클래스). 이 패턴은 OcrApi이(가) 스레드 안전하지 않기 때문에 필요했습니다 — 스레드 간에 하나의 인스턴스를 공유하는 것은 경쟁 조건을 유발하므로, 정적 필드는 잠금으로 보호되거나 필드 이름과는 다르게 실제로 요청당 재생성되었습니다.
해결책: DI 컨테이너를 통해 진정한 스레드 안전 싱글톤으로 IronTesseract을 등록하십시오. 잠금 해제, static 필드 제거, 요청별 재생성 제거:
// Remove: private static OcrApi _instance; / private static readonly object _lock = new();
// Replace with DI registration in Program.cs
builder.Services.AddSingleton<IronTesseract>();
// In consuming classes — constructor injection
public class DocumentProcessor
{
private readonly IronTesseract _ocr;
public DocumentProcessor(IronTesseract ocr) => _ocr = ocr;
public async Task<string> ProcessAsync(string path)
{
using var input = new OcrInput();
input.LoadImage(path);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
문제 3: 배포 후 Tessdata 폴더가 누락됨
Tesseract.NET SDK: IronOCR로 전환한 후에도 팀들이 CI/CD 파이프라인에 tessdata 배포 단계를 남겨두는 경우가 있습니다. 빌드 스크립트 및 배포 매니페스트에서 참조되는 tessdata/ 폴더는 더 이상 존재하지 않습니다 — 이는 이전 SDK의 언어 모델 관리의 일부였습니다. 스크립트는 더 이상 존재하지 않는 폴더를 복사하거나 확인하려고 할 때 실패합니다.
해결책: 배포 스크립트, .csproj 복사 대상, Docker COPY 명령 및 CI/CD 파이프라인 단계에서 모든 tessdata 참조를 제거하십시오.IronOCR언어 데이터는 NuGet 패키지와 함께 제공됩니다. dotnet restore을 실행하면 언어 데이터가 제공됩니다. 그 외에는 필요하지 않습니다:
# Remove from CI/CD pipeline
# BEFORE (delete these lines):
# - cp -r tessdata/ $DEPLOY_PATH/tessdata/
# - test -f $DEPLOY_PATH/tessdata/eng.traineddata
# AFTER: nothing — language data is in the NuGet package restore output
dotnet restore # Downloads IronOcr and any IronOcr.Languages.* packages
dotnet publish # Includes language data automatically
다국어 가이드에는 오프라인/에어갭(airgapped) 배포를 위해 특정 언어 팩을 NuGet 패키지로 설치하는 방법이 설명되어 있습니다.
이슈 4: 32/64비트 불일치에서 BadImageFormatException
Tesseract.NET SDK: 이 SDK는 x86 및 x64용 Windows 네이티브 바이너리를 별도로 제공합니다. AnyCPU을 대상으로 하는 프로젝트는 프로세스 아키텍처에 따라 때때로 잘못된 바이너리로 해결됩니다. 이 오류는 출력 폴더 내 네이티브 DLL과 프로세스 아키텍처가 일치하지 않는 머신에서 런타임에 BadImageFormatException 또는 DllNotFoundException로 표면화됩니다.
해결책: IronOCR은 각 플랫폼에 대해 올바른 네이티브 바이너리를 NuGet 패키지 안에 번들로 포함하고, 패키지 레이아웃의 runtimes/ 폴더를 통해 자동으로 올바른 바이너리를 해결합니다. Platform 대상 설정 없음, 아키텍처 조건부 복사 명령 없음, 관리할 x64 하위 폴더 없음:
<!-- Remove architecture-specific build configurations from .csproj -->
<!-- BEFORE: Conditional native DLL copy based on Platform target -->
<!--
<ItemGroup Condition="'$(Platform)' == 'x64'">
<Content Include="$(SolutionDir)libs\x64\*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
-->
<!-- AFTER: Nothing.IronOCR resolves the correct binary automatically. -->
이슈 5: 구성 문자열 마이그레이션
Tesseract.NET SDK: Tesseract 엔진 변수는 Tesseract API 참조에서 가져온 원시 문자열 키를 사용하여 api.SetVariable(string name, string value)을 통해 설정됩니다 (예: "tessedit_char_whitelist", "tessedit_pageseg_mode"). 이들은 타입이 지정되지 않은 문자열로, IDE 자동 완성 기능이 지원되지 않습니다. 오타는 조용한 오류를 유발합니다 — 변수가 무시될 뿐, 예외가 발생하지는 않습니다.
해결책: IronOCR은 엔진 구성을 ocr.Configuration의 형식화된 속성으로 노출합니다. 오타는 컴파일 시 오류로 이어집니다:
// Before: untyped string variables, silent failures on typos
api.SetVariable("tessedit_char_whitelist", "0123456789");
api.SetVariable("tessedit_pageseg_mode", "7");
// After: typed properties, compile-time validation, IDE completion
ocr.Configuration.WhiteListCharacters = "0123456789";
ocr.Configuration.PageSegmentationMode = TesseractPageSegmentationMode.SingleLine;
IronTesseract API 참조 문서에는 모든 구성 속성과 해당 유형 및 허용되는 값이 기록되어 있습니다.
이슈 6: 긴 배치 작업에 대한 진행 상황 보고
Tesseract.NET SDK: IProgress<t>을 사용하여 프로그레스 보고 코드는 배치 처리 코드(job 레벨에서 각 파일 후 카운터 증가)에서 동작합니다만, 단일 문서 내에서 보고할 수 없습니다 — GetTextFromImage() 내 콜백 메커니즘이 없습니다. 500페이지 분량의 문서의 경우, 문서 전체가 완료될 때까지 진행률 표시줄이 멈춘 상태로 유지됩니다.
해결책: IronOCR은 OcrInput에서 OcrProgress 이벤트를 통해 내장된 진행 추적을 제공합니다. 페이지당 진행 상황을 추적하여, 여러 페이지로 구성된 긴 문서에서도 정확한 진행률 표시줄을 제공합니다:
// IronOCR: page-level progress tracking for multi-page documents
using IronOcr;
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("large-archive.pdf");
// Subscribe to page-level progress events
input.OcrProgress += (sender, e) =>
{
Console.WriteLine($"Processing page {e.CurrentPage} of {e.TotalPages} " +
$"({e.ProgressPercent:F0}%)");
};
var result = ocr.Read(input);
Console.WriteLine($"Complete: {result.Pages.Count} pages extracted");
진행 상황 추적 가이드는 브라우저 클라이언트에 실시간 진행 상황을 푸시하기 위한 .NET Core SignalR과의 통합을 다룹니다.
Tesseract.NET SDK마이그레이션 체크리스트
사전 마이그레이션
코드를 수정하기 전에 코드베이스에서Tesseract.NET SDK사용처를 모두 검토하십시오:
# Find all files referencing Patagames namespace
grep -rl "Patagames" --include="*.cs" .
# Find all OcrApi instantiation points
grep -rn "OcrApi.Create" --include="*.cs" .
# Find tessdata references in project and build files
grep -rn "tessdata" --include="*.cs" --include="*.csproj" --include="*.yaml" --include="*.yml" .
# Find platform guard checks that can be removed after migration
grep -rn "IsOSPlatform.*Windows" --include="*.cs" .
# Find Task.Run wrappers around synchronous OCR calls
grep -rn "Task.Run" --include="*.cs" . | grep -i "ocr\|image\|text"
# Count distinct OcrApi.Create() call sites to estimate migration scope
grep -c "OcrApi.Create" $(find . -name "*.cs")
OcrApi.Create() 호출 사이트의 개수를 문서화하십시오 — 각각은 싱글톤 주입 대체의 후보입니다. 모더나이제이션을 위한 모든 try/finally 폐기 패턴을 주목하십시오. Global.asax, Application_Start 또는 정적 생성자 초기화가 Program.cs으로 이동할 것을 식별하십시오.
코드 마이그레이션
- 모든
.csproj파일에서<TargetFramework>를net8.0(또는 대상 최신 런타임)로 업데이트하십시오 - 각 프로젝트에서
dotnet remove package Tesseract.Net.SDK을 실행하십시오 - 존재할 경우
dotnet remove package PdfiumViewer(또는 동등한 PDF 렌더링 패키지)를 실행하십시오 - 각 프로젝트에서
dotnet add package IronOcr을 실행하십시오 IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";을Program.cs이나 호스트 빌더에 추가하십시오- DI 컨테이너에서
IronTesseract을 싱글톤으로 등록하십시오:services.AddSingleton<IronTesseract>() - 모든
using Patagames.Ocr;및using Patagames.Ocr.Enums;을using IronOcr;로 교체하십시오 OcrApi.Create()+api.Init(Languages.X)을 생성자에 주입된IronTesseract으로 교체하십시오using (var api = OcrApi.Create()) { ...을 다음으로 대체하십시오. }blocks withusing var 입력 = new OcrInput()` 선언api.GetTextFromImage(path)을ocr.Read(input).Text또는await ocr.ReadAsync(input)로 교체하십시오Task.Run(() =>)을 직접await ocr.ReadAsync(input)으로 교체하십시오api.GetMeanConfidence()을result.Confidence으로 교체하십시오- Bitmap 프레임 반복 TIFF 루프를
input.LoadImageFrames(tiffPath)으로 교체하십시오 api.SetVariable("tessedit_char_whitelist", x)을ocr.Configuration.WhiteListCharacters = x으로 교체하십시오- 프로젝트에서 tessdata 폴더를 삭제하고, tessdata에 대한 모든 배포 스크립트 참조를 제거하십시오.
마이그레이션 이후
- 프로젝트를
net8.0을 대상으로 컴파일하고 빌드 출력에Patagames참조가 남아 있지 않은지 확인하십시오 - 애플리케이션을 Linux 호스트 또는 Linux Docker 컨테이너에서 실행하고
DllNotFoundException이 없는지 확인하십시오 - 실제 문서 중 대표적인 샘플(10~20개 문서)을 대상으로 OCR 텍스트 출력이 마이그레이션 전 출력과 일치하는지 확인하십시오.
- 다중 페이지 TIFF 처리 테스트를 수행하고 페이지 수가 원본 프레임 수와 일치하는지 확인하십시오.
ReadAsync()을 사용하여 ASP.NET Core 엔드포인트에서 로드 테스트를 실행하고 스레드 풀 메트릭에서 차단이 없음을 확인하십시오- DI 컨테이너가
IronTesseract을 싱글톤으로 해석하는지 확인하십시오 (요청 간 동일한 인스턴스) - tessdata 복사 단계가 제거되었으므로 CI/CD 파이프라인이 오류 없이 완료되는지 확인하십시오
- Linux 기반 이미지에서 Docker 이미지 빌드 및 컨테이너 실행 테스트
- 다중 페이지 문서(PDF 또는 TIFF)에서 진행 상황 이벤트가 올바르게 호출되는지 확인하십시오.
- 신뢰도 점수가 정상으로 확인된 문서에 대해 예상 범위 내에 있는지 확인하십시오
IronOCR로 마이그레이션할 때의 주요 이점
.NET 업그레이드 차단 요소가 사라졌습니다. 이전에는 .NET Framework 4.x에서 .NET 8로 서비스를 이전하려는 모든 계획이 OCR 계층에서 중단되었습니다. 마이그레이션 후, OCR 서비스는 동일한 패키지 참조를 통해 .NET Framework 4.6.2, .NET 6, .NET 8및 .NET 9에서 컴파일되고 실행됩니다. 업그레이드 경로는 차단되지 않습니다. OCR 전용으로 별도의 레거시 런타임 배포 환경을 유지하던 팀은 이를 단일한 최신 런타임 환경으로 통합할 수 있습니다.
컨테이너 배포가 타협 없이 작동합니다. Linux 기반 이미지에서의 DllNotFoundException이 제거됩니다. 개발자의 Windows 워크스테이션에서 실행되는 같은 애플리케이션 바이너리는 Dockerfile의 하나의 apt-get 라인과 함께 Debian 또는 Alpine 컨테이너 내에서 실행됩니다. Kubernetes 배포, Azure Container Apps 및 AWS ECS 작업이 Linux 노드 풀에서 Windows 컨테이너 라이선스, 더 큰 이미지 크기 또는 아키텍처 조건부 코드 경로 없이 모두 작동합니다. Docker 배포 가이드와 Azure 가이드는 각 대상 환경에 대한 정확한 구성 방법을 설명합니다.
비동기 우선 파이프라인은 스레드 풀 압박을 제거합니다. 비동기 메서드 안에 동기식 OCR를 래핑한 Task.Run 해결책이 ReadAsync()으로 대체됩니다. .NET Core 요청 스레드는 OCR 처리 중에 차단되지 않고 해제됩니다. 높은 동시 처리량 환경에서는, 이는 OCR 엔드포인트뿐만 아니라 애플리케이션 전체에 걸쳐 더 높은 요청 처리량과 더 낮은 지연 시간으로 직접 이어집니다.
메모리 소비가 동시성과 비례하여 감소합니다. 이전에 동시 요청당 하나의 OcrApi 인스턴스를 생성했던 서비스 — 각각 40100MB의 언어 데이터를 로드하는 — 는 이제 그 데이터를 싱글톤 1000MB의 차이가 발생합니다. 이러한 감소 효과는 컨테이너 리소스 메트릭에서 즉시 확인할 수 있으며, 더 작은 포드 메모리 제한, 더 높은 포드 밀도, 그리고 더 낮은 클라우드 인프라 비용을 가능하게 합니다.IronTesseract 인스턴스에 한 번 로드합니다. 동시 요청이 10건일 때, 단일 고정 부하와 비교하여 400
현대 C# 패턴이 .NET Framework 풍습을 대체합니다. try/finally 폐기 보호, 중첩 using 블록, TIFF 프레임 간 GC.Collect() 호출 — 이는 모두 사라집니다. using var input = new OcrInput()은 전체 리소스 관리 패턴입니다. 코드 리뷰는 더 짧습니다. 새로운 개발자가 OCR 서비스를 시작하는 데 걸리는 시간이 단축됩니다. OcrResult API 참조 문서는 구조화된 데이터, 신뢰도 점수, 검색 가능한 PDF 출력을 포함한 전체 결과 객체 모델을 상세히 설명하며, 이는 기존 SDK의 수동 결과 처리 방식을 대체합니다.
상업적 지원은 개인 개발자에 대한 의존성을 대체합니다. Tesseract.NET SDK는 SLA(서비스 수준 계약)나 조직의 지속성 보장이 없는 개인 개발자가 운영하고 있습니다. IronOCR은 전용 지원 채널, 문서화된 보안 공개 절차, 그리고 Enterprise 조달 요건을 충족하는 라이선스 약관을 갖춘 상업 기업인 Iron Software에서 개발했습니다. IronOCR 라이선싱 페이지는 지원 계층 및 .NET 스택을 현대화하면서 Windows 전용 인프라를 유지하는 숨겨진 비용과 Patagames SDK 수수료를 대체하는 영구 라이선스 모델( $999에서 부터)을 다룹니다.
