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

어떤 Tesseract OCR 라이브러리를 선택해야 할까요? 상위 세 가지 옵션에 대한 개발자의 비교

Veryfi는 귀하가 _client.ProcessDocumentAsync(bytes)를 호출할 때마다 귀하의 은행 계좌 번호, 라우팅 번호, 거래 금액, 공급업체 관계를 제3자 클라우드 서버로 전송합니다. 이것이 바로 베리피 평가 전체를 규정하는 아키텍처적 현실입니다. 구조화된 JSON 형식의 데이터가 한 줄이라도 반환되기 전에, 조직에서 가장 민감한 재무 데이터가 포함된 경비 문서가 이미 인프라를 벗어난 상태입니다. 많은 팀들에게 있어서, 그것으로 평가가 끝납니다.

베리피 이해하기

Veryfi는 경비 및 재무 문서 유형에 특화된 클라우드 기반 문서 인텔리전스 API입니다. 이 제품의 핵심 특징은 구조화된 출력입니다. 하위 단계에서 파싱이 필요한 원시 OCR 텍스트 대신, 베리피 API 호출은 공급업체 이름, 총액, 품목, 세금, 결제 카드 번호 뒷자리 4자리, 그리고 송장의 경우 은행 계좌 번호 및 라우팅 번호와 같은 미리 추출된 필드를 반환합니다. 해당 모델들은 대량의 금융 문서를 기반으로 사전 학습되었으며, 지원하는 문서 범주에 대해 99% 이상의 정확도를 자랑합니다.

아키텍처는 순수 클라우드 기반입니다. 모든 문서는 애플리케이션에서 HTTPS를 통해 베리피 서버로 전송되고, Veryfi의 AI/ML 파이프라인을 거쳐 JSON 형식으로 다시 애플리케이션으로 돌아옵니다. 온프레미스 배포 옵션도 없고, 에어갭 모드도 없으며, 문서를 외부로 전송하지 않고 처리할 방법도 없습니다.

주요 건축적 특징:

  • 클라우드 전용 처리: 모든 문서가 로컬 처리 경로 없이 api.veryfi.com로 업로드됩니다.
  • 4단계 인증: VeryfiClient은(는) clientId, clientSecret, usernameapiKey을(를) 요구하며, 이 네 가지 비밀을 관리하고 안전하게 저장하며 회전시켜야 합니다.
  • 문서당 가격 책정: 문서 유형과 볼륨 등급별로 Veryfi에 현재 요금을 문의하십시오
  • 비동기 전용 API: ProcessDocumentAsync가 주 방법입니다; 동기 경로가 없습니다
  • 전문 분야 문서 범위: 영수증, 송장, 수표, 은행 명세서, W-2 양식 및 명함; 일반 문서, 의료 기록, 계약서 및 기술 도면은 신뢰할 수 있는 보험 적용 범위에 포함되지 않습니다.
  • 독자적인 JSON 스키마: Veryfi의 응답 형식은 Veryfi에 특화되어 있습니다. 공급업체를 바꾸면 추출 로직을 다시 작성해야 하는 경우
  • 처리량 제한: 대용량 처리에는 HTTP 429 응답 처리를 위해 백오프 및 재시도 로직이 필요합니다.

베리피 영수증 처리

Veryfi SDK는 문서 처리를 위한 단 하나의 주요 메서드를 제공합니다.

using Veryfi;

public class VeryfiReceiptService
{
    private readonly VeryfiClient _client;

    public VeryfiReceiptService(string clientId, string clientSecret,
                                string username, string apiKey)
    {
        // Four credentials required — four secrets to manage
        _client = new VeryfiClient(clientId, clientSecret, username, apiKey);
    }

    public async Task<ReceiptData> ProcessReceiptAsync(string imagePath)
    {
        // Receipt image leaves your infrastructure here

        var imageBytes = File.ReadAllBytes(imagePath);
        var base64Image = Convert.ToBase64String(imageBytes);

        var response = await _client.ProcessDocumentAsync(
            fileData: base64Image,
            fileName: Path.GetFileName(imagePath)
        );

        return new ReceiptData
        {
            VendorName   = response.Vendor?.Name,
            Total        = response.Total,
            Date         = response.Date,
            Tax          = response.Tax,
            PaymentType  = response.Payment?.Type,
            CardLastFour = response.Payment?.Last4,
            LineItems    = response.LineItems?.Select(li => new LineItem
            {
                Description = li.Description,
                Quantity    = li.Quantity,
                UnitPrice   = li.UnitPrice,
                Total       = li.Total
            }).ToList()
        };
    }
}
using Veryfi;

public class VeryfiReceiptService
{
    private readonly VeryfiClient _client;

    public VeryfiReceiptService(string clientId, string clientSecret,
                                string username, string apiKey)
    {
        // Four credentials required — four secrets to manage
        _client = new VeryfiClient(clientId, clientSecret, username, apiKey);
    }

    public async Task<ReceiptData> ProcessReceiptAsync(string imagePath)
    {
        // Receipt image leaves your infrastructure here

        var imageBytes = File.ReadAllBytes(imagePath);
        var base64Image = Convert.ToBase64String(imageBytes);

        var response = await _client.ProcessDocumentAsync(
            fileData: base64Image,
            fileName: Path.GetFileName(imagePath)
        );

        return new ReceiptData
        {
            VendorName   = response.Vendor?.Name,
            Total        = response.Total,
            Date         = response.Date,
            Tax          = response.Tax,
            PaymentType  = response.Payment?.Type,
            CardLastFour = response.Payment?.Last4,
            LineItems    = response.LineItems?.Select(li => new LineItem
            {
                Description = li.Description,
                Quantity    = li.Quantity,
                UnitPrice   = li.UnitPrice,
                Total       = li.Total
            }).ToList()
        };
    }
}
Imports Veryfi
Imports System.IO
Imports System.Threading.Tasks

Public Class VeryfiReceiptService
    Private ReadOnly _client As VeryfiClient

    Public Sub New(clientId As String, clientSecret As String, username As String, apiKey As String)
        ' Four credentials required — four secrets to manage
        _client = New VeryfiClient(clientId, clientSecret, username, apiKey)
    End Sub

    Public Async Function ProcessReceiptAsync(imagePath As String) As Task(Of ReceiptData)
        ' Receipt image leaves your infrastructure here

        Dim imageBytes = File.ReadAllBytes(imagePath)
        Dim base64Image = Convert.ToBase64String(imageBytes)

        Dim response = Await _client.ProcessDocumentAsync(
            fileData:=base64Image,
            fileName:=Path.GetFileName(imagePath)
        )

        Return New ReceiptData With {
            .VendorName = response.Vendor?.Name,
            .Total = response.Total,
            .Date = response.Date,
            .Tax = response.Tax,
            .PaymentType = response.Payment?.Type,
            .CardLastFour = response.Payment?.Last4,
            .LineItems = response.LineItems?.Select(Function(li) New LineItem With {
                .Description = li.Description,
                .Quantity = li.Quantity,
                .UnitPrice = li.UnitPrice,
                .Total = li.Total
            }).ToList()
        }
    End Function
End Class
$vbLabelText   $csharpLabel

청구서는 민감도를 높입니다. 같은 ProcessDocumentAsync 패턴은 종종 은행 계좌 번호, 라우팅 번호, 공급업체 세금 ID 및 결제 조건이 포함된 문서를 전송합니다:

