IRONSOFTWAREHOME
동영상

TesseractOcrMaui에서 IronOCR로 마이그레이션하기

칸나오팟 우돈판트
Kannapat Udonpant
Updated: 2026년 8월 1일

이 가이드는 TesseractOcrMaui에서 IronOCR로의 완전한 마이그레이션 과정을 단계별로 안내하며, 각 단계마다 실제 적용 전후 코드 예제를 제공합니다. 이 가이드는 이미 MAUI 플랫폼의 제약을 벗어나기로 결정했으며, 모바일 앱, 서버 측 API, 백그라운드 워커, 클라우드 함수에서 동일하게 실행되는 라이브러리로 전환하기 위한 체계적인 경로가 필요한 개발자를 대상으로 합니다. 비교 기사를 미리 읽을 필요는 없습니다.

TesseractOcrMaui에서 마이그레이션해야 하는 이유

TesseractOcrMaui는 실제적인 공백을 메우기 위해 개발되었습니다. 기존의 .NET Tesseract 래퍼들은 모바일 플랫폼과의 상호 운용성 문제를 자체적으로 해결할 수 없었기 때문입니다. 서버 자원이 전혀 필요 없는 순수 MAUI 프로토타입의 경우, 이 도구는 그 공백을 메워줍니다. 하지만 제품이 그 좁은 범위를 벗어나 성장하는 순간 문제가 드러납니다.

MAUI 전용 타겟 프레임워크가 코드 공유를 방지합니다. TesseractOcrMaui는 net8.0-ios, net8.0-androidnet8.0-windows에 대한 타겟을 제공합니다 — 모두 MAUI 플랫폼 이름입니다. 패키지에는 net8.0, netstandard2.1가 없으며, 서버 호환 타겟이 없습니다. 클래스 라이브러리, ASP.NET Core프로젝트 또는 Azure Function에서 이를 참조하면 컴파일 오류가 발생합니다. 대안은 없습니다. 이 패키지는 아키텍처상 MAUI 호스트 외부에서는 실행될 수 없습니다. MAUI 환경이 아닌 곳에서 OCR 기능이 필요할 때마다, 별도의 라이브러리를 도입하여 병행 관리해야 합니다.

필수 MAUI 종속성 주입 연결. AddTesseractOcr() 호출은 MauiProgram.cs에서 ITesseract을 MAUI 서비스 공급자에 연결합니다. DI 그래프 외부에는 팩토리 메서드, 정적 진입점, 생성자가 없습니다. 이는 OCR 로직을 휴대용 클래스 라이브러리로 추출할 수 없음을 의미합니다. 생성자에서 ITesseract을 취하는 모든 클래스는 전체 수명 동안 MAUI 애플리케이션 호스트에 고정됩니다.

어떤 단계에서도 PDF 입력은 허용되지 않습니다. PDF 문서는 스캔된 계약서, 청구서 및 신분증의 가장 일반적인 형식입니다. TesseractOcrMaui는 모든 PDF 입력에서 NotSupportedException을 발생시킵니다. PDF를 처리하려면 별도의 PDF 렌더링 라이브러리를 추가하고, 페이지별 이미지 추출 코드를 작성하며, 장치 캐시 내의 임시 파일을 관리하고, 호출 후 매번 해당 파일을 정리해야 합니다. 단 하나의 OCR 호출이 실행되기 전까지 100줄 이상의 인프라 코드가 필요하며, 여전히 MAUI에서만 작동합니다.

실제 이미지에 대한 내장 전처리 기능이 없습니다. 모바일 카메라로 촬영된 이미지는 회전, 센서 노이즈, 기기 모델 간 DPI 불일치 등의 문제가 있습니다. TesseractOcrMaui는 사전 처리 과정 없이 이미지를 Tesseract 엔진으로 직접 전달합니다. 더 높은 정확도가 필요한 팀은 SkiaSharp 또는 ImageSharp를 추가하고, 기울기 보정 및 노이즈 제거 알고리즘을 수동으로 구현하며, 임시 파일 관리 기능을 작성하고, iOS 및 Android 기기 변형 전반에 걸쳐 모든 기능을 테스트해야 합니다. 대부분은 건너뜁니다. 그 결과 실제 모바일 화면 캡처의 정확도가 떨어집니다.

프로덕션 의존성에 대한 단일 개발자 유지 관리 위험. TesseractOcrMaui는 한 명의 개발자가 유지 관리하고 있습니다. 이 프로젝트에는 운영 주체가 없으며, SLA(서비스 수준 계약), 보안 패치 제공 약속, GitHub 이슈 외의 에스컬레이션 경로도 없습니다. 금융, 의료, 법률 등 규제 산업 분야의 실제 운영 애플리케이션에 있어, 총 NuGet 다운로드 수가 약 33,900건에 불과한 자원봉사자가 관리하는 라이브러리는 허용 가능한 종속성이 아닙니다.

근본적인 문제

TesseractOcrMaui는 MAUI 프로젝트 내에서만 컴파일됩니다. 다른 유형의 프로젝트에서 OCR이 필요해지는 순간, 아키텍처는 무너집니다:

// TesseractOcrMaui: wired to MAUI host — cannot escape to a shared library
// This code compiles only inside a .NET MAUI application
public class OcrService
{
    private readonly ITesseract _tesseract; // resolved from MAUI DI — no other source exists

    public OcrService(ITesseract tesseract) { _tesseract = tesseract; }

    public async Task<string> ReadAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng"); // traineddata must be bundled as MauiAsset
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Cannot reference this class from ASP.NET Core, Azure Functions, or Docker
}
C#
// IronOCR: plain instantiable class — compiles in any .NET project type
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract(); // no DI, no MAUI host

    public string Read(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
    // Place this in a netstandard2.1 library — reference from MAUI, API, and Functions together
}
C#

