2GB가 넘는 대형 TIFF 파일 로드 실패

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronOCR은 내부 AnyBitmap 유형을 통해 이미지 입력을 단일 인메모리 버퍼에 로드합니다. 그 버퍼는 32비트 정수로 인덱싱되어 시스템 메모리가 얼마든지 빠지지 않고 약 2GB로 제한됩니다. 2GB보다 큰 TIFF는 이 제한을 초과하여 로드에 실패합니다.

Loaded pages: 0

OcrInput.LoadImage(filePath)는 내부적으로 AnyBitmap를 생성하고 전체 이미지를 하나의 버퍼로 시물레이션합니다. 그 버퍼는 int로 인덱싱되어 사실상 약 2GB로 제한되며, TIFF가 약간 더 큰 경우 보유할 수 없고 로드가 실패합니다. 이것은 각 .NET 플랫폼에 동일하게 영향을 미치는 OS 비특정 런타임 제약입니다.

경고LoadImage(filePath)는 현재 명확한 예외를 던지는 대신 0개 페이지가 로드된 상태로 반환합니다. 이 무음 실패는 알려진 문제입니다; 명확한 예외가 계획되어 있습니다. 단일 버퍼 설계는 아키텍처적 한계이며, 네이티브 페이지별 TIFF 스트리밍은 아직 사용할 수 없습니다.

해결책

수정 방법은 TIFF를 2GB 이하의 청크로 분할하여 파일 경로 대신 바이트 배열로 IronOCR에 전달하는 것입니다.

1. Magick.NET 추가하기

IronOCR에 전달하기 전에 TIFF를 분할하기 위해 Magick.NET을 사용하십시오. 프로젝트와 일치하는 변종(Q8/Q16, AnyCPU/x64)을 선택하십시오.

dotnet add package Magick.NET-Q16-AnyCPU
dotnet add package Magick.NET-Q16-AnyCPU
SHELL

2. TIFF를 분할하고 각 청크 로드하기

TIFF를 MagickImageCollection으로 열고, 각 청크가 2GB 이하로 유지되도록 페이지 단위로 나누고 모든 청크를 바이트 배열로 변환하여 OcrInput.LoadImage(byte[])로 로드하십시오.

var inputPath = "input.tiff";
var pagesPerChunk = 100;
using var allPages = new MagickImageCollection(inputPath);
int chunkNumber = 1;
for (int i = 0; i < allPages.Count; i += pagesPerChunk)
{
    using var chunk = new MagickImageCollection();
    for (int j = i; j < Math.Min(i + pagesPerChunk, allPages.Count); j++)
    {
        chunk.Add(allPages[j].Clone());
    }
    foreach (var image in chunk)
    {
        image.SetCompression(CompressionMethod.LZW);
    }
    var chunkBytes = chunk.ToByteArray();
    using (var ocrInput = new OcrInput())
    {
        ocrInput.LoadImage(chunkBytes);
        var pages = ocrInput.GetPages().ToList();
        Console.WriteLine($"Loaded pages: {pages.Count}");
        var result = new IronTesseract().Read(ocrInput);
        Console.WriteLine("OCR Text Length: " + (result.Text?.Length ?? 0));
    }
    Console.WriteLine($"Chunk {chunkNumber} processed");
    chunkNumber++;
}
var inputPath = "input.tiff";
var pagesPerChunk = 100;
using var allPages = new MagickImageCollection(inputPath);
int chunkNumber = 1;
for (int i = 0; i < allPages.Count; i += pagesPerChunk)
{
    using var chunk = new MagickImageCollection();
    for (int j = i; j < Math.Min(i + pagesPerChunk, allPages.Count); j++)
    {
        chunk.Add(allPages[j].Clone());
    }
    foreach (var image in chunk)
    {
        image.SetCompression(CompressionMethod.LZW);
    }
    var chunkBytes = chunk.ToByteArray();
    using (var ocrInput = new OcrInput())
    {
        ocrInput.LoadImage(chunkBytes);
        var pages = ocrInput.GetPages().ToList();
        Console.WriteLine($"Loaded pages: {pages.Count}");
        var result = new IronTesseract().Read(ocrInput);
        Console.WriteLine("OCR Text Length: " + (result.Text?.Length ?? 0));
    }
    Console.WriteLine($"Chunk {chunkNumber} processed");
    chunkNumber++;
}
Imports System
Imports System.Linq
Imports ImageMagick

Dim inputPath As String = "input.tiff"
Dim pagesPerChunk As Integer = 100
Using allPages As New MagickImageCollection(inputPath)
    Dim chunkNumber As Integer = 1
    For i As Integer = 0 To allPages.Count - 1 Step pagesPerChunk
        Using chunk As New MagickImageCollection()
            For j As Integer = i To Math.Min(i + pagesPerChunk, allPages.Count) - 1
                chunk.Add(allPages(j).Clone())
            Next
            For Each image In chunk
                image.SetCompression(CompressionMethod.LZW)
            Next
            Dim chunkBytes = chunk.ToByteArray()
            Using ocrInput As New OcrInput()
                ocrInput.LoadImage(chunkBytes)
                Dim pages = ocrInput.GetPages().ToList()
                Console.WriteLine($"Loaded pages: {pages.Count}")
                Dim result = New IronTesseract().Read(ocrInput)
                Console.WriteLine("OCR Text Length: " & If(result.Text?.Length, 0))
            End Using
        End Using
        Console.WriteLine($"Chunk {chunkNumber} processed")
        chunkNumber += 1
    Next
End Using
$vbLabelText   $csharpLabel

각 청크는 원시 바이트로 LoadImage(chunkBytes)를 통해 이동되며, 모든 버퍼는 2GB 한계 내에 유지됩니다. SetCompression(CompressionMethod.LZW)는 바이트 배열로 변환되기 전에 각 청크를 줄입니다.

3. 청크 크기 조정

데이터에 맞게 pagesPerChunk를 조정하십시오. 청크가 2GB에 접근하거나 메모리가 빡빡할 경우 낮추십시오; 작은 페이지에 대해서는 오버헤드를 줄이기 위해 올리십시오.

4. 배포 시 Magick.NET 고려하기

Magick.NET은 ImageMagick 네이티브 바이너리를 함께 배포합니다. 배포 시 패키지 크기 및 네이티브 종속성 발자국을 고려하십시오.

Curtis Chau
기술 문서 작성자

커티스 차우는 칼턴 대학교에서 컴퓨터 과학 학사 학위를 취득했으며, Node.js, TypeScript, JavaScript, React를 전문으로 하는 프론트엔드 개발자입니다. 직관적이고 미적으로 뛰어난 사용자 인터페이스를 만드는 데 열정을 가진 그는 최신 프레임워크를 활용하고, 잘 구성되고 시각적으로 매력적인 매뉴얼을 제작하는 것을 즐깁니다.

커티스는 개발 분야 외에도 사물 인터넷(IoT)에 깊은 관심을 가지고 있으며, 하드웨어와 소프트웨어를 통합하는 혁신적인 방법을 연구합니다. 여가 시간에는 게임을 즐기거나 디스코드 봇을 만들면서 기술에 대한 애정과 창의성을 결합합니다.

시작할 준비 되셨나요?
Nuget 다운로드 6,136,090 | 버전: 2026.7 방금 출시
Still Scrolling Icon

아직도 스크롤하고 계신가요?

빠른 증거를 원하시나요? PM > Install-Package IronOcr
샘플을 실행하세요 이미지가 검색 가능한 텍스트로 바뀌는 것을 확인해 보세요.