public async Task<InvoiceData> ProcessInvoiceAsync(string pdfPath)
{
    var pdfBytes = File.ReadAllBytes(pdfPath);

    // Invoice uploaded to 베리피 — banking details included
    var response = await _client.ProcessDocumentAsync(
        fileData: pdfBytes,
        fileName: Path.GetFileName(pdfPath),
        categories: new[] { "invoices" }
    );

    return new InvoiceData
    {
        InvoiceNumber    = response.InvoiceNumber,
        VendorName       = response.Vendor?.Name,
        VendorTaxId      = response.Vendor?.TaxId,       // transmitted
        Total            = response.Total,
        DueDate          = response.DueDate,
        PaymentTerms     = response.PaymentTerms,
        BankAccountNumber = response.BankAccount?.AccountNumber, // transmitted
        BankRoutingNumber = response.BankAccount?.RoutingNumber  // transmitted
    };
}
public async Task<InvoiceData> ProcessInvoiceAsync(string pdfPath)
{
    var pdfBytes = File.ReadAllBytes(pdfPath);

    // Invoice uploaded to 베리피 — banking details included
    var response = await _client.ProcessDocumentAsync(
        fileData: pdfBytes,
        fileName: Path.GetFileName(pdfPath),
        categories: new[] { "invoices" }
    );

    return new InvoiceData
    {
        InvoiceNumber    = response.InvoiceNumber,
        VendorName       = response.Vendor?.Name,
        VendorTaxId      = response.Vendor?.TaxId,       // transmitted
        Total            = response.Total,
        DueDate          = response.DueDate,
        PaymentTerms     = response.PaymentTerms,
        BankAccountNumber = response.BankAccount?.AccountNumber, // transmitted
        BankRoutingNumber = response.BankAccount?.RoutingNumber  // transmitted
    };
}
Imports System.IO
Imports System.Threading.Tasks

Public Async Function ProcessInvoiceAsync(pdfPath As String) As Task(Of InvoiceData)
    Dim pdfBytes = File.ReadAllBytes(pdfPath)

    ' Invoice uploaded to 베리피 — banking details included
    Dim response = Await _client.ProcessDocumentAsync(
        fileData:=pdfBytes,
        fileName:=Path.GetFileName(pdfPath),
        categories:=New String() {"invoices"}
    )

    Return New InvoiceData With {
        .InvoiceNumber = response.InvoiceNumber,
        .VendorName = response.Vendor?.Name,
        .VendorTaxId = response.Vendor?.TaxId, ' transmitted
        .Total = response.Total,
        .DueDate = response.DueDate,
        .PaymentTerms = response.PaymentTerms,
        .BankAccountNumber = response.BankAccount?.AccountNumber, ' transmitted
        .BankRoutingNumber = response.BankAccount?.RoutingNumber ' transmitted
    }
End Function
$vbLabelText   $csharpLabel

은행 명세서 엔드포인트는 가장 민감합니다. ProcessDocumentAsync을(를) categories: new[] { "bank_statements" }으로 호출하면 전체 계좌 번호, 라우팅 번호, 전체 거래 내역, 시작과 종료 잔고 및 송금 세부 사항이 Veryfi의 인프라로 전송됩니다.

IronOCR 이해하기

IronOCR 모든 문서를 로컬에서 처리하는 .NET 용 상용 온프레미스 OCR 라이브러리입니다. 문서 바이트가 인프라 외부로 유출되지 않습니다. 이 라이브러리는 최적화된 Tesseract 5 엔진과 자동 전처리, 네이티브 PDF 지원, 125개 이상의 언어 팩을 제공하며, 이 모든 것이 영구 라이선스가 포함된 단일 NuGet 패키지로 제공됩니다.

주요 특징:

  • 온프레미스 설계: 모든 처리는 사용자 하드웨어에서 이루어집니다. OCR에 대한 네트워크 호출 없음
  • 자동 전처리: 기울기 보정, 노이즈 제거, 대비 조정, 이진화 및 해상도 향상이 별도의 설정 없이 자동으로 적용됩니다.
  • 네이티브 PDF 입력: 별도의 PDF 라이브러리가 필요 없이 LoadPdf()를 통해 스캔 및 디지털 PDF를 직접 읽습니다.
  • 영구 라이선스: $999 Lite / $1,499 Plus / $2,999 Professional / $5,999 Unlimited - 한 번 결제하면 무제한 문서를 처리합니다.
  • 구조화된 결과 접근: 단어, 줄, 단락, 페이지와 X/Y 좌표 및 단어별 신뢰도 점수 제공
  • 스레드 안전 및 병렬 처리 가능: IronTesseract 인스턴스는 추가 동기화 없이 스레드 간에 사용할 수 있습니다.
  • 125개 이상의 언어 지원: NuGet 패키지로 설치되므로 tessdata 폴더를 관리할 필요가 없습니다.
  • 크로스 플랫폼: Windows, Linux, macOS, Docker, AWS, Azure - 하나의 패키지로 모든 대상을 지원합니다.

기능 비교

기능 베리피 IronOCR
데이터 위치 베리피 클라우드 서버 귀사의 인프라
배포 모델 클라우드 API 전용 온프레미스
가격 모델 문서당 가격 책정 (Veryfi에 문의하여 가격을 확인하세요) 영구 라이선스 ($999–$5,999)
오프라인 지원 아니요
문서 범위 경비 증빙 서류만 해당 모든 문서 유형
설정 4개의 API 자격 증명 라이선스 키 1개

상세 기능 비교

기능 베리피 IronOCR
데이터 개인정보
문서가 인프라를 떠납니다 예 (모든 통화) 절대
에어갭 배포 불가능 완전히 지원
온프레미스 처리 불가능 기본 동작
HIPAA 준수 (사업 제휴 계약(BAA) 불필요) 아니요 (BAA 필요)
ITAR/CMMC 호환 가능 복잡함
문서 지원
영수증 처리 예 (전문 분야) 예 (OCR + 추출을 통해)
송장 처리 예 (전문 분야) 예 (OCR + 추출을 통해)
은행 거래 내역 처리 예 (전문 분야) 예 (OCR + 추출을 통해)
일반 비즈니스 문서 저조한 결과
의료 기록 지원되지 않음
법률 계약 제한적
사용자 지정/임의 문서 유형 유급 교육 필수 모든 유형
여러 페이지로 구성된 PDF 파일
인위적인
인터넷 연결이 필요합니다. 예 (모든 문서) 아니요
동기식 API 사용 가능 아니요
이미지 전처리 자동(클라우드) 자동(로컬)
PDF 입력(기본)
검색 가능한 PDF 출력 아니요
바코드 판독 아니요
영역 기반 OCR 아니요
신뢰도 점수 필드별 단어별 및 전체
개발
관리할 자격 증명 4 (클라이언트 ID, 클라이언트 시크릿, 사용자 이름, API 키) 1 (라이선스 키)
단위 테스트 복잡성 HTTP 모킹이 필요합니다. 현지 직접 검사
오류 처리 HTTP 상태 코드 + VeryfiApiException 로컬 .NET 예외
언어 지원 제한적 125개 이상의 언어
비용
비용 상한선 계약상 한도가 없는 경우는 없습니다. 라이선스 가격
대량 생산 시 비용 선형적으로 확장됩니다 평평한

금융 문서 관련 데이터 개인정보 보호

Veryfi에서 처리하는 재무 문서에는 모든 조직에서 가장 민감한 데이터 범주가 포함되어 있습니다. 이는 이론적인 문제가 아니라, 제품이 작동하는 방식에 대한 구체적인 구조적 사실입니다.

베리피 접근 방식

모든 베리피 API 호출은 문서 바이트를 HTTPS를 통해 api.veryfi.com로 전송합니다. 해당 문서에서 추출된 데이터(계좌 번호, 라우팅 번호, 거래 내역, 공급업체 세금 ID, 결제 카드 정보 및 지출 패턴)는 Veryfi의 인프라에서 처리됩니다. 데이터 상주, 보존 정책, 하위 처리자 체계 및 침해 대응 절차는 모두 Veryfi의 약관에 따라 규정되며 귀사의 약관과는 무관합니다.