##IronOCR대 TesseractOcrMaui: 기능 비교

아래 표는 이번 마이그레이션을 검토하는 팀에 관련된 기능상의 차이점을 다루고 있습니다.

기능테서랙트오크르MAUIIronOCR
.NET MAUI(iOS)네 (IronOcr.iOS)
.NET MAUI (안드로이드)네 (IronOcr.Android)
.NET MAUI(Windows)
ASP.NET Core아니요
Azure Functions아니요
AWS 람다아니요
Docker / Linux 컨테이너아니요
콘솔 애플리케이션아니요
WPF / WinForms아니요
공유되는 .NET 클래스 라이브러리아니요
PDF 입력(기본)아니요
비밀번호로 보호된 PDF 입력아니요
스트림 입력아니요
바이트 배열 입력아니요
여러 페이지로 구성된 TIFF 입력아니요
검색 가능한 PDF 출력아니요
hOCR 내보내기아니요
자동 기울기 보정아니요
자동 노이즈 제거아니요
명암 대비 강화아니요
이진화아니요
영역 기반 OCR아니요
OCR 중 바코드 판독아니요
단어 수준 좌표아니요
다국어 동시아니요
지원되는 언어수동으로 번들링된 훈련 데이터NuGet 패키지를 통해 125개 이상
나사 안전수동내장형
상업적 지원없음 (단일 개발자)예 (Iron Software)
라이센스Apache 2.0 (무료)$999에서 영구적으로
NuGet 다운로드약 33,900530만+

빠른 시작: TesseractOcrMaui에서 IronOCR로의 마이그레이션

1단계: NuGet 패키지 교체

MAUI 프로젝트에서 테서랙트오크르MAUI 제거:

dotnet remove package TesseractOcrMaui
SHELL

IronOCR을 설치하십시오. MAUI 프로젝트의 경우, 핵심 패키지와 함께 플랫폼별 패키지를 추가하십시오:

dotnet add package IronOcr, IronOcr.Android, IronOcr.iOS

서버 측 프로젝트(ASP.NET Core, Azure Functions, 콘솔)의 경우:

dotnet add package IronOcr

IronOCR NuGet 패키지 페이지에는 사용 가능한 모든 플랫폼 패키지가 나열되어 있습니다.

단계 2: 네임스페이스 업데이트

TesseractOcrMaui 네임스페이스를IronOCR네임스페이스로 교체하십시오:

// Before (TesseractOcrMaui)
using TesseractOcrMaui;
using TesseractOcrMaui.Results;
using Microsoft.Maui.Storage;

// After (IronOCR)
using IronOcr;
C#

단계 3: 라이선스 초기화

애플리케이션 시작 시 라이선스 초기화 추가. MAUI 앱에서는 MauiProgram.cs에 추가합니다; ASP.NET Core에서는 Program.cs에 추가합니다:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

코드 마이그레이션 예제

MAUI 의존성 주입 등록 교체

TesseractOCRMaui를 사용하려면 MAUI 서비스 제공자를 통해 OCR 엔진을 등록해야 합니다. 해당 등록을 제거하는 것이 첫 번째 아키텍처 단계입니다. 이는 이후의 모든 OCR 코드를 MAUI 호스트에 고정시키는 요소이기 때문입니다.

TesseractOcrMaui 접근 방식:

// MauiProgram.cs — OCR engine registered here; nowhere else resolves it
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // Binds OCR to MAUI DI — no standalone path exists after this
        builder.Services.AddTesseractOcr();

        return builder.Build();
    }
}

// Any class that needs OCR must receive ITesseract from the MAUI container
public class InvoicePageViewModel
{
    private readonly ITesseract _tesseract;

    public InvoicePageViewModel(ITesseract tesseract)
    {
        _tesseract = tesseract; // fails to construct outside MAUI host
    }

    public async Task<string> ScanInvoiceAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.RecognizedText ?? string.Empty;
    }
}
C#

IronOCR 접근 방식:

// MauiProgram.cs — license only; no DI registration needed
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // One-line initialization — works for all project types
        IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

        return builder.Build();
    }
}

// 아니요 constructor injection needed — IronTesseract instantiates directly
public class InvoicePageViewModel
{
    public string ScanInvoice(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}
C#

AddTesseractOcr() 제거하면 MAUI DI 연결이 제거됩니다. IronTesseract 클래스는 공공 매개변수 없는 생성자를 가지고 있으며 플랫폼 종속성이 없습니다 — 어디서나 인스턴스화할 수 있습니다. 엔진 모드 및 언어 구성 등 초기화 옵션에 대해서는 IronTesseract 설정 가이드를 참조하십시오.

OCR 로직을 공유 클래스 라이브러리로 이동

TesseractOcrMaui를 사용하면 프로젝트 유형 간에 OCR 로직을 공유하는 것이 구조적으로 불가능합니다. IronOCR를 사용하면 마이그레이션 경로가 간단합니다: 서비스를 .NET Standard 2.1 또는 net8.0 클래스 라이브러리로 추출하고 솔루션의 모든 프로젝트에서 참조합니다.

TesseractOcrMaui 접근 방식:

// This service CANNOT be extracted to a shared library.
// It compiles only in a project that references TesseractOcrMaui,
// which only has MAUI platform targets.
//
// Result: every non-MAUI project must use a different OCR library,
// duplicating language config, error handling, and accuracy tuning.

public class DocumentOcrService
{
    private readonly ITesseract _tesseract; // MAUI DI only

