푸터 콘텐츠로 바로가기
다른 구성 요소와 비교

송장 OCR 오픈 소스 비교: 최고의 도구를 찾아보세요

LEADTOOLS는 1990년부터 SDK 소프트웨어를 공급해왔으며, 그 OCR 통합은 그 유산을 완전히 이어받고 있습니다: 단일 문자를 인식하기 전에, 애플리케이션은 디스크에서 두 개의 바이너리 파일을 찾아야 하고, LEADTOOLS.LICLEADTOOLS.LIC.KEY 사이의 쌍 인증, RasterCodecs 인스턴스 초기화, 세 가지 별개의 옵션 중에서 엔진 유형 선택, 실행 디렉터리 경로와 함께 engine.Startup() 호출을 수행해야 실제 인식 작업이 시작됩니다. 모든 운영 시스템에는 라이선스 파일이 특정 경로에 배포되어야 합니다. Docker컨테이너를 사용하려면 해당 파일을 마운트하거나 빌드해야 합니다. CI/CD 파이프라인은 파일이 올바른 위치에 있어야 하며, 그렇지 않으면 애플리케이션 시작 시 오류가 발생합니다. 또한 개발자가 잘못된 번들을 구매한 경우 OCR 모듈이 전혀 포함되지 않을 수 있습니다. LEADTOOLS는 OCR 기능을 이미지 코덱과 별도의 모듈로 판매하기 때문입니다.

리드툴즈 OCR 이해하기

LEADTOOLS는 1990년부터 상용 SDK 소프트웨어를 출시해 온 LEAD Technologies의 문서 이미지 처리 플랫폼입니다. OCR 기능은 문서 뷰어, 의료 영상(DICOM/PACS), 바코드 판독, 양식 인식, 주석 달기, PDF 조작 등 다양한 기능을 포함하는 툴킷의 여러 모듈 중 하나입니다. 이러한 아키텍처는 LEADTOOLS가 OCR 라이브러리가 아니라 OCR 기능을 포함하는 이미지 처리 플랫폼임을 의미합니다.

LEADTOOLS OCR의 주요 아키텍처 특징:

  • 세 가지 개별 OCR 엔진: LEAD 독점 엔진(기본 라이선스에 포함), Tesseract 래퍼(tessdata 파일 필요), OmniPage 엔진(별도의 Kofax 라이선스 계약 및 다른 공급업체와의 협력 필요). 엔진 선택은 코드와 비용 모두에 영향을 미칩니다.
  • 파일 기반 라이선스 배포: 두 파일 — LEADTOOLS.LICLEADTOOLS.LIC.KEY는 런타임에 읽을 수 있어야 합니다. 경로는 하드코딩되거나 시작 시 해결됩니다. 경로 해결은 IIS 대 콘솔 호스트, Docker대 베어 메탈, 릴리스 빌드 대 디버그에서 다르게 동작합니다.
  • RasterCodecs을 필요로 하는 중간 요소: 이미지 로딩은 OCR 엔진으로 직접 이동하지 않습니다. 모든 이미지 — PDF 페이지를 포함한다 —는 처음에 RasterCodecs 인스턴스를 통해 로드되며, 엔진이 시작되기 전에 초기화되어야 합니다.
  • 명시적 엔진 라이프사이클: OcrEngineManager.CreateEngine()가 엔진을 생성하고, engine.Startup()가 그것을 메모리에 로드하면 (500–2000 ms), engine.Shutdown()Dispose() 전에 호출되어야 합니다. 종료 호출 순서를 잘못하면 오류가 발생합니다.
  • 번들 가격 책정의 복잡성: LEADTOOLS는 가격을 공개적으로 게시하지 않습니다. 귀하의 특정 요구 사항에 따라 견적을 받으려면 LEADTOOLS 영업 부서에 연락하십시오. 업데이트를 받기 위해 연간 유지보수 요금을 내야 합니다.
  • 큰 배포 발자국: 생산 배포에는 여러 LEADTOOLS DLL, OcrRuntime/ 디렉터리, 라이선스 파일이 포함되며, Tesseract 엔진을 사용하는 경우 선택적으로 tessdata/ 폴더도 포함됩니다.

초기화 시퀀스

LEADTOOLS를 사용하려면 인식이 이루어지기 전에 특정 단계의 설정 과정을 거쳐야 합니다. 순서가 선택 사항이 아닙니다 — Startup()SetLicense() 전에 또는 RasterCodecs가 초기화되기 전에 호출하면 런타임 오류가 발생합니다:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Initialize image codec layer
        _codecs = new RasterCodecs();

        // Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);
        using var document = _ocrEngine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);   // Recognition is not automatic
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown(); // Must call before Dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Initialize image codec layer
        _codecs = new RasterCodecs();

        // Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);
        using var document = _ocrEngine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);   // Recognition is not automatic
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown(); // Must call before Dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System.IO

Public Class LeadtoolsOcrService
    Implements IDisposable

    Private _ocrEngine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        ' Step 1: Locate and validate both license files
        RasterSupport.SetLicense(
            "C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText("C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"))

        ' Step 2: Initialize image codec layer
        _codecs = New RasterCodecs()

        ' Step 3: Select engine type — wrong choice means different behavior
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)

        ' Step 4: Load runtime into memory (500–2000ms)
        _ocrEngine.Startup(_codecs, Nothing, Nothing,
            "C:\LEADTOOLS\OCR\OcrRuntime")
    End Sub

    Public Function ExtractText(imagePath As String) As String
        Using image = _codecs.Load(imagePath)
            Using document = _ocrEngine.DocumentManager.CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing)
                page.Recognize(Nothing) ' Recognition is not automatic
                Return page.GetText(-1)
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If _ocrEngine IsNot Nothing Then
            _ocrEngine.Shutdown() ' Must call before Dispose
            _ocrEngine.Dispose()
        End If
        If _codecs IsNot Nothing Then
            _codecs.Dispose()
        End If
    End Sub
End Class
$vbLabelText   $csharpLabel

이는 최소한의 실행 가능한 구현입니다. 이는 라이선스 경로 실패, 엔진 상태 유효성 검사 또는 배치 처리에 필요한 메모리 관리(여기서 RasterImage 인스턴스를 해제하는 것을 잊으면 프로세스가 충돌할 때까지 메모리가 축적됨)에는 포함되지 않습니다.

IronOCR이해하기

IronOCR 최적화된 Tesseract 5 LSTM 엔진을 기반으로 구축된 상 for .NET OCR 라이브러리입니다. IronOCR은 OCR 기능에 특화된 제품이며, OCR을 하나의 모듈로 포함하는 이미지 처리 플랫폼이 아닙니다. 설계 목표는 개발자와 인식된 텍스트 사이에 있는 모든 인프라 오버헤드를 제거하는 것입니다.

IronOCR의 주요 특징:

  • 단일 NuGet 패키지: dotnet add package IronOcr는 필요한 모든 것이 포함된 네이티브 종속성과 함께 추가 런타임 디렉터리, tessdata 폴더, 배포할 라이선스 파일 없이 설치됩니다.
  • 문자열 기반 라이선싱: 한 줄로 라이선스 키를 할당할 수 있습니다. 키는 환경 변수, appsettings.json, Azure Key Vault 또는 AWS Secrets Manager에서 제공될 수 있으며, 이미 사용 중인 비밀 관리 패턴을 사용할 수 있습니다. 디스크에 파일이 없습니다.
  • 엔진 라이프사이클 없음: IronTesseract는 첫 사용 시 지연 로딩으로 초기화됩니다. Startup() 호출이 없으며, Shutdown() 호출이 없으며, 작업 간 엔진 자체를 해제할 필요도 없습니다.
  • 네이티브 PDF 입력: PDF는 OcrInput.LoadPdf()을 통해 직접 로드됩니다. 페이지별 배스터라이제이션 루프, 바이트 순서 지정, 중간 RasterImage 객체의 수동 해제도 없습니다.
  • 자동 전처리: 데스크유, 노이즈 제거, 대비 강화, 이진화, 해상도 정규화는 OcrInput에서 단일 메소드 호출로 가능합니다. 이 규칙들은 모든 페이지에 동시에 적용됩니다.
  • NuGet을 통해 125+ 언어: 각 언어는 별도의 NuGet 패키지 (IronOcr.Languages.French 등)로 제공됩니다. 관리할 tessdata 디렉터리가 없으며, 경로 구성도 필요 없습니다.
  • 기본적으로 스레드 안전: IronTesseract 인스턴스는 동시 사용 시 안전합니다. 병렬 처리는 동기화 코드를 필요로 하지 않습니다.
  • 영구 라이선스: $999 Lite / $1,499 Plus / $2,999 Professional / $5,999 Unlimited, 1년 업데이트가 포함된 일회성 구매.

