2GB가 넘는 대형 TIFF 파일 로드 실패
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
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
각 청크는 원시 바이트로 LoadImage(chunkBytes)를 통해 이동되며, 모든 버퍼는 2GB 한계 내에 유지됩니다. SetCompression(CompressionMethod.LZW)는 바이트 배열로 변환되기 전에 각 청크를 줄입니다.
3. 청크 크기 조정
데이터에 맞게 pagesPerChunk를 조정하십시오. 청크가 2GB에 접근하거나 메모리가 빡빡할 경우 낮추십시오; 작은 페이지에 대해서는 오버헤드를 줄이기 위해 올리십시오.
4. 배포 시 Magick.NET 고려하기
Magick.NET은 ImageMagick 네이티브 바이너리를 함께 배포합니다. 배포 시 패키지 크기 및 네이티브 종속성 발자국을 고려하십시오.