// 은행 거래 내역 처리 — critical sensitivity
public async Task<BankStatementData> ProcessBankStatementAsync(string pdfPath)
{
    var pdfBytes = File.ReadAllBytes(pdfPath);

    // AT THIS POINT: full financial history leaves your infrastructure
    // Account numbers, transaction history, balances — all transmitted
    var response = await _client.ProcessDocumentAsync(
        fileData: pdfBytes,
        categories: new[] { "bank_statements" }
    );

    return new BankStatementData
    {
        AccountNumber  = response.AccountNumber,  // critical — transmitted
        RoutingNumber  = response.RoutingNumber,  // critical — transmitted
        OpeningBalance = response.OpeningBalance,
        ClosingBalance = response.ClosingBalance,
        Transactions   = response.Transactions?.Select(t => new Transaction
        {
            Date        = t.Date,
            Description = t.Description,
            Amount      = t.Amount,
            Balance     = t.RunningBalance
        }).ToList()
    };
}
// 은행 거래 내역 처리 — critical sensitivity
public async Task<BankStatementData> ProcessBankStatementAsync(string pdfPath)
{
    var pdfBytes = File.ReadAllBytes(pdfPath);

    // AT THIS POINT: full financial history leaves your infrastructure
    // Account numbers, transaction history, balances — all transmitted
    var response = await _client.ProcessDocumentAsync(
        fileData: pdfBytes,
        categories: new[] { "bank_statements" }
    );

    return new BankStatementData
    {
        AccountNumber  = response.AccountNumber,  // critical — transmitted
        RoutingNumber  = response.RoutingNumber,  // critical — transmitted
        OpeningBalance = response.OpeningBalance,
        ClosingBalance = response.ClosingBalance,
        Transactions   = response.Transactions?.Select(t => new Transaction
        {
            Date        = t.Date,
            Description = t.Description,
            Amount      = t.Amount,
            Balance     = t.RunningBalance
        }).ToList()
    };
}
Imports System.IO
Imports System.Threading.Tasks

' 은행 거래 내역 처리 — critical sensitivity
Public Async Function ProcessBankStatementAsync(pdfPath As String) As Task(Of BankStatementData)
    Dim pdfBytes = File.ReadAllBytes(pdfPath)

    ' AT THIS POINT: full financial history leaves your infrastructure
    ' Account numbers, transaction history, balances — all transmitted
    Dim response = Await _client.ProcessDocumentAsync(
        fileData:=pdfBytes,
        categories:=New String() {"bank_statements"}
    )

    Return New BankStatementData With {
        .AccountNumber = response.AccountNumber,  ' critical — transmitted
        .RoutingNumber = response.RoutingNumber,  ' critical — transmitted
        .OpeningBalance = response.OpeningBalance,
        .ClosingBalance = response.ClosingBalance,
        .Transactions = If(response.Transactions?.Select(Function(t) New Transaction With {
            .Date = t.Date,
            .Description = t.Description,
            .Amount = t.Amount,
            .Balance = t.RunningBalance
        }).ToList(), Nothing)
    }
End Function
$vbLabelText   $csharpLabel

Veryfi는 SOC 2 Type II, GDPR 및 HIPAA(사업 제휴 계약 포함) 인증을 보유하고 있습니다. 해당 인증은 Veryfi가 명시된 보안 규정을 준수하고 있음을 확인시켜 줍니다. 이는 귀하의 데이터가 귀하의 통제 하에 있거나, 데이터 상주 위치를 귀하가 제어하거나, Veryfi의 하위 처리자가 데이터에 접근할 수 없다는 것을 의미하지 않습니다. CMMC 레벨 2 이상, ITAR, SOX 또는 GLBA의 적용을 받는 조직의 경우 Veryfi를 데이터 처리자로 추가하면 법률 검토 및 지속적인 감독이 필요한 규정 준수 범위가 추가됩니다.

IronOCR 접근법

IronOCR 네트워크 전송 없이 문서를 처리합니다. OCR 엔진은 사용자의 하드웨어에서 실행됩니다. 은행 명세서, 송금 번호가 포함된 청구서, 계좌 번호가 적힌 수표는 절대 서버를 벗어나지 않습니다.

using IronOcr;
using System.Text.RegularExpressions;

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

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

    public BankStatementResult ProcessBankStatement(string pdfPath)
    {
        // All processing on your infrastructure
        // 아니요 network calls — no external access
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);

        var result = _ocr.Read(input);
        var text   = result.Text;

        // Account numbers stay on your server
        return new BankStatementResult
        {
            AccountNumber = ExtractAccountNumber(text),
            Balance       = ExtractBalance(text),
            RawText       = text,
            Confidence    = result.Confidence
        };
    }

    private string ExtractAccountNumber(string text)
    {
        var match = Regex.Match(text,
            @"Account\s*#?\s*:?\s*(\d{4,})",
            RegexOptions.IgnoreCase);
        return match.Success ? match.Groups[1].Value : null;
    }

    private decimal? ExtractBalance(string text)
    {
        var match = Regex.Match(text,
            @"Balance:?\s*\$?([\d,]+\.?\d*)",
            RegexOptions.IgnoreCase);
        if (match.Success && decimal.TryParse(
            match.Groups[1].Value.Replace(",", ""), out var bal))
            return bal;
        return null;
    }
}
using IronOcr;
using System.Text.RegularExpressions;

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

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

    public BankStatementResult ProcessBankStatement(string pdfPath)
    {
        // All processing on your infrastructure
        // 아니요 network calls — no external access
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);

        var result = _ocr.Read(input);
        var text   = result.Text;

        // Account numbers stay on your server
        return new BankStatementResult
        {
            AccountNumber = ExtractAccountNumber(text),
            Balance       = ExtractBalance(text),
            RawText       = text,
            Confidence    = result.Confidence
        };
    }

    private string ExtractAccountNumber(string text)
    {
        var match = Regex.Match(text,
            @"Account\s*#?\s*:?\s*(\d{4,})",
            RegexOptions.IgnoreCase);
        return match.Success ? match.Groups[1].Value : null;
    }

    private decimal? ExtractBalance(string text)
    {
        var match = Regex.Match(text,
            @"Balance:?\s*\$?([\d,]+\.?\d*)",
            RegexOptions.IgnoreCase);
        if (match.Success && decimal.TryParse(
            match.Groups[1].Value.Replace(",", ""), out var bal))
            return bal;
        return null;
    }
}
Imports IronOcr
Imports System.Text.RegularExpressions

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

Public Class LocalFinancialDocumentProcessor
    Private ReadOnly _ocr As New IronTesseract()

    Public Function ProcessBankStatement(pdfPath As String) As BankStatementResult
        ' All processing on your infrastructure
        ' 아니요 network calls — no external access
        Using input As New OcrInput()
            input.LoadPdf(pdfPath)

            Dim result = _ocr.Read(input)
            Dim text = result.Text

            ' Account numbers stay on your server
            Return New BankStatementResult With {
                .AccountNumber = ExtractAccountNumber(text),
                .Balance = ExtractBalance(text),
                .RawText = text,
                .Confidence = result.Confidence
            }
        End Using
    End Function

    Private Function ExtractAccountNumber(text As String) As String
        Dim match = Regex.Match(text,
            "Account\s*#?\s*:?\s*(\d{4,})",
            RegexOptions.IgnoreCase)
        Return If(match.Success, match.Groups(1).Value, Nothing)
    End Function

    Private Function ExtractBalance(text As String) As Decimal?
        Dim match = Regex.Match(text,
            "Balance:?\s*\$?([\d,]+\.?\d*)",
            RegexOptions.IgnoreCase)
        If match.Success AndAlso Decimal.TryParse(
            match.Groups(1).Value.Replace(",", ""), bal) Then
            Return bal
        End If
        Return Nothing
    End Function