기능 비교

기능 리드툴즈 OCR IronOCR
설정 복잡성 높음 — 4단계 초기화 시퀀스 낮음 — NuGet 패키지 1개
라이선스 배포 모든 기기의 두 파일 (.LIC + .LIC.KEY) 문자열 키, 어디에든 저장
가격 모델 가격 책정을 위해 LEADTOOLS 영업 부서에 연락하십시오. $5,999 일회성 영구
PDF 지원 페이지별 수동 래스터화 네이티브 LoadPdf()
전처리 수동 - 개별 이미지 처리 명령 내장 필터 메서드
엔진 수명 주기 수동 Startup() / Shutdown() 필요 자동, 게으름
NuGet 패키지 다중(Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Pdf) 하나님 (IronOcr)
스레드 안전성 세심한 관리가 필요합니다. 내장형

상세 기능 비교

기능 리드툴즈 OCR IronOCR
라이선스
라이선스 메커니즘 .LIC + .LIC.KEY 파일 쌍 문자열 키
라이선스 배포 모든 생산 장비에 있는 파일 환경 변수 또는 설정
가격 투명성 판매 상담 필요 웹사이트에 게시됨
영구 라이선스 아니요 (연간 유지 보수 필요 없음)
설정 및 설치
NuGet 패키지가 필요합니다. 최소 3~4페이지 (PDF 파일은 더 많이 필요) 1
런타임 파일 필요 예 — OcrRuntime/ 디렉토리 아니요
엔진 초기화 런타임 경로 가이드에 의한 수동 Startup() None
엔진 정지 Shutdown() 전에 수동 Dispose() None
tessdata management 테서랙트 엔진 옵션에 필요합니다. 아니요
OCR 기능
엔진 옵션 LEAD, Tesseract, OmniPage (별도 라이선스 필요) IronTesseract(최적화된 Tesseract 5 LSTM)
언어 60~120 (엔진 종류에 따라 다름) NuGet 통해 125개 이상
언어 배포 tessdata files or engine-bundled NuGet 언어 패키지
신뢰도 점수 page.RecognizeStatus result.Confidence (백분율)
구조화된 출력 페이지, 영역 수준 페이지, 단락, 줄, 단어, 문자
바코드 판독 LEADTOOLS 바코드 모듈 별도 구매 내장 (ReadBarCodes = true)
PDF 처리
PDF 입력 페이지별 래스터화 루프 네이티브 LoadPdf()
비밀번호 PDF Leadtools.Pdf 모듈 필요 (추가 라이선스) 내장 Password 매개변수
검색 가능한 PDF 출력 DocumentWriter 구성 + document.Save() result.SaveAsSearchablePdf()
페이지 범위 선택 수동 루프 경계 LoadPdfPages(path, start, end)
전처리
디스큐 DeskewCommand (수동으로 이미지별) input.Deskew()
노이즈 제거 DespeckleCommand (수동으로 이미지별) input.DeNoise()
이진화 AutoBinarizeCommand (수동으로 이미지별) input.Binarize()
명암 대비 강화 ContrastBrightnessCommand (수동) input.Contrast()
해상도 향상 수동 회색조 + 리샘플링 명령 input.EnhanceResolution(300)
배포
Docker LIC/KEY 파일은 마운트되거나 베이크되어야 합니다. 표준 dotnet publish
Linux 네이티브 종속성으로 지원됩니다. 지원됨, 종속성 포함
에어갭
CI/CD 복잡성 라이선스 파일 및 런타임 경로는 모든 환경에서 사용됩니다. 시크릿 관리자의 라이선스 키

라이선스 아키텍처: 파일 배포 방식 vs. 문자열 키 방식

LEADTOOLS와IronOCR의 라이선스 아키텍처 차이는 단순히 개발자 편의성의 문제만이 아니라 배포 파이프라인, 컨테이너 전략 및 운영 오버헤드에 직접적인 영향을 미칩니다.

LEADTOOLS 접근법

LEADTOOLS는 애플리케이션 시작 시 존재하고 읽을 수 있는 두 개의 물리적 파일을 필요로 합니다. .cs 소스 파일의 코드는 패턴을 확인합니다:

// From leadtools-migration-examples.cs
public void InitializeLicense()
{
    // Option 1: Absolute paths — deployment dependent
    string licPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC";
    string keyPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY";

    // Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC");
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY");

    // Read key file content (not the path — the content)
    string key = File.ReadAllText(keyPath);

    // Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key);

    // Verify license is valid for the module you purchased
    if (!RasterSupport.IsLocked(RasterSupportType.Document))
    {
        throw new InvalidOperationException("Document module not licensed");
    }
}
// From leadtools-migration-examples.cs
public void InitializeLicense()
{
    // Option 1: Absolute paths — deployment dependent
    string licPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC";
    string keyPath = @"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY";

    // Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC");
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY");

    // Read key file content (not the path — the content)
    string key = File.ReadAllText(keyPath);

    // Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key);

    // Verify license is valid for the module you purchased
    if (!RasterSupport.IsLocked(RasterSupportType.Document))
    {
        throw new InvalidOperationException("Document module not licensed");
    }
}
Imports System
Imports System.IO

Public Sub InitializeLicense()
    ' Option 1: Absolute paths — deployment dependent
    Dim licPath As String = "C:\LEADTOOLS\License\LEADTOOLS.LIC"
    Dim keyPath As String = "C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"

    ' Option 2: Relative paths — working directory dependent
    licPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC")
    keyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LEADTOOLS.LIC.KEY")

    ' Read key file content (not the path — the content)
    Dim key As String = File.ReadAllText(keyPath)

    ' Set license — silent failure on some error types
    RasterSupport.SetLicense(licPath, key)

    ' Verify license is valid for the module you purchased
    If Not RasterSupport.IsLocked(RasterSupportType.Document) Then
        Throw New InvalidOperationException("Document module not licensed")
    End If
End Sub
$vbLabelText   $csharpLabel

고장 유형은 다양하며 각각 별도의 해결책이 필요합니다. 경로 해결은 IIS와 콘솔 호스트 간에 다르게 동작합니다. bin/Debug의 상대 경로는 bin/Release 또는 Docker컨테이너의 경로와 일치하지 않으므로 명시적으로 매핑되지 않는 한 그렇습니다. LIC 파일과 KEY 파일은 반드시 동일한 다운로드 경로에서 가져온 것이어야 합니다. 서로 다른 다운로드 경로에서 가져온 파일을 사용하면 "키가 라이선스 파일과 일치하지 않습니다"라는 오류가 발생합니다. 라이선스가 문서 번들만 포함하는 경우, 코드가 Recognition 번들의 기능을 사용하면 IsLocked()가 false를 반환하여 애플리케이션이 시작 시 차이를 처리해야 합니다.

제작 과정에서 흔히 발생하는 오류:

  • "License file not found at specified path" — 경로가 잘못된 디렉토리로 해결됨
  • "License key does not match license file" — 다른 다운로드에서 파일이 다운로드되었거나 전송 중 손상됨
  • "Document module not licensed" — 잘못된 번들을 구입하셨습니다
  • "License has expired" — 평가 라이센스 만료 또는 유지보수 중단

IronOCR접근법

IronOCR 라이선스는 단일 문자열 할당 방식입니다. 파일 없음, 경로 확인 불가, 2단계 검증 불가:

// From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY";

