Bulut depolamasından doğrudan ** çok sayfalık TIFF** albümleri oluşturmak, büyük görüntü setlerini (scanslar, ürün fotoğrafları, sayfa görüntüleri) arşivlemek veya değiştirmek için harika bir yoldur. Aspose.Imaging for .NET ile, Azure Blob Storage (veya S3)‘den stream görüntüler alabilirsiniz, bunları TifF çerçevelerine dönüştürebilirsiniz ve tek, sıkıştırılmış çok sayfalı TFF - hiçbir temp dosyası gerektirmez.
Bu makalede bir komple, inline, copy-paste örneği ile çamur değiştirilir ve TIFF seçenekleri, düzeltme , DPI ve * hafıza kullanımı** için doğru ayrıntılar eklenir.
Tam Örnek (Inline, Copy-Paste Ready)
Bu program ne yapıyor:
- Görüntüleri bir Azure Blob Storage konteynerinde listeler (genişletme ile filtrelenir).
- Her blok hafızaya aktarılır (temp dosyaları yoktur).
- LZW kompresyonu kullanarak 300 DPI çok sayfalık bir TIFF oluşturur.
- TIFF’yi yerel diske kaydeder ** ve** (opsiyonel olarak) konteynerine geri yükler.
Gereksinimler:
- .NET 8 (veya 6+)
- NuGet paketleri :-
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;
}
}
Neden bu seçenekler?
• Kompresyon * :
TiffLzwRgbkayıp kompresyon ve yüksek uyumluluk sağlar (arşivleme veya değişim için idealdir).Alternatifler :
TiffDeflateRgb(genellikle daha küçük, Deflate desteği gerektirir); bilevel taramaları →TiffCcittFax4.*Devamı için :
ResolutionSetting(300, 300)Scanlar için baskı dostu; boyutunu azaltmak için sadece web için 150 seçin.• Hafıza * :
RasterImage.CacheData()performansı iyileştirir çünkü kaynak pikselleri çerçeve kopyası öncesinde gizlenir.** Sipariş**: Blob isimlerinin sınıflandırılması istikrarlı sayfa sırasını sağlar (örneğin,
page_001…page_999).
Albümü bulutlara geri yükleme
Örnek yerel diske gidiyor ve hemen yükleme aynı konteyner kullanılarak. eğer çalışma akışı yerel dosyaları tamamen önlemek gerekir, TIFF’yi bir MemoryStream ve Çağrı UploadAsync Çok büyük albümler için, hafıza kullanımını öngörülebilir tutmak için **zamanlı bir dosyaya ** tasarruf etmeyi tercih edin.
Amazon S3 versiyonu (snippet)
Eğer S3’te iseniz, mantık aynıdır - Azure SDK aramaları AWS SDk aramalarla değiştirin:
// 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 bölümlerini aynı tutun; yalnızca listing/downloading kodunu değiştirin.
hatalar ve dayanıklılık
- ** Boş konteyner/prefix**: uygulama bir mesajla şefkatle çıkıyor.
- Korrupt görüntü: Wrap
Image.LoadA’datry/catch· Kötü çerçeveleri atlayın ve devam edin, ya da politikaya dayalı kürtaj. - Çok büyük setler: dosya boyutlarını ve tarayıcı / araç sınırlarını sınırlamak için (örneğin, 1000 resim başına bir TIFF oluşturun) çarpışmayı düşünün.
- ** Dosya adı**: izlenebilirlik için çıkış adında tarih/saat veya şifre içerir (örneğin,
album-2025-07-03_1500.tiff).
En iyi uygulamalar
- Sürdürülebilir boyutlar: karışık yönlendirmeler/çerçeveler iyidir, ancak eşit sonuçlar için çerçeve kopyası öncesinde görüntüleri önceden normalleştirir.
- Renk derinliği: metin taramaları, TIFF montajından önce gri ölçeğe dönüştürülürse daha iyi sıkıştırılabilir (Aspose.Imaging filtrelerini kullanın).
- Metadata: Gerekirse kaydetmeden önce çerçeve başına EXIF/IPTC/XMP ekleyebilirsiniz.
- Testing: Çeşitli izleyicilerde (Windows Photos, IrfanView, Preview, ImageMagick) ve düşük akış tüketicileri (DMS, PACS, vb.) çıkışını doğrulayın.
Sonuç
- Azure Blob Storage’dan doğrudan ** çok sayfalık TIFF albümlerini oluşturmak için ** test edilmiş bir şablonunuz var ** (ve kolayca ** S3**‘ye taşınabilir). Örnek hafıza kullanımını öngörülebilir tutar, ** kayıp olmayan LZW kompresyonu kullanır** ve pratik bir ** 300 DPI** varsayımını ayarlar - arşivleme, değişim ve baskı için hazır.
Yukarıdaki kodu projenize klonlayın, bağlantı çubuğunuzda / konteynerinizde kablo yapın ve dakikalar içinde üretim derecesi TIFF albümleri alacaksınız.
More in this category
- Aspose.Imaging ile .NET'te animasyon GIF'leri optimize etmek
- Aspose ile .NET'te arşiv için çok sayfalık TIFF'leri optimize edin
- Aspose.Imaging ile .NET'te veri yönlendirilmiş animasyonlar
- Aspose.Imaging ile C#'da TIFF'yi PDF'ye dönüştürmek
- E-Ticaret Platformları için Ürün Görüntüleri Aspose.Imaging için .NET