Креирање Мулти-страница ТИФФ албума директно из облачног складиштења је одличан начин за архивирање или размену великих сетова слика (сканирање, фотографије производа, слике странице). са Аспозе.Имање за .НЕТ, можете приток слика из Азуре Блоб Сцхоаге (или С3), конвертирати их у ТИСФ оквире, и сачувати јединствену, компресирани вишестранице ТИХФ – нема потребе за брзим датотекама.
Овај чланак замењује гвожђе са потпуним, у линији, копирање-пасте примјером и додаје тачне детаље за ТИФФ опције, компресија , *ДПИ и коришћење меморије.
Kompletni primer (Inline, Copy-Paste Ready)
Шта овај програм ради:
- Списак слика у контејнеру Azure Blob Storage (филтрирање по проширењу).
- Покреће сваки блоб у меморију (без темпера датотеке).
- Изграђује Мулти-страница ТИФФ користећи ЛЗВ компресију на 300 ДПИ.
- Сачува ТИФФ на локални диск ** и** (опционално) враћа га у контејнер.
Захтеви су:
- .NET 8 (или 6+)
- НУГЕТ паковања:-
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;
}
}
Зашто ове опције?
- компресија * :
TiffLzwRgbдаје без губитка компресију и високу компатибилност (идеално за архивирање или размену).
- компресија * :
Алтернативе је:
TiffDeflateRgb(понекад мање, потребна је подршка за дефлате); биљевел скенирање →TiffCcittFax4.- ДПИ * * :
ResolutionSetting(300, 300)је штампано-пријатан за скенирање; изаберите 150 за веб само да бисте смањили величину.
- ДПИ * * :
- у меморији * :
RasterImage.CacheData()побољшава перформансе јер се изворни пиксели сакривају пре копирања оквира.
- у меморији * :
Наред: Сортирање имена блоба обезбеђује стабилан ред странице (на пример,
page_001…page_999).
Преузмите албум назад у облак
Проба спустити на локални диск и одмах наплатити назад користећи исти контејнер. ако ваш радни ток треба да избегне локалне датотеке у потпуности, пребаците ТИФФ на MemoryStream и позива UploadAsync За веома велике албуме, преферирајте штедњу на временом датотеку како би се користила меморија предвидиво.
Амазон С3 варијанта (Снипт)
Ако сте на С3, логика је иста – заменити Азуре СДК позиве са АВС СДП позива:
// 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)
}
Држите Aspose.Imaging делове идентичне; само listing/downloading кодови се мењају.
Управљање грешкама и отпорност
- ** празан контејнер/префикс**: апликација мило излази са поруком.
- ** Корумпирана слика**: Врап
Image.Loadу Аtry/catchПропусти лоше оквире и настави, или абортус на основу политике. - Веома велики сетови: размотрите шункирање (на пример, креирајте један ТИФФ по 1.000 слика) да бисте ограничили величину датотеке и границе скенера/инструмента.
- Назив датотеке: укључује датум/време или префикс у име излаза за праћеност (на пример,
album-2025-07-03_1500.tiff).
Најбоља пракса
- Конзистентне димензије: мешане оријентације / величине су фине, али за јединствене резултате пре-нормализују слике (скале / ротате) пре копије оквира.
- Боја дубина: Скенирање текста може да се компресира боље ако се конвертује у сиву скалу пре скупљања ТИФФ (користите Асписе.Имање филтере).
- Метадате: можете причврстити ЕКСИФ/ИПТЦ/КСМП по оквиру пре него што спасите ако је потребно.
- Тестирање: проверите излаз у више гледалаца (Windows Photos, IrfanView, Preview, ImageMagick) и са потрошачима доњег тока (ДМС, ПАЦС, итд.).
Закључак
Сада имате пробани образац за изградњу Мулти-страница ТИФФ албума директно из Azure Blob Storage (и лако се преноси на S3). Пример држи употребу меморије предвидивом, користи без губитка ЛЗВ компресију и поставља практичан 300 ДПИ подразумевање – спреман за архивирање, размену и штампање.
Клонирајте горе наведени код у свој пројекат, жицајте у везу / контејнер и добићете ТИФФ албуме производње степена за неколико минута.
More in this category
- Оптимизација анимираних ГИФ-а у .NET-у користећи Aspose.Imaging
- Оптимизирајте мулти-странице ТИФФ-а за архивирање у .NET-у са Асписом
- Анимације на основу података у .NET-у са Aspose.Imaging
- Бесплатна и квалитетно дефинисана компресија слике у .NET-у са аспозом.Имање
- Оптимизација високо резолуционих слика за мобилне и веб у .NET-у