// Production: pull from environment variable
IronOcr.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration["IronOCR:LicenseKey"];
// From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY";

// Production: pull from environment variable
IronOcr.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONOCR_LICENSE");

// Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration["IronOCR:LicenseKey"];
' From application startup — store key using any secrets management pattern
IronOcr.License.LicenseKey = "IRONSUITE.YOUR-LICENSE-KEY"

' Production: pull from environment variable
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")

' Or from ASP.NET configuration
IronOcr.License.LicenseKey = Configuration("IronOCR:LicenseKey")
$vbLabelText   $csharpLabel

키는 Azure Key Vault, AWS Secrets Manager, Kubernetes Secrets 또는 Docker환경 변수에 저장할 수 있습니다. Docker 이미지에 포함할 파일은 없습니다. CI/CD 파이프라인 단계 중 라이선스 아티팩트를 빌드 에이전트로 복사하는 단계는 없습니다. IronOCR 라이선스 페이지에는 영업 담당자와의 통화 없이도 이용 가능한 라이선스 등급이 직접 명시되어 있습니다.

엔진 설정 및 상세 출력

기본 OCR 작업에 대한 LEADTOOLS와IronOCR의 코드 차이는 각 라이브러리의 API 철학을 잘 보여줍니다.

LEADTOOLS 접근법

최소 작업 가능한 LEADTOOLS 구현 (leadtools-vs-ironocr-examples.cs에서 직접 가져옴)은 텍스트가 반환되기 전에 10개의 별개의 작업이 필요합니다:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: License files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Codec layer
        _codecs = new RasterCodecs();

        // Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);          // Step 5: Load via codecs
        using var document = _ocrEngine.DocumentManager     // Step 6: Create document
                                       .CreateDocument();
        var page = document.Pages.AddPage(image, null);     // Step 7: Add page
        page.Recognize(null);                               // Step 8: Explicit recognize
        return page.GetText(-1);                            // Step 9: Extract text
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown();  // Step 10: Shutdown before dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _ocrEngine;
    private RasterCodecs _codecs;

    public LeadtoolsOcrService()
    {
        // Step 1: License files
        RasterSupport.SetLicense(
            @"C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText(@"C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"));

        // Step 2: Codec layer
        _codecs = new RasterCodecs();

        // Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, null, null,
            @"C:\LEADTOOLS\OCR\OcrRuntime");
    }

    public string ExtractText(string imagePath)
    {
        using var image = _codecs.Load(imagePath);          // Step 5: Load via codecs
        using var document = _ocrEngine.DocumentManager     // Step 6: Create document
                                       .CreateDocument();
        var page = document.Pages.AddPage(image, null);     // Step 7: Add page
        page.Recognize(null);                               // Step 8: Explicit recognize
        return page.GetText(-1);                            // Step 9: Extract text
    }

    public void Dispose()
    {
        _ocrEngine?.Shutdown();  // Step 10: Shutdown before dispose
        _ocrEngine?.Dispose();
        _codecs?.Dispose();
    }
}
Imports Leadtools
Imports Leadtools.Ocr
Imports Leadtools.Codecs
Imports System.IO

Public Class LeadtoolsOcrService
    Implements IDisposable

    Private _ocrEngine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        ' Step 1: License files
        RasterSupport.SetLicense(
            "C:\LEADTOOLS\License\LEADTOOLS.LIC",
            File.ReadAllText("C:\LEADTOOLS\License\LEADTOOLS.LIC.KEY"))

        ' Step 2: Codec layer
        _codecs = New RasterCodecs()

        ' Step 3: Engine factory
        _ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)

        ' Step 4: Engine startup (500–2000ms blocking call)
        _ocrEngine.Startup(_codecs, Nothing, Nothing,
            "C:\LEADTOOLS\OCR\OcrRuntime")
    End Sub

    Public Function ExtractText(imagePath As String) As String
        Using image = _codecs.Load(imagePath) ' Step 5: Load via codecs
            Using document = _ocrEngine.DocumentManager ' Step 6: Create document
                                           .CreateDocument()
                Dim page = document.Pages.AddPage(image, Nothing) ' Step 7: Add page
                page.Recognize(Nothing) ' Step 8: Explicit recognize
                Return page.GetText(-1) ' Step 9: Extract text
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        _ocrEngine?.Shutdown() ' Step 10: Shutdown before dispose
        _ocrEngine?.Dispose()
        _codecs?.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

DocumentManager.CreateDocument() / Pages.AddPage() / page.Recognize() / page.GetText() 체인은 축소 불가능합니다. 각 단계는 별도의 API 호출입니다. page.Recognize(null)page.GetText(-1) 전에 생략하면 빈 텍스트가 반환됩니다 — 페이지를 추가한다고 자동으로 인식이 실행되지 않습니다.

IronOCR접근법

동일한 비교 파일에서 가져온IronOCR해당 구현은 핵심 작업에 대해 한 줄이며 수명 주기 관리는 전혀 없습니다.

using IronOcr;