    public DocumentOcrService(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessDocumentAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Server team writes their own version using a different library
    // Two codebases, two accuracy profiles, two maintenance tracks
}
C#

IronOCR 접근 방식:

// Place this in: MyCompany.OcrCore (net8.0 or netstandard2.1 class library)
// Reference from: MyCompany.MauiApp, MyCompany.Api, MyCompany.BatchWorker

using IronOcr;

namespace MyCompany.OcrCore
{
    public class DocumentOcrService
    {
        private readonly IronTesseract _ocr;

        public DocumentOcrService()
        {
            _ocr = new IronTesseract();
        }

        public string ProcessDocument(string imagePath)
        {
            using var input = new OcrInput();
            input.LoadImage(imagePath);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromBytes(byte[] imageData)
        {
            using var input = new OcrInput();
            input.LoadImage(imageData);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromStream(Stream imageStream)
        {
            using var input = new OcrInput();
            input.LoadImage(imageStream);
            return _ocr.Read(input).Text;
        }
    }
}
C#

하나의 클래스 라이브러리, 하나의 테스트 세트, 하나의 정확성 프로파일. MAUI 앱은 ProcessDocument(photoPath)을 호출하고, ASP.NET CoreAPI는 ProcessDocumentFromBytes(uploadedBytes)을 호출하며, Azure Function은 ProcessDocumentFromStream(blobStream)을 호출합니다 — 모두 동일한 구현을 지원합니다. 스트림 입력 가이드이미지 입력 가이드는 모든 OcrInput 로딩 변수를 문서화합니다.

ASP.NET Core에서 서버 측 OCR 활성화

TesseractOcrMaui는 .NET Core 프로젝트에서 참조할 수 없습니다. 문서 업로드 엔드포인트를 추가하는 팀은 완전히 다른 라이브러리를 사용해야만 합니다. IronOCR은 라이선스 키 외에는 별도의 구성 변경 없이 ASP.NET Core에서 실행됩니다.

TesseractOcrMaui 접근 방식:

// ASP.NET CoreWeb API — 테서랙트오크르MAUI CANNOT be used here.
// The package has no net8.0 or netstandard target.
// Referencing it produces: "The given project does not support targeting net8.0-ios/android/windows."
//
// Team is forced to add a second OCR library — Tesseract charlesw wrapper,
// a cloud API, or another solution — creating a split codebase.

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    // Cannot inject ITesseract here — no MAUI host, no MAUI DI container
    // Must use a completely different OCR library for server-side processing
}
C#

IronOCR 접근 방식:

// ASP.NET Core—IronOCR works without modification
using IronOcr;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    [HttpPost("extract-text")]
    public async Task<IActionResult> ExtractText(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file uploaded.");

        var ocr = new IronTesseract();
        using var input = new OcrInput();

        // Load directly from the upload stream — no temp files
        using var stream = file.OpenReadStream();

        if (file.ContentType == "application/pdf")
            input.LoadPdf(stream);
        else
            input.LoadImage(stream);

        input.Deskew();
        input.DeNoise();

        var result = ocr.Read(input);

        return Ok(new
        {
            text = result.Text,
            confidence = result.Confidence,
            pageCount = result.Pages.Count()
        });
    }

    [HttpPost("extract-text-batch")]
    public async Task<IActionResult> ExtractTextBatch(List<IFormFile> files)
    {
        var results = new List<object>();

        // Thread-safe: create one IronTesseract per thread
        await Parallel.ForEachAsync(files, async (file, ct) =>
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();
            using var stream = file.OpenReadStream();
            input.LoadImage(stream);
            var result = ocr.Read(input);

            lock (results)
            {
                results.Add(new { file = file.FileName, text = result.Text });
            }
        });

        return Ok(results);
    }
}
C#

동일한 코드를 IIS, Kestrel 또는 Linux Docker 컨테이너에 변경 없이 배포할 수 있습니다. ASP.NET OCR 가이드에는 미들웨어 구성이 설명되어 있으며, Docker 배포 가이드에는 Linux 컨테이너 설정 방법이 기술되어 있습니다.

플랫폼별 핸들러 코드 제거

TesseractOcrMaui의 MAUI 전용 아키텍처로 인해 개발자는 OCR을 다중 대상 솔루션에 통합하려고 할 때 플랫폼 조건부 코드를 작성해야 합니다. IronOCR은 동일한 패키지가 모든 대상에서 올바르게 해결되므로 플랫폼 조건문을 사용할 필요가 없습니다.

TesseractOcrMaui 접근 방식:

// Attempting to share OCR logic across MAUI and non-MAUI targets
// requires platform-conditional compilation — a maintenance hazard

#if ANDROID || IOS || WINDOWS
// Only compile this block in MAUI targets
// Non-MAUI targets cannot reference 테서랙트오크르MAUI at all
using TesseractOcrMaui;

public class PlatformOcrHandler
{
    private readonly ITesseract _tesseract;

    public PlatformOcrHandler(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var r = await _tesseract.RecognizeTextAsync(imagePath);
        return r.RecognizedText ?? string.Empty;
    }
}
#else
// Server targets need a completely different implementation
public class PlatformOcrHandler
{
    public string ProcessAsync(string imagePath)
    {
        // Duplicate logic using a different library
        throw new PlatformNotSupportedException("Use server OCR library here");
    }
}
#endif
C#

IronOCR 접근 방식:

// One implementation — no conditional compilation, no duplicate logic
using IronOcr;

public class PlatformOcrHandler
{
    // This class compiles identically for:
    // net8.0-android, net8.0-ios, net8.0-windows (MAUI targets)
    // net8.0 (server targets)
    // netstandard2.1 (shared library targets)