End Class
$vbLabelText   $csharpLabel

규정 준수가 중요한 환경에서는 현지 처리를 통해 제3자 감사 범위를 완전히 없앨 수 있습니다.IronOCR에는 BAA가 없습니다. 하위 처리업체 정보는 공개되지 않았습니다. 데이터 상주 위치에 대한 질문은 없습니다. Windows, Linux, Docker 및 에어갭 환경에 걸친 배포 구성에 대한 자세한 내용은 IronTesseract 설정 가이드를 참조하십시오.

전문가 범위 vs. 일반 OCR

Veryfi의 좁은 문서 범위에 초점을 맞춘다는 점은 가장 큰 장점이자 가장 큰 한계점이기도 합니다. 사전 학습된 모델은 특정 문서 유형에 대해 매우 빠르고 구조화된 결과를 제공합니다. 문제는 조직에서 해당 목록에 없는 OCR 기능이 필요할 때 발생합니다.

베리피 접근 방식

Veryfi는 자신들의 분야에서 훌륭하게 작동합니다. 영수증 이미지를 제출하면 판매자, 총액, 세금, 결제 방법 및 품목 정보가 포함된 응답을 받게 됩니다. 사용자 측에서 정규 표현식을 사용할 필요가 없습니다. 하지만 그 범위는 비용 및 재무 문서의 경계에서 끝납니다. README 파일에는 다음과 같이 명시되어 있습니다. 일반 비즈니스 문서, 의료 기록, 기술 도면, 다국어 문서 및 학습 데이터 세트에 포함되지 않은 사용자 지정 양식 유형은 성능이 저하되거나 유료 맞춤형 모델 학습이 필요합니다.

실제 조직은 단 하나의 문서 범주만 처리하는 경우는 드뭅니다. 인사 부서는 직원의 입사 서류를 처리합니다. 법무팀은 계약서 전문이 필요합니다. 운영팀은 선적 서류와 물류 양식을 처리합니다. Veryfi의 범위를 벗어나는 각 범주는 스택에 두 번째 솔루션을 추가하도록 강제합니다.

// Veryfi: works for invoices, fails for shipping manifests
var invoiceResponse = await _client.ProcessDocumentAsync(
    fileData: invoiceBytes,
    categories: new[] { "invoices" }
);

// For anything outside the supported list, you need a second tool
// Contracts: limited support
// Medical forms: not supported
// Shipping documents: not supported
// Custom forms: paid training required
// Veryfi: works for invoices, fails for shipping manifests
var invoiceResponse = await _client.ProcessDocumentAsync(
    fileData: invoiceBytes,
    categories: new[] { "invoices" }
);

// For anything outside the supported list, you need a second tool
// Contracts: limited support
// Medical forms: not supported
// Shipping documents: not supported
// Custom forms: paid training required
Imports System.Threading.Tasks

' Veryfi: works for invoices, fails for shipping manifests
Dim invoiceResponse = Await _client.ProcessDocumentAsync(
    fileData:=invoiceBytes,
    categories:=New String() {"invoices"}
)

' For anything outside the supported list, you need a second tool
' Contracts: limited support
' Medical forms: not supported
' Shipping documents: not supported
' Custom forms: paid training required
$vbLabelText   $csharpLabel

IronOCR 접근법

IronOCR 모든 유형의 문서를 처리합니다. 추출 로직은 직접 작성해야 하므로, 모든 경비 문서에서 공통적으로 나타날 필드를 미리 학습된 모델이 추측하는 것이 아니라, 문서에 포함된 실제 필드를 정확하게 처리합니다. 같은 IronTesseract 인스턴스는 영수증, 계약서, 의료 양식, 배송 문서 및 사용자 정의 내부 양식을 처리합니다:

using IronOcr;

var ocr = new IronTesseract();

// Receipts
var receiptResult = ocr.Read("receipt.jpg");
var receiptTotal  = ExtractTotal(receiptResult.Text);

// Contracts — not in Veryfi's scope
using var contractInput = new OcrInput();
contractInput.LoadPdf("contract.pdf");
var contractResult = ocr.Read(contractInput);
var parties        = ExtractContractParties(contractResult.Text);

// Medical forms — requires HIPAA BAA with Veryfi; stays local with IronOCR
var medicalResult = ocr.Read("patient-intake-form.jpg");
var patientName   = medicalResult.Lines.FirstOrDefault()?.Text;

// Shipping documents
var shipResult    = ocr.Read("bill-of-lading.jpg");
var trackingNum   = ExtractPattern(shipResult.Text, @"Tracking\s*#?\s*:?\s*(\w+)");
using IronOcr;

var ocr = new IronTesseract();

// Receipts
var receiptResult = ocr.Read("receipt.jpg");
var receiptTotal  = ExtractTotal(receiptResult.Text);

// Contracts — not in Veryfi's scope
using var contractInput = new OcrInput();
contractInput.LoadPdf("contract.pdf");
var contractResult = ocr.Read(contractInput);
var parties        = ExtractContractParties(contractResult.Text);

// Medical forms — requires HIPAA BAA with Veryfi; stays local with IronOCR
var medicalResult = ocr.Read("patient-intake-form.jpg");
var patientName   = medicalResult.Lines.FirstOrDefault()?.Text;

// Shipping documents
var shipResult    = ocr.Read("bill-of-lading.jpg");
var trackingNum   = ExtractPattern(shipResult.Text, @"Tracking\s*#?\s*:?\s*(\w+)");
Imports IronOcr

Dim ocr As New IronTesseract()

' Receipts
Dim receiptResult = ocr.Read("receipt.jpg")
Dim receiptTotal = ExtractTotal(receiptResult.Text)

' Contracts — not in Veryfi's scope
Using contractInput As New OcrInput()
    contractInput.LoadPdf("contract.pdf")
    Dim contractResult = ocr.Read(contractInput)
    Dim parties = ExtractContractParties(contractResult.Text)
End Using

' Medical forms — requires HIPAA BAA with Veryfi; stays local with IronOCR
Dim medicalResult = ocr.Read("patient-intake-form.jpg")
Dim patientName = medicalResult.Lines.FirstOrDefault()?.Text

' Shipping documents
Dim shipResult = ocr.Read("bill-of-lading.jpg")
Dim trackingNum = ExtractPattern(shipResult.Text, "Tracking\s*#?\s*:?\s*(\w+)")
$vbLabelText   $csharpLabel

일관된 패턴을 따르는 청구서와 영수증 필드의 경우, IronOCR의 구조화된 데이터 추출은 추출 로직을 정확하게 만드는 단어 수준 위치를 제공합니다. Y 위치별로 정렬된 result.Lines 컬렉션은 영수증 헤더에서 공급업체 이름을 신뢰성 있게 나타냅니다. 이미지 품질 보정 필터는 실제 경비 처리 과정에서 발생하는 구겨지거나, 흐릿하거나, 사진으로 찍힌 영수증을 처리합니다.

문서별 클라우드 비용 vs. 영구 라이선스

Veryfi와IronOCR의 비용 차이는 처리하는 문서가 많을수록 누적됩니다. Veryfi의 문서별 요금제는 계약상 협의를 통해 상한선을 정하지 않는 한, 문서량에 정확히 비례하여 비용이 증가한다는 것을 의미합니다.