public class OcrService
{
    public string ExtractText(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
using IronOcr;

public class OcrService
{
    public string ExtractText(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
Imports IronOcr

Public Class OcrService
    Public Function ExtractText(imagePath As String) As String
        Return New IronTesseract().Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

생산 사용 시 IronTesseract 인스턴스가 호출 간에 재사용되는 경우:

public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string ExtractText(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string ExtractText(string imagePath)
    {
        return _ocr.Read(imagePath).Text;
    }
}
Imports IronTesseract

Public Class OcrService
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ExtractText(imagePath As String) As String
        Return _ocr.Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

Startup() 없음, Shutdown() 없음, 코덱 레이어 없음, 문서 컨테이너 없음, 명시적 인식 호출 없음. IronTesseract API 참조에는 전체 표면적이 나와 있습니다. 설치 가이드에서는 운영 환경에 맞는 구성 옵션을 다룹니다.

PDF 처리

PDF OCR은 LEADTOOLS의 페이지별 래스터화 모델이 가장 잘 드러나는 분야입니다. LEADTOOLS는 네이티브 PDF 인식 경로를 제공하지 않습니다 — 각 PDF 페이지는 RasterCodecs를 통해 래스터 이미지로 로드된 다음, IOcrDocument에 추가된 다음, 개별적으로 인식되고, 개별적으로 텍스트가 추출되어야 합니다.

LEADTOOLS 접근법

leadtools-pdf-processing.cs부터, 기본 PDF 워크플로우:

public string ExtractTextFromPdf(string pdfPath)
{
    var text = new StringBuilder();

    // Get page count first — separate call
    var pdfInfo = _codecs.GetInformation(pdfPath, true);
    int totalPages = pdfInfo.TotalPages;

    using var document = _ocrEngine.DocumentManager.CreateDocument();

    for (int pageNum = 1; pageNum <= totalPages; pageNum++)
    {
        // Load each page as a raster image — must dispose each
        using var pageImage = _codecs.Load(
            pdfPath,
            0,                            // bitsPerPixel
            CodecsLoadByteOrder.BgrOrGray,
            pageNum,                      // firstPage
            pageNum);                     // lastPage

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
public string ExtractTextFromPdf(string pdfPath)
{
    var text = new StringBuilder();

    // Get page count first — separate call
    var pdfInfo = _codecs.GetInformation(pdfPath, true);
    int totalPages = pdfInfo.TotalPages;

    using var document = _ocrEngine.DocumentManager.CreateDocument();

    for (int pageNum = 1; pageNum <= totalPages; pageNum++)
    {
        // Load each page as a raster image — must dispose each
        using var pageImage = _codecs.Load(
            pdfPath,
            0,                            // bitsPerPixel
            CodecsLoadByteOrder.BgrOrGray,
            pageNum,                      // firstPage
            pageNum);                     // lastPage

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
Imports System.Text

Public Function ExtractTextFromPdf(ByVal pdfPath As String) As String
    Dim text As New StringBuilder()

    ' Get page count first — separate call
    Dim pdfInfo = _codecs.GetInformation(pdfPath, True)
    Dim totalPages As Integer = pdfInfo.TotalPages

    Using document = _ocrEngine.DocumentManager.CreateDocument()

        For pageNum As Integer = 1 To totalPages
            ' Load each page as a raster image — must dispose each
            Using pageImage = _codecs.Load(pdfPath, 0, CodecsLoadByteOrder.BgrOrGray, pageNum, pageNum)
                Dim page = document.Pages.AddPage(pageImage, Nothing)
                page.Recognize(Nothing)
                text.AppendLine(page.GetText(-1))
            End Using
        Next
    End Using

    Return text.ToString()
End Function
$vbLabelText   $csharpLabel

암호로 보호된 PDF 파일을 처리하는 것은 또 다른 종속성을 추가합니다. leadtools-pdf-processing.cs에서:

// Requires Leadtools.Pdf module — additional license
using Leadtools.Pdf;

public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    var pdfFile = new PDFFile(pdfPath);
    pdfFile.Password = password;

    var loadOptions = new CodecsLoadOptions();
    _codecs.Options.Pdf.Load.Password = password;
    // ... same page iteration loop follows
}
// Requires Leadtools.Pdf module — additional license
using Leadtools.Pdf;

public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    var pdfFile = new PDFFile(pdfPath);
    pdfFile.Password = password;

    var loadOptions = new CodecsLoadOptions();
    _codecs.Options.Pdf.Load.Password = password;
    // ... same page iteration loop follows
}
Imports Leadtools.Pdf

Public Function ExtractFromEncryptedPdf(ByVal pdfPath As String, ByVal password As String) As String
    Dim pdfFile As New PDFFile(pdfPath)
    pdfFile.Password = password

    Dim loadOptions As New CodecsLoadOptions()
    _codecs.Options.Pdf.Load.Password = password
    ' ... same page iteration loop follows
End Function
$vbLabelText   $csharpLabel

Leadtools.Pdf 네임스페이스는 별도의 모듈입니다. 개발팀이 OCR 모듈은 구매했지만 PDF 모듈은 구매하지 않은 경우, 별도의 라이선스 구매 없이는 암호화된 PDF 지원 기능을 사용할 수 없습니다.

검색 가능한 PDF 출력을 만들려면 저장하기 전에 DocumentWriter을 구성해야 합니다:

// From leadtools-pdf-processing.cs
var pdfOptions = new PdfDocumentOptions
{
    DocumentType = PdfDocumentType.Pdf,
    ImageOverText = true,
    Linearized = false,
    Title = Path.GetFileNameWithoutExtension(inputPdfPath)
};

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
document.Save(outputPdfPath, DocumentFormat.Pdf, null);
// From leadtools-pdf-processing.cs
var pdfOptions = new PdfDocumentOptions
{
    DocumentType = PdfDocumentType.Pdf,
    ImageOverText = true,
    Linearized = false,
    Title = Path.GetFileNameWithoutExtension(inputPdfPath)
};

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
document.Save(outputPdfPath, DocumentFormat.Pdf, null);
Imports System.IO

Dim pdfOptions As New PdfDocumentOptions With {
    .DocumentType = PdfDocumentType.Pdf,
    .ImageOverText = True,
    .Linearized = False,
    .Title = Path.GetFileNameWithoutExtension(inputPdfPath)
}

_engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions)
document.Save(outputPdfPath, DocumentFormat.Pdf, Nothing)
$vbLabelText   $csharpLabel

IronOCR접근법

IronOCR PDF 파일을 기본적으로 지원합니다. 기본 PDF, 암호로 보호된 PDF, 검색 가능한 PDF 출력 등 세 가지 시나리오 모두 각각 2~3줄로 간소화됩니다.

using IronOcr;

// Basic PDF — all pages, automatic handling
public string ExtractTextFromPdf(string pdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return new IronTesseract().Read(input).Text;
}

// Password-protected PDF — no additional module required
public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return new IronTesseract().Read(input).Text;
}

// 검색 가능한 PDF 출력 — one method call
public void CreateSearchablePdf(string inputPdfPath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(inputPdfPath);
    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
using IronOcr;

// Basic PDF — all pages, automatic handling
public string ExtractTextFromPdf(string pdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath);
    return new IronTesseract().Read(input).Text;
}

// Password-protected PDF — no additional module required
public string ExtractFromEncryptedPdf(string pdfPath, string password)
{
    using var input = new OcrInput();
    input.LoadPdf(pdfPath, Password: password);
    return new IronTesseract().Read(input).Text;
}

// 검색 가능한 PDF 출력 — one method call
public void CreateSearchablePdf(string inputPdfPath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadPdf(inputPdfPath);
    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
Imports IronOcr

' Basic PDF — all pages, automatic handling
Public Function ExtractTextFromPdf(pdfPath As String) As String
    Using input As New OcrInput()
        input.LoadPdf(pdfPath)
        Return New IronTesseract().Read(input).Text
    End Using
End Function

' Password-protected PDF — no additional module required
Public Function ExtractFromEncryptedPdf(pdfPath As String, password As String) As String
    Using input As New OcrInput()
        input.LoadPdf(pdfPath, Password:=password)
        Return New IronTesseract().Read(input).Text
    End Using
End Function

' 검색 가능한 PDF 출력 — one method call
Public Sub CreateSearchablePdf(inputPdfPath As String, outputPdfPath As String)
    Using input As New OcrInput()
        input.LoadPdf(inputPdfPath)
        Dim result = New IronTesseract().Read(input)
        result.SaveAsSearchablePdf(outputPdfPath)
    End Using
End Sub
$vbLabelText   $csharpLabel

PDF 입력 가이드는 페이지 범위 선택, 스트림 입력 및 페이지별 결과 접근 방법을 다룹니다. 검색 가능한 PDF 예시는 전체 출력 워크플로를 보여줍니다. 인식 전에 품질이 낮은 스캔 PDF를 전처리하려면 이미지 품질 보정 가이드를 참조하십시오.

전처리: 수동 명령 vs. 내장 필터

LEADTOOLS는 별도의 Leadtools.ImageProcessing 네임스페이스를 통해 이미지 처리 명령을 제공합니다. 이 명령은 이미지가 OCR 엔진에 전달되기 전에 각 RasterImage 인스턴스에 개별적으로 적용되어야 합니다.

LEADTOOLS 접근법

leadtools-pdf-processing.cs에서, PDF 페이지 전처리:

using Leadtools.ImageProcessing;

public string ProcessLowQualityPdf(string pdfPath)
{
    var text = new StringBuilder();
    var pdfInfo = _codecs.GetInformation(pdfPath, true);

    using var document = _engine.DocumentManager.CreateDocument();

    for (int i = 1; i <= pdfInfo.TotalPages; i++)
    {
        using var pageImage = _codecs.Load(pdfPath, 0,
            CodecsLoadByteOrder.BgrOrGray, i, i);

        // Each command is a separate instantiation and Run() call
        var deskewCommand = new DeskewCommand();
        deskewCommand.Run(pageImage);

        var despeckleCommand = new DespeckleCommand();
        despeckleCommand.Run(pageImage);

        if (pageImage.BitsPerPixel > 8)
        {
            var grayscaleCommand = new GrayscaleCommand(8);
            grayscaleCommand.Run(pageImage);
        }

        var binarizeCommand = new AutoBinarizeCommand();
        binarizeCommand.Run(pageImage);

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
using Leadtools.ImageProcessing;

public string ProcessLowQualityPdf(string pdfPath)
{
    var text = new StringBuilder();
    var pdfInfo = _codecs.GetInformation(pdfPath, true);

    using var document = _engine.DocumentManager.CreateDocument();

    for (int i = 1; i <= pdfInfo.TotalPages; i++)
    {
        using var pageImage = _codecs.Load(pdfPath, 0,
            CodecsLoadByteOrder.BgrOrGray, i, i);

        // Each command is a separate instantiation and Run() call
        var deskewCommand = new DeskewCommand();
        deskewCommand.Run(pageImage);

        var despeckleCommand = new DespeckleCommand();
        despeckleCommand.Run(pageImage);

        if (pageImage.BitsPerPixel > 8)
        {
            var grayscaleCommand = new GrayscaleCommand(8);
            grayscaleCommand.Run(pageImage);
        }

        var binarizeCommand = new AutoBinarizeCommand();
        binarizeCommand.Run(pageImage);

        var page = document.Pages.AddPage(pageImage, null);
        page.Recognize(null);
        text.AppendLine(page.GetText(-1));
    }

    return text.ToString();
}
Imports Leadtools.ImageProcessing
Imports System.Text

Public Function ProcessLowQualityPdf(pdfPath As String) As String
    Dim text As New StringBuilder()
    Dim pdfInfo = _codecs.GetInformation(pdfPath, True)

    Using document = _engine.DocumentManager.CreateDocument()
        For i As Integer = 1 To pdfInfo.TotalPages
            Using pageImage = _codecs.Load(pdfPath, 0, CodecsLoadByteOrder.BgrOrGray, i, i)
                ' Each command is a separate instantiation and Run() call
                Dim deskewCommand As New DeskewCommand()
                deskewCommand.Run(pageImage)

                Dim despeckleCommand As New DespeckleCommand()
                despeckleCommand.Run(pageImage)

                If pageImage.BitsPerPixel > 8 Then
                    Dim grayscaleCommand As New GrayscaleCommand(8)
                    grayscaleCommand.Run(pageImage)
                End If

                Dim binarizeCommand As New AutoBinarizeCommand()
                binarizeCommand.Run(pageImage)

                Dim page = document.Pages.AddPage(pageImage, Nothing)
                page.Recognize(Nothing)
                text.AppendLine(page.GetText(-1))
            End Using
        Next
    End Using

    Return text.ToString()
End Function
$vbLabelText   $csharpLabel

각 전처리 단계는 명령 클래스의 인스턴스를 생성하고 이미지를 대상으로 .Run()를 호출해야 합니다. 개발자는 각 변환의 순서와 적용 가능성을 관리합니다. 이미지가 이미 이진인 경우, AutoBinarizeCommand는 품질을 저하할 수 있습니다. 조건부 BitsPerPixel 체크는 개발자의 책임입니다.

IronOCR접근법

IronOCR 전처리는 OcrInput 객체에 적용되며, 동시에 로드된 모든 페이지에 영향을 미칩니다:

using IronOcr;

public string ProcessLowQualityPdf(string pdfPath)
{
    var ocr = new IronTesseract();

    using var input = new OcrInput();
    input.LoadPdf(pdfPath);

    // Applied to all pages
    input.Deskew();
    input.DeNoise();
    input.Binarize();
    input.Contrast();
    input.EnhanceResolution(300);

    var result = ocr.Read(input);
    Console.WriteLine($"Confidence: {result.Confidence}%");
    return result.Text;
}
using IronOcr;

public string ProcessLowQualityPdf(string pdfPath)
{
    var ocr = new IronTesseract();

    using var input = new OcrInput();
    input.LoadPdf(pdfPath);

    // Applied to all pages
    input.Deskew();
    input.DeNoise();
    input.Binarize();
    input.Contrast();
    input.EnhanceResolution(300);

    var result = ocr.Read(input);
    Console.WriteLine($"Confidence: {result.Confidence}%");
    return result.Text;
}
Imports IronOcr

Public Function ProcessLowQualityPdf(pdfPath As String) As String
    Dim ocr = New IronTesseract()

    Using input As New OcrInput()
        input.LoadPdf(pdfPath)

        ' Applied to all pages
        input.Deskew()
        input.DeNoise()
        input.Binarize()
        input.Contrast()
        input.EnhanceResolution(300)

        Dim result = ocr.Read(input)
        Console.WriteLine($"Confidence: {result.Confidence}%")
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

다섯 개의 전처리 단계는 모든 페이지에 균일하게 적용되며, 페이지별 루프가 없습니다. IronOCR의 자동 전처리도 기본적으로 모든 Read() 호출에서 실행되어, 명시적 필터 호출 없이 일반적인 스캔 문제를 처리합니다. 이미지 필터 튜토리얼에서는 전체 필터 카탈로그를 다룹니다. 저화질 스캔 예시는 까다로운 문서에 대한 전처리 전후의 차이를 보여줍니다.

API 매핑 참조

리드툴 API IronOCR에 상응하는
RasterSupport.SetLicense(licPath, key) IronOcr.License.LicenseKey = "key"
RasterCodecs OcrInput
_codecs.Load(path) input.LoadImage(path) 또는 input.LoadPdf(path)
_codecs.GetInformation(path, true).TotalPages 자동 - 페이지 수 계산 필요 없음
OcrEngineManager.CreateEngine(OcrEngineType.LEAD) new IronTesseract()
engine.Startup(_codecs, null, null, runtimePath) 필요하지 않음
engine.Shutdown() 필요하지 않음
engine.DocumentManager.CreateDocument() 필요하지 않음
document.Pages.AddPage(image, null) input.LoadImage(path)
page.Recognize(null) ocr.Read(input) (인식은 읽기의 일부입니다)
page.GetText(-1) result.Text
page.RecognizeStatus result.Confidence
OcrZoneBounds = new LeadRect(x, y, w, h) new CropRectangle(x, y, w, h)input.LoadImage()에 전달됩니다
OcrZoneType.Text 기본값 — 유형 지정이 필요하지 않습니다.
page.Zones.Add(zone) input.LoadImage(path, cropRect)
DeskewCommand().Run(image) input.Deskew()
DespeckleCommand().Run(image) input.DeNoise()
AutoBinarizeCommand().Run(image) input.Binarize()
PdfDocumentOptions { ImageOverText = true } result.SaveAsSearchablePdf()에서 처리
_engine.DocumentWriterInstance.SetOptions(...) 필요하지 않음
document.Save(path, DocumentFormat.Pdf, null) result.SaveAsSearchablePdf(path)
CodecsLoadByteOrder.BgrOrGray 필수 사항이 아닙니다. 자동으로 처리됩니다.
_codecs.Options.Pdf.Load.Password = password input.LoadPdf(path, Password: password)

팀이 LEADTOOLS OCR에서IronOCR로 전환을 고려할 때

이미지 처리 툴킷이 필요 없는 OCR 전용 프로젝트

LEADTOOLS는 문서 뷰어, 의료 영상, 양식 인식 및 OCR과 같은 여러 모듈이 통합 플랫폼에서 함께 작동해야 하는 팀에게 재정적, 아키텍처적으로 합리적인 선택입니다. 이미지와 PDF에서 텍스트를 추출해야 하는 경우 계산 방식이 달라집니다. LEADTOOLS 라이선스 비용은 견적을 위해 영업 담당자의 참여가 필요합니다 — 현재 가격표는 LEADTOOLS에 문의하십시오. 라이선스 비용 외에도 연간 유지보수가 필요합니다. Professional 계층에서 $2,999의 IronOCR은 10명의 개발자를 지원하며, 지속적인 사용을 위한 갱신 요구사항이 없습니다. LEADTOOLS 갱신 주기가 끝나고 비용을 재평가하는 팀들은 종종 번들 구성품 중에서 OCR 모듈만 사용했다는 사실을 발견합니다.

컨테이너 기반 및 서버리스 배포

LEADTOOLS의 파일 기반 라이선스는 최신 배포 아키텍처에서 주요 마찰 요인이 됩니다. Docker컨테이너에는 두 개의 물리적 라이선스 파일이 필요합니다. 이 파일은 이미지에 내장되어 레이어 기록에 노출되거나, 모든 오케스트레이션 환경에서 볼륨 조정을 통해 런타임에 마운트될 수 있습니다. Azure Functions와 AWS Lambda는 별도의 해결 방법 없이는 라이선스 파일을 배포할 수 있는 명확한 메커니즘이 없습니다. LEADTOOLS는 또한 런타임 파일을 메모리에 로드하는 블로킹 엔진 시작을 실행하여 콜드 스타트 ​​시간에 500~2000ms를 추가합니다. 이는 지연 시간이 사용자 경험에 직접적인 영향을 미치는 서버리스 함수에 있어 중요한 문제입니다.IronOCR표준 NuGet 참조로 배포되고, 환경 변수에서 라이선스 키를 설정하며, 처음 사용할 때 지연 초기화됩니다. Docker 배포 가이드AWS 배포 가이드는 일반적인 컨테이너화 시나리오에 대한 구체적인 내용을 다룹니다.

잘못된 묶음 문제

LEADTOOLS의 모듈 구조는IronOCR없는 문제, 즉 잘못된 등급을 구매하는 문제를 야기합니다. OCR 기능은 모든 LEADTOOLS 번들에 포함되어 있는 것은 아닙니다. 암호로 보호된 PDF를 지원하려면 별도의 PDF 모듈이 필요하며, 이 모듈은 모든 OCR 중심 라이선스에 포함되어 있지 않습니다. 더 높은 정확도를 제공하는 엔진 옵션을 사용하려면 LEADTOOLS 구매 외에 별도의 공급업체 계약이 필요합니다. 구매에 필요한 기능이 포함되어 있다고 생각했던 팀이 실제 운영 환경에서 실행 중에 그렇지 않다는 사실을 발견하게 되면, 해당 기능을 활성화하기 전에 영업팀과 재협상 과정을 거쳐야 합니다.IronOCR라이선스는 각 등급의 모든 기능을 포함합니다. 별도의 PDF 모듈도 없고, 비밀번호로 보호된 문서를 위한 추가 기능도 없으며, 더 높은 정확도의 엔진을 제공하는 다른 공급업체도 없습니다.

유지보수 및 자원 관리의 복잡성

LEADTOOLS의 엔진 수명주기는 단순한 설정 과정이 아니라 지속적인 유지보수 기반을 제공합니다. 엔진은 올바른 순서대로 시동하고, 사용하고, 끄고, 폐기해야 합니다. 해당 순서에서 벗어나면 오류가 발생합니다. LEADTOOLS 배치 처리 구현에서 발생하는 메모리 누수는 일반적으로 제대로 해제되지 않은 중간 이미지 객체, 처리 후 열린 상태로 남아 있는 문서 컨테이너, 또는 적절한 정리 없이 여러 번 생성된 엔진 인스턴스에서 비롯됩니다. 실제 운영 환경에서 사용되는 배치 프로세서는 이러한 문제를 해결하기 위해 문서 청크 사이에 강제 가비지 컬렉션을 호출하는 경우가 많은데, 이는 기본 객체 모델이 런타임과 충돌하고 있음을 시사합니다. 새벽 2시에 문서 처리 서비스의 메모리 증가 문제를 디버깅하는 팀은 종종 LEADTOOLS의 객체 해제 패턴에서 근본 원인을 발견하곤 합니다.IronOCR표준 .NET 해제 범위를 사용합니다. 입력 컨테이너만 명시적으로 해제해야 합니다. 엔진 자체는 상태를 저장하지 않으며 스레드 안전합니다.

다중 환경 배포 일관성

개발, 스테이징 및 프로덕션 환경 모두에서 LEADTOOLS 라이선스 파일이 일관된 경로에 있어야 하며, 애플리케이션이 시작 시 예상하는 정확한 경로에 런타임 디렉터리가 Plus 합니다. 환경 간의 불일치(예: 스테이징 서버의 런타임 디렉터리 경로가 프로덕션 서버와 드라이브 문자 하나만 다른 경우)는 해당 환경에 특정한 오류를 발생시키며, 이를 해결하려면 코드 또는 구성 변경이 필요합니다. IronOCR의 라이선스 키와 단일 NuGet 패키지는 모든 환경에서 동일하게 작동합니다. 라이선스 키는 유일하게 환경별로 구분되는 값이며, 모든 .NET 팀에서 데이터베이스 연결 문자열 및 API 키에 이미 사용하고 있는 것과 동일한 비밀 관리 패턴을 따릅니다.

일반적인 마이그레이션 고려사항

엔진 수명 주기 제거

LEADTOOLS 코드는 엔진의 생명주기를 관리해야 하므로 IDisposable을 구현하는 서비스 클래스에 엔진을 래핑합니다. 이번 마이그레이션으로 해당 요구 사항이 완전히 사라졌습니다.

// LEADTOOLS: Service class required for lifecycle management
public class LeadtoolsService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;

    public LeadtoolsService()
    {
        RasterSupport.SetLicense(licPath, key);
        _codecs = new RasterCodecs();
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);
        _engine.Startup(_codecs, null, null, runtimePath);
    }

    public string Process(string path)
    {
        using var image = _codecs.Load(path);
        using var doc = _engine.DocumentManager.CreateDocument();
        var page = doc.Pages.AddPage(image, null);
        page.Recognize(null);
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _engine?.Shutdown();
        _engine?.Dispose();
        _codecs?.Dispose();
    }
}

// IronOCR: 아니요 lifecycle to manage
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string Process(string path) => _ocr.Read(path).Text;
}
// LEADTOOLS: Service class required for lifecycle management
public class LeadtoolsService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;

    public LeadtoolsService()
    {
        RasterSupport.SetLicense(licPath, key);
        _codecs = new RasterCodecs();
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);
        _engine.Startup(_codecs, null, null, runtimePath);
    }

    public string Process(string path)
    {
        using var image = _codecs.Load(path);
        using var doc = _engine.DocumentManager.CreateDocument();
        var page = doc.Pages.AddPage(image, null);
        page.Recognize(null);
        return page.GetText(-1);
    }

    public void Dispose()
    {
        _engine?.Shutdown();
        _engine?.Dispose();
        _codecs?.Dispose();
    }
}

// IronOCR: 아니요 lifecycle to manage
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public string Process(string path) => _ocr.Read(path).Text;
}
Imports System
Imports Leadtools
Imports Leadtools.Codecs
Imports Leadtools.Ocr

' LEADTOOLS: Service class required for lifecycle management
Public Class LeadtoolsService
    Implements IDisposable