    public string Process(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();
        return ocr.Read(input).Text;
    }
}

// Multi-target .csproj — no conditional package references needed
// <TargetFrameworks>net8.0;net8.0-android;net8.0-ios</TargetFrameworks>
// IronOcr resolves correctly for all three targets from one package reference
C#

OCR 처리 코드의 플랫폼 조건문은 시간이 지남에 따라 누적되는 아키텍처 분할을 나타냅니다. 모든 언어 구성 변경, 모든 전처리 조정, 모든 신뢰도 임계값 조정은 두 브랜치 모두에 적용되어야 합니다. IronOCR을 사용하면 분할할 필요가 없습니다. .NET OCR 라이브러리 개요에서는 다중 대상 프로젝트 구조를 상세히 다룹니다.

단어 좌표를 이용한 구조화된 데이터 추출

TesseractOcrMaui는 오직 result.RecognizedText와 최상위 신뢰도 점수만을 노출합니다. 폼 필드 유효성 검사, 문서 파싱 또는 하이라이트 오버레이에 필요한 개별 WORD의 바운딩 박스 추출은 불가능합니다. IronOCR은 페이지, 단락, 줄, 단어, 문자 등 픽셀 좌표가 포함된 완전한 문서 객체 모델을 제공합니다.

TesseractOcrMaui 접근 방식:

// TesseractOcrMaui: flat text string only — no structure, no coordinates
public class TesseractMauiFormParser
{
    private readonly ITesseract _tesseract;

    public TesseractMauiFormParser(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<Dictionary<string, string>> ParseFormAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);

        // result.RecognizedText is one flat string — no field positions
        // Parsing requires fragile line-splitting and regex heuristics
        var fields = new Dictionary<string, string>();
        var lines = result.RecognizedText?.Split('\n') ?? Array.Empty<string>();

        foreach (var line in lines)
        {
            // Hope the layout stays consistent enough to parse
            var parts = line.Split(':');
            if (parts.Length == 2)
                fields[parts[0].Trim()] = parts[1].Trim();
        }

        return fields;
        // 아니요 way to validate against expected field positions
        // 아니요 confidence per word — only document-level confidence
    }
}
C#

IronOCR 접근 방식:

// IronOCR: full document structure with bounding boxes per word
using IronOcr;

public class IronOcrFormParser
{
    public List<WordLocation> ExtractWordsWithPositions(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);

        var result = ocr.Read(input);
        var wordLocations = new List<WordLocation>();

        foreach (var page in result.Pages)
        {
            foreach (var word in page.Words)
            {
                wordLocations.Add(new WordLocation
                {
                    Text = word.Text,
                    Confidence = word.Confidence,
                    X = word.X,
                    Y = word.Y,
                    Width = word.Width,
                    Height = word.Height
                });
            }
        }

        return wordLocations;
    }

    public FormData ParseStructuredForm(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();

        var result = ocr.Read(input);
        var form = new FormData();

        foreach (var page in result.Pages)
        {
            foreach (var paragraph in page.Paragraphs)
            {
                // Use Y coordinate to identify form regions
                if (paragraph.Y < 200)
                    form.HeaderText += paragraph.Text + " ";
                else if (paragraph.Y > 800)
                    form.FooterText += paragraph.Text + " ";
                else
                    form.BodyLines.Add(paragraph.Text);
            }
        }

        form.OverallConfidence = result.Confidence;
        return form;
    }
}

public class WordLocation
{
    public string Text { get; set; }
    public float Confidence { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}

public class FormData
{
    public string HeaderText { get; set; } = string.Empty;
    public string FooterText { get; set; } = string.Empty;
    public List<string> BodyLines { get; set; } = new();
    public float OverallConfidence { get; set; }
}
C#

WORD 좌표는 알려진 양식 템플릿에 대한 검증, 수동 검토를 위한 신뢰도 기반 표시, 문서 뷰어 UI에서의 강조 표시 오버레이를 가능하게 합니다. 구조화된 결과 가이드는 문자 수준 접근과 포함 단어당 신뢰도 필터링 패턴을 포함한 전체 OcrResult 개체 모델을 문서화합니다.

네이티브 비동기 및 진행 상황 추적을 활용한 백그라운드 처리

TesseractOcrMaui는 비동기 API(RecognizeTextAsync)를 노출하지만 오직 MAUI 애플리케이션 컨텍스트 내에서만 작동합니다. 장시간 실행되는 배치 작업은 백그라운드 서비스, Azure Function 또는 작업자 프로세스에서 실행되어야 하며, TesseractOcrMaui는 이 중 어느 것도 대상으로 할 수 없습니다. IronOCR은 모든 호스팅 서비스에서 작동하는 네이티브 비동기 지원을 제공합니다.

TesseractOcrMaui 접근 방식:

// Background processing is impossible with TesseractOcrMaui.
// IHostedService runs in a server context — 테서랙트오크르MAUI has no server target.
// The MAUI async API exists, but there is nowhere to run it outside the MAUI app host.

public class DocumentBatchWorker : BackgroundService
{
    // ITesseract cannot be injected here — no MAUI DI in a hosted service
    // Attempting to reference 테서랙트오크르MAUI will fail to compile:
    // error: Package 테서랙트오크르MAUI does not support target net8.0
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        throw new PlatformNotSupportedException(
            "TesseractOcrMaui has no server target. Use a different OCR library.");
    }
}
C#

IronOCR 접근 방식:

// IronOCR: hosted service background batch processor
using IronOcr;
using Microsoft.Extensions.Hosting;

