Grandes Arquivos TIFF Acima de 2 GB Não Carregam
O IronOCR carrega entradas de imagem em um único buffer na memória através de seu tipo interno AnyBitmap. Esse buffer é indexado por um inteiro de 32 bits, por isso é limitado a cerca de 2 GB, independentemente de quanta memória do sistema você tem. Um TIFF maior que 2 GB excede esse limite e falha ao carregar.
Loaded pages: 0
OcrInput.LoadImage(filePath) cria internamente um AnyBitmap e materializa a imagem inteira em um buffer. Porque esse buffer é indexado por int, ele é efetivamente limitado a cerca de 2 GB, não importa quanta memória esteja livre, então um TIFF um pouco acima do limite não pode ser mantido e o carregamento falha. Isso é uma limitação em tempo de execução, não específica do sistema operacional, portanto, afeta todas as plataformas .NET igualmente.
LoadImage(filePath) atualmente retorna zero páginas carregadas em vez de lançar uma exceção clara. Essa falha silenciosa é um problema conhecido; uma exceção mais clara está planejada. O design de um único buffer é um limite arquitetônico, e o streaming nativo de TIFF por página ainda não está disponível.Solução
A solução é dividir o TIFF em pedaços de menos de 2 GB e passar cada pedaço para o IronOCR como um array de bytes, em vez de um caminho de arquivo.
1. Adicionar Magick.NET
Use o Magick.NET para dividir o TIFF antes de passá-lo para o IronOCR. Escolha a variante que corresponde ao seu projeto (Q8/Q16, AnyCPU/x64).
dotnet add package Magick.NET-Q16-AnyCPU
dotnet add package Magick.NET-Q16-AnyCPU
2. Dividir o TIFF e Carregar Cada Pedaço
Abra o TIFF como um MagickImageCollection, divida-o em pedaços pelo número de páginas, cada um com menos de 2 GB, converta cada pedaço em um array de bytes e carregue-o com 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
Cada pedaço passa por LoadImage(chunkBytes) como bytes brutos, mantendo cada buffer abaixo do limite de 2 GB. SetCompression(CompressionMethod.LZW) reduz cada pedaço antes de ser convertido em um array de bytes.
3. Ajustar o Tamanho dos Pedaços
Ajuste pagesPerChunk para seus dados. Reduza-o se um pedaço se aproximar de 2 GB ou se a memória estiver apertada; aumente-o para páginas menores para reduzir a sobrecarga.
4. Contabilizar o Magick.NET na Implantação
Magick.NET envia binários nativos do ImageMagick. Considere o tamanho adicional do pacote e a pegada de dependência nativa ao implantar.