    Private _engine As IOcrEngine
    Private _codecs As RasterCodecs

    Public Sub New()
        RasterSupport.SetLicense(licPath, key)
        _codecs = New RasterCodecs()
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)
        _engine.Startup(_codecs, Nothing, Nothing, runtimePath)
    End Sub

    Public Function Process(path As String) As String
        Using image = _codecs.Load(path)
            Using doc = _engine.DocumentManager.CreateDocument()
                Dim page = doc.Pages.AddPage(image, Nothing)
                page.Recognize(Nothing)
                Return page.GetText(-1)
            End Using
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If _engine IsNot Nothing Then
            _engine.Shutdown()
            _engine.Dispose()
        End If
        If _codecs IsNot Nothing Then
            _codecs.Dispose()
        End If
    End Sub
End Class

' IronOCR: 아니요 lifecycle to manage
Public Class OcrService
    Private ReadOnly _ocr As New IronTesseract()

    Public Function Process(path As String) As String
        Return _ocr.Read(path).Text
    End Function
End Class
$vbLabelText   $csharpLabel

IronTesseract 인스턴스는 스레드 안전하며 싱글톤으로 공유할 수 있습니다. 엔진의 이점을 위해 서비스 클래스에서 IDisposable을 구현할 필요가 없습니다.