public class DocumentBatchWorker : BackgroundService
{
    private readonly ILogger<DocumentBatchWorker> _logger;
    private readonly string _inputFolder;
    private readonly string _outputFolder;

    public DocumentBatchWorker(ILogger<DocumentBatchWorker> logger, IConfiguration config)
    {
        _logger = logger;
        _inputFolder = config["Ocr:InputFolder"];
        _outputFolder = config["Ocr:OutputFolder"];
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var pendingFiles = Directory.GetFiles(_inputFolder, "*.pdf")
                .Concat(Directory.GetFiles(_inputFolder, "*.jpg"))
                .ToList();

            if (pendingFiles.Count > 0)
            {
                _logger.LogInformation("Processing {Count} documents.", pendingFiles.Count);

                // Thread-safe parallel processing — one IronTesseract per thread
                await Parallel.ForEachAsync(pendingFiles,
                    new ParallelOptions { MaxDegreeOfParallelism = 4, CancellationToken = stoppingToken },
                    async (filePath, ct) =>
                    {
                        await ProcessDocumentAsync(filePath, ct);
                    });
            }

            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
        }
    }

    private async Task ProcessDocumentAsync(string filePath, CancellationToken ct)
    {
        try
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();

            if (Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
                input.LoadPdf(filePath);
            else
                input.LoadImage(filePath);

            input.Deskew();
            input.DeNoise();

            var result = await Task.Run(() => ocr.Read(input), ct);

            // Produce searchable PDF from the same OCR pass
            var outputPath = Path.Combine(_outputFolder,
                Path.GetFileNameWithoutExtension(filePath) + "_searchable.pdf");
            result.SaveAsSearchablePdf(outputPath);

            File.Delete(filePath); // move from input queue
            _logger.LogInformation("Processed {File}: {Confidence:F1}% confidence.", filePath, result.Confidence);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process {File}.", filePath);
        }
    }
}
C#

워커는 Program.cs에서 builder.Services.AddHostedService<DocumentBatchWorker>()와 함께 등록되며, Windows 서비스, Linux systemd 유닛, Docker 컨테이너, Azure 컨테이너 앱 같은 .NET 8 호스트에서 실행됩니다. 비동기 OCR 가이드는 비동기 패턴을 다루며, 검색 가능한 PDF 가이드SaveAsSearchablePdf 출력 옵션을 문서화합니다.

테서랙트오크르MAUI API에서 IronOCR로의 매핑 참조

테서랙트오크르MAUIIronOCR에 상응하는
dotnet add package TesseractOcrMauidotnet add package IronOcr
builder.Services.AddTesseractOcr()전체 삭제 — 등록 불필요
ITesseract (주입됨)new IronTesseract() (직접 인스턴스화)
_tesseract.InitAsync("eng")ocr.Language = OcrLanguage.English; (또는 기본 영어 생략)
_tesseract.RecognizeTextAsync(imagePath)ocr.Read(input)
result.RecognizedTextresult.Text
result.Success예외 기반; 부울 플래그 없음
result.Statuscatch (Exception ex) 메시지
result.Confidenceresult.Confidence (또한 단어당)
TesseractOcrMaui.Results.RecognitionResultIronOcr.OcrResult
<MauiAsset> 훈련 데이터 번들dotnet add package IronOcr.Languages.French
Resources/Raw/tessdata/eng.traineddata제거 — 언어 데이터는 NuGet 패키지 내에 있습니다
FileSystem.OpenAppPackageFileAsync() (훈련 데이터용)제거 — 필요 없음
PDF를 지원하지 않습니다.input.LoadPdf(path) 또는 input.LoadPdf(stream)
전처리 없음input.Deskew(), input.DeNoise(), input.Binarize(), input.Contrast()
검색 가능한 PDF 출력 없음result.SaveAsSearchablePdf(outputPath)
WORD 간 간격 없음result.Pages[0].Words[i].X, .Y, .Width, .Height
단어별 신뢰도 없음result.Pages[0].Words[i].Confidence
net8.0-ios 목표만net8.0 + IronOcr.iOS 패키지
net8.0-android 목표만net8.0 + IronOcr.Android 패키지

일반적인 마이그레이션 문제와 해결책

이슈 1: AddTesseractOcr은 종속 클래스를 손상시키지 않고는 제거할 수 없습니다

TesseractOcrMaui: OCR를 수행하는 모든 클래스는 생성자 주입을 통해 ITesseract을 받습니다. AddTesseractOcr()을 제거하면 DI 해결 예외와 함께 즉시 이러한 생성자들이 깨집니다.

해결책: 생성자 매개변수를 제거하고 직접 IronTesseract 인스턴스화로 교체합니다. 프로젝트에서 DI 컨테이너를 사용하고 주입 가능한 패턴을 유지하고 싶다면, IronTesseract을 수동으로 등록합니다:

// Option A: Direct instantiation (recommended for most cases)
public class ScanPageViewModel
{
    public string ScanDocument(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}

// Option B: Register IronTesseract in DI if your architecture requires it
// In MauiProgram.cs or Program.cs:
builder.Services.AddSingleton<IronTesseract>();

// Then inject normally:
public class ScanPageViewModel
{
    private readonly IronTesseract _ocr;
    public ScanPageViewModel(IronTesseract ocr) { _ocr = ocr; }

