IronOCR 과 Azure OCR PDF 중 어떤 솔루션이 텍스트 추출 성능이 더 뛰어날까요?
TesseractOcrMaui는 플랫폼 경계를 아키텍처에 하드코딩합니다. 이 라이브러리는 .NET MAUI 애플리케이션 내에서만 존재하며 다른 프로젝트 유형에서는 참조할 수 없습니다. MAUI 모바일 앱을 ASP.NET CoreAPI, Azure Function 또는 Docker 기반 백엔드와 함께 운영하는 모든 팀은 앱용 OCR 구현과 그 외 모든 용도를 위한 OCR 구현, 이렇게 완전히 별개의 두 가지 OCR 구현을 작성하고 유지 관리해야 합니다. 그것은 로드맵에서 빠진 기능이 아니라, 라이브러리가 설계된 방식입니다. 이 비교에서는 해당 제약 조건이 실제로 어떤 비용을 발생시키는지, 그리고 IronOCR 해당 제약 조건을 어떻게 제거하는지 살펴봅니다.
테서랙트오크르MAUI 이해하기
TesseractOcrMaui는 Tesseract 5.3.3을 기반으로 하는 오픈 소스 .NET MAUI 래퍼로, 커뮤니티 개발자 한 명인 Henri Vainio가 개발하고 유지 관리합니다. 패키지는 net8.0-ios, net8.0-android, 및 net8.0-windows을 대상으로 합니다 — 모두 MAUI 타겟 프레임워크입니다. 이 라이브러리는 진정한 공백을 메우기 위해 개발되었습니다. 데스크톱 .NET 용 기존 Tesseract 래퍼는 모바일 플랫폼 상호 운용성 요구 사항을 해결할 수 없었기 때문에, 이 라이브러리가 등장하기 전까지 MAUI 개발자들은 Tesseract를 사용할 수 있는 명확한 방법이 없었습니다.
이 라이브러리의 아키텍처는 MAUI 고유의 의존성 주입에 기반합니다. OCR 엔진은 builder.Services.AddTesseractOcr()를 통해 MauiProgram.cs에 등록되며, 그런 다음 ITesseract를 페이지와 서비스에 주입합니다. MAUI DI 컨테이너와의 긴밀한 결합 때문에 클래스 라이브러리, 콘솔 도구 또는 웹 프로젝트에서 참조하는 것이 불가능합니다.
주요 건축적 특징:
- MAUI 전용 타겟 프레임워크:
net8.0-ios,net8.0-android, 및net8.0-windows만 지원 —net8.0,netstandard2.1는 지원하지 않으며 서버 타겟은 없습니다 - 필수
AddTesseractOcr()등록: 엔진은 MAUI 서비스 제공자를 통해 연결됩니다; 독립형 인스턴스화 경로가 존재하지 않음 - 훈련된 데이터 포함되지 않음: 언어 파일은 각각 10~50 MB 크기이며, 수동으로 다운로드,
Resources/Raw/tessdata/에 위치시키고 프로젝트 파일에서<MauiAsset>요소로 선언해야 합니다 - 단일 관리자: 앙리 바이니오가 유일한 개발자입니다. 2026년 기준 NuGet 총 다운로드 횟수 약 33,900회
- 아파치 2.0 라이선스: 라이선스 비용 없이 무료로 사용 가능
- 비동기 우선 API 표면:
InitAsync(language)및RecognizeTextAsync(imagePath)는 주요 호출입니다; 동기 경로가 노출되지 않음
MAUI Lock-In 코드
AddTesseractOcr()를 호출하는 순간 OCR 로직이 MAUI 애플리케이션 호스트에 바인딩됩니다. 이를 공유 라이브러리로 추출할 방법이 없습니다:
// MauiProgram.cs — this registration only compiles inside a MAUI project
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Registers ITesseract — MAUI DI only, no standalone equivalent
builder.Services.AddTesseractOcr();
return builder.Build();
}
// OCR service — ITesseract injected from MAUI container
public class MobileOcrService
{
private readonly ITesseract _tesseract;
public MobileOcrService(ITesseract tesseract)
{
_tesseract = tesseract; // Cannot be constructed outside MAUI host
}
public async Task<string> ExtractTextAsync(string imagePath)
{
await _tesseract.InitAsync("eng"); // traineddata must be bundled
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
}
// MauiProgram.cs — this registration only compiles inside a MAUI project
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Registers ITesseract — MAUI DI only, no standalone equivalent
builder.Services.AddTesseractOcr();
return builder.Build();
}
// OCR service — ITesseract injected from MAUI container
public class MobileOcrService
{
private readonly ITesseract _tesseract;
public MobileOcrService(ITesseract tesseract)
{
_tesseract = tesseract; // Cannot be constructed outside MAUI host
}
public async Task<string> ExtractTextAsync(string imagePath)
{
await _tesseract.InitAsync("eng"); // traineddata must be bundled
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
}
Imports Microsoft.Maui
Imports Microsoft.Extensions.DependencyInjection
' MauiProgram.vb — this registration only compiles inside a MAUI project
Public Module MauiProgram
Public Function CreateMauiApp() As MauiApp
Dim builder = MauiApp.CreateBuilder()
builder.UseMauiApp(Of App)()
' Registers ITesseract — MAUI DI only, no standalone equivalent
builder.Services.AddTesseractOcr()
Return builder.Build()
End Function
End Module
' OCR service — ITesseract injected from MAUI container
Public Class MobileOcrService
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract ' Cannot be constructed outside MAUI host
End Sub
Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng") ' traineddata must be bundled
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.Success, result.RecognizedText, String.Empty)
End Function
End Class
제품이 성장하여 업로드된 문서를 처리하거나, 스캔한 양식을 검증하거나, 서버 측에서 검색 가능한 PDF를 생성하는 등 동일한 OCR 로직이 필요한 백엔드 API를 포함하게 되면, 이 코드는 재사용할 수 없습니다. 이 파일들은 MAUI 프로젝트 외부에서는 컴파일되지 않습니다. 다른 라이브러리를 사용하여 처음부터 다시 작성해야 합니다.
IronOCR 이해하기
IronOCR 최적화된 Tesseract 5 엔진과 자동 이미지 전처리, 네이티브 PDF 입력, 스레드 안전 병렬 처리를 제공하는 .NET 용 상용 OCR 라이브러리입니다. NuGet 패키지로 배포되며 (IronOcr), net8.0, netstandard2.0, 및 모든 표준 .NET 타겟을 대상으로 하여 어떤 프로젝트 유형에서도 참조할 수 있습니다.
주요 특징:
- 범 for .NET 타겟팅: MAUI, ASP.NET Core, 콘솔 앱, WPF, WinForms, Azure Functions, AWS Lambda, Docker 컨테이너 및 공유 클래스 라이브러리 등 모든 환경에서 동일한 패키지와 API를 통해 작동합니다.
- tessdata 관리 없음: 언어 데이터는 별개의 NuGet 언어 팩 (
IronOcr.Languages.French등)으로 패키지됩니다; 파일 다운로드 없음, 경로 구성 없음, 버전 일치 없음 - 자동 사전처리:
Deskew(),DeNoise(),Contrast(),Binarize(), 및EnhanceResolution()은 읽기 전에OcrInput에 대한 한 줄 호출입니다 - 네이티브 PDF 지원:
input.LoadPdf()은 스캔된 PDF를 직접 처리합니다;result.SaveAsSearchablePdf()은 색인된 출력을 생성합니다 - 전용 모바일 패키지:
IronOcr.Android및IronOcr.iOS은 같은 API의 플랫폼 최적화된 변형으로, 솔루션 내 모든 다른 프로젝트 유형과 함께 MAUI에서 사용할 수 있습니다 - 상업적 지원: SLA 기반 이메일, 채팅 및 전화 지원; 영구 라이선스는 $999에서 시작합니다
기능 비교
| 기능 | 테서랙트오크르MAUI | IronOCR |
|---|---|---|
| 플랫폼 지원 | .NET MAUI 전용 | 모든 .NET 플랫폼 |
| 공유 클래스 라이브러리 지원 | 아니요 | 예 |
| PDF 입력 | 아니요 | 예 (내장형) |
| 자동 전처리 | 아니요 | 예 (필터 40개 이상) |
| 언어 데이터 관리 | 수동 파일 묶음 | NuGet 언어 팩 |
| 유지보수 담당자 | 단일 커뮤니티 개발자 | Iron Software (회사) |
| NuGet 총 다운로드 수 | 약 33,900 | 수백만 |
| 라이선스 | Apache 2.0 (무료) | $999+ 영구 |
상세 기능 비교
| 기능 | 테서랙트오크르MAUI | IronOCR |
|---|---|---|
| 플랫폼 적용 범위 | ||
| .NET MAUI(iOS) | 예 | 예 (IronOCR) |
| .NET MAUI (안드로이드) | 예 | 예 (IronOCR) |
| .NET MAUI(Windows) | 예 | 예 |
| .NET MAUI(macOS) | 아니요 | 예 |
| ASP.NET Core | 아니요 | 예 |
| 콘솔 애플리케이션 | 아니요 | 예 |
| WPF / WinForms | 아니요 | 예 |
| Azure Functions | 아니요 | 예 |
| Docker/리눅스 | 아니요 | 예 |
| AWS 람다 | 아니요 | 예 |
| 공유되는 .NET 클래스 라이브러리 | 아니요 | 예 |
| 입력 소스 | ||
| 이미지 파일(JPEG, PNG, TIFF) | 예 | 예 |
| PDF 문서 | 아니요 | 예 |
| 비밀번호로 보호된 PDF 파일 | 아니요 | 예 |
| 스트림 | 아니요 | 예 |
| 바이트 배열 | 아니요 | 예 |
| 전처리 | ||
| 디스큐 | 아니요 | 예 |
| 디노이즈 | 아니요 | 예 |
| 명암 대비 강화 | 아니요 | 예 |
| 이진화 | 아니요 | 예 |
| 해상도 스케일링 | 아니요 | 예 |
| 반전 / 선명하게 / 확대 | 아니요 | 예 |
| 산출 | ||
| 일반 텍스트 | 예 | 예 |
| 검색 가능한 PDF | 아니요 | 예 |
| hOCR 내보내기 | 아니요 | 예 |
| 단어 수준 좌표 | 아니요 | 예 |
| 신뢰도 점수 | 예 (결과에 따라) | 네 (단어당) |
| 아키텍처 | ||
| 나사산 안전 | 수동 | 내장형 |
| OCR 중 바코드 판독 | 아니요 | 예 |
| 다국어 동시 | 아니요 (호출당 초기화 1회) | 예 |
| 지원 | ||
| 상업용 SLA | 아니요 | 예 |
| 보안 패치 보장 | 커뮤니티 의존 | 예 |
| 문서화 | 기본 README | 100페이지 이상 |
플랫폼 지원 범위: MAUI 전용 vs. 유니버설 .NET
TesseractOcrMaui를 평가할 때 가장 중요한 질문은 MAUI 프로젝트 외에서 OCR이 필요할 경우가 과연 있을지 여부입니다. 대부분의 실제 운영 환경에서는 답은 '예'입니다.
테서랙트OcrMAUI 접근법
TesseractOcrMaui는 MAUI 호스트 외부에서는 컴파일할 수 없습니다. ITesseract 인터페이스는 MAUI DI 컨테이너에서 해결됩니다; 팩토리도 없고, 고정된 진입점도 없고, 독립 실행형 생성자도 없습니다. 다음 패턴만 지원됩니다.
// MAUI-only: will not compile in ASP.NET Core, console, or class library
public class DocumentScanService
{
private readonly ITesseract _tesseract;
public DocumentScanService(ITesseract tesseract) // MAUI DI injection only
{
_tesseract = tesseract;
}
public async Task<string> ProcessAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.RecognizedText ?? string.Empty;
}
}
// MAUI-only: will not compile in ASP.NET Core, console, or class library
public class DocumentScanService
{
private readonly ITesseract _tesseract;
public DocumentScanService(ITesseract tesseract) // MAUI DI injection only
{
_tesseract = tesseract;
}
public async Task<string> ProcessAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.RecognizedText ?? string.Empty;
}
}
Imports System.Threading.Tasks
' MAUI-only: will not compile in ASP.NET Core, console, or class library
Public Class DocumentScanService
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract) ' MAUI DI injection only
_tesseract = tesseract
End Sub
Public Async Function ProcessAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng")
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.RecognizedText, String.Empty)
End Function
End Class
ASP.NET Core API 컨트롤러에서 업로드된 문서를 OCR 처리해야 하는 팀은 이 클래스를 호출할 수 없습니다. 그들은 두 번째 OCR 라이브러리(일반적으로 다른 Tesseract 래퍼 또는 클라우드 API)를 추가하고 언어 구성, 오류 처리 및 정확도 조정 작업을 중복 수행합니다. 두 개의 라이브러리, 두 개의 유지보수 트랙, 두 세트의 버그 수정.
IronOCR 접근법
IronOCR 프로젝트 유형에 제한을 두지 않습니다. 동일한 클래스가 수정 없이 MAUI 앱, ASP.NET Core컨트롤러, Azure Function 및 .NET Standard 클래스 라이브러리에서 컴파일됩니다.
// Works in every project type — MAUI, ASP.NET Core, console, Azure Functions, Docker
public class SharedOcrService
{
private readonly IronTesseract _ocr = new IronTesseract();
public string ExtractText(string imagePath)
{
using var input = new OcrInput(imagePath);
return _ocr.Read(input).Text;
}
public string ExtractTextFromBytes(byte[] imageData)
{
using var input = new OcrInput(imageData);
return _ocr.Read(input).Text;
}
}
// Works in every project type — MAUI, ASP.NET Core, console, Azure Functions, Docker
public class SharedOcrService
{
private readonly IronTesseract _ocr = new IronTesseract();
public string ExtractText(string imagePath)
{
using var input = new OcrInput(imagePath);
return _ocr.Read(input).Text;
}
public string ExtractTextFromBytes(byte[] imageData)
{
using var input = new OcrInput(imageData);
return _ocr.Read(input).Text;
}
}
Imports IronTesseract
Public Class SharedOcrService
Private ReadOnly _ocr As New IronTesseract()
Public Function ExtractText(imagePath As String) As String
Using input As New OcrInput(imagePath)
Return _ocr.Read(input).Text
End Using
End Function
Public Function ExtractTextFromBytes(imageData As Byte()) As String
Using input As New OcrInput(imageData)
Return _ocr.Read(input).Text
End Using
End Function
End Class
이 클래스를 .NET Standard 2.1 또는 net8.0 클래스 라이브러리에 배치하고 MAUI 프로젝트, API 프로젝트, 백그라운드 워커에서 동시에 참조합니다. 하나의 구현, 하나의 유지 관리 인터페이스, 하나의 테스트 세트. IronTesseract 설정 가이드에서는 모든 대상에 동일하게 적용되는 구성 옵션을 단계별로 안내합니다.
모바일 특화 시나리오에서는 IronOcr.Android 및 IronOcr.iOS이 플랫폼 최적화된 네이티브 바이너리를 제공하면서 동일한 IronTesseract API를 노출합니다 — 따라서 공유 클래스 라이브러리가 모바일에서 변함없이 작동합니다. 서버 배포의 경우, Docker 배포 가이드와 Linux 배포 가이드가 컨테이너 구성에 대해 다룹니다. 모바일 기기에 맞춘 설정 방법을 보여주는 MAUI OCR 전용 튜토리얼 도 있습니다.
서버 측 기능
서버 측 OCR은 TesseractOcrMaui를 완전히 무력화시키는 시나리오입니다. 서버에서 문서를 처리해야 하는 모든 요구 사항(배치 작업, API 엔드포인트, 서버리스 함수 등)에는 완전히 다른 라이브러리가 필요합니다.
테서랙트OcrMAUI 접근법
TesseractOcrMaui에는 서버 측 접근 방식이 없습니다. 이 라이브러리는 net8.0-ios, net8.0-android, 및 net8.0-windows (MAUI)만을 대상으로 합니다. TesseractOcrMaui를 참조하는 ASP.NET Core프로젝트는 빌드에 실패합니다. 이는 설정 문제가 아닙니다. 해당 패키지에는 서버 런타임이 로드할 수 있는 대상이 포함되어 있지 않습니다.
라이브러리 자체 문서의 ProcessPdfAsync 메서드는 명시적으로 그 차이를 확인합니다:
// TesseractOcrMaui: PDF processing throws NotSupportedException
public async Task<List<string>> ProcessPdfAsync(string pdfPath)
{
// Cannot process PDFs at all — requires manual conversion to images first
// AND requires a separate PDF library you must add yourself
throw new NotSupportedException(
"TesseractOcrMaui does not support PDF processing. " +
"You must manually convert PDF pages to images first.");
}
// TesseractOcrMaui: PDF processing throws NotSupportedException
public async Task<List<string>> ProcessPdfAsync(string pdfPath)
{
// Cannot process PDFs at all — requires manual conversion to images first
// AND requires a separate PDF library you must add yourself
throw new NotSupportedException(
"TesseractOcrMaui does not support PDF processing. " +
"You must manually convert PDF pages to images first.");
}
Imports System
Imports System.Threading.Tasks
Public Class TesseractOcrMaui
Public Async Function ProcessPdfAsync(pdfPath As String) As Task(Of List(Of String))
' Cannot process PDFs at all — requires manual conversion to images first
' AND requires a separate PDF library you must add yourself
Throw New NotSupportedException("TesseractOcrMaui does not support PDF processing. " &
"You must manually convert PDF pages to images first.")
End Function
End Class
MAUI 앱 내에서도 PDF 문서를 직접 전달할 수는 없습니다. 모든 페이지는 두 번째 라이브러리에 의해 임시 이미지 파일로 렌더링된 다음, 디바이스 캐시에 저장되고, RecognizeTextAsync로 전달되며, 이후 정리됩니다. 수백 개의 문서를 처리하는 서버 워크로드에서는 그 아키텍처가 지속 가능하지 않습니다.
IronOCR 접근법
IronOCR 모바일에서 사용하는 것과 동일한 API로 서버 측 OCR을 처리합니다. PDF 입력은 네이티브 방식으로 이루어지며, 중간 이미지 변환이나 임시 파일, 별도의 라이브러리가 필요하지 않습니다.
// ASP.NET Corecontroller — handles PDF uploads directly
[HttpPost("ocr")]
public async Task<IActionResult> ProcessUpload(IFormFile file)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
if (file.ContentType == "application/pdf")
{
using var stream = file.OpenReadStream();
input.LoadPdf(stream); // direct PDF stream — no temp files
}
else
{
using var stream = file.OpenReadStream();
input.LoadImage(stream);
}
input.Deskew(); // handle scanned document skew
input.DeNoise(); // mobile camera noise
var result = ocr.Read(input);
return Ok(new { text = result.Text, confidence = result.Confidence });
}
// ASP.NET Corecontroller — handles PDF uploads directly
[HttpPost("ocr")]
public async Task<IActionResult> ProcessUpload(IFormFile file)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
if (file.ContentType == "application/pdf")
{
using var stream = file.OpenReadStream();
input.LoadPdf(stream); // direct PDF stream — no temp files
}
else
{
using var stream = file.OpenReadStream();
input.LoadImage(stream);
}
input.Deskew(); // handle scanned document skew
input.DeNoise(); // mobile camera noise
var result = ocr.Read(input);
return Ok(new { text = result.Text, confidence = result.Confidence });
}
Imports Microsoft.AspNetCore.Mvc
Imports IronOcr
<HttpPost("ocr")>
Public Async Function ProcessUpload(file As IFormFile) As Task(Of IActionResult)
Dim ocr As New IronTesseract()
Using input As New OcrInput()
If file.ContentType = "application/pdf" Then
Using stream = file.OpenReadStream()
input.LoadPdf(stream) ' direct PDF stream — no temp files
End Using
Else
Using stream = file.OpenReadStream()
input.LoadImage(stream)
End Using
End If
input.Deskew() ' handle scanned document skew
input.DeNoise() ' mobile camera noise
Dim result = ocr.Read(input)
Return Ok(New With {Key .text = result.Text, Key .confidence = result.Confidence})
End Using
End Function
MAUI 앱을 구동하는 동일한 IronTesseract 인스턴스가 이 엔드포인트도 구동합니다. 한 번 설치된 언어 팩은 두 대상을 모두 지원합니다.Azure Functions또는 AWS 람다 배포의 경우, Azure 배포 가이드 와 AWS 배포 가이드에 구성 방법이 설명되어 있습니다. PDF 입력 방법 안내서는 페이지 범위, 암호로 보호된 파일, 스트림 입력 등 모든 PDF 로드 패턴을 다룹니다.
단일 개발자 유지보수 위험
2026년 기준 총 다운로드 횟수가 약 33,900회인 TesseractOcrMaui는 .NET OCR 생태계에서 다소 좁은 영역을 차지하고 있습니다. 다운로드 횟수가 적다는 것은 단순히 인기도를 나타내는 지표가 아니라, 버그 보고, 해결 방법, Stack Overflow 답변 및 기여된 수정 사항에 참여할 수 있는 커뮤니티 규모를 보여주는 지표입니다.
테서랙트OcrMAUI 접근법
TesseractOcrMaui의 유지 관리의 모든 측면은 Henri Vainio가 계속해서 시간을 내어 적극적으로 참여해 주는 것에 달려 있습니다. 이 프로젝트에는 상업적 주체가 없으며, 서비스 수준 계약(SLA)도 없고, 보안 패치 일정도 보장되지 않으며, GitHub 이슈를 제기하는 것 외에는 문제 해결을 위한 별도의 절차가 없습니다. 프로젝트는 진행 중이지만 구조적 위험은 실제로 존재합니다.
훈련된 데이터 관리 모델은 이러한 위험을 운영상 증폭시킵니다. 개발자는 언어 파일을 다운로드하고, <MauiAsset> 요소로 선언하며, iOS와 Android 간의 플랫폼별 경로 차이를 런타임에 해결하고, 시작 시 해당 파일이 존재하는지 확인해야 합니다:
// Required startup validation — common crash source
public async Task<bool> ValidateTraineddataAsync()
{
try
{
// Fails if eng.traineddata is missing, path-resolved incorrectly,
// or mismatched with the Tesseract engine version
await _tesseract.InitAsync("eng");
return true;
}
catch (FileNotFoundException)
{
// Need to diagnose: missing file, wrong path, or wrong bundling config?
Console.WriteLine("ERROR: eng.traineddata not found in bundle");
return false;
}
catch (DllNotFoundException)
{
// Native library resolution failure — platform-specific debugging
Console.WriteLine("Native Tesseract library missing");
return false;
}
}
// Required startup validation — common crash source
public async Task<bool> ValidateTraineddataAsync()
{
try
{
// Fails if eng.traineddata is missing, path-resolved incorrectly,
// or mismatched with the Tesseract engine version
await _tesseract.InitAsync("eng");
return true;
}
catch (FileNotFoundException)
{
// Need to diagnose: missing file, wrong path, or wrong bundling config?
Console.WriteLine("ERROR: eng.traineddata not found in bundle");
return false;
}
catch (DllNotFoundException)
{
// Native library resolution failure — platform-specific debugging
Console.WriteLine("Native Tesseract library missing");
return false;
}
}
Imports System
Imports System.IO
Imports System.Threading.Tasks
Public Class Validator
' Required startup validation — common crash source
Public Async Function ValidateTraineddataAsync() As Task(Of Boolean)
Try
' Fails if eng.traineddata is missing, path-resolved incorrectly,
' or mismatched with the Tesseract engine version
Await _tesseract.InitAsync("eng")
Return True
Catch ex As FileNotFoundException
' Need to diagnose: missing file, wrong path, or wrong bundling config?
Console.WriteLine("ERROR: eng.traineddata not found in bundle")
Return False
Catch ex As DllNotFoundException
' Native library resolution failure — platform-specific debugging
Console.WriteLine("Native Tesseract library missing")
Return False
End Try
End Function
Private _tesseract As Tesseract ' Assuming Tesseract is a defined class elsewhere
End Class
프로덕션 환경에서 특정 Android API 레벨에서, iOS 업데이트 후 또는 앱 스토어 제출 후 이러한 문제가 발생하면 디버깅 경로는 단일 개발자 프로젝트의 GitHub 이슈를 통해 진행됩니다. 지원 이메일, 채팅 채널, 전화 문의를 통한 문제 해결 절차는 없습니다.
IronOCR 접근법
IronOCR 전담 엔지니어링 팀과 상업적 지원 계약을 보유한 Iron Software 에서 개발 및 유지 관리합니다. 언어 데이터는 NuGet 패키지에 포함되어 제공되며 — dotnet add package IronOcr.Languages.French가 전체 설치 과정입니다. 관리해야 할 파일도 없고, 구성해야 할 경로도 없으며, 유지 관리해야 할 번들링 선언도 없습니다.
그에 따라 오차면이 축소됩니다. 학습 데이터 손실 문제가 없어지면서 런타임 오류의 한 유형이 완전히 사라집니다.IronOCR초기화 모델은 시작 시 단일 라이선스 키를 사용합니다.
// Application startup — the entire configuration
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Then OCR works anywhere, any project type, any file format
var text = new IronTesseract().Read("document.jpg").Text;
// Application startup — the entire configuration
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Then OCR works anywhere, any project type, any file format
var text = new IronTesseract().Read("document.jpg").Text;
Imports IronOcr
' Application startup — the entire configuration
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
' Then OCR works anywhere, any project type, any file format
Dim text As String = New IronTesseract().Read("document.jpg").Text
Enterprise 고객의 경우 이메일(업무 시간), 실시간 채팅 및 전화로 지원 문제를 처리합니다. 라이선스 페이지에는 모든 등급이 포함되어 있습니다. 문서 허브에는 100페이지가 넘는 가이드가 포함되어 있습니다. 특정 기능에 대한 질문이 있는 경우, 튜토리얼 허브에서 일반적인 시나리오에 대한 예제를 제공합니다.
API 매핑 참조
| 테서랙트오크르MAUI | IronOCR에 상응하는 |
|---|---|
dotnet add package TesseractOcrMaui |
dotnet add package IronOcr |
builder.Services.AddTesseractOcr() |
필요 없음 — DI 등록이 필요하지 않습니다. |
ITesseract (주입됨) |
new IronTesseract() (직접 인스턴스화) |
_tesseract.InitAsync("eng") |
ocr.Language = OcrLanguage.English; (또는 기본값) |
_tesseract.RecognizeTextAsync(imagePath) |
ocr.Read(imagePath) |
result.RecognizedText |
result.Text |
result.Success |
예외 기반; 성공 플래그 필요 없음 |
result.Status |
예외 메시지 |
result.Confidence |
result.Confidence (또한 result.Words를 통해 단어별) |
<MauiAsset> 훈련된 데이터 번들 |
dotnet add package IronOcr.Languages.French |
TesseractOcrMaui.Results 네임스페이스 |
IronOcr 네임스페이스 |
| PDF를 지원하지 않습니다. | input.LoadPdf(path) |
| 전처리 없음 | input.Deskew(), input.DeNoise(), input.Binarize() |
MediaPicker.CapturePhotoAsync() + RecognizeTextAsync() |
MediaPicker.CapturePhotoAsync() + ocr.Read(path) |
팀이 TesseractOcrMaui에서IronOCR로 전환을 고려할 때
백엔드 확장 문제
모바일 우선 개발팀이 TesseractOcrMaui를 사용하여 MAUI 문서 스캔 앱을 출시했습니다. 이 기능은 정상적으로 작동합니다. 그런 다음 제품 로드맵에 서버 측 문서 처리 기능이 추가됩니다. 업로드된 PDF 파일은 색인 생성 전에 OCR 처리가 필요하고, 웹 포털에도 동일한 추출 로직이 필요하며, 야간 배치 작업으로 수백 개의 스캔된 양식을 처리해야 합니다. TesseractOcrMaui는 이러한 컨텍스트에서 참조할 수 없습니다. 이제 팀은 두 개의 병렬 OCR 코드베이스(하나는 MAUI, 하나는 서버)를 유지할지, 아니면 두 시스템 모두에서 작동하는 라이브러리로 모든 것을 마이그레이션할지 선택해야 합니다. 이주 비용은 한 번만 지불하면 됩니다. 두 가지 구현 방식을 유지하는 비용은 무한히 증가합니다.
모바일에서 PDF 요구 사항
실제 모바일 문서 워크플로에는 PDF가 포함됩니다. 사용자는 계약서를 사진으로 찍거나, PDF 형식으로 도착한 영수증을 스캔하거나, 신분증을 PDF 형태로 받습니다. TesseractOcrMaui는 PDF 입력시 NotSupportedException를 던집니다 — 소스 코드는 이를 명시합니다. PDF 페이지를 이미지로 렌더링하는 두 번째 라이브러리를 추가하고, 기기 캐시의 임시 파일을 관리하고, 정리 작업을 올바르게 처리하는 것은 모바일 앱에 상당한 복잡성과 불안정성을 초래합니다. 초기 MAUI 버전을 출시한 후 이러한 제약을 발견한 팀은 사용자가 실제로 전송하는 문서 유형을 처리하기 위해 상당한 재작업에 직면하게 됩니다.
실제 모바일 촬영에서의 정확도
TesseractOcrMaui는 카메라에서 들어오는 모든 이미지에 대해 Tesseract의 정확도를 있는 그대로 제공합니다. 모바일 카메라로 찍은 사진은 손 각도로 인한 미세한 회전, 저조도 환경에서의 센서 노이즈, 기기 모델별 해상도 차이 등 여러 가지 이유로 이상적인 경우가 드뭅니다. TesseractOcrMaui는 전처리 기능을 제공하지 않으므로, 기울기 보정, 노이즈 제거 및 대비 향상을 수동으로 추가하려면 SkiaSharp 또는 ImageSharp를 불러와 알고리즘을 구현하고 임시 파일을 저장하고 파이프라인을 관리해야 합니다. 대부분의 팀은 이 단계를 건너뜁니다. 그 결과, 조명이 좋지 않은 환경에서는 정확도가 40~60%에 불과하지만, 전처리 과정을 거치면 85~92%의 정확도를 보입니다. 계약서, 영수증 또는 신분증과 관련된 사용 사례의 경우, 그러한 격차는 용납할 수 없습니다.
단일 개발자의 대역폭을 넘어 확장하기
실제 운영 환경에서는 당일 대응이 필요한 버그가 종종 발생합니다. 플랫폼 업데이트로 인해 안드로이드에서 네이티브 라이브러리 해상도 기능이 작동하지 않습니다. 번들링 변경으로 인해 iOS 앱 스토어 제출이 실패했습니다. TesseractOcrMaui의 33,900회 다운로드 커뮤니티는 Stack Overflow에서 제한적인 정보만 제공하며, GitHub 단 한 명의 관리자가 관리하는 이슈 큐만 있습니다. 특히 규제 산업 분야에서 생산 SLA 의무를 가진 팀은 명확하게 정의된 문제 해결 경로가 필요합니다. 자원봉사 기반 지원은 그러한 지원을 제공하지 않습니다.
다양한 포트폴리오 전반에 걸친 코드 공유
Enterprise 개발팀이 하나의 애플리케이션만 유지 관리하는 경우는 드뭅니다. MAUI 모바일 앱, ASP.NET Core웹 포털, 콘솔 배치 프로세서 및 Azure Function 파이프라인으로 구성된 제품군 Suite 모바일 앱으로 TesseractOcrMaui를 선택하는 경우 OCR 로직을 공유할 수 없습니다. 각 프로젝트는 자체적인 OCR 통합 기능을 갖게 됩니다. 정확도 요구 사항이 변경될 경우(예: 새 언어 추가, 새 문서 유형에 대한 전처리 조정) 각 통합 작업에서 개별적으로 변경해야 합니다. IronOCR의 범 for .NET 타기팅은 모든 프로젝트가 동시에 참조하는 netstandard 라이브러리에서 단일 SharedOcrService 클래스를 가능하게 합니다.
일반적인 마이그레이션 고려사항
ITesseract를 IronTesseract로 교체
TesseractOcrMaui의 ITesseract는 MAUI DI 컨테이너를 통해 해결되며 주입되어야 합니다. IronOCR의 IronTesseract는 일반적으로 인스턴스화할 수 있는 클래스입니다. 생성자 매개변수를 제거하고 InitAsync 호출을 제거하십시오; RecognizeTextAsync을 Read로 교체하십시오:
// Before — MAUI DI required
public class OcrService
{
private readonly ITesseract _tesseract;
public OcrService(ITesseract tesseract) { _tesseract = tesseract; }
public async Task<string> ProcessAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
}
// After — works in any project type
public class OcrService
{
public string Process(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput(imagePath);
return ocr.Read(input).Text;
}
}
// Before — MAUI DI required
public class OcrService
{
private readonly ITesseract _tesseract;
public OcrService(ITesseract tesseract) { _tesseract = tesseract; }
public async Task<string> ProcessAsync(string imagePath)
{
await _tesseract.InitAsync("eng");
var result = await _tesseract.RecognizeTextAsync(imagePath);
return result.Success ? result.RecognizedText : string.Empty;
}
}
// After — works in any project type
public class OcrService
{
public string Process(string imagePath)
{
var ocr = new IronTesseract();
using var input = new OcrInput(imagePath);
return ocr.Read(input).Text;
}
}
Imports System.Threading.Tasks
' Before — MAUI DI required
Public Class OcrService
Private ReadOnly _tesseract As ITesseract
Public Sub New(tesseract As ITesseract)
_tesseract = tesseract
End Sub
Public Async Function ProcessAsync(imagePath As String) As Task(Of String)
Await _tesseract.InitAsync("eng")
Dim result = Await _tesseract.RecognizeTextAsync(imagePath)
Return If(result.Success, result.RecognizedText, String.Empty)
End Function
End Class
' After — works in any project type
Public Class OcrService
Public Function Process(imagePath As String) As String
Dim ocr = New IronTesseract()
Using input = New OcrInput(imagePath)
Return ocr.Read(input).Text
End Using
End Function
End Class
TesseractOcrMaui의 비동기 패턴은 필요에 따라 Task.Run(() => ocr.Read(input))을 사용하여 UI 스레드 문제에 대한 솔루션으로 보존할 수 있지만, 동기식 경로는 서버 시나리오에 깨끗하고 충분합니다. 이미지 입력 사용법은 모든 OcrInput 로딩 변형을 문서화합니다.
학습 데이터 인프라 제거
TesseractOcrMaui는 Resources/Raw/tessdata/ 폴더, 다운로드된 .traineddata 파일, <MauiAsset> 프로젝트 파일 선언, 플랫폼별 경로 해결 코드, 시작 시 점검을 필요로 합니다.IronOCR로 마이그레이션할 때 이 모든 것이 삭제됩니다. NuGet 통해 언어 팩을 설치합니다.
dotnet remove package TesseractOcrMaui
dotnet add package IronOcr
dotnet add package IronOcr.Android # for MAUI Android target
dotnet add package IronOcr.iOS # for MAUI iOS target
dotnet add package IronOcr.Languages.French # if French was needed
dotnet remove package TesseractOcrMaui
dotnet add package IronOcr
dotnet add package IronOcr.Android # for MAUI Android target
dotnet add package IronOcr.iOS # for MAUI iOS target
dotnet add package IronOcr.Languages.French # if French was needed
Resources/Raw/tessdata/ 폴더를 삭제하고 프로젝트 파일에서 <MauiAsset> 항목을 제거하십시오. builder.Services.AddTesseractOcr()를 MauiProgram.cs에서 제거하십시오. 학습 데이터 파일이 누락되었는지 확인하는 시작 유효성 검사 클래스는IronOCR에 상응하는 클래스가 없습니다. 왜냐하면 누락될 파일이 없기 때문입니다. IronTesseract 설정 가이드에서 해당 초기화 단계를 다룹니다.
정확도 동등성을 위한 전처리 추가
TesseractOcrMaui는 사전 처리를 적용하지 않습니다. 기존 앱이 테서랙트의 정확도에 맞춰 조정되었다면,IronOCR전처리 기능을 추가하면 저품질 이미지에서도 결과가 향상될 것입니다. 특히 모바일 카메라 입력의 경우, 3단계 필터 파이프라인이 가장 일반적인 오류 모드를 처리합니다.
using var input = new OcrInput(imagePath);
input.Deskew(); // camera angle correction
input.DeNoise(); // sensor noise from low light
input.EnhanceResolution(300); // normalize DPI across device models
var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
using var input = new OcrInput(imagePath);
input.Deskew(); // camera angle correction
input.DeNoise(); // sensor noise from low light
input.EnhanceResolution(300); // normalize DPI across device models
var result = new IronTesseract().Read(input);
Console.WriteLine($"Confidence: {result.Confidence}%");
Imports IronOcr
Using input As New OcrInput(imagePath)
input.Deskew() ' camera angle correction
input.DeNoise() ' sensor noise from low light
input.EnhanceResolution(300) ' normalize DPI across device models
Dim result = New IronTesseract().Read(input)
Console.WriteLine($"Confidence: {result.Confidence}%")
End Using
이미지 품질 보정 방법 과 이미지 방향 보정 방법은 각 필터에 대해 자세히 설명합니다. 저품질 스캔 예시는 까다로운 실제 문서를 처리하는 전체 파이프라인을 보여줍니다.
OCR 로직을 공유 라이브러리로 이전
MAUI 특화 ITesseract 의존성이 제거되면 OCR 서비스 클래스는 휴대 가능합니다. 새 netstandard2.1 또는 net8.0 클래스 라이브러리를 생성하고, 서비스를 거기에 이동하고, MAUI 프로젝트 및 솔루션 내 모든 서버 사이드 프로젝트에서 참조합니다. 이는 TesseractOcrMaui가 구조적으로 불가능하게 만드는 반면IronOCR은 아주 간단하게 만드는 건축적 단계입니다. .NET OCR 라이브러리 개요에서는 대상 지정 시 고려 사항을 다룹니다.
IronOCR의 추가 기능
위에서 설명한 기능 외에도IronOCR앞부분에서 다루지 않은 기능이 포함되어 있습니다.
- 비동기 OCR : 결과가 병렬 파이프라인으로 전달되는 고처리량 서버 시나리오를 위한 네이티브 비동기 지원
- 이미지의 특정 영역 OCR:
new CropRectangle(x, y, width, height)는 처리를 정의된 영역으로 제한하여, 구조화된 양식에서 소음을 줄이고 속도를 향상시킵니다 - 스캔 문서 처리 : 여러 페이지로 구성된 스캔 문서에 대한 특수 처리 기능으로, 자동 회전 감지 및 페이지별 기울기 보정 기능을 제공합니다.
- 여권 및 신분증 판독 : 여행 서류의 기계 판독 가능 영역을 추출하기 위한 특수 설계 기능
- 표 추출 : 스캔한 문서에서 행과 열 구조를 인식하여 표 형식 데이터를 추출합니다.
.NET 호환성 및 미래 준비
IronOCR는 netstandard2.0, net6.0, net8.0을 대상으로 하며, 현재 활발히 개발 중인 .NET 릴리스에 대해 유지 관리됩니다. IronOcr.Android와 IronOcr.iOS 패키지는 MAUI 릴리스 주기를 추적합니다. Iron Software 새로운 .NET 주요 릴리스가 나올 때마다 업데이트를 게시합니다. 이 라이브러리는 현재 .NET 9와 호환되며, 출시되면 .NET 10도 지원할 예정입니다. TesseractOcrMaui는 net8.0-* MAUI 프레임워크를 대상으로 하며, 싱글 유지관리자가 결정한 로드맵 외에는 선언된 것이 없습니다 — 하나의 개발자의 지속적인 가용성에 대한 의존은 .NET 릴리스가 누적됨에 따라 호환성 위험을 초래합니다.
결론
TesseractOcrMaui는 다음과 같은 특정 상황에서 실질적인 문제를 해결합니다. 백엔드 구성 요소가 없는 MAUI 전용 애플리케이션, 예산 제로, 간단한 이미지 입력, 그리고 학습 데이터 관리 오버헤드와 단일 개발자 유지 관리 위험을 감수할 의향이 있는 팀이 필요합니다. 해당 특정 조합의 경우, 플랫폼별 네이티브 코드 없이도 모바일에서 Tesseract에 무료로 액세스할 수 있습니다.
MAUI 종속성은 미묘한 차이가 아니라, 결정적인 제약 조건입니다. 실제 제품 평가에서는 반드시 다음 질문에 답해야 합니다. OCR 기능이 MAUI 앱 외에서 필요할 경우가 있을까요? 만약 그렇다면, TesseractOcrMaui는 기능 비교를 시작하기도 전에 평가 대상에서 제외됩니다. 백엔드 API, 웹 포털, Azure Function 또는 배치 프로세서를 추가하는 팀은 해당 프로젝트와 테서랙트오크르MAUI 코드를 한 줄도 공유할 수 없습니다. 그들은 두 가지 OCR 통합 기능을 개발하고 둘 다 무기한으로 유지 관리합니다.
IronOCR 플랫폼 경계를 없애줍니다. 동일한 IronTesseract 클래스, 동일한 OcrInput 전처리 파이프라인, 동일한 언어 구성이 MAUI 모바일 앱과 Docker에 배포된 ASP.NET CoreAPI에서 동일하게 작동합니다. 공유 클래스 라이브러리는 솔루션 전체에 걸쳐 OCR 로직을 전달합니다. 제품이 성장함에 따라 — 그리고 제품은 성장합니다 — OCR 레이어는 재작성 없이 함께 성장합니다. $999 영구 라이선스는 내장된 PDF 지원, 실제 모바일 이미지를 처리하는 전처리, 그리고 생산 문제 발생 시 상업적 지원과 함께 그 아키텍처적 자유를 제공합니다.
TesseractOcrMaui의 다운로드 횟수는 약 33,900회인 반면IronOCR은 수백만 회에 달하는데, 이는 특정 분야에서 실험적으로 사용되는 도구와 팀에서 대규모로 프로덕션 환경에 배포하는 라이브러리 간의 차이를 반영합니다. 서버 측 요구 사항이 없는 MAUI 전용 프로젝트의 개념 증명 작업에는 TesseractOcrMaui가 합리적인 무료 시작점입니다. 실제 운영 환경에서 사용할 경우, 이러한 아키텍처적 제약을 해결하는 데 드는 비용이IronOCR라이선스 구매 비용보다 더 많이 들게 될 것입니다.
[{i:Tesseract는 해당 소유자의 등록 상표입니다. 이 사이트는 Google과 관련이 없으며, Google의 승인을 받거나 지원을 받지 않습니다. 모든 제품명, 로고 및 브랜드는 해당 소유자의 자산입니다. 비교는 정보 제공 목적으로만 사용되며, 작성 시점에 공개적으로 이용 가능한 정보를 반영합니다.
자주 묻는 질문
Tesseract.MAUI란 무엇인가요?
Tesseract.MAUI 는 개발자와 기업이 이미지와 문서에서 텍스트를 추출하는 데 사용하는 OCR 솔루션입니다. 이 솔루션은 .NET 애플리케이션 개발용 IronOCR과 함께 평가된 여러 OCR 옵션 중 하나입니다.
IronOCR은 .NET 개발자를 위한 Tesseract.MAUI와 어떻게 다른가요?
IronOCR은 IronTesseract를 핵심 엔진으로 사용하는 NuGet 네이티브 .NET OCR 라이브러리입니다. Tesseract.MAUI에 비해 배포가 간단하고(SDK 설치 프로그램 없음), 정액제 요금이 적용되며, COM 인터롭이나 클라우드 종속성이 없는 깔끔한 C# API를 제공합니다.
IronOCR이 Tesseract.MAUI보다 설정이 더 쉬운가요?
IronOCR은 단일 NuGet 패키지를 통해 설치됩니다. SDK 설치 프로그램, 복사할 라이선스 파일, 등록할 COM 구성 요소 또는 관리해야 할 별도의 런타임 바이너리가 없습니다. 전체 OCR 엔진이 패키지에 번들로 제공됩니다.
Tesseract.MAUI와 IronOCR 사이에는 어떤 정확도 차이가 있나요?
IronOCR은 표준 비즈니스 문서, 송장, 영수증, 스캔 양식에 대해 높은 인식 정확도를 달성합니다. 품질이 많이 저하된 문서나 일반적이지 않은 스크립트의 경우 정확도는 소스 품질에 따라 달라집니다. IronOCR에는 이미지 전처리 필터가 포함되어 있어 저품질 입력에 대한 인식률을 향상시킵니다.
IronOCR은 PDF 텍스트 추출을 지원하나요?
예. IronOCR은 한 번의 호출로 원본 PDF와 스캔한 PDF 이미지 모두에서 텍스트를 추출합니다. 또한 여러 페이지의 TIFF 파일, 이미지, 스트림도 지원합니다. 스캔한 PDF의 경우 OCR은 페이지별 결과 개체를 사용하여 페이지별로 적용됩니다.
Tesseract.MAUI 라이선싱은 IronOCR과 어떻게 다른가요?
IronOCR은 페이지당 또는 스캔당 요금이 없는 정액제 영구 라이선스를 사용합니다. 대량의 문서를 처리하는 조직은 문서 양에 관계없이 동일한 라이선스 비용을 지불합니다. 자세한 내용과 볼륨 가격은 IronOCR 라이선스 페이지에서 확인할 수 있습니다.
IronOCR 어떤 언어를 지원하나요?
IronOCR은 별도의 NuGet 언어 팩을 통해 127개 언어를 지원합니다. 언어를 추가하려면 '닷넷 추가 패키지 IronOcr.Languages.{Language}' 명령 하나만 있으면 됩니다. 수동으로 파일을 배치하거나 경로를 구성할 필요가 없습니다.
.NET 프로젝트에 IronOCR 설치하는 방법은 무엇인가요?
NuGet을 통해 설치합니다: 패키지 관리자 콘솔에서 '설치-패키지 IronOcr' 또는 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행합니다. 추가 언어 팩도 같은 방법으로 설치됩니다. 기본 SDK 인스톨러가 필요하지 않습니다.
IronOCR은 Tesseract.MAUI와 달리 Docker 및 컨테이너화된 배포에 적합한가요?
예. IronOCR은 NuGet 패키지를 통해 Docker 컨테이너에서 작동합니다. 라이선스 키는 환경 변수를 통해 설정됩니다. OCR 엔진 자체에는 라이선스 파일, SDK 경로 또는 볼륨 마운트가 필요하지 않습니다.
구매하기 전에 Tesseract.MAUI와 비교하여 IronOCR을 사용해 볼 수 있나요?
예. IronOCR 평가판 모드는 문서를 처리하고 출력물에 워터마크 오버레이가 포함된 OCR 결과를 반환합니다. 라이선스를 구매하기 전에 자신의 문서에서 정확성을 확인할 수 있습니다.
IronOCR은 텍스트 추출과 함께 바코드 판독을 지원하나요?
IronOCR은 텍스트 추출과 OCR에 중점을 둡니다. 바코드 판독을 위해 Iron Software는 동반 라이브러리로 IronBarcode를 제공합니다. 두 가지 모두 개별적으로 또는 Iron Suite 번들의 일부로 사용할 수 있습니다.
Tesseract.MAUI에서 IronOCR로 쉽게 마이그레이션할 수 있나요?
Tesseract.MAUI에서 IronOCR로의 마이그레이션에는 일반적으로 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리를 제거하고, API 호출을 업데이트하는 작업이 포함됩니다. 대부분의 마이그레이션은 코드 복잡성을 크게 줄여줍니다.