영역 기반 OCR 마이그레이션

LEADTOOLS 구역 구성은 OcrZoneLeadRect 경계가 사용되며, 사용자 정의 구역을 추가하기 전에 자동 감지된 구역을 지워야 합니다. IronOCR는 CropRectangleLoadImage()에 직접 전달하여 사용합니다:

// LEADTOOLS zone setup
var zone = new OcrZone
{
    Bounds = new LeadRect(x, y, width, height),
    ZoneType = OcrZoneType.Text,
    CharacterFilters = OcrZoneCharacterFilters.None,
    RecognitionModule = OcrZoneRecognitionModule.Auto
};
page.Zones.Clear();  // Must clear auto-detected zones first
page.Zones.Add(zone);

//IronOCR equivalent
using var input = new OcrInput();
input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
var text = new IronTesseract().Read(input).Text;
// LEADTOOLS zone setup
var zone = new OcrZone
{
    Bounds = new LeadRect(x, y, width, height),
    ZoneType = OcrZoneType.Text,
    CharacterFilters = OcrZoneCharacterFilters.None,
    RecognitionModule = OcrZoneRecognitionModule.Auto
};
page.Zones.Clear();  // Must clear auto-detected zones first
page.Zones.Add(zone);

//IronOCR equivalent
using var input = new OcrInput();
input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
var text = new IronTesseract().Read(input).Text;
Imports Leadtools
Imports IronOcr