    public string ScanDocument(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
}
C#

문제 2: 패키지 제거 후 훈련 데이터 파일 누락

TesseractOcrMaui: Resources/Raw/tessdata/ 폴더, 그 안의 .traineddata 파일, 그리고 .csproj에 있는 <MauiAsset> 선언들을 모두 제거해야 합니다. 이들을 제거하지 않으면 빌드 경고가 발생하고 사용되지 않는 파일들로 인해 앱 번들 크기가 불필요하게 커집니다.

해결책: tessdata 폴더를 삭제하고, <MauiAsset> 항목을 제거하며 수동으로 다운로드한 각 언어를 제거합니다. 대신 해당IronOCR언어 팩을 설치하십시오:

# Delete traineddata assets
rm -rf Resources/Raw/tessdata

# Remove from .csproj (delete the MauiAsset ItemGroup):
# <ItemGroup>
#   <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />
# </ItemGroup>

# InstallIronOCR language pack (if non-English language was needed)
dotnet add package IronOcr.Languages.French
dotnet add package IronOcr.Languages.German
SHELL

IronOCR의 언어 패키지는 빌드 시점에 자동으로 해결되며, 별도의 수동 파일 관리 없이 번들로 제공됩니다. 다국어 가이드에는 사용 가능한 모든 패키지와 동시 다국어 구성이 상세히 설명되어 있습니다.

문제 3: RecognizeTextAsync를 호출하기 전에 반드시 InitAsync를 호출해야 합니다

TesseractOcrMaui: 모든 RecognizeTextAsync 호출 전에는 ITesseract.InitAsync(language) 호출이 있어야 합니다. 팀은 종종 _isInitialized 가드 플래그, 이중 체크 잠금 또는 세마포어를 추가하여 반복 초기화를 피합니다. 마이그레이션 후에는 해당 코드 전체가 사멸 코드가 됩니다.

해결책: IronTesseract에는 초기화 단계가 없습니다. 언어 설정은 인스턴스에서 한 번만 설정됩니다. 모든 InitAsync 호출, 모든 _isInitialized 플래그 및 모든 초기화 가드 로직을 제거합니다.

// Before: initialization guard required before every OCR call
private bool _isInitialized = false;
private readonly SemaphoreSlim _initLock = new SemaphoreSlim(1, 1);

public async Task<string> GetTextAsync(string imagePath)
{
    await _initLock.WaitAsync();
    try
    {
        if (!_isInitialized)
        {
            await _tesseract.InitAsync("eng");
            _isInitialized = true;
        }
    }
    finally { _initLock.Release(); }

    var result = await _tesseract.RecognizeTextAsync(imagePath);
    return result.RecognizedText ?? string.Empty;
}

// After: no initialization, no guard, no semaphore
public string GetText(string imagePath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    return ocr.Read(input).Text;
}
C#

문제 4: result.Success 확인 패턴을 반드시 교체해야 함

TesseractOcrMaui: RecognizeTextAsync 반환값에는 Success 부울과 Status 문자열이 포함됩니다. if (!result.Success)을 검사하고 오류 정보를 위해 result.Status을 읽는 코드를 다시 작성해야 합니다.

해결책: IronOCR은 표준 .NET 예외 세ман틱을 사용합니다. success-flag 검사를 try/catch로 대체하십시오. 성공 시에는 .Text이 항상 채워져 있습니다(텍스트가 없을 경우 빈 문자열):

// Before: success-flag pattern
var result = await _tesseract.RecognizeTextAsync(imagePath);
if (!result.Success)
{
    logger.LogError("OCR failed: {Status}", result.Status);
    return string.Empty;
}
return result.RecognizedText ?? string.Empty;

// After: exception pattern
try
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    var result = ocr.Read(input);
    return result.Text; // empty string if no text found — never null
}
catch (Exception ex)
{
    logger.LogError(ex, "OCR failed for {Path}.", imagePath);
    return string.Empty;
}
C#

이슈 5: 공유 라이브러리 프로젝트에서 MAUI 전용 대상 프레임워크

TesseractOcrMaui: TesseractOcrMaui을 참조하는 클래스 라이브러리는 자동으로 플랫폼 제약을 상속합니다. 라이브러리의 <TargetFramework>은 MAUI 이름(net8.0-android, net8.0-ios 또는 net8.0-windows)으로 설정되어야 하며, 이는 서버 프로젝트에서 참조할 수 없게 합니다.

해결책: 클래스 라이브러리 타겟을 net8.0 또는 netstandard2.1로 변경하고 IronOcr을 대신 참조합니다. 이제 이 라이브러리는 이를 사용하는 모든 프로젝트에서 올바르게 해결됩니다:

<!-- Before: locked to MAUI target because 테서랙트오크르MAUI has no net8.0 target -->
<TargetFramework>net8.0-android</TargetFramework>
<PackageReference Include="TesseractOcrMaui" Version="*" />

<!-- After: universal target — referenced from MAUI, API, worker, and Functions -->
<TargetFramework>net8.0</TargetFramework>
<PackageReference Include="IronOcr" Version="*" />
XML

문제 6: PDF 처리를 위해 두 번째 라이브러리를 제거해야 함

TesseractOcrMaui: PDF 지원을 구현한 팀은 PDF 페이지를 이미지로 변환하기 위해 PDFium, PdfPig 또는 클라우드 렌더러와 같은 두 번째 라이브러리를 추가했습니다. IronOCR로 마이그레이션한 후에는 해당 두 번째 라이브러리와 모든 페이지 렌더링 코드를 삭제할 수 있습니다.

해결책: PDF 렌더링 라이브러리를 제거하고 전체 페이지 추출 파이프라인을 input.LoadPdf()으로 교체합니다.

// Before: PDF library + manual temp file management (50+ lines)
using var pdfDoc = PdfDocument.Open(pdfPath);
var results = new List<string>();
foreach (var page in pdfDoc.GetPages())
{
    var tempImagePath = Path.Combine(FileSystem.CacheDirectory, $"page_{page.Number}.png");
    RenderPageToImage(page, tempImagePath, dpi: 300);
    await _tesseract.InitAsync("eng");
    var r = await _tesseract.RecognizeTextAsync(tempImagePath);
    results.Add(r.RecognizedText ?? string.Empty);
    File.Delete(tempImagePath);
}
return string.Join("\n", results);

// After: native PDF support — 5 lines
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
return result.Text;
C#

PDF 입력 가이드에는 페이지 범위 선택, 암호로 보호된 PDF, 스트림 기반 로딩에 대한 내용이 포함되어 있습니다.

테서랙트오크르MAUI 마이그레이션 체크리스트

사전 마이그레이션

코드를 변경하기 전에 코드베이스를 검토하여 TesseractOcrMaui의 모든 사용처를 파악하십시오:

# Find all files that reference 테서랙트오크르MAUI namespaces
grep -r "TesseractOcrMaui" --include="*.cs" .

# Find all ITesseract injection points
grep -r "ITesseract" --include="*.cs" .

# Find all AddTesseractOcr registrations
grep -r "AddTesseractOcr" --include="*.cs" .

# Find all InitAsync calls
grep -r "InitAsync" --include="*.cs" .

# Find all RecognizeTextAsync calls
grep -r "RecognizeTextAsync" --include="*.cs" .

# Find traineddata asset declarations in project files
grep -r "tessdata" --include="*.csproj" .

# Find MauiAsset traineddata declarations
grep -r "MauiAsset" --include="*.csproj" .

# Identify projects with MAUI-only target frameworks that hold OCR logic
grep -r "net8.0-android\|net8.0-ios\|net8.0-windows" --include="*.csproj" .
SHELL

생성자에서 ITesseract을 취하는 모든 클래스를 노트하세요 – 그 생성자가 변경될 것입니다. 훈련데이터를 위해 <MauiAsset>을 선언한 모든 프로젝트 파일을 기록하세요 – 해당 선언을 삭제할 것입니다. PDF 렌더링 라이브러리가 포함되어 있는지, 그리고 해당 라이브러리가 OCR 전처리 전용으로 사용되는지 여부를 확인하십시오.

코드 마이그레이션