베리피 접근 방식

Veryfi는 문서당 요금을 부과합니다. 요금은 문서 유형 및 볼륨 등급에 따라 결정됩니다 — 현재 가격을 확인하려면 Veryfi에 문의하세요. 비용은 계약으로 하나를 협상하지 않는 이상 볼륨에 비례하여 직접적으로 증가하며, 고객으로 사용한 기간에 상관없이 이후 연도에도 감소하지 않습니다.

// This method call costs money — every time
// Costs accumulate with every document processed
var response = await _client.ProcessDocumentAsync(bytes);
// This method call costs money — every time
// Costs accumulate with every document processed
var response = await _client.ProcessDocumentAsync(bytes);
' This method call costs money — every time
' Costs accumulate with every document processed
Dim response = Await _client.ProcessDocumentAsync(bytes)
$vbLabelText   $csharpLabel

숨겨진 비용이 총액을 증가시킵니다. HTTP 429에서 속도 제한을 걸면 재시도 로직이 강제됩니다. API 버전 변경에는 SDK 업데이트가 필요합니다. 데이터 처리 계약에 대한 보안 검토로 인해 법적 소요 시간이 추가되며, 계절적 사용량이 계획된 예상치를 초과할 경우 초과 요금이 발생합니다.

IronOCR 접근법

IronOCR 라이선스는 일회성 구매입니다. $2,999의 Professional 라이선스는 10명의 개발자를 커버하며, 월간 무제한 문서 처리를 지원하고, 처리를 계속하기 위한 갱신이 필요하지 않습니다. 2년차 처리 비용은 0달러입니다. 5년차 처리 비용은 0달러입니다.

// Configure once at startup — no per-call cost
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

// This processes 50,000 documents/month at $0 marginal cost
foreach (var documentPath in documentBatch)
{
    var result = ocr.Read(documentPath);
    ProcessExtractedData(result.Text, result.Lines);
}
// Configure once at startup — no per-call cost
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

// This processes 50,000 documents/month at $0 marginal cost
foreach (var documentPath in documentBatch)
{
    var result = ocr.Read(documentPath);
    ProcessExtractedData(result.Text, result.Lines);
}
Imports IronOcr

' Configure once at startup — no per-call cost
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr As New IronTesseract()

' This processes 50,000 documents/month at $0 marginal cost
For Each documentPath In documentBatch
    Dim result = ocr.Read(documentPath)
    ProcessExtractedData(result.Text, result.Lines)
Next
$vbLabelText   $csharpLabel

높은 문서 볼륨에서 3년 비교: IronOCR는 추출 패턴을 구축하기 위해 약 8-16시간의 개발 시간을 더하여 $2,999를 총합하며, Veryfi는 처리되는 각 문서마다 비용이 누적됩니다. 대개 사용 첫 몇 개월 내에 손익 분기점에 도달합니다.

현재 클라우드 OCR에 비용을 지출하고 있는 팀의 경우, IronOCR 라이선스 페이지에서 등급별 세부 정보와 연간 청구를 선호하는 팀을 위한 SaaS 구독 옵션을 확인할 수 있습니다.

웹훅 및 비동기 처리 vs. 동기식 로컬 결과

Veryfi의 클라우드 아키텍처는 비동기 처리 모델만을 채택하고 있습니다. 문서는 원격 서버로 전송되어 원격 파이프라인에서 처리되고, 네트워크 왕복 후 응답이 도착합니다. 대용량 배치 처리의 경우 Veryfi는 폴링 방식보다는 웹훅 기반 알림 방식을 권장합니다.IronOCR기본적으로 동기식으로 처리하며, 실행 과정에 네트워크 종속성이 없습니다.

베리피 접근 방식

Veryfi의 모든 처리는 클라우드 기반이기 때문에 비동기적으로 이루어집니다. ProcessDocumentAsync 방법은 HTTP 호출을 시작하고, Veryfi의 파이프라인이 완료될 때까지 대기한 다음 결과를 반환합니다. 총 지연 시간에는 네트워크 전송, 베리피 인프라의 대기 시간, 모델 추론 및 응답 전송이 포함됩니다.