' LEADTOOLS zone setup
Dim zone As New OcrZone With {
    .Bounds = New LeadRect(x, y, width, height),
    .ZoneType = OcrZoneType.Text,
    .CharacterFilters = OcrZoneCharacterFilters.None,
    .RecognitionModule = OcrZoneRecognitionModule.Auto
}
page.Zones.Clear() ' Must clear auto-detected zones first
page.Zones.Add(zone)

' IronOCR equivalent
Using input As New OcrInput()
    input.LoadImage(imagePath, New CropRectangle(x, y, width, height))
    Dim text As String = New IronTesseract().Read(input).Text
End Using
$vbLabelText   $csharpLabel

영역 기반 OCR 가이드는 단일 영역 및 다중 영역 추출 패턴을 다룹니다. 지역별 작물 재배 예시는 송장 헤더 추출을 실제 사용 사례로 보여줍니다.

NuGet 패키지 정리

LEADTOOLS를 사용하려면 여러 패키지가 필요합니다. 마이그레이션 과정에서 기존 항목들이 모두 제거되고 하나가 추가됩니다.

# Remove LEADTOOLS packages
dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Pdf

# Add IronOCR
dotnet add package IronOcr
# Remove LEADTOOLS packages
dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Pdf

# Add IronOCR
dotnet add package IronOcr
SHELL

구축에 필요한 공간 감소 효과가 상당합니다. 빌드 출력에서 사라짐: LEADTOOLS.LIC, LEADTOOLS.LIC.KEY, OcrRuntime/ 디렉토리, 여러 LEADTOOLS DLL, 그리고 Tesseract 엔진 옵션의 모든 tessdata/ 폴더. 남은 것은 하나의 패키지 참조뿐입니다. IronOCR NuGet 패키지에는 모든 기본 종속성이 포함되어 있습니다.

신뢰도 점수 접근

LEADTOOLS는 page.RecognizeStatus을 통해 인식 품질을 열거형으로 공개합니다 (OcrPageRecognizeStatus.Done은 완료를 나타내지만 정확성 수준은 아닙니다). IronOCR는 result.Confidence를 통해 직접 백분율을 제공합니다:

var result = new IronTesseract().Read("document.jpg");
Console.WriteLine($"Confidence: {result.Confidence}%");

// Branch on quality threshold
if (result.Confidence < 60)
{
    // Apply additional preprocessing and retry
    using var input = new OcrInput();
    input.LoadImage("document.jpg");
    input.Deskew();
    input.DeNoise();
    input.EnhanceResolution(300);
    result = new IronTesseract().Read(input);
}
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine($"Confidence: {result.Confidence}%");

// Branch on quality threshold
if (result.Confidence < 60)
{
    // Apply additional preprocessing and retry
    using var input = new OcrInput();
    input.LoadImage("document.jpg");
    input.Deskew();
    input.DeNoise();
    input.EnhanceResolution(300);
    result = new IronTesseract().Read(input);
}
Imports System
Imports IronOcr

Dim result = New IronTesseract().Read("document.jpg")
Console.WriteLine($"Confidence: {result.Confidence}%")

' Branch on quality threshold
If result.Confidence < 60 Then
    ' Apply additional preprocessing and retry
    Using input As New OcrInput()
        input.LoadImage("document.jpg")
        input.Deskew()
        input.DeNoise()
        input.EnhanceResolution(300)
        result = New IronTesseract().Read(input)
    End Using
End If
$vbLabelText   $csharpLabel

신뢰도 점수 가이드는 임계값 선택 및 품질 기반 재시도 패턴을 다룹니다.

IronOCR의 추가 기능

위에서 언급한 비교 사항 외에도IronOCR LEADTOOLS OCR에는 없거나 추가 모듈 구매가 필요한 기능이 포함되어 있습니다.

  • OCR 동안 바코드 읽기: ocr.Configuration.ReadBarCodes = true를 설정하고 바코드는 단일 Read() 패스로 텍스트와 함께 추출됩니다. LEADTOOLS 바코드 모듈 라이선스는 별도로 필요하지 않습니다. 바코드 판독 가이드바코드 OCR 예시를 참조하세요.
  • 구조화된 데이터 추출: result.Pages, result.Paragraphs, result.Lines, result.Words, 그리고 result.Characters은 문서 전체 구조를 경계 상자와 요소별 신뢰도 점수와 함께 노출합니다. 읽기 결과 가이드는 전체 출력 모델을 다룹니다.
  • hOCR 내보내기: result.SaveAsHocrFile()는 내포된 위치 데이터가 포함된 HTML을 생성하여 다운스트림 레이아웃 분석을 가능하게 합니다. hOCR 내보내기 가이드를 참조하세요.
  • 125개 이상의 언어 지원: 각 언어는 NuGet 패키지로 제공됩니다. tessdata 디렉터리가 없고, 파일 경로 구성도 없습니다. 전체 언어 목록다국어 가이드를 참조하세요.
  • 비동기 OCR: await ocr.ReadAsync(input)은 ASP.NET 및 백그라운드 서비스에서 비차단 문서 처리를 위해 사용됩니다. 비동기 OCR 가이드를 참조하세요.
  • 특수 문서 인식: 여권, 차량 번호판, MICR 수표 및 필기 인식을 지원합니다. 특수 기능 페이지를 참조하십시오.
  • 진행 상황 추적: ocr.Configuration.ProgressCallback은 지속적으로 실행되는 대량 작업의 페이지별 진행 상황을 보고합니다. 진행 상황 추적 가이드를 참조하세요.

.NET 호환성 및 미래 준비

IronOCR .NET 6, .NET 7, .NET 8, .NET 9 및 .NET Standard 2.0을 대상으로 하며, .NET Standard 2.0은 .NET Framework 4.6.2 이상을 포함합니다. 크로스 플랫폼 지원은 Windows(x86 및 x64), Linuxx64, macOS, Azure App Service, AWS Lambda 및 Docker를 포함하며, 모든 네이티브 종속성은 NuGet 패키지에 포함되어 있습니다. 플랫폼별 구성은 필요하지 않습니다. 이 패키지는 런타임에 올바른 네이티브 바이너리를 선택합니다. LEADTOOLS는 크로스 플랫폼 .NET 배포를 지원하지만, 각 대상 환경에 대해 플랫폼별 런타임 파일과 해당 경로 구성이 필요합니다. Linux컨테이너 또는 macOS 개발 환경과 Windows 프로덕션 서버를 모두 대상으로 하는 팀의 경우, IronOCR의 단일 패키지 배포 방식을 통해 플랫폼별 구성 단계를 없앨 수 있습니다.

결론

LEADTOOLS OCR은 35년간의 개발 역사를 가진 광범위한 이미지 플랫폼 내에 존재하는 성숙한 기술입니다. 문서 뷰어, 의료 이미지 또는 양식 인식 기능을 위해 이미 LEADTOOLS를 표준으로 사용하는 조직의 경우, 기존 투자에 OCR 기능을 추가하는 것은 합리적인 결정입니다. 통합 비용은 이미 지불되었고, 통합 API 인터페이스는 그 자체로 가치가 있기 때문입니다.

이미지와 PDF에서 텍스트를 추출해야 하는 팀의 경우 계산 방식이 다릅니다. LEADTOOLS의 4단계 초기화 시퀀스, 파일 기반 라이선스 배포, 별도의 코덱 계층 및 명확한 엔진 수명 주기는 OCR 정확도나 기능을 제공하는 복잡성이 아닙니다. 이는 팀의 모든 개발자가 이해해야 하고, 모든 배포 환경이 수용해야 하며, 모든 CI/CD 파이프라인이 처리해야 하는 인프라 오버헤드입니다. 잘못된 번들 구매(PDF 모듈이 없는 OCR 모듈 또는 OmniPage 정확도 등급이 없는 LEAD 엔진)는 구매 시점이 아닌 실제 운영 환경에서 드러나는 숨겨진 오류를 발생시킵니다.