  1. dotnet remove package TesseractOcrMaui을 해당을 참조하는 모든 프로젝트에서 실행합니다
  2. OCR을 수행할 모든 프로젝트에서 dotnet add package IronOcr을 실행합니다
  3. Android를 타겟으로 하는 MAUI 프로젝트에서 dotnet add package IronOcr.Android을 실행합니다
  4. iOS를 타겟으로 하는 MAUI 프로젝트에서 dotnet add package IronOcr.iOS을 실행합니다
  5. 이전에 훈련 데이터로 묶인 모든 비영어권 언어에 대해 dotnet add package IronOcr.Languages.*을 실행합니다
  6. 각 진입점 프로젝트의 애플리케이션 시작 시 IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";을 추가합니다
  7. Resources/Raw/tessdata/와 모든 .traineddata 파일을 MAUI 프로젝트에서 삭제합니다
  8. 모든 .csproj 파일에서 <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" /> 줄을 제거합니다
  9. 모든 MauiProgram.cs 파일에서 builder.Services.AddTesseractOcr()을 제거합니다
  10. 모든 using TesseractOcrMaui;using TesseractOcrMaui.Results;using IronOcr;으로 교체합니다
  11. 모든 서비스 및 뷰 모델 클래스에서 ITesseract 생성자 매개변수를 제거합니다
  12. 필요에 따라 await _tesseract.InitAsync("eng") 호출을 ocr.Language = OcrLanguage.English;으로 교체합니다 (기본값은 영어입니다)
  13. OcrInput 인스턴스를 사용하여 ocr.Read(input)await _tesseract.RecognizeTextAsync(imagePath)을 교체합니다
  14. result.Textresult.RecognizedText을 교체합니다
  15. if (!result.Success) 검사와 try/catch 블록을 교체합니다
  16. TesseractOcrMaui를 지원하기 위해 추가된 PDF 렌더링 라이브러리가 더 이상 필요하지 않다면, 그것을 제거하고 페이지 추출 코드를 input.LoadPdf()으로 대체합니다
  17. OCR 로직을 보유한 클래스 라이브러리에서 MAUI 전용 타겟 프레임워크를 net8.0 또는 netstandard2.1로 변경합니다

마이그레이션 이후

