찰스 테서랙트에서 IronOCR로 마이그레이션하기
.NET 개발자가 charlesw/tesseract NuGet 패키지 (Tesseract)에서 IronOCR로 이동하는 과정을 설명합니다. 이 마이그레이션은 특히 한 가지 문제에 초점을 맞춥니다: charlesw 래퍼가 강요하는 네이티브 바이너리 배포 모델과 그 모델이 개발자로 하여금 작성하도록 강요하는 플랫폼 조건부 코드. CI에서 DllNotFoundException와 씨름하거나, Linux에서 Leptonica 라이브러리 경로와 씨름하거나, OCR과 전혀 관련이 없는 OS 감지 블록을 작성한 팀은 이 가이드에서 전환 후 사라지는 요소가 무엇인지 정확히 알 수 있습니다.
찰스 테서랙트에서 마이그레이션하는 이유는 무엇인가요?
보관된 charlesw/tesseract 패키지가 문제가 되는 이유는 API 자체가 나빠서가 아니라, 요구되는 배포 모델이 현대 .NET 인프라에서는 유효하지 않은 가정에 기반해 설계되었기 때문입니다. 다음은 이주 결정을 좌우하는 요인입니다.
플랫폼별 네이티브 바이너리 배포. Tesseract NuGet 패키지는 플랫폼 특정 네이티브 바이너리를 제공합니다: Windows x64에서는 tesseract50.dll, x86을 위한 별도 빌드, Linux x64에서는 libtesseract.so. 이러한 바이너리는 P/Invoke 호출이 성공하려면 런타임에 올바른 위치에 있어야 합니다. 개발자 워크스테이션에서 SDK는 해당 파일들을 자동으로 복사합니다. Docker 컨테이너, ARM64 빌드 에이전트 또는 표준 애플리케이션 루트가 아닌 Azure App Service에서는 그렇지 않습니다. 새로운 배포 대상이 생길 때마다 디버깅 세션이 시작됩니다.
Leptonica는 숨겨진 종속성입니다. Tesseract의 이미지 로딩은 Leptonica 라이브러리에서 처리하며, 이 라이브러리는 Tesseract 바이너리와 함께 자체 네이티브 DLL 세트로 제공됩니다. Windows에서는 leptonica-1.82.0.dll가 출력 디렉토리에 있어야 합니다. 리눅스에서 Leptonica 공유 라이브러리는 번들로 제공되거나 시스템 패키지로 설치되어야 합니다. Debian 기반 Docker 이미지에 libleptonica-dev가 없는 경우 Pix.LoadFromFile()에서 유용하지 않은 네이티브 예외가 발생하며, 이를 해결하려면 어느 시스템 패키지가 의존성을 해결하는지 알아야 합니다.
앱 로직의 플랫폼 조건부 코드. 네이티브 바이너리 로딩과 tessdata 경로 해상도의 결합은 개발자로 하여금 대상별로 다른 논리, 환경 변수 감지, 경로 구축 논리를 작성하도록 강요합니다. 저 코드들은 OCR 로직과는 전혀 관련이 없습니다. 이는 패키지의 바이너리 관리가 불완전하기 때문에 존재하는 배포 인프라일 뿐입니다.
복구 경로가 없는 보관된 패키지입니다. 해당 저장소는 2021년부터 보관 처리되었습니다. Linux 호스트에서 시스템 패키지 업데이트로 인해 Leptonica ABI가 변경되거나 새로운 .NET 런타임으로 인해 네이티브 바이너리 로딩 동작이 변경되는 경우, 업데이트할 버전이 없습니다. 유일한 선택지는 네이티브 빌드 파이프라인을 포크하거나 라이브러리를 교체하는 것뿐입니다.
Tesseract 4.1.1 엔진 동결. 이 패키지는 Tesseract 4.1.1을 포함합니다. Tesseract 5의 새롭게 작성된 LSTM 모델은 손상된 문서에서 훨씬 더 높은 정확도를 제공합니다. 해당 업그레이드는 charlesw 패키지를 통해서는 제공되지 않으며, 라이브러리를 변경해야 합니다.
표준 패턴 없는 신뢰도 처리. charlesw 래퍼는 page.GetMeanConfidence()를 0과 1 사이의 부동 소수점으로 제공하지만, 단어 또는 문자 수준에서의 신뢰도 임계값을 적용하려면 iter.GetConfidence(PageIteratorLevel.Word) 패턴이 필요합니다. 표준 필터링 API는 없습니다. 각 팀마다 임계값 로직을 구현하는 방식이 다릅니다.
근본적인 문제
charlesw 래퍼를 실행하려면 OCR을 실행하기 전에 플랫폼별 네이티브 바이너리 구성이 필요합니다.
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
Imports System
Imports System.Runtime.InteropServices
Imports Tesseract
' charlesw Tesseract: OS detection required just to find native DLLs
' DllNotFoundException on any platform where binaries do not resolve
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib")
End If
Dim engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath) ' Requires leptonica native DLL
Using page As Page = engine.Process(img)
Return page.GetText()
End Using
End Using
IronOCR 에는 기본 바이너리 구성 파일이 없습니다.
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
' IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text
IronOCR과 Charlesw Tesseract의 기능 비교
다음 표는 이번 마이그레이션을 평가하는 팀에 필요한 기능을 정리한 것입니다.
| 기능 | 찰스 테서랙트 | IronOCR |
|---|---|---|
| 유지보수 상태 | 보관됨 (2021년 이후 업데이트 없음) | 적극적으로 유지보수됨 |
| 테서랙트 엔진 버전 | 4.1.1 (냉동) | 5 (현재, 최적화됨) |
| 라이선스 | Apache 2.0 (무료) | 상업용 ($999–$2,999 영구) |
| NuGet 설치 | Tesseract |
IronOcr |
| 네이티브 바이너리 관리 | 플랫폼별 수동 DLL 배포 | 번들로 제공되며 별도의 설정이 필요 없습니다. |
| 렙토니카 의존성 | leptonica-1.82.0.dll / libleptonica-dev 필요 |
해당 사항 없음 (내부 처리) |
| 테스데이터 관리 | 수동 다운로드 및 .csproj 복사 항목 |
NuGet 언어 팩 |
| 플랫폼 조건부 코드 | 다중 대상 배포에 필요합니다. | 필요하지 않음 |
| Docker 배포 | 명시적 tessdata COPY + Leptonica apt-get 필요 |
표준 .NET 컨테이너 요구 사항만 충족하면 됩니다. |
| ARM64 지원 | 미확인 게시물 아카이브 | 번들로 제공되고 검증되었습니다. |
| 이미지 입력 형식 | TIFF, PNG, BMP, JPG (Leptonica 제공) | JPG, PNG, BMP, TIFF, GIF 등 |
| 여러 페이지로 구성된 TIFF 파일 | 수동 프레임 반복 | input.LoadImageFrames() |
| 네이티브 PDF 입력 | 아니요 (보조 라이브러리 필요) | 예 |
| 검색 가능한 PDF 출력 | 아니요 | 예 (result.SaveAsSearchablePdf()) |
| 내장 전처리 기능 | None | 기울기 보정, 노이즈 제거, 대비 조정, 이진화, 선명도 향상, 크기 조정, 확대/축소, 침식, 반전 |
| 신뢰도 필터링 API | GetConfidence()와 수동 반복기 |
result.Confidence, word.Confidence |
| 구조화된 결과 | 반복기 패턴 (ResultIterator) |
직접 수집(페이지, 단락, 줄, 단어) |
| 바코드 판독 | 아니요 | 예 (OCR 통과 시) |
| 영역 기반 OCR | 아니요 | 예 (CropRectangle) |
| 스레드 안전성 | 발신자 책임 | 내장형 |
| 125개 이상의 언어 팩 | 수동 tessdata 다운로드 | dotnet add package IronOcr.Languages.* |
| 크로스 플랫폼 .NET | 예 (.NET Standard 2.0) | 예 (.NET Framework 4.6.2 이상, .NET 5/6/7/8/9) |
| 보안 패치 주기 | 없음 (보관됨) | 정기적인 릴리즈 |
빠른 시작: Charlesw Tesseract에서IronOCR로 마이그레이션
1단계: NuGet 패키지 교체
charlesw Tesseract 패키지를 제거하세요:
dotnet remove package Tesseract
dotnet remove package Tesseract
NuGet 에서IronOCR설치하세요.
dotnet add package IronOcr
단계 2: 네임스페이스 업데이트
// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;
// Before (charlesw Tesseract)
using Tesseract;
// After (IronOCR)
using IronOcr;
Imports IronOcr
단계 3: 라이선스 초기화
애플리케이션 시작 시, OCR 작업이 실행되기 전에 다음 호출을 한 번만 추가하십시오.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
IronOCR 라이선스 페이지 에서 무료 평가판 라이선스를 이용할 수 있습니다. 이 체험판을 사용하면 출력물에서 워터마크가 제거되고 API에 대한 전체 액세스가 가능해집니다.
코드 마이그레이션 예제
네이티브 바이너리 경로 구성 제거
CharlesW/Tesseract 프로젝트에서 가장 일반적인 초기화 패턴은 TessData 경로를 구축하고 환경별로 네이티브 라이브러리 로딩을 구성하는 팩토리 또는 헬퍼 클래스입니다. 이 코드는 순전히 래퍼의 배포 모델 때문에 존재합니다.
찰스 테서랙트 접근법:
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
private static string GetTessDataPath()
{
// Different path per environment — all wrong until explicitly configured
if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
return "/app/tessdata"; // Docker
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "/usr/local/share/tessdata"; // macOS Homebrew install
return @".\tessdata"; // Windows dev machine
}
public static TesseractEngine Create(string language = "eng")
{
// If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
// If tessdata folder is missing: TesseractException at engine construction
return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
}
}
// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports Tesseract
Public Module OcrEngineFactory
Private Function GetTessDataPath() As String
' Different path per environment — all wrong until explicitly configured
If Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") = "true" Then
Return "/app/tessdata" ' Docker
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
Return Path.Combine(AppContext.BaseDirectory, "tessdata") ' Linux bare metal
End If
If RuntimeInformation.IsOSPlatform(OSPlatform.OSX) Then
Return "/usr/local/share/tessdata" ' macOS Homebrew install
End If
Return ".\tessdata" ' Windows dev machine
End Function
Public Function Create(Optional language As String = "eng") As TesseractEngine
' If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
' If tessdata folder is missing: TesseractException at engine construction
Return New TesseractEngine(GetTessDataPath(), language, EngineMode.Default)
End Function
End Module
' Call site
Using engine As TesseractEngine = OcrEngineFactory.Create()
Using img As Pix = Pix.LoadFromFile("invoice.jpg")
Using page As Page = engine.Process(img)
Console.WriteLine(page.GetText())
End Using
End Using
End Using
IronOCR 접근 방식:
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
' IronOCR: no factory, no path logic, no OS detection
' Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("invoice.jpg")
Console.WriteLine(result.Text)
전체 OcrEngineFactory 클래스 삭제. 플랫폼 조건부 경로 논리, DOTNET_RUNNING_IN_CONTAINER 검사, Leptonica DLL 의존성이 모두 사라집니다. 개발자 워크스테이션, CI 에이전트, Docker 컨테이너, 클라우드 VM 등 모든 환경에서 동일한 두 줄의 코드가 실행됩니다. IronTesseract 설정 가이드 에서는 기본 설정을 조정해야 할 때 사용할 수 있는 구성 옵션을 다루지만, 대부분의 배포 환경에서는 조정이 필요하지 않습니다.
렙토니카 이미지 변환 교체
charlesw 래퍼는 Leptonica의 Pix 유형을 이미지 표현으로 사용합니다. OCR 전에 이미지를 조작하는 모든 코드는 반드시 Pix를 통해 변환해야 하며, 이는 Leptonica 네이티브 DLL이 로드되고 작동해야 합니다. 이 패턴을 OcrInput으로 교체하면 Leptonica 의존성을 완전히 제거할 수 있습니다.
찰스 테서랙트 접근법:
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
// 아니요 direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
// 아니요 direct Bitmap → Pix conversion; must write to temp file
var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
try
{
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile(tempPath); // Leptonica file I/O
using var page = engine.Process(pix);
return page.GetText();
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
Imports System
Imports System.Drawing
Imports System.IO
Imports Tesseract
Public Class ImageProcessor
' Pix is Leptonica's image type — requires leptonica native DLL
' Converting from System.Drawing.Bitmap requires a temp file round-trip
Public Function ProcessInMemoryImage(bitmap As Bitmap) As String
' 아니요 direct Bitmap → Pix conversion; must write to temp file
Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png")
Try
bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using pix As Pix = Pix.LoadFromFile(tempPath) ' Leptonica file I/O
Using page As Page = engine.Process(pix)
Return page.GetText()
End Using
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
End Function
End Class
IronOCR 접근 방식:
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // Direct byte array loading
var result = new IronTesseract().Read(input);
return result.Text;
}
// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = new IronTesseract().Read(input);
return result.Text;
}
Imports System.IO
' OcrInput accepts byte arrays and streams — no temp file, no Leptonica
Public Function ProcessInMemoryImage(imageBytes As Byte()) As String
Using input As New OcrInput()
input.LoadImage(imageBytes) ' Direct byte array loading
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
End Function
' Or from a stream — same pattern
Public Function ProcessFromStream(imageStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(imageStream)
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
End Function
임시 파일 왕복 과정이 사라집니다. 디스크에 파일이 작성되지 않으며, 변환을 위해 Leptonica DLL이 호출되지 않으며, 정리해야 할 finally 블록이 없습니다. 이미지 입력 가이드와 스트림 입력 가이드는 URL 및 메모리 맵 파일에서 로드하는 것을 포함한 모든 지원 입력 소스를 문서화합니다.
신뢰도 임계값 필터링
charlesw 래퍼는 두 수준에서 신뢰도를 노출합니다: 전체 페이지에 대한 page.GetMeanConfidence(), 개별 단어에 대한 iter.GetConfidence(PageIteratorLevel.Word). 신뢰도가 낮은 단어를 출력에서 걸러내려면 반복 루프를 수동으로 관리해야 합니다.IronOCR결과 객체에 신뢰도를 직접 표시하여 임계값 논리를 LINQ 표현식으로 만듭니다.
찰스 테서랙트 접근법:
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
var highConfidenceWords = new List<string>();
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
// Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");
using var iter = page.GetIterator();
iter.Begin();
do
{
if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
{
var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
var wordConf = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
highConfidenceWords.Add(wordText);
}
} while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));
return highConfidenceWords;
}
Imports System
Imports Tesseract
Public Class WordExtractor
Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Single = 0.8F) As List(Of String)
Dim highConfidenceWords As New List(Of String)()
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath)
Using page As Page = engine.Process(img)
' Page-level confidence only: fine-grained requires the iterator
Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}")
Using iter As ResultIterator = page.GetIterator()
iter.Begin()
Do
If iter.IsAtBeginningOf(PageIteratorLevel.Word) Then
Dim wordText As String = iter.GetText(PageIteratorLevel.Word)?.Trim()
Dim wordConf As Single = iter.GetConfidence(PageIteratorLevel.Word) / 100.0F ' Returns 0-100
If Not String.IsNullOrEmpty(wordText) AndAlso wordConf >= minConfidence Then
highConfidenceWords.Add(wordText)
End If
End If
Loop While iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word)
End Using
End Using
End Using
End Using
Return highConfidenceWords
End Function
End Class
IronOCR 접근 방식:
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
var result = new IronTesseract().Read(imagePath);
Console.WriteLine($"Page confidence: {result.Confidence}%");
// LINQ directly on the word collection — no iterator state management
return result.Pages
.SelectMany(p => p.Lines)
.SelectMany(l => l.Words)
.Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
.Select(w => w.Text)
.ToList();
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Double = 80.0) As List(Of String)
Dim result = New IronTesseract().Read(imagePath)
Console.WriteLine($"Page confidence: {result.Confidence}%")
' LINQ directly on the word collection — no iterator state management
Return result.Pages _
.SelectMany(Function(p) p.Lines) _
.SelectMany(Function(l) l.Words) _
.Where(Function(w) w.Confidence >= minConfidence AndAlso Not String.IsNullOrWhiteSpace(w.Text)) _
.Select(Function(w) w.Text) _
.ToList()
End Function
이터레이터 상태 머신이 사라졌습니다.IronOCR의 신뢰도 값은 항상 0~100 척도로 표시되며, 100으로 나눌 필요가 없습니다. 신뢰도 점수 가이드는 단어별, 줄별, 페이지별 신뢰도 접근 패턴을 다룹니다. 읽기 결과 가이드는 구조화된 결과 계층 구조 전체를 탐색하는 방법을 보여줍니다.
다중 페이지 TIFF 일괄 처리
여러 프레임으로 구성된 TIFF 파일은 문서 스캔 워크플로에서 흔히 사용됩니다. charlesw 래퍼에는 멀티프레임 TIFF 지원 기능이 내장되어 있지 않습니다. 각 프레임은 처리하기 전에 수동으로 추출해야 합니다.IronOCR단일 로드 호출로 여러 프레임으로 구성된 TIFF 파일을 기본적으로 처리합니다.
찰스 테서랙트 접근법:
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
var fullText = new StringBuilder();
using var tiffImage = Image.FromFile(tiffPath);
var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
for (int i = 0; i < frameCount; i++)
{
tiffImage.SelectActiveFrame(FrameDimension.Page, i);
// Must save each frame as a temp file for Pix to load
var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
try
{
tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);
using var pix = Pix.LoadFromFile(tempPath);
using var page = engine.Process(pix);
fullText.AppendLine(page.GetText());
}
finally
{
if (File.Exists(tempPath)) File.Delete(tempPath);
}
}
return fullText.ToString();
}
Imports System.Drawing
Imports System.Drawing.Imaging
Imports Tesseract
Imports System.IO
Imports System.Text
Public Function ProcessMultiFrameTiff(tiffPath As String) As String
Dim fullText As New StringBuilder()
Using tiffImage As Image = Image.FromFile(tiffPath)
Dim frameCount As Integer = tiffImage.GetFrameCount(FrameDimension.Page)
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
For i As Integer = 0 To frameCount - 1
tiffImage.SelectActiveFrame(FrameDimension.Page, i)
' Must save each frame as a temp file for Pix to load
Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png")
Try
tiffImage.Save(tempPath, Imaging.ImageFormat.Png)
Using pix As Pix = Pix.LoadFromFile(tempPath)
Using page As Page = engine.Process(pix)
fullText.AppendLine(page.GetText())
End Using
End Using
Finally
If File.Exists(tempPath) Then File.Delete(tempPath)
End Try
Next
End Using
End Using
Return fullText.ToString()
End Function
IronOCR 접근 방식:
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // All frames loaded in one call
var result = new IronTesseract().Read(input);
// Pages maps directly to TIFF frames
foreach (var page in result.Pages)
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");
return result.Text;
}
Imports System
Imports IronOcr
Public Class TiffProcessor
' LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
Public Function ProcessMultiFrameTiff(tiffPath As String) As String
Using input As New OcrInput()
input.LoadImageFrames(tiffPath) ' All frames loaded in one call
Dim result = New IronTesseract().Read(input)
' Pages maps directly to TIFF frames
For Each page In result.Pages
Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words")
Next
Return result.Text
End Using
End Function
End Class
임시 파일 추출 루프와 프레임별 폐기 과정이 사라졌습니다. 프레임 수 감지가 FrameDimension.Page을 통해 사라집니다. IronOCR는 TIFF 프레임을 OcrResult.Pages에 매핑하므로, 프레임 별 텍스트 접근에는 추가 반복 논리가 필요하지 않습니다. TIFF/GIF 입력 가이드 에서는 프레임 선택 및 부분 TIFF 처리와 같은 추가 옵션에 대해 설명합니다.
검색 가능한 PDF 생성
charlesw 래퍼는 텍스트 출력만 생성합니다. 스캔된 문서를 검색 가능한 PDF로 변환하는 것은 문서 관리 시스템을 위한 일반적인 요구 사항이며, 추출한 텍스트를 원본 이미지 페이지에 오버레이하기 위해 보조 PDF 라이브러리(IronPDF, PDFSharp 또는 유사한 것이 필요합니다.IronOCR별도의 라이브러리 없이 단 한 번의 메서드 호출로 검색 가능한 PDF 파일을 생성합니다.
찰스 테서랙트 접근법:
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
// Step 1: Extract text from image
string extractedText;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath);
using var page = engine.Process(img);
extractedText = page.GetText();
// Step 2: Build a PDF with the image as background and text overlay
// Requires a separate PDF library (not shown — 50-100+ additional lines)
// The text layer must be positioned to match the original image layout
// Word-level coordinates from the iterator are needed for accurate alignment
throw new NotImplementedException(
"Searchable PDF generation requires a separate PDF library. " +
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
Imports Tesseract
Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
' Step 1: Extract text from image
Dim extractedText As String
Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath)
Using page As Page = engine.Process(img)
extractedText = page.GetText()
End Using
End Using
End Using
' Step 2: Build a PDF with the image as background and text overlay
' Requires a separate PDF library (not shown — 50-100+ additional lines)
' The text layer must be positioned to match the original image layout
' Word-level coordinates from the iterator are needed for accurate alignment
Throw New NotImplementedException("Searchable PDF generation requires a separate PDF library. " & _
"Add PdfSharp, IronPDF, or similar, then implement text layer overlay.")
End Sub
IronOCR 접근 방식:
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
// 아니요 secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
// 아니요 secondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
var result = new IronTesseract().Read(imagePath);
result.SaveAsSearchablePdf(outputPdfPath);
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}
// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
var result = new IronTesseract().Read(scannedPdfPath);
result.SaveAsSearchablePdf(outputPdfPath);
}
Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(imagePath)
result.SaveAsSearchablePdf(outputPdfPath)
Console.WriteLine($"Searchable PDF saved: {outputPdfPath}")
End Sub
Public Sub MakePdfSearchable(scannedPdfPath As String, outputPdfPath As String)
Dim result = New IronTesseract().Read(scannedPdfPath)
result.SaveAsSearchablePdf(outputPdfPath)
End Sub
SaveAsSearchablePdf()는 OCR 텍스트를 인식된 단어에 맞춰 조정된 보이지 않는 레이어로 삽입하여, 문서의 시각적 외관을 변경하지 않고도 전체 텍스트 검색이 가능하도록 합니다. 검색 가능한 PDF 형식의 사용 설명서에는 페이지 범위 선택 및 압축 옵션이 설명되어 있습니다. 작동 예시는 검색 가능한 PDF 예시 페이지 에서 확인할 수 있습니다.
찰스 테서랙트 API에서IronOCR매핑 참조
| 찰스 테서랙트 | IronOCR에 상응하는 |
|---|---|
new TesseractEngine(tessDataPath, "eng", EngineMode.Default) |
new IronTesseract() |
Pix.LoadFromFile(imagePath) |
input.LoadImage(imagePath) |
Pix.LoadFromMemory(bytes) |
input.LoadImage(imageBytes) |
engine.Process(pix) |
ocr.Read(input) |
page.GetText() |
result.Text |
page.GetMeanConfidence() |
result.Confidence (0–100 점수) |
page.GetIterator() |
result.Pages, result.Words (직접 수집) |
iter.GetText(PageIteratorLevel.Word) |
word.Text |
iter.GetConfidence(PageIteratorLevel.Word) |
word.Confidence |
iter.TryGetBoundingBox(PageIteratorLevel.Word, out var b) |
word.X, word.Y, word.Width, word.Height |
iter.GetText(PageIteratorLevel.Para) |
paragraph.Text |
iter.IsAtBeginningOf(PageIteratorLevel.Block) |
page.Paragraphs (직접 반복) |
EngineMode.Default |
자동 (Tesseract 5 LSTM 기본값) |
EngineMode.TesseractOnly |
ocr.Configuration.PageSegmentationMode |
수동 tessdata .traineddata 파일 |
dotnet add package IronOcr.Languages.French |
TessDataPath 상수 + .csproj 복사 항목 |
해당 사항 없음 — 번들 상품 |
Pix.LoadFromFile() Leptonica DLL을 통해 |
input.LoadImage() — 네이티브 DLL 필요 없음 |
플랫폼 GetTessDataPath() 방법 |
해당 사항 없음 — 삭제됨 |
leptonica-1.82.0.dll / libleptonica-dev |
해당 사항 없음 — 렙토니카 의존성 없음 |
| TIFF 파일의 임시 프레임을 수동으로 추출하는 방법 | input.LoadImageFrames(tiffPath) |
| 검색 가능한 PDF 출력 없음 | result.SaveAsSearchablePdf(outputPath) |
new TesseractEngine() 스레드당 |
하나의 IronTesseract — 스레드 안전 |
일반적인 마이그레이션 문제와 해결책
문제 1: Leptonica 또는 Tesseract 바이너리에서 DllNotFoundException 발생
Charlesw Tesseract: System.DllNotFoundException: Unable to load DLL 'leptonica-1.82.0': The specified module could not be found. Leptonica 네이티브 DLL이 예상 위치에 없을 때 이 예외가 발생합니다. 신선한 Docker 컨테이너, CI 에이전트, 또는 NuGet 패키지의 runtimes/ 폴더가 올바르게 복사되지 않은 환경에서 일반적입니다.
해결책: Tesseract 패키지를 제거하십시오. IronOcr를 설치하십시오.IronOCR모든 네이티브 바이너리를 내부적으로 번들링하며 시스템 Leptonica에 P/Invoke를 사용하지 않습니다. 외부 Leptonica 종속성이 없으므로 예외가 발생할 수 없습니다.
dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
apt-get install libleptonica-dev 필요 없음. 네이티브 DLL에 대한 <CopyToOutputDirectory> 항목 필요 없음.
문제 2: 배포 후 Tessdata 경로 오류 발생
Charlesw Tesseract: Tesseract.TesseractException: Failed to initialise tesseract engine. 런타임 시 TessDataPath가 해결되지 않을 때 발생합니다. 오류 없이 컴파일되며, 런타임에만 실패하며, 실패 경로는 배포 환경에 따라 달라집니다.
해결책:IronOCR에는 tessdata 경로 개념이 존재하지 않습니다. 상수를 삭제하고, .csproj 내의 CopyToOutputDirectory XML을 삭제하고, 이를 빌드하는 팩토리 메소드를 삭제하십시오. 언어 데이터는 NuGet 패키지로 배포됩니다.
# Replace this manual tessdata file management:
# tessdata/eng.traineddata (15 MB, manually downloaded)
# tessdata/fra.traineddata (15 MB, manually downloaded)
# .csproj <CopyToOutputDirectory> entry
# With NuGet packages:
dotnet add package IronOcr.Languages.French
# Replace this manual tessdata file management:
# tessdata/eng.traineddata (15 MB, manually downloaded)
# tessdata/fra.traineddata (15 MB, manually downloaded)
# .csproj <CopyToOutputDirectory> entry
# With NuGet packages:
dotnet add package IronOcr.Languages.French
다국어 가이드에서는 언어 패키지를 추가한 후 다국어 인식을 구성하는 방법을 보여줍니다.
문제 3: 기본 이미지 업데이트 시 컨테이너 빌드가 실패함
Charlesw Tesseract: Dockerfile은 Leptonica 네이티브 의존성을 만족시키기 위해 apt-get install -y libleptonica-dev를 포함합니다. 기본 이미지가 Debian Bullseye에서 Bookworm으로 변경되거나 Leptonica 패키지 이름이 배포판마다 변경될 경우, apt 오류와 함께 빌드가 중단됩니다. 이 문제를 해결하려면 새 배포판에서 사용할 패키지 이름을 알아야 합니다.
해결책: Leptonica apt-get 줄을 완전히 제거하십시오. 리눅스의 IronOCR는 System.Drawing을 사용하는 모든 .NET 응용 프로그램이 이미 필요한 표준 libgdiplus 패키지만 필요합니다:
# Before: Leptonica explicit install — breaks on base image updates
RUN apt-get update && apt-get install -y libleptonica-dev
# After: standard .NET Linux requirement only
RUN apt-get update && apt-get install -y libgdiplus
Docker 배포 가이드는 일반적인 기본 이미지에 대한 테스트를 거친 Dockerfile 템플릿을 제공합니다. charlesw 관련 특정 인프라 코드는 필요하지 않습니다.
문제 4: 빈 페이지 또는 공백 페이지에서 반복자 패턴이 깨짐
Charlesw Tesseract: ResultIterator는 일부 페이지 세그먼트에서 iter.GetText()를 반환하여, 루프 전체에서 명시적인 널 검사가 필요합니다. 널 검사를 누락하면 텍스트를 인식할 수 없는 빈 페이지나 이미지에서 NullReferenceException가 발생합니다.
해결책:IronOCR결과 컬렉션은 절대 null이 아닙니다. 빈 페이지는 빈 컬렉션을 반환합니다. null 참조 대신 텍스트 내용을 확인하세요.
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
results.Add(wordText.Trim());
// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
if (!string.IsNullOrWhiteSpace(word.Text))
results.Add(word.Text);
}
' Before: null checks required at every iterator level
Dim wordText = iter.GetText(PageIteratorLevel.Word)
If wordText IsNot Nothing AndAlso wordText.Trim().Length > 0 Then
results.Add(wordText.Trim())
End If
' After: collection is safe to enumerate; check content as needed
For Each word In result.Pages.SelectMany(Function(p) p.Lines).SelectMany(Function(l) l.Words)
If Not String.IsNullOrWhiteSpace(word.Text) Then
results.Add(word.Text)
End If
Next
문제 5: 하중을 받는 상황에서의 나사산 안전 위반
Charlesw Tesseract: TesseractEngine는 스레드 안전하지 않습니다. ASP.NET 애플리케이션에서 여러 동시 요청이 하나의 인스턴스를 공유하면 액세스 위반이나 손상된 결과가 발생할 수 있습니다. 일반적인 해결 방법은 스레드당 하나의 엔진을 생성하는 것이지만, 이는 API에서 명확하게 드러나지 않으며, 오류가 발생할 경우 모호한 네이티브 예외 메시지가 표시됩니다.
해결책: IronTesseract는 스레드 안전합니다. 하나의 인스턴스가 동시 요청에 서비스할 수 있거나, 최대 처리량을 위해 스레드별 Parallel.ForEach를 생성하십시오. 두 패턴 모두 수정 없이 작동합니다:
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
var ocr = new IronTesseract();
var result = ocr.Read(imagePath);
results.Add(result.Text);
});
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
' Thread-safe parallel processing — IronTesseract handles concurrent access
Dim results As New ConcurrentBag(Of String)()
Parallel.ForEach(imageFiles, Sub(imagePath)
Dim ocr As New IronTesseract()
Dim result = ocr.Read(imagePath)
results.Add(result.Text)
End Sub)
비동기 OCR 가이드는 스레드 차단이 허용되지 않는 ASP.NET Core 컨트롤러의 비동기 패턴을 다룹니다.
문제 6: 런타임 시 ARM64 바이너리 파일 누락
Charlesw Tesseract: AWS Graviton(Linux ARM64) 또는 Apple Silicon CI 에이전트에서 아카이브된 패키지에 ARM64 네이티브 바이너리가 포함되지 않을 수 있습니다. 실패는 패키지가 지원할 경로가 없는 플랫폼에서의 엔진 생성 시 DllNotFoundException 또는 BadImageFormatException입니다 — 런타임 오류입니다.
해결책:IronOCR Linux와 macOS 모두에서 사용 가능한 검증된 ARM64 바이너리를 제공합니다. 코드 변경 없이 ARM64에 배포할 수 있습니다. Linux 배포 가이드 와 macOS 배포 가이드에서 지원되는 런타임 식별자를 확인할 수 있습니다.
찰스 테서랙트 이주 체크리스트
사전 마이그레이션
변경될 모든 패턴을 파악하기 위해 코드베이스를 검토하십시오.
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .
# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .
# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .
# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .
# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .
# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .
# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .
# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .
# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .
# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .
# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .
# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .
# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .
# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .
# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
프로젝트가 대상으로 하는 배포 환경(Docker, Linux, ARM64, Azure, AWS)을 확인하십시오. 이러한 환경은 charlesw/tesseract에 가장 많은 구성이 필요한 환경이며,IronOCR이러한 구성 작업을 간소화합니다.
코드 마이그레이션
dotnet remove package Tesseract를 실행하여 charlesw 래퍼를 제거하십시오dotnet add package IronOcr를 실행하여 IronOCR를 설치하십시오- 응용 프로그램 시작 시
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";를 추가하십시오 - 모든
using Tesseract;문을using IronOcr;으로 교체하십시오 - tessdata 경로 상수와 환경별 경로를 생성하는 모든 메서드를 삭제합니다.
- tessdata 경로 선택을 위해 작성된 모든
RuntimeInformation.IsOSPlatform()블록을 제거하십시오 - 모든
.csproj파일에서 tessdata 파일에 대한<CopyToOutputDirectory>항목을 제거하십시오 - 소스 제어 또는 배포 아티팩트 저장소에서 tessdata
.traineddata파일을 삭제하십시오 - 이전에
.traineddata파일로 배포된 각 언어에 대해dotnet add package IronOcr.Languages.*를 추가하십시오 TesseractEngine+Pix.LoadFromFile()+engine.Process()체인을new IronTesseract().Read()으로 교체하십시오- 모든
Pix.LoadFromFile()및Pix.LoadFromMemory()호출을input.LoadImage()로 교체하십시오 - 모든
page.GetText()호출을result.Text로 교체하십시오 - 반복기 기반의 단어/라인 추출을
result.Pages의 직접 수집 접근으로 교체하십시오 iter.GetConfidence()임계값 논리를result.Words또는result.Lines에 대한 LINQ로 교체하십시오- Dockerfiles 및 배포 스크립트에서
libleptonica-dev/leptonica-1.82.0.dll를 제거하십시오
마이그레이션 이후
코드 업데이트 완료 후 다음 사항을 확인하십시오.
- OCR은 Windows에서 네이티브 DLL 오류 없이 성공적으로 실행됩니다.
- OCR은
libgdiplus를 제외한 변경 없이 Docker Linux 컨테이너에서 성공적으로 실행됩니다
- OCR은
- OCR은 배포 매트릭스에 ARM64 플랫폼이 포함되어 있는 경우 해당 플랫폼에서 텍스트 출력을 생성합니다.
- 여러 페이지로 구성된 TIFF 파일은 첫 번째 프레임뿐만 아니라 모든 프레임의 텍스트를 반환합니다.
- 신뢰도 필터링은 이전 반복자 구현과 동일한 논리적으로 신뢰도가 높은 단어 집합을 반환합니다.
- 언어별 문서(프랑스어, 독일어 등)는 해당 언어 NuGet 패키지를 설치한 후 올바르게 인식됩니다.
- 병렬 OCR 작업이 예외 없이 또는 출력물 손상 없이 완료되었습니다.
- 이전 구현에서는 텍스트만 반환했지만, 이제는 검색 가능한 PDF 출력을 생성합니다.
- TessData 다운로드 단계나 Leptonica 설치 명령 없이 CI/CD 파이프라인을 구축합니다.
- 이전 구현을 검증하는 데 사용했던 동일한 이미지 코퍼스를 대상으로 스모크 테스트를 수행했습니다.
IronOCR로 마이그레이션할 때의 주요 이점
자체 포함형 배포 모델. 마이그레이션 후 OCR 종속성은 단일 NuGet 패키지 참조로 완벽하게 설명됩니다. 소스 제어에 tessdata 파일 없음, CopyToOutputDirectory 항목 없음, 네이티브 DLL 배포 단계 없음, Leptonica 시스템 패키지 없음. 이전에 다중 단계 아티팩트 관리가 필요한 CI/CD 파이프라인이 dotnet publish로 감소합니다. charlesw 래퍼를 지원하기 위해 축적되었던 배포 관련 코드가 영구적으로 삭제되었습니다.
조건부 로직 없이 플랫폼 호환성을 제공합니다. 동일한 애플리케이션 바이너리가 수정 없이 Windows x64, Linux x64, Linux ARM64, macOS x64 및 macOS ARM64에서 실행됩니다. AWS Graviton, Apple Silicon CI 또는 Raspberry Pi 등 ARM64 배포 대상을 추가하는 팀은 새로운 플랫폼 감지 코드를 작성할 필요가 없습니다. Linux 배포 가이드 와 AWS 배포 가이드에서 테스트를 거친 구성이 확인되었습니다.
Tesseract 5의 내장 전처리 기능을 통한 정확도 향상. Tesseract 4.1.1에서 Tesseract 5로의 업그레이드는 손상된 문서에서의 인식률을 향상시킵니다.IronOCR엔진 업그레이드에 더해 자동 전처리 기능을 추가하여 엔진이 각 이미지를 처리하기 전에 기울기 보정, 노이즈 제거, 대비 정규화 및 이진화를 적용합니다. 이전에는 허용 가능한 정확도 기준에 도달하기 위해 사용자 지정 전처리 파이프라인이 필요했던 문서들이 이제 추가 코드 없이도 해당 기준에 도달합니다. 이미지 품질 보정 가이드 에는 기본 설정 이상의 조정이 필요한 경우에 대한 명확한 전처리 옵션이 설명되어 있습니다.
반복기 보일러플레이트를 대체하는 직접 결과 탐색. charlesw 반복기 패턴 — GetIterator(), Begin(), Next(), IsAtBeginningOf(), 전반적인 null 검사 — 단순한 컬렉션으로 대체됩니다. 단어, 줄, 단락 및 페이지는 결과 객체의 속성입니다. 신뢰도 기반 필터링은 LINQ 표현식입니다. 이전에는 단어 수준 데이터를 추출하는 코드에 15~30줄의 반복자 관리 코드가 필요했습니다.IronOCR에서는 2~3줄에 해당합니다. OCR 결과 요약 페이지에는 전체 구조화된 출력 모델이 자세히 설명되어 있습니다.
보조 라이브러리 없이 검색 가능한 PDF 출력. result.SaveAsSearchablePdf()은 인식된 단어에 맞춘 텍스트 레이어가 포함된 PDF를 생성하며, 추가적인 PDF 라이브러리가 필요하지 않습니다. 검색 가능한 PDF를 입력받는 문서 관리 시스템은 더 이상 별도의 PDF 생성 단계를 필요로 하지 않습니다. 추출된 텍스트를 제공하는 동일한 결과 객체가 검색 가능한 파일도 생성하므로, 문서 처리 파이프라인은 단일 라이브러리 종속성으로 유지됩니다.
활발한 유지 관리 및 보안 패치 적용.IronOCR Tesseract 5 모델 개선 사항, .NET 런타임 호환성 검증 및 기본 C++ 엔진의 보안 패치 적용 현황을 추적하는 정기적인 업데이트를 받습니다. 이제 해당 종속성은 보관된 패키지의 위험 프로필을 갖지 않으며, 규정 준수 검토 시 누락된 보안 패치 경로에 대한 오류가 발생하지 않습니다. .NET 10이 2026년까지 일반에 공개됨에 따라 IronOCR 문서 허브는 별도의 해결 방법이나 포크 없이도 현재 호환성을 반영할 것입니다.
자주 묻는 질문
Charlesw/tesseract(.NET 테서랙트 래퍼)에서 IronOCR로 마이그레이션해야 하는 이유는 무엇인가요?
일반적인 동인으로는 COM 상호 운용의 복잡성 제거, 파일 기반 라이선스 관리 대체, 페이지당 과금 방지, Docker/컨테이너 배포 활성화, 표준 .NET 툴링과 통합되는 NuGet 네이티브 워크플로 채택 등이 있습니다.
찰스W/테서랙트(.NET 테서랙트 래퍼)에서 IronOCR로 마이그레이션할 때 변경되는 주요 코드는 무엇인가요?
찰스W/테서랙트 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리(명시적 생성/로드/폐쇄 패턴)를 제거하고, 결과 속성 이름을 업데이트합니다. 그 결과 상용구 줄이 훨씬 줄어듭니다.
마이그레이션을 시작하려면 IronOCR을 어떻게 설치하나요?
패키지 관리자 콘솔에서 '설치-패키지 IronOcr'을 실행하거나 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행하세요. 언어 팩은 별도의 패키지입니다: 예를 들어 프랑스어의 경우 '닷넷 추가 패키지 IronOcr.Languages.French'를 실행합니다.
IronOCR은 표준 비즈니스 문서에 대한 찰스W/테서랙트(.NET 테서랙트 래퍼)의 OCR 정확도와 일치하나요?
IronOCR은 송장, 계약서, 영수증, 타이핑된 양식 등 표준 비즈니스 콘텐츠에 대해 높은 정확도를 달성합니다. 이미지 전처리 필터(데스큐, 노이즈 제거, 대비 향상)는 품질이 저하된 입력에 대한 인식률을 더욱 향상시킵니다.
IronOCR은 찰스W/테서랙트(.NET 테서랙트 래퍼)가 별도로 설치하는 언어 데이터를 어떻게 처리하나요?
IronOCR의 언어 데이터는 NuGet 패키지로 배포됩니다. '닷넷 추가 패키지 IronOcr.Languages.German'은 독일어 지원을 설치합니다. 수동 파일 배치나 디렉터리 경로는 필요하지 않습니다.
Charlesw/tesseract(.NET 테서랙트 래퍼)에서 IronOCR로 마이그레이션하려면 배포 인프라를 변경해야 하나요?
IronOCR은 찰스W/테서랙트(.NET 테서랙트 래퍼)보다 인프라 변경이 덜 필요합니다. SDK 바이너리 경로, 라이선스 파일 배치 또는 라이선스 서버 구성이 필요하지 않습니다. NuGet 패키지에는 전체 OCR 엔진이 포함되어 있으며 라이선스 키는 애플리케이션 코드에 설정된 문자열입니다.
마이그레이션 후 IronOCR 라이선싱은 어떻게 구성하나요?
애플리케이션 시작 코드에 IronOcr.License.LicenseKey = "YOUR-KEY"를 할당하세요. Docker 또는 Kubernetes에서 키를 환경 변수로 저장하고 시작 시 키를 읽습니다. 트래픽을 수락하기 전에 License.IsValidLicense를 사용하여 유효성을 검사하세요.
IronOCR은 charlesw/tesseract와 같은 방식으로 PDF를 처리할 수 있나요?
예. IronOCR은 원본 및 스캔한 PDF를 모두 읽습니다. IronTesseract를 인스턴스화하고, 입력이 PDF 경로 또는 OcrPdfInput인 경우 ocr.Read(input)를 호출하고, OcrResult 페이지를 반복하면 됩니다. 별도의 PDF 렌더링 파이프라인이 필요하지 않습니다.
IronOCR은 대량 처리에서 스레딩을 어떻게 처리하나요?
IronTesseract는 스레드별로 인스턴스화해도 안전합니다. Parallel.ForEach 또는 Task 풀에서 스레드당 하나의 인스턴스를 스핀업하고, OCR을 동시에 실행하고, 완료되면 각 인스턴스를 폐기하면 됩니다. 전역 상태나 잠금이 필요하지 않습니다.
IronOCR은 텍스트 추출 후 어떤 출력 형식을 지원하나요?
IronOCR은 텍스트, 단어 좌표, 신뢰도 점수, 페이지 구조를 포함한 구조화된 결과를 반환합니다. 내보내기 옵션에는 일반 텍스트, 검색 가능한 PDF, 다운스트림 처리를 위한 구조화된 결과 개체가 포함됩니다.
워크로드 확장을 위해 IronOCR 가격이 charlesw/tesseract(.NET Tesseract 래퍼)보다 더 예측 가능한가요?
IronOCR은 페이지당 또는 볼륨당 요금이 없는 정액제 영구 라이선스를 사용합니다. 10,000페이지를 처리하든 1,000만 페이지를 처리하든 라이선스 비용은 일정하게 유지됩니다. 볼륨 및 팀 라이선스 옵션은 IronOCR 가격 페이지에서 확인할 수 있습니다.
찰스W/테서랙트(.NET 테서랙트 래퍼)에서 IronOCR로 마이그레이션한 후 기존 테스트는 어떻게 되나요?
추출된 텍스트 콘텐츠에 대해 어설트하는 테스트는 마이그레이션 후에도 계속 통과해야 합니다. API 호출 패턴 또는 COM 개체 수명 주기의 유효성을 검사하는 테스트는 IronOCR의 더 간단한 초기화 및 결과 모델을 반영하도록 업데이트해야 합니다.