IronOCR은 단일 NuGet 패키지, 문자열 기반 라이선스, 그리고 한 줄 인식 경로를 통해 프로덕션 OCR에 중요한 기능(자동 전처리, 네이티브 PDF 지원, 암호로 보호된 문서 처리, 구조화된 출력 추출, 125개 이상의 언어 지원, 스레드 안전 병렬 처리)을 희생하지 않고도 오버헤드를 제거합니다. 가격 차이는 크다 — $2,999 영구 vs. LEADTOOLS의 다년간 라이선스 및 유지보수 비용. 이는 일회성 엔지니어링 도구 구매와 매년 예산 정당화가 필요한 지속적인 구독 간의 차이입니다.

처음에 제기된 문제점, 즉 모든 운영 환경에 라이선스 파일이 존재하고, 번들 구성이 복잡하며, 문자를 읽기 전에 초기화 절차를 거쳐야 한다는 점은 실제 배포 및 운영 비용을 반영합니다. 두 가지 옵션을 모두 검토하는 팀은 최종 결정을 내리기 전에 LEADTOOLS 초기화 시퀀스를 컨테이너 전략, CI/CD 파이프라인 및 시크릿 관리 방식과 비교하여 실행해야 합니다. 그 답은 종종 선택을 명확하게 해준다.

참고해 주세요Kofax OmniPage, LEADTOOLS 및 Tesseract는 각각의 소유주가 등록한 상표입니다. 이 사이트는 Apryse, Google, Kofax 또는 LEAD Technologies와 관련이 없으며, 그들의 인증이나 후원을 받지 않았습니다. 모든 제품명, 로고 및 브랜드는 해당 소유자의 자산입니다. 비교는 정보 제공 목적으로만 사용되며, 작성 시점에 공개적으로 이용 가능한 정보를 반영합니다.

자주 묻는 질문

리드툴즈 OCR이란 무엇인가요?

리드툴즈 OCR은 개발자와 기업이 이미지와 문서에서 텍스트를 추출하는 데 사용하는 OCR 솔루션입니다. 이 솔루션은 .NET 애플리케이션 개발용 IronOCR과 함께 평가된 여러 OCR 옵션 중 하나입니다.

IronOCR은 .NET 개발자용 리드툴즈 OCR과 어떻게 다른가요?

IronOCR은 IronTesseract를 핵심 엔진으로 사용하는 NuGet 네이티브 .NET OCR 라이브러리입니다. LEADTOOLS OCR에 비해 배포가 간편하고(SDK 설치 프로그램 없음), 정액제 요금제를 제공하며, COM 상호 운용이나 클라우드 종속성이 없는 깔끔한 C# API를 제공합니다.

IronOCR이 LEADTOOLS OCR보다 설정이 더 쉬운가요?

IronOCR은 단일 NuGet 패키지를 통해 설치됩니다. SDK 설치 프로그램, 복사할 라이선스 파일, 등록할 COM 구성 요소 또는 관리해야 할 별도의 런타임 바이너리가 없습니다. 전체 OCR 엔진이 패키지에 번들로 제공됩니다.

LEADTOOLS OCR과 IronOCR에는 어떤 정확도 차이가 있나요?

IronOCR은 표준 비즈니스 문서, 송장, 영수증, 스캔 양식에 대해 높은 인식 정확도를 달성합니다. 품질이 많이 저하된 문서나 일반적이지 않은 스크립트의 경우 정확도는 소스 품질에 따라 달라집니다. IronOCR에는 이미지 전처리 필터가 포함되어 있어 저품질 입력에 대한 인식률을 향상시킵니다.

IronOCR은 PDF 텍스트 추출을 지원하나요?

예. IronOCR은 한 번의 호출로 원본 PDF와 스캔한 PDF 이미지 모두에서 텍스트를 추출합니다. 또한 여러 페이지의 TIFF 파일, 이미지, 스트림도 지원합니다. 스캔한 PDF의 경우 OCR은 페이지별 결과 개체를 사용하여 페이지별로 적용됩니다.

LEADTOOLS OCR 라이선싱은 IronOCR과 어떻게 다른가요?

IronOCR은 페이지당 또는 스캔당 요금이 없는 정액제 영구 라이선스를 사용합니다. 대량의 문서를 처리하는 조직은 문서 양에 관계없이 동일한 라이선스 비용을 지불합니다. 자세한 내용과 볼륨 가격은 IronOCR 라이선스 페이지에서 확인할 수 있습니다.

IronOCR 어떤 언어를 지원하나요?

IronOCR은 별도의 NuGet 언어 팩을 통해 127개 언어를 지원합니다. 언어를 추가하려면 '닷넷 추가 패키지 IronOcr.Languages.{Language}' 명령 하나만 있으면 됩니다. 수동으로 파일을 배치하거나 경로를 구성할 필요가 없습니다.

.NET 프로젝트에 IronOCR 설치하는 방법은 무엇인가요?

NuGet을 통해 설치합니다: 패키지 관리자 콘솔에서 '설치-패키지 IronOcr' 또는 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행합니다. 추가 언어 팩도 같은 방법으로 설치됩니다. 기본 SDK 인스톨러가 필요하지 않습니다.

IronOCR은 리드툴즈 OCR과 달리 Docker 및 컨테이너화된 배포에 적합하나요?

예. IronOCR은 NuGet 패키지를 통해 Docker 컨테이너에서 작동합니다. 라이선스 키는 환경 변수를 통해 설정됩니다. OCR 엔진 자체에는 라이선스 파일, SDK 경로 또는 볼륨 마운트가 필요하지 않습니다.

LEADTOOLS OCR과 비교하여 구매하기 전에 IronOCR을 사용해 볼 수 있나요?

예. IronOCR 평가판 모드는 문서를 처리하고 출력물에 워터마크 오버레이가 포함된 OCR 결과를 반환합니다. 라이선스를 구매하기 전에 자신의 문서에서 정확성을 확인할 수 있습니다.

IronOCR은 텍스트 추출과 함께 바코드 판독을 지원하나요?

IronOCR은 텍스트 추출과 OCR에 중점을 둡니다. 바코드 판독을 위해 Iron Software는 동반 라이브러리로 IronBarcode를 제공합니다. 두 가지 모두 개별적으로 또는 Iron Suite 번들의 일부로 사용할 수 있습니다.

LEADTOOLS OCR에서 IronOCR로 쉽게 마이그레이션할 수 있나요?

리드툴즈 OCR에서 IronOCR로의 마이그레이션에는 일반적으로 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리를 제거하며, API 호출을 업데이트하는 작업이 포함됩니다. 대부분의 마이그레이션은 코드 복잡성을 크게 줄여줍니다.

칸나오팟 우돈판트
소프트웨어 엔지니어
카나팟은 소프트웨어 엔지니어가 되기 전 일본 홋카이도 대학교에서 환경 자원학 박사 학위를 취득했습니다. 학위 과정 중에는 생물생산공학과 소속 차량 로봇 연구실에서 활동하기도 했습니다. 2022년에는 C# 기술을 활용하여 Iron Software의 엔지니어링 팀에 합류했고, 현재 IronPDF 개발에 집중하고 있습니다. 카나팟은 IronPDF에 사용되는 대부분의 코드를 직접 작성하는 개발자로부터 배울 수 있다는 점에 만족하며, 동료들과의 소통을 통해 배우는 것 외에도 Iron Software에서 일하는 즐거움을 누리고 있습니다. 코딩이나 문서 작업을 하지 않을 때는 주로 PS5로 게임을 하거나 The Last of Us를 다시 시청하는 것을 즐깁니다.

아이언 서포트 팀

저희는 주 5일, 24시간 온라인으로 운영합니다.
채팅
이메일
전화해