  • iOS 및 Android 대상 기기에서 기기 카메라로 촬영한 JPEG 이미지에 대해 OCR이 텍스트를 생성하는지 확인하십시오.
  • 서버 사이드 API 엔드포인트에서 byte[]을 통해 로드된 동일한 이미지에서 OCR이 텍스트를 생성하는지 확인합니다
  • 공유 클래스 라이브러리가 MAUI 및 .NET Core 프로젝트에서 참조될 때 동일하게 컴파일되고 실행되는지 확인하십시오.
  • 임시 파일을 생성하지 않고 PDF 입력이 종단 간(end-to-end)으로 작동하는지 테스트하십시오
  • SaveAsSearchablePdf 출력이 PDF 뷰어에서 인덱싱 가능한지 확인합니다
  • 신뢰도 점수가 result.Confidencepage.Words[i].Confidence에서 존재하는지 확인합니다
  • MAUI 앱이 traineddata 파일 미검출 예외 없이 오류 없는 시작 로그를 생성하는지 테스트하십시오
  • 릴리스 빌드에서 MAUI 앱 번들에 Resources/Raw/tessdata/ 폴더가 없다는 것을 확인합니다
  • 스레드 안전성을 확인하기 위해 10개 이상의 문서를 사용하여 병렬 배치 작업을 실행하십시오
  • InitAsync 제거가 어떤 서비스 클래스에도 고아된 세마포어 또는 _isInitialized 상태 변수를 남기지 않았는지 확인합니다

##IronOCR로 마이그레이션할 때의 주요 이점

전체 제품에 걸친 하나의 코드베이스. 마이그레이션 후 솔루션의 모든 프로젝트 — MAUI 모바일 앱, ASP.NET CoreAPI, Azure Function, 백그라운드 워커 —는 동일한 공유 라이브러리에서 동일한 DocumentOcrService 클래스를 호출합니다. 언어 구성, 전처리 설정 및 정확도 조정은 한 곳에서 이루어집니다. 새로운 문서 유형에 새로운 전처리 필터가 필요한 경우, 변경 사항은 한 번만 적용하면 모든 곳에 반영됩니다.

재작성 없이 서버 측 배포. IronOCR은 수정 없이 Linux 컨테이너, Windows Server, Azure App Service, AWS 람다 및 기타 모든 .NET 8 런타임 대상에 배포할 수 있습니다. 모바일 카메라 캡처를 처리하는 것과 같은 IronTesseract 인스턴스가 서버 사이드 PDF 업로드도 처리합니다. Azure 배포 가이드AWS 배포 가이드에는 플랫폼별 구성 단계가 설명되어 있습니다.

두 번째 라이브러리 없는 PDF 처리. input.LoadPdf()를 통한 네이티브 PDF 입력은 PDF 렌더링 라이브러리, 페이지별 이미지 추출 루프, 임시 파일 관리, TesseractOcrMaui의 아키텍처가 요구하는 정리 코드를 제거합니다. 스캔된 PDF 계약서, 인보이스, 신분증은 한 줄에 로드됩니다. 텍스트를 추출하는 동일한 OCR 통과가 result.SaveAsSearchablePdf()와 함께 검색 가능한 PDF를 생성할 수 있으며, 이는 어느 수준에서도 TesseractOcrMaui가 제공할 수 없는 기능입니다.

실제 모바일 이미지를 처리하는 전처리. input.Deskew(), input.DeNoise(), input.Binarize(), input.Sharpen()은 교정된 이미지 보정을 적용하기 위한 단일 메서드 호출로, Tesseract 엔진이 데이터를 보기 전에 적용됩니다. 전처리 없이 저조도 모바일 촬영 이미지에서 4060%의 정확도를 수용하던 팀들은 3단계 필터 파이프라인을 추가한 후 일반적으로 8590% 이상의 정확도를 달성합니다. SkiaSharp, ImageSharp, 알고리즘 구현이 필요하지 않습니다. 이미지 품질 보정 가이드에는 사용 가능한 모든 필터와 적용 시기가 상세히 설명되어 있습니다.

명확한 에스컬레이션 절차가 마련된 유료 지원. Iron Software는 모든IronOCR라이선스 등급에 대해 이메일 지원을 제공하며, Professional 및 Enterprise 등급에는 우선순위 전화 및 채팅 지원을 제공합니다. 특정 Android API 레벨에서 플랫폼 업데이트로 인해 네이티브 라이브러리 해결이 중단되는 경우(TesseractOcrMaui의 GitHub 이슈 큐에서 자원봉사자들이 처리하는 유형의 오류), 이에 대응할 의무가 있는 실제 엔지니어링 팀이 존재합니다. 영구 라이선스는 Lite 티어의 $999에서 시작합니다; 라이선스 페이지에는 모든 요금제와 해당 요금제에 포함된 지원 수준이 나열되어 있습니다.

앱 번들 용량 증가 없이 NuGet을 통해 125개 이상의 언어를 지원합니다. TesseractOcrMaui는 훈련된 데이터 파일을 MAUI 앱 내에 번들로 포함합니다. 각 언어는 앱 다운로드 크기에 10~50MB를 추가합니다.IronOCR언어 팩은 NuGet을 통해 설치되며, 서버 측 빌드나 명시적으로 참조된 플랫폼 빌드에만 포함됩니다. 모바일 앱 번들은 가볍게 유지됩니다; 서버 측 빌드에서는 전체 언어 세트를 사용할 수 있습니다. 새로운 언어 추가는 프로젝트 파일 변경 없이 그리고 파일 관리 없이 dotnet add package 명령 하나로 가능합니다. 전체 언어 카탈로그에는 이용 가능한 125개 이상의 팩이 모두 나열되어 있습니다.

참고해 주세요: PDFium, PdfPig, 및 Tesseract는 각각의 소유자가 등록한 상표입니다. 이 사이트는 Chromium Project, Google, 또는 UglyToad와 제휴나 보증, 후원을 받지 않았습니다. 모든 제품명, 로고 및 브랜드는 해당 소유자의 자산입니다. 비교는 정보 제공 목적으로만 사용되며, 작성 시점에 공개적으로 이용 가능한 정보를 반영합니다.

관련 기사

Key in blue circle

무료 30일 체험 키를 즉시 받으세요.

Your trial license will be sent to your email address

제한 없음. 100% 무제한 이용. 신용카드 불필요.

bullet_checked신용카드나 계정 생성은 필요하지 않습니다.제한 없음. 100% 무제한 이용. 신용카드 불필요.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
부담 없는 무료 상담을 받아보세요
아래 양식을 작성하시거나 sales@ironsoftware.com으로 이메일을 보내주세요.
고객님의 정보는 항상 비밀로 유지됩니다.
전 세계 수백만 엔지니어들이 신뢰하는 제품입니다.
Iron Software의 고객 로고
지금 바로 30일 무료 체험판 키를 받으세요.
신용카드나 계정 생성은 필요하지 않습니다.