Créer des albums TIFF à plusieurs pages directement à partir du stockage dans le cloud est un excellent moyen d’archiver ou de échanger de grands ensembles d’images (scans, photos de produit, images de page). Avec Aspose.Imaging pour .NET, vous pouvez stream des images du Azure Blob Storage (ou S3), les convertir dans des cadres TifF, et sauvegarder un seul, compressé multi-page tiff – aucun fichier temp requis.
Cet article remplacera le gêne par un exemple complet, en ligne, copie-paste et ajoute des détails précis pour Options TIFF, Compression , DPI ou Utilisation de mémoire.
Exemple complet (Inline, Copy-Paste Ready)
Ce que ce programme fait :
- Liste des images dans un récipient ** Azure Blob Storage** (filtré par extension).
- Chaque blob est versé dans la mémoire (pas de fichiers temp).
- Créez un TIFF de plusieurs pages en utilisant la compression LZW à 300 DPI.
- Économisez le TIFF sur le disque local ** et** (optionnellement) le téléchargez à nouveau dans le conteneur.
Requisiti:
- .NET 8 (ou 6+)
- Nouveaux paquets :-
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;
}
}
Pourquoi ces options ?
• La compression :
TiffLzwRgb
Il offre compression sans perte et une grande compatibilité (idéal pour l’archivage ou le partage).Les alternatives :
TiffDeflateRgb
(souvent plus petit, nécessite un support de déflate); scans bilevelTiffCcittFax4
.- Le DPI est :
ResolutionSetting(300, 300)
est imprimable pour les scans ; choisissez 150 pour le web uniquement pour réduire la taille.
- Le DPI est :
« Mémoire » :
RasterImage.CacheData()
améliore les performances car les pixels source sont cachés avant la copie du cadre.Order: La sortie des noms de blob assure une ordre de page stable (par exemple,
page_001…page_999
).
Télécharger l’album dans le cloud
L’échantillon sage sur le disque local et recharge immédiatement ** en utilisant le même conteneur**. Si votre flux de travail devrait éviter les fichiers locaux entièrement, envoyer le TIFF à un MemoryStream
et appeler UploadAsync
Pour les albums très grands, préférez économiser sur un fichier ** temporaire** pour garder l’utilisation de la mémoire prévisible.
Amazon S3 variante (snippet)
Si vous êtes sur S3, la logique est la même – remplacez les appels Azure SDK avec AWS :
// 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)
}
Gardez les pièces Aspose.Imaging identiques; seuls les changements du code Listing/Downloading.
Traitement des erreurs et résilience
- Container vide/prefix: l’application sort gracieusement avec un message.
- Image corrompu : enveloppe
Image.Load
Dans Atry/catch
· échapper aux mauvais cadres et continuer, ou l’avortement basé sur la politique. - Sets très grands: considérez le chunking (par exemple, construire un TIFF par 1000 images) pour limiter les tailles de fichiers et les limites de scanner/outil.
- Nomination du fichier: inclut la date/heure ou la préfixe dans le nom de sortie pour la traçabilité (par exemple,
album-2025-07-03_1500.tiff
).
Les meilleures pratiques
- Dimensions cohérentes: les orientations/size mélangées sont fines, mais pour les résultats uniques, pré-normalisez les images (scale/rotat) avant la copie du cadre.
- De profondeur de couleur: les scans de texte peuvent être mieux compressés si convertis en grayscale avant l’assemblage TIFF (utilisez les filtres Aspose.Imaging).
- Metadata: vous pouvez ajouter EXIF/IPTC/XMP par cadre avant de sauvegarder si nécessaire.
- Testing: vérifier la sortie dans plusieurs téléspectateurs (Windows Photos, IrfanView, Preview, ImageMagick) et avec des consommateurs en dessous (DMS, PACS, etc.).
Conclusion
Vous disposez désormais d’un modèle testé pour construire des albums TIFF de plusieurs pages** directement à partir de Azure Blob Storage (et facilement portable à S3).L’exemple maintient l’utilisation de la mémoire prévisible, utilise compression LZW sans perte, et établit un défaut pratique 300 DPI – prêt à être archivé, échangé et imprimé.
Clonez le code ci-dessus dans votre projet, envoyez-le à votre connexion / conteneur, et vous aurez des albums TIFF de niveau de production en quelques minutes.
More in this category
- Optimiser les GIF animés dans .NET en utilisant Aspose.Imaging
- Optimiser les TIFF multi-page pour l'archivage dans .NET avec Aspose
- Animations à base de données dans .NET avec Aspose.Imaging
- Comparer Lossy vs. Lossless Image Compression dans .NET en utilisant Aspose.Imaging
- Compression d'image sans perte et déterminée de qualité dans .NET avec Aspose.Imaging