Het creëren van multi-page TIFF albums rechtstreeks uit cloudopslag is een geweldige manier om grote afbeeldingssets (scans, productfoto’s, pagina-afbeeldingen) te archiveren of uit te wisselen. met Aspose.Imaging voor .NET, kunt u stream beelden van Azure Blob Storage (of S3), ze om te zetten in tiff-frames, en een enkele, gecomprimeerde multi-pagina Tif - geen temp bestanden vereist.
Dit artikel vervangt de gier met een complete, inline, copy-paste voorbeeld en voegt nauwkeurige details toe voor TIFF-opties, *compressie, DPI en memoriegebruik.
Volledige voorbeeld (Inline, Copy-Paste Ready)
Wat dit programma doet:
- Lijst van afbeeldingen in een Azure Blob Storage container (filterend door uitbreiding).
- Stromen elke blob in het geheugen (geen temp bestanden).
- Maak een multi-page TIFF met behulp van LZW compressie op 300 DPI.
- Speelt de TIFF op de lokale schijf ** en** (optieel) loopt het terug naar de container.
Aanbevelingen :
- .NET 8 (of 6+)
- NuGet pakketten:-
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;
}
}
Waarom deze opties?
• Compressie * :
TiffLzwRgb
geeft lossless compressie en hoge compatibiliteit (ideal voor archivering of uitwisseling).De alternatieven:
TiffDeflateRgb
(meestal kleiner, nodig Deflate ondersteuning); bilevel scans →TiffCcittFax4
.- De DPI* :
ResolutionSetting(300, 300)
is drukvriendelijk voor scans; selecteer 150 voor web alleen om de grootte te verminderen.
- De DPI* :
- Het geheugen * :
RasterImage.CacheData()
verbetert de prestaties omdat de bron pixels worden cached vóór de frame-copie.
- Het geheugen * :
Ordering: Het sorteren van blob-namen zorgt voor een stabiele pagina-ordre (bijv.
page_001…page_999
).
Download het album terug naar de cloud
Het monster zendt naar de lokale schijf en loopt onmiddellijk op terug met dezelfde container.Als uw werkstroom lokaal bestanden volledig moet vermijden, draai de TIFF naar een MemoryStream
en bellen UploadAsync
Voor zeer grote albums, liever besparen op een temporary file om het geheugengebruik voorspelbaar te houden.
Amazon S3 variant (snippet)
Als u op S3 bent, is de logica hetzelfde — vervang Azure SDK-oproepen met AWS SDk-opdrachten:
// 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)
}
Houd de Aspose.Imaging delen identiek; alleen de Listing/Downloading* code verandert.
Foutbehandeling & resilience
- Vuite container/prefix: de app vertrekt dankbaar met een bericht.
- Korrupte afbeelding: wrap
Image.Load
In de Atry/catch
; overwinnen slechte kaders en voortzetten, of abortus gebaseerd op beleid. - Veel grote sets: overweeg chunking (bijvoorbeeld een TIFF per 1000 afbeeldingen bouwen) om bestandsgrootte en scanner/toolgrens te beperken.
- File name: datum/tijd of voorschrift in de uitgangsnaam voor traceerbaarheid (bijv.
album-2025-07-03_1500.tiff
).
Beste praktijken
- Consistente dimensies: gemengde richtsnoeren/gewijzen zijn fijn, maar voor uniforme resultaten pre-normaliseren afbeeldingen (scale/rotat) vóór de frame kopie.
- Kleurdichtheid: tekstscans kunnen beter worden gecomprimeerd als ze worden omgezet naar grayscale vóór de TIFF-assembly (gebruik Aspose.Imaging filters).
- Metadata: u kunt EXIF/IPTC/XMP per frame toevoegen voordat u zo nodig opslaat.
- Testing: verificatie van de uitkomst in meerdere kijkers (Windows Photos, IrfanView, Preview, ImageMagick) en met downstream consumenten (DMS, PACS, enz.).
Conclusie
U hebt nu een beproefd patroon voor het bouwen van multi-page TIFF albums rechtstreeks vanaf Azure Blob Storage (en gemakkelijk te dragen naar S3).Het voorbeeld houdt het geheugengebruik voorspelbaar, gebruikt lossless LZW compression en stelt een praktische 300 DPI standaard - klaar voor archivering, uitwisseling en afdrukking.
Cloneer de bovenstaande code in je project, draai in uw verbindingstring/container en je zult in minuten productie-grade TIFF albums hebben.
More in this category
- Het optimaliseren van geanimeerde GIF's in .NET met behulp van Aspose.Imaging
- Optimaliseren van multi-page TIFF's voor archief in .NET met Aspose
- Convert TIFF naar PDF in C# met Aspose.Imaging
- Cropping Product Images voor E-Commerce Platforms met behulp van Aspose.Imaging voor .NET
- Data-Driven Animaties in .NET met Aspose.Imaging