// 베리피 error categories reflect cloud dependencies
public async Task<ReceiptData> ProcessWithHandlingAsync(string path)
{
    try
    {
        var bytes    = File.ReadAllBytes(path);
        var response = await _client.ProcessDocumentAsync(bytes);
        return MapToReceiptData(response);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 401)
    {
        // Credential failure — check all four credentials
        throw new Exception("Authentication failed. Verify clientId, clientSecret, username, apiKey.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 402)
    {
        // Plan quota exceeded — processing halted until billing resolved
        throw new Exception("Quota exceeded. Check plan limits and billing.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 429)
    {
        // Rate limited — requires exponential backoff implementation
        throw new Exception("Rate limit exceeded. Implement retry with backoff.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 500)
    {
        // 베리피 infrastructure failure — your processing is down
        throw new Exception("Veryfi server error. Processing unavailable.", ex);
    }
}
// 베리피 error categories reflect cloud dependencies
public async Task<ReceiptData> ProcessWithHandlingAsync(string path)
{
    try
    {
        var bytes    = File.ReadAllBytes(path);
        var response = await _client.ProcessDocumentAsync(bytes);
        return MapToReceiptData(response);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 401)
    {
        // Credential failure — check all four credentials
        throw new Exception("Authentication failed. Verify clientId, clientSecret, username, apiKey.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 402)
    {
        // Plan quota exceeded — processing halted until billing resolved
        throw new Exception("Quota exceeded. Check plan limits and billing.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 429)
    {
        // Rate limited — requires exponential backoff implementation
        throw new Exception("Rate limit exceeded. Implement retry with backoff.", ex);
    }
    catch (VeryfiApiException ex) when (ex.StatusCode == 500)
    {
        // 베리피 infrastructure failure — your processing is down
        throw new Exception("Veryfi server error. Processing unavailable.", ex);
    }
}
Imports System.IO
Imports System.Threading.Tasks

Public Async Function ProcessWithHandlingAsync(path As String) As Task(Of ReceiptData)
    Try
        Dim bytes = File.ReadAllBytes(path)
        Dim response = Await _client.ProcessDocumentAsync(bytes)
        Return MapToReceiptData(response)
    Catch ex As VeryfiApiException When ex.StatusCode = 401
        ' Credential failure — check all four credentials
        Throw New Exception("Authentication failed. Verify clientId, clientSecret, username, apiKey.", ex)
    Catch ex As VeryfiApiException When ex.StatusCode = 402
        ' Plan quota exceeded — processing halted until billing resolved
        Throw New Exception("Quota exceeded. Check plan limits and billing.", ex)
    Catch ex As VeryfiApiException When ex.StatusCode = 429
        ' Rate limited — requires exponential backoff implementation
        Throw New Exception("Rate limit exceeded. Implement retry with backoff.", ex)
    Catch ex As VeryfiApiException When ex.StatusCode = 500
        ' 베리피 infrastructure failure — your processing is down
        Throw New Exception("Veryfi server error. Processing unavailable.", ex)
    End Try
End Function
$vbLabelText   $csharpLabel

네트워크 장애로 인해 처리가 중단됩니다. 베리피 인프라 장애로 인해 처리가 중단됩니다. 속도 제한으로 인해 처리가 중단됩니다. 이러한 요소들은 모두 애플리케이션이 제어할 수 없는 외부 종속성입니다.

IronOCR 접근법

IronOCR 네트워크에 전혀 의존하지 않고 동기적으로 처리됩니다. 결과는 Read()가 돌아온 직후 즉시 사용 가능하며, 폴링도, 웹훅 구성도, 네트워크 실패에 대한 재시도 로직도 필요 없습니다.

using IronOcr;

var ocr = new IronTesseract();

// Synchronous — result immediately available
// 아니요 network, no quota, no rate limits
var result = ocr.Read("receipt.jpg");

Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");

// Word-level positioning for precise field extraction
foreach (var line in result.Lines)
{
    Console.WriteLine($"Y={line.Y}: {line.Text}");
}
using IronOcr;

var ocr = new IronTesseract();

// Synchronous — result immediately available
// 아니요 network, no quota, no rate limits
var result = ocr.Read("receipt.jpg");

Console.WriteLine(result.Text);
Console.WriteLine($"Confidence: {result.Confidence}%");

// Word-level positioning for precise field extraction
foreach (var line in result.Lines)
{
    Console.WriteLine($"Y={line.Y}: {line.Text}");
}
Imports IronOcr

Dim ocr As New IronTesseract()

' Synchronous — result immediately available
' 아니요 network, no quota, no rate limits
Dim result = ocr.Read("receipt.jpg")

Console.WriteLine(result.Text)
Console.WriteLine($"Confidence: {result.Confidence}%")

' Word-level positioning for precise field extraction
For Each line In result.Lines
    Console.WriteLine($"Y={line.Y}: {line.Text}")
Next
$vbLabelText   $csharpLabel

UI 응답성을 위한 비동기 동작이 필요한 애플리케이션의 경우, IronOCR는 Task.Run 래핑 또는 비동기 API 표면을 통해 비동기 OCR도 지원합니다. 차이점은IronOCR에서 비동기(async)는 원격 호출에 의해 부과되는 요구 사항이 아니라 동시성 패턴이라는 점입니다. 새벽 2시에 네트워크 장애가 발생해도 배치 프로세스는 중단되지 않습니다.

영수증 스캔 워크플로의 경우, 영수증 스캔 튜토리얼송장 OCR 가이드 에서 전체 추출 패턴 구현 방법을 다룹니다. 신뢰도 점수는 단어별 신뢰도 신호를 제공하여 추출된 데이터를 하위 시스템으로 전송하기 전에 품질이 낮은 스캔을 식별하는 데 도움을 줍니다.

API 매핑 참조

베리피 IronOCR에 상응하는
new VeryfiClient(clientId, clientSecret, username, apiKey) new IronTesseract() + IronOcr.License.LicenseKey = "key"
_client.ProcessDocumentAsync(bytes) ocr.Read(filePath) 또는 ocr.Read(ocrInput)
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" }) input.LoadPdf(pdfPath); ocr.Read(input)
response.Vendor?.Name result.Lines.FirstOrDefault()?.Text
response.Total 정규 표현식을 통한 ExtractTotal(result.Text)
response.Date 정규 표현식을 통한 ExtractDate(result.Text)
response.LineItems 위치 기반 추출을 통한 result.Lines
response.InvoiceNumber Regex.Match(result.Text, @"Invoice\s*#?\s*:?\s*(\w+)")
response.ConfidenceScore result.Confidence
response.Payment?.Last4 Regex.Match(result.Text, @"\d{4}$")
response.BankAccount?.AccountNumber Regex.Match(result.Text, @"Account\s*#?\s*:?\s*(\d+)")
VeryfiApiException (HTTP 401/402/429/500) 표준 .NET 예외(로컬, 네트워크 코드 없음)
업로드 전 Base64 인코딩 필요 없음 - ocr.Read(filePath) 파일 경로를 직접 수락합니다
구성에 있는 네 가지 자격 증명 단일 라이선스 키

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

데이터 주권은 협상 불가능한 원칙이 되었습니다.

IronOCR 평가하게 되는 가장 일반적인 계기는 Veryfi가 민감한 금융 기록을 처리하는 데이터 처리업체로 드러나는 규정 준수 감사 또는 법률 검토입니다. HIPAA 평가 결과, 개인 건강 정보(PHI)가 포함된 경비 문서는 Veryfi와의 사업 제휴 계약 및 지속적인 감사 감독이 필요한 것으로 나타났습니다. CMMC 레벨 2 평가에서 클라우드를 통해 전송되는 재무 문서가 잠재적인 취약점으로 지적되었습니다. 법률팀은 고객 사건 관련 비용 데이터를 제3자에게 전송하지 않도록 권고했습니다. 각 시나리오에서 규정 준수를 위한 경로는 외부 데이터 전송을 제거하는 것, 즉 Veryfi를 온프레미스 OCR로 교체하는 것입니다. IronOCR의 로컬 처리 모델은 기본적으로 다음과 같은 요구 사항을 충족합니다. BAA(비즈니스 계약) 없음, 하위 처리 체인 없음, 제3자 감사 범위 없음.

문서 유형이 경비 항목을 넘어 확장되고 있습니다.

Veryfi를 도입하여 경비 자동화를 구현하는 조직은 종종 6~12개월 이내에 관련 팀에서 Veryfi의 학습 데이터 세트에 포함되지 않은 문서에 대한 OCR 기능이 필요하다는 사실을 알게 됩니다. 인사팀에서 신입 직원 온보딩 서류 처리를 요청합니다. 법률 관련 계약서 전문을 추출했습니다. 운영 부서에서는 선하증권 데이터 수집이 필요합니다. 새로운 문서 카테고리를 추가할 때마다 Veryfi의 범용 엔드포인트에서 제대로 된 결과가 나오지 않거나, 유료 맞춤형 모델 학습이 필요하거나, 인프라에 두 번째 OCR 솔루션을 도입해야 하는 상황이 발생합니다.IronOCR라이선스 하나로 동일한 API를 통해 이 모든 기능을 사용할 수 있습니다. 특정 문서 읽기 튜토리얼에서는 구조화된 양식 레이아웃에 대한 추출 전략을 다룹니다.

문서당 비용이 사업 타당성 기준치를 초과함

한 달에 25,000건 이상의 문서를 처리하는 팀의 경우IronOCR투자 회수 기간이 일반적으로 3개월 미만입니다. 높은 문서 볼륨에서, $2,999의IronOCR Professional 라이선스는 일반적으로 동일한 베리피 지출의 첫 번째 달 내에 비용이 상쇄됩니다. 문서별 클라우드 가격 책정에 대한 총 소유 비용 분석을 수행하는 재무팀은 필연적으로 이러한 비교에 도달하게 됩니다. 팀에서 필요로 하는 특정 필드에 대한 정규 표현식 추출 패턴을 구축하는 마이그레이션 작업은 문서의 복잡성과 워크플로에 포함된 문서 유형의 수에 따라 일반적으로 8~24시간이 소요됩니다.

오프라인 및 연결이 끊긴 환경

현장 서비스 조직, 원격 근무지, 모바일 경비 입력 앱, 그리고 인터넷 연결이 끊긴 정부 환경은 공통적으로 OCR이 인터넷 없이 작동해야 한다는 요구 사항을 가지고 있습니다. Veryfi는 아키텍처적으로 이러한 요구 사항을 충족할 수 없습니다. 네트워크 연결이 없으면 모든 문서 처리 호출이 실패합니다.IronOCR설계상 오프라인으로 처리됩니다. 모바일 경비 앱을 사용하는 현장 기술자, 방화벽으로 보호되는 네트워크를 사용하는 제조 공장, 그리고 SCIF(민감 정보 보호 시설) 내의 방위 산업체 모두IronOCR수정 없이 실행할 수 있습니다. Docker 배포 가이드Linux 배포 가이드는 네트워크 송신이 제한된 컨테이너 환경을 다룹니다.

벤더 종속성 및 스키마 의존성

Veryfi의 JSON 응답 스키마는 독점 기술입니다. 벤더 이름, 합계, 라우팅 번호 또는 품목 필드를 읽는 모든 추출 코드 줄은 Veryfi에서만 작동하는 코드입니다. 경쟁 클라우드 API 또는 온프레미스 솔루션으로 전환하려면 모든 추출 로직을 다시 작성해야 합니다. Veryfi와 다년간 계약을 협상하는 조직들은 가격 변동이나 제품 로드맵 변경 시 이러한 의존성을 발견하게 됩니다.IronOCR추출 로직은 표준 .NET 정규 표현식을 사용하여 원시 텍스트에서 데이터를 읽어옵니다. 따라서 이식성이 뛰어나고 특정 공급업체의 스키마에 종속되지 않습니다.

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

구조화된 출력을 패턴 추출로 대체

Veryfi는 미리 구문 분석된 필드를 반환합니다.IronOCR OCR 처리된 원본 텍스트를 반환합니다. 마이그레이션 작업은 Veryfi가 클라우드에서 수행했던 추출 패턴을 작성하는 것입니다. 레이아웃이 일관된 영수증과 청구서의 경우, 이 과정은 간단합니다.

using IronOcr;
using System.Text.RegularExpressions;

var ocr    = new IronTesseract();
var result = ocr.Read("receipt.jpg");
var text   = result.Text;

// Vendor: first non-empty line, ordered by Y position
var vendor = result.Lines
    .OrderBy(l => l.Y)
    .Select(l => l.Text.Trim())
    .FirstOrDefault(t => !string.IsNullOrWhiteSpace(t) && t.Length > 3);

// Total: pattern matching against common receipt labels
decimal? total = null;
foreach (var pattern in new[] {
    @"Total:?\s*\$?\s*([\d,]+\.?\d*)",
    @"Grand Total:?\s*\$?\s*([\d,]+\.?\d*)",
    @"Amount Due:?\s*\$?\s*([\d,]+\.?\d*)" })
{
    var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
    if (match.Success && decimal.TryParse(
        match.Groups[1].Value.Replace(",", ""), out var t))
    {
        total = t;
        break;
    }
}

// Tax
var taxMatch = Regex.Match(text,
    @"(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.?\d*)",
    RegexOptions.IgnoreCase);
using IronOcr;
using System.Text.RegularExpressions;

var ocr    = new IronTesseract();
var result = ocr.Read("receipt.jpg");
var text   = result.Text;

// Vendor: first non-empty line, ordered by Y position
var vendor = result.Lines
    .OrderBy(l => l.Y)
    .Select(l => l.Text.Trim())
    .FirstOrDefault(t => !string.IsNullOrWhiteSpace(t) && t.Length > 3);

// Total: pattern matching against common receipt labels
decimal? total = null;
foreach (var pattern in new[] {
    @"Total:?\s*\$?\s*([\d,]+\.?\d*)",
    @"Grand Total:?\s*\$?\s*([\d,]+\.?\d*)",
    @"Amount Due:?\s*\$?\s*([\d,]+\.?\d*)" })
{
    var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
    if (match.Success && decimal.TryParse(
        match.Groups[1].Value.Replace(",", ""), out var t))
    {
        total = t;
        break;
    }
}

// Tax
var taxMatch = Regex.Match(text,
    @"(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.?\d*)",
    RegexOptions.IgnoreCase);
Imports IronOcr
Imports System.Text.RegularExpressions

Dim ocr As New IronTesseract()
Dim result = ocr.Read("receipt.jpg")
Dim text = result.Text

' Vendor: first non-empty line, ordered by Y position
Dim vendor = result.Lines _
    .OrderBy(Function(l) l.Y) _
    .Select(Function(l) l.Text.Trim()) _
    .FirstOrDefault(Function(t) Not String.IsNullOrWhiteSpace(t) AndAlso t.Length > 3)

' Total: pattern matching against common receipt labels
Dim total As Decimal? = Nothing
For Each pattern In {
    "Total:?\s*\$?\s*([\d,]+\.?\d*)",
    "Grand Total:?\s*\$?\s*([\d,]+\.?\d*)",
    "Amount Due:?\s*\$?\s*([\d,]+\.?\d*)"
}
    Dim match = Regex.Match(text, pattern, RegexOptions.IgnoreCase)
    If match.Success AndAlso Decimal.TryParse(match.Groups(1).Value.Replace(",", ""), total) Then
        Exit For
    End If
Next

' Tax
Dim taxMatch = Regex.Match(text,
    "(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.?\d*)",
    RegexOptions.IgnoreCase)
$vbLabelText   $csharpLabel

레이아웃이 특이하거나 인쇄 상태가 흐릿한 영수증의 경우, IronOCR의 전처리 필터는 추출 실행 전에 원본 데이터의 정확도를 향상시킵니다. 실제 영수증 스캔 품질을 처리하는 방법에 대해서는 이미지 품질 보정 가이드이미지 색상 보정 가이드를 참조하십시오.

비동기에서 동기로의 전환 처리

Veryfi의 전체 API 표면은 비동기식입니다. IronOCR의 기본 경로는 동기식입니다. 애플리케이션 코드에 있는 기존 비동기 메서드 시그니처는 래핑을 통해 유지할 수 있습니다.

// Preserve async signature during transition
public async Task<ReceiptResult> ProcessReceiptAsync(string path)
{
    // RunIronOCR on a background thread
    return await Task.Run(() =>
    {
        var result = _ocr.Read(path);
        return new ReceiptResult
        {
            Vendor = result.Lines.FirstOrDefault()?.Text,
            Total  = ExtractTotal(result.Text),
            Date   = ExtractDate(result.Text)
        };
    });
}
// Preserve async signature during transition
public async Task<ReceiptResult> ProcessReceiptAsync(string path)
{
    // RunIronOCR on a background thread
    return await Task.Run(() =>
    {
        var result = _ocr.Read(path);
        return new ReceiptResult
        {
            Vendor = result.Lines.FirstOrDefault()?.Text,
            Total  = ExtractTotal(result.Text),
            Date   = ExtractDate(result.Text)
        };
    });
}
Imports System.Threading.Tasks
Imports System.Linq

Public Async Function ProcessReceiptAsync(path As String) As Task(Of ReceiptResult)
    ' RunIronOCR on a background thread
    Return Await Task.Run(Function()
                              Dim result = _ocr.Read(path)
                              Return New ReceiptResult With {
                                  .Vendor = result.Lines.FirstOrDefault()?.Text,
                                  .Total = ExtractTotal(result.Text),
                                  .Date = ExtractDate(result.Text)
                              }
                          End Function)
End Function
$vbLabelText   $csharpLabel

고성능 시나리오를 위해, IronOCR는 스레드 안전하며 여러 IronTesseract 인스턴스가 동기화 없이 문서를 병렬로 처리할 수 있습니다. 속도 최적화 가이드는 대규모 환경에서 처리 시간을 최소화하는 인스턴스 재사용 패턴과 배치 로딩 전략을 다룹니다.

자격 증명 정리

Veryfi는 ClientId, ClientSecret, UsernameApiKey의 네 가지 자격 증명을 요구합니다. 마이그레이션 후에는 이 네 가지 항목을 구성 파일, 환경 변수, 키 자격 증명 모음 및 CI/CD 파이프라인에서 모두 제거해야 합니다.IronOCR단일 라이선스 키 문자열을 필요로 합니다. 마이그레이션 체크리스트: 모든 환경에서 네 가지 베리피 비밀을 제거하고, 단일 IRONOCR_LICENSE 환경 변수를 추가하며, 베리피 자격 증명 삽입을 제거하기 위해 배포 파이프라인을 업데이트합니다.

송장 PDF 처리

Veryfi는 ProcessDocumentAsync을 통해 PDF 바이트를 수락합니다. IronOCR는 OcrInput.LoadPdf()을 통해 PDF를 네이티브로 처리합니다:

// Multi-page invoice PDF — all pages processed locally
using var input = new OcrInput();
input.LoadPdf("invoice.pdf");

var result       = new IronTesseract().Read(input);
var invoiceText  = result.Text;
var invoiceNumber = Regex.Match(invoiceText,
    @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
    RegexOptions.IgnoreCase).Groups[1].Value;
// Multi-page invoice PDF — all pages processed locally
using var input = new OcrInput();
input.LoadPdf("invoice.pdf");

var result       = new IronTesseract().Read(input);
var invoiceText  = result.Text;
var invoiceNumber = Regex.Match(invoiceText,
    @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
    RegexOptions.IgnoreCase).Groups[1].Value;
Imports System.Text.RegularExpressions
Imports IronOcr

' Multi-page invoice PDF — all pages processed locally
Dim input As New OcrInput()
input.LoadPdf("invoice.pdf")

Dim result = New IronTesseract().Read(input)
Dim invoiceText As String = result.Text
Dim invoiceNumber As String = Regex.Match(invoiceText, _
    "Invoice\s*#?\s*:?\s*(\w+[-\w]*)", _
    RegexOptions.IgnoreCase).Groups(1).Value
$vbLabelText   $csharpLabel

검색 가능한 PDF 아카이브를 생성하는 청구서 워크플로의 경우, IronOCR의 SaveAsSearchablePdf() 방법은 스캔 입력에서 PDF/A 호환 출력을 생성하며, 이는 Veryfi의 클라우드 API가 제공하지 않는 기능입니다. 구현 세부 정보는 검색 가능한 PDF 가이드를 참조하세요.

IronOCR의 추가 기능

핵심 비교 영역 외에도IronOCR Veryfi의 범위를 완전히 벗어나는 기능을 제공합니다.

  • 표 추출 : 은행 명세서 및 상세 청구서와 같이 그리드 레이아웃이 있는 문서에서 구조화된 표를 읽어오는 기능
  • 필기 인식 : Veryfi의 사전 학습된 모델이 처리하도록 설계되지 않은 필기 메모, 서명 및 필기 양식 필드를 처리합니다.
  • MICR/수표 판독 : 수표 처리 워크플로우를 위한 전용 MICR 라인 추출 기능을 제공하여 라우팅 및 계좌 번호 추출을 사내에서 처리합니다.
  • hOCR 내보내기 : OCR 결과를 hOCR(위치 데이터가 포함된 HTML) 형식으로 내보내어 후속 문서 분석 파이프라인에서 사용할 수 있도록 합니다.
  • 진행 상황 추적 : 원격 API를 폴링하지 않고 장시간 실행되는 배치 작업의 처리 진행 상황을 모니터링합니다.
  • 여권 및 신분증 판독 : 온보딩 및 KYC 워크플로우를 위해 여권 및 신분증에서 기계 판독 가능 영역 데이터를 추출합니다.
  • AWS 및 Azure 배포 : 클라우드 인프라에 배포하면서 문서 처리는 자체 클라우드 계정 내에서 유지합니다. 외부 SaaS 데이터 처리 업체를 규정 준수 범위에 추가할 필요가 없습니다.

.NET 호환성 및 미래 준비

IronOCR .NET 8, .NET 9, 그리고 곧 출시될 .NET 10을 대상으로 하며, 레거시 호환성을 위해 .NET Standard 2.0 이상도 지원합니다. Windows x64/x86, Linux x64, macOS 및 ARM64에서 실행되며 Docker 컨테이너, Azure App Service, AWS Lambda 및 온프레미스 Linux 서버를 포함한 모든 최신 .NET 배포 대상을 지원합니다. 단일 패키지 배포 모델은 환경 전반에 걸쳐 네이티브 바이너리 관리가 불가능하다는 것을 의미합니다. 동일한 NuGet 참조가 지원되는 모든 플랫폼에서 올바르게 해결됩니다. Veryfi의 C# SDK는 .NET Standard 대상으로 하며 HTTP 클라이언트 래퍼 역할을 합니다. 즉, "호환성"은 OCR 엔진의 깊이보다는 HTTP 스택에 주로 좌우됩니다. 이는 플랫폼 제약이나 네트워크 제한이 있는 경우 중요한 차이점이 됩니다.

결론

Veryfi는 특정 문제를 신속하게 해결합니다. 즉, 경비 문서를 제출하면 구문 분석 로직을 작성할 필요 없이 구조화된 JSON 필드를 받을 수 있습니다. 클라우드 데이터 전송이 허용되는 환경에서 소규모 비용 자동화를 구현하는 경우, 이러한 제안은 진정한 가치를 지닙니다. 문제는 문서 처리량이 증가하여 문서당 비용이 몇 주 안에 영구 라이선스 비용을 초과하거나, 문서 유형이 Veryfi에서 학습한 범주를 넘어서거나, 규정 준수 요건으로 인해 제3자 금융 문서 처리가 비현실적이거나, 애플리케이션이 인터넷 연결 없이 작동해야 하는 경우에 발생합니다.

4가지 자격 증명을 사용하는 인증 모델, 비동기 전용 API, 속도 제한, 일괄 처리를 중단시키는 HTTP 402 결제 실패, 그리고 모든 추출 로직을 단일 공급업체에 종속시키는 독점적인 JSON 스키마는 예외적인 상황이 아닙니다. 이는 Veryfi를 대규모로 운영하는 팀이 매일 직면하는 현실적인 문제입니다.

IronOCR Veryfi가 자동으로 처리하는 추출 패턴을 작성해야 합니다. 이는 실제 개발 비용입니다. 문서 종류에 따라 영수증과 송장에서 정규 표현식을 추출하는 데 8~24시간이 소요될 것으로 예상됩니다. 하지만 그 투자는 한 번만 이루어집니다. 생성된 코드는 사용자의 인프라에서 실행되고, 모든 문서 유형을 처리하며, 오프라인에서 작동하고, 문서당 비용이 발생하지 않습니다. 은행 거래 내역, 라우팅 번호, 계좌 번호 및 거래 내역은 절대 서버를 벗어나지 않습니다.

금융 서비스, 의료, 방위 산업 계약 또는 법률 서비스 등 제3자 클라우드에 경비 문서를 전송하는 것이 규정 준수 문제로 여겨지는 모든 분야의 팀에게IronOCR은 그러한 논의 자체를 완전히 없애줍니다. 현재 Veryfi에 월 5,000달러에서 20,000달러를 지출하는 팀의 경우 계산은 간단합니다. 경비 문서 외에도 일반적인 OCR 기능이 필요한 팀의 경우 선택은 명확합니다. 클라우드 전문 솔루션과 로컬 범용 라이브러리는 동등한 도구가 아니며, 후자는 일회성 라이선스 비용으로 클라우드 전문 솔루션이 문서당 가격으로는 제공할 수 없는 무한한 유연성을 제공합니다.

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

자주 묻는 질문

Veryfi OCR API란 무엇인가요?

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

IronOCR은 .NET 개발자를 위한 Veryfi OCR API와 어떻게 다른가요?

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

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

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

Veryfi OCR API와 IronOCR 사이에는 어떤 정확도 차이가 있나요?

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

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

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

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

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

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

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

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

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

IronOCR은 Veryfi와 달리 Docker 및 컨테이너화된 배포에 적합한가요?

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

구매하기 전에 IronOCR을 미리 사용해 볼 수 있나요?

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

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

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

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

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

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

아이언 서포트 팀

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