Criar álbuns TIFF de múltiplas páginas diretamente do armazenamento em nuvem é uma ótima maneira de arquivar ou trocar grandes conjuntos de imagens (escans, fotos de produto, imagens de página). com Aspose.Imaging para .NET, você pode stream imagens do Azure Blob Storage (ou S3), convertê-los em quadros TifF, e salvar um único, comprimido multi-páginas TFF – nenhum arquivo de tempo necessário.
Este artigo substitui o gesto com um exemplo completo, inline, copiar-paste e adiciona detalhes precisos para as opções TIFF, compressão , DPI ea utilização da memória**.
Exemplo completo (Inline, Copy-Paste Ready)
O que este programa faz:
- Lista imagens em um recipiente Azure Blob Storage (filtrado por extensão).
- Streams cada blob para a memória (sem arquivos temp).
- Construa um multi-page TIFF usando a compressão LZW em 300 DPI.
- Salve o TIFF para o disco local ** e** (opcionalmente) o carrega de volta ao recipiente.
Requisitos:
- .NET 8 (ou 6+)
- Embalagens de NuGet:-
Aspose.Imaging
Azure.Storage.Blobs
// File: Program.cs
// Build deps:
// dotnet add package Aspose.Imaging
// dotnet add package Azure.Storage.Blobs
//
// Run (example):
// setx AZURE_STORAGE_CONNECTION_STRING "<your-connection-string>"
// dotnet run -- "<container-name>" "album-output.tiff" // uploads album-output.tiff back to same container
//
// Notes:
// - Streams JPEG/PNG/BMP/TIFF/GIF web-safe inputs and assembles a multi-page LZW RGB TIFF at 300 DPI.
// - If there are no images, the program exits gracefully.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Tiff;
using Aspose.Imaging.FileFormats.Tiff.Enums;
using Aspose.Imaging.ImageOptions;
class Program
{
// Accepted extensions (case-insensitive)
private static readonly string[] ImageExts = new[]
{
".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tif", ".tiff"
};
static async Task<int> Main(string[] args)
{
if (args.Length < 2)
{
Console.Error.WriteLine("Usage: dotnet run -- <containerName> <albumFileName.tiff> [prefix]");
Console.Error.WriteLine("Example: dotnet run -- scans album-2025-07.tiff scans/incoming/");
return 1;
}
string containerName = args[0];
string albumFileName = args[1];
string prefix = args.Length > 2 ? args[2] : string.Empty;
string? conn = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING");
if (string.IsNullOrWhiteSpace(conn))
{
Console.Error.WriteLine("AZURE_STORAGE_CONNECTION_STRING is not set.");
return 2;
}
try
{
var container = new BlobContainerClient(conn, containerName);
// 1) Enumerate candidate image blobs (optionally under a prefix)
var images = await ListImageBlobsAsync(container, prefix);
if (images.Count == 0)
{
Console.WriteLine("No images found. Nothing to do.");
return 0;
}
Console.WriteLine($"Found {images.Count} image(s). Building multi-page TIFF…");
// 2) Build multipage TIFF in memory (for safety, stream to file to avoid huge RAM for very large sets)
// We will construct a TiffImage and append frames.
string localAlbumPath = Path.GetFullPath(albumFileName);
BuildMultipageTiffFromBlobs(container, images, localAlbumPath);
Console.WriteLine($"✅ Saved multi-page TIFF locally: {localAlbumPath}");
// 3) Optional: upload back to same container
var albumBlob = container.GetBlobClient(Path.GetFileName(albumFileName));
Console.WriteLine($"Uploading album back to container as: {albumBlob.Name} …");
using (var fs = File.OpenRead(localAlbumPath))
{
await albumBlob.UploadAsync(fs, overwrite: true);
}
Console.WriteLine("✅ Upload complete.");
return 0;
}
catch (RequestFailedException are)
{
Console.Error.WriteLine("Azure error: " + are.Message);
return 3;
}
catch (Exception ex)
{
Console.Error.WriteLine("Error: " + ex.Message);
return 4;
}
}
private static async Task<List<BlobItem>> ListImageBlobsAsync(BlobContainerClient container, string prefix)
{
var result = new List<BlobItem>();
await foreach (var item in container.GetBlobsAsync(prefix: prefix))
{
// Skip virtual folders
if (item.Properties.BlobType != BlobType.Block)
continue;
if (HasImageExtension(item.Name))
result.Add(item);
}
// Optional: stable order by name (e.g., page_001.jpg … page_999.jpg)
result.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
return result;
}
private static bool HasImageExtension(string blobName)
{
string ext = Path.GetExtension(blobName) ?? string.Empty;
return ImageExts.Contains(ext, StringComparer.OrdinalIgnoreCase);
}
private static void BuildMultipageTiffFromBlobs(BlobContainerClient container, List<BlobItem> images, string outputTiffPath)
{
// TIFF encoder defaults:
// - LZW compression is a good balance of size & compatibility for RGB images.
// - 300 DPI is print-friendly; change if you need web-only output.
var tiffOptions = new TiffOptions(TiffExpectedFormat.TiffLzwRgb)
{
ResolutionSettings = new ResolutionSetting(300, 300)
};
TiffImage? tiff = null;
try
{
for (int index = 0; index < images.Count; index++)
{
var blobClient = container.GetBlobClient(images[index].Name);
Console.WriteLine($"Downloading & adding: {blobClient.Name}");
using var ms = new MemoryStream();
blobClient.DownloadTo(ms);
ms.Position = 0;
// Load the image with Aspose.Imaging (auto-detects format)
using var src = Image.Load(ms);
// Cache pixel data to speed up frame copy (especially for network streams)
if (src is RasterImage raster)
raster.CacheData();
// Create a TIFF frame by copying from the source image
// NOTE: TiffFrame.CopyFrame(tiffOptions, <RasterImage>) is preferred when available
TiffFrame frame;
if (src is RasterImage rimg)
{
frame = TiffFrame.CopyFrame(tiffOptions, rimg);
}
else
{
// Fallback: render non-raster formats into a rasterized frame
frame = CreateRasterFrameFromAny(src, tiffOptions);
}
if (index == 0)
{
// First frame defines the TiffImage
tiff = new TiffImage(frame);
}
else
{
tiff!.AddFrame(frame);
}
}
if (tiff == null)
throw new InvalidOperationException("No frames were created. Aborting.");
// Save to local TIFF file
tiff.Save(outputTiffPath);
}
finally
{
tiff?.Dispose();
}
}
private static TiffFrame CreateRasterFrameFromAny(Image src, TiffOptions opts)
{
// Create a blank frame and draw the source into it
// This is a compatibility path if the loaded image isn’t a RasterImage
var frame = new TiffFrame(opts, src.Width, src.Height);
using (var graphics = new Aspose.Imaging.Graphics(frame))
{
graphics.Clear(Aspose.Imaging.Color.White);
graphics.DrawImage(src, new Aspose.Imaging.Rectangle(0, 0, src.Width, src.Height));
}
return frame;
}
}
Por que essas opções?
• Compressão :
TiffLzwRgb
dá compressão ** sem perda* e alta compatibilidade (ideal para arquivamento ou intercâmbio).As alternativas:
TiffDeflateRgb
(muitas vezes menores, necessitam de suporte Deflate); rastreamento de bilevel →TiffCcittFax4
.- Página inicial *:
ResolutionSetting(300, 300)
É amigável à impressão para scans; selecione 150 para web apenas para reduzir o tamanho.
- Página inicial *:
• Memória *:
RasterImage.CacheData()
Melhora o desempenho porque os pixels de origem são cache antes da cópia do frame.Order: A classificação dos nomes de blob garante uma ordem de página estável (por exemplo,
page_001…page_999
).
Carregar o álbum de volta para a nuvem
A amostra save para o disco local e imediatamente upload back usando o mesmo recipiente.Se o seu fluxo de trabalho deve evitar os arquivos locais inteiramente, flua o TIFF para um MemoryStream
e chamar UploadAsync
Para álbuns muito grandes, prefira economizar em um arquivo temporário para manter o uso da memória previsível.
Variação do Amazon S3 (snippet)
Se você está no S3, a lógica é a mesma – substituir as chamadas do Azure SDK com os chamados do AWSSDK:
// NuGet:
// dotnet add package AWSSDK.S3
using Amazon.S3;
using Amazon.S3.Model;
// Listing:
using var s3 = new AmazonS3Client(Amazon.RegionEndpoint.APSouth1);
var list = await s3.ListObjectsV2Async(new ListObjectsV2Request
{
BucketName = "your-bucket",
Prefix = "images/"
});
foreach (var obj in list.S3Objects.Where(o => HasImageExtension(o.Key)))
{
using var get = await s3.GetObjectAsync("your-bucket", obj.Key);
using var ms = new MemoryStream();
await get.ResponseStream.CopyToAsync(ms);
ms.Position = 0;
using var src = Image.Load(ms);
// (same TiffFrame.CopyFrame logic as above)
}
Mantenha as partes Aspose.Imaging idênticas; apenas os códigos listing/downloading mudam.
Manejo de erros e resistência
- Conteúdo vazio/prefixo**: o aplicativo sai graciosamente com uma mensagem.
- ** Imagem corrompida**: embalagem
Image.Load
Em Atry/catch
Escape os péssimos quadros e continue, ou aborto com base na política. - Sete muito grande: considere chunking (por exemplo, construir um TIFF por 1.000 imagens) para limitar os tamanhos de arquivo e os limites do scanner/tool.
- Nome do arquivo: inclui data/tempo ou prefixo no nome de saída para rastreabilidade (por exemplo,
album-2025-07-03_1500.tiff
).
Melhores práticas
- Dimensões consistentes: as orientações/visões mistas são finas, mas para resultados uniformes pre-normalizar imagens (escala/rotado) antes da cópia do quadro.
- Dificuldade de cor: os scans de texto podem ser melhor comprimidos se convertidos em grayscale antes da assembléia TIFF (usando filtros Aspose.Imaging).
- Metadados: você pode ligar EXIF/IPTC/XMP por frame antes de salvar se necessário.
- Testing: verifica a saída em múltiplos espectadores (Windows Photos, IrfanView, Preview, ImageMagick) e com consumidores de baixo fluxo (DMS, PACS, etc.).
Conclusão
Agora você tem um padrão testeado para construir álbuns TIFF de múltiplas páginas** diretamente do Azure Blob Storage (e facilmente portátil para S3).O exemplo mantém o uso da memória previsível, usa compressão LZW sem perda, e coloca um default prático 300 DPI – pronto para arquivamento, troca e impressão.
Clone o código acima em seu projeto, ligue em sua corrente de conexão/container e você terá álbuns TIFF de nível de produção em minutos.
More in this category
- Otimizar GIFs animados em .NET usando Aspose.Imaging
- Otimize TIFFs multi-páginas para arquivo em .NET com Aspose
- Animações de dados em .NET com Aspose.Imaging
- Compare compressão de imagem sem perda em .NET usando Aspose.Imaging
- Compressão de imagem sem perda e de qualidade definida em .NET com Aspose.Imaging