BatchImageLoaderLibrary 1.0.9

dotnet add package BatchImageLoaderLibrary --version 1.0.9
                    
NuGet\Install-Package BatchImageLoaderLibrary -Version 1.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BatchImageLoaderLibrary" Version="1.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BatchImageLoaderLibrary" Version="1.0.9" />
                    
Directory.Packages.props
<PackageReference Include="BatchImageLoaderLibrary" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BatchImageLoaderLibrary --version 1.0.9
                    
#r "nuget: BatchImageLoaderLibrary, 1.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BatchImageLoaderLibrary@1.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BatchImageLoaderLibrary&version=1.0.9
                    
Install as a Cake Addin
#tool nuget:?package=BatchImageLoaderLibrary&version=1.0.9
                    
Install as a Cake Tool

BatchImageLoaderLibrary

Batch image loader for .NET with concurrent downloading, request de-duplication, optional thumbnail generation, and pluggable on-disk caching (SQLite or filesystem).

Built for the common desktop scenario: you have a long list of image URLs (e.g. gallery thumbnails) and want to load them fast, in parallel, with a persistent cache so the next run is instant.

Features

  • Concurrent batch loading with a hard concurrency cap (SemaphoreSlim).
  • Request de-duplication — the same URL requested from many places loads exactly once; all callers await the same result (Lazy<Task<…>>), no polling.
  • Two cache backends behind one interface: SQLite (single .sqlite file) or filesystem (one file per image).
  • Per-size caching — thumbnails of different sizes for one URL coexist; the size is part of the cache key.
  • Thumbnail generation via System.Drawing (toggleable).
  • Shared, pooled HttpClient with a request timeout — no socket exhaustion under heavy batches.
  • Embedded 404 placeholder — failed loads return a built-in stub and are not cached, so a transient network error never permanently poisons a URL.
  • Thread-safe — designed to be hammered from many threads at once.

Requirements

  • .NET 6 (net6.0-windows) — referenceable from net6 / net8 / net9 Windows consumers.
  • Windows — uses System.Drawing (GDI+) for thumbnails, WPF imaging for ToBitmapImage(), and NTFS Alternate Data Streams in the filesystem backend.

Installation

Reference the project, or build and reference BatchImageLoaderLibrary.dll. The 404 placeholder ships embedded in the assembly — nothing extra to copy.

Quick start

using BatchImageLoaderLibrary;

// Configure BEFORE the first load.
BatchImageLoader.StorageType = StorageType.DB;        // or StorageType.FILE
BatchImageLoader.Instance.MaxThreadsCount = 8;        // concurrency cap
BatchImageLoader.Instance.ThumbnailWidth  = 120;
BatchImageLoader.Instance.ThumbnailHeigth = 120;      // note: property is spelled "Heigth"

// Optional: warm the in-memory cache from the persistent store.
await BatchImageLoader.Instance.LoadFromCache();

// Load many URLs concurrently.
var tasks = urls.Select(u => BatchImageLoader.Instance.GetImageFromUrl(u));
CachedImage[] images = await Task.WhenAll(tasks);

// Use the result.
byte[]? bytes = images[0].ToByteArray();
using Image? img = images[0].ToImage();

Configuration

All flags are set on BatchImageLoader.Instance (except StorageType, which is static). Set them before the first GetImageFromUrl call.

Member Default Description
BatchImageLoader.StorageType DB DB (SQLite) or FILE (filesystem).
MaxThreadsCount 64 Max concurrent downloads. Captured on first load.
CreateThumbnails true Resize to ThumbnailWidth × ThumbnailHeigth; if false, the original bytes are cached as orig.
ThumbnailWidth 120 Thumbnail width.
ThumbnailHeigth 120 Thumbnail height (sic — the property name is misspelled).
NeedSaveToCache true Persist successfully loaded images to the cache.

Progress counters (read-only)

ImagesLoaded, ImagesLoading, ImagesInQueue, ImagesProcessing, ThreadCount — useful for status displays and back-pressure (e.g. keep enqueuing while ImagesProcessing < N).

Public API

BatchImageLoader

Task<CachedImage> GetImageFromUrl(string url);   // load (or return cached); de-duplicated
Task LoadFromCache();                            // preload persistent cache into memory
static void ClearCacheForUrl(string url);        // drop all sizes of one URL from the cache
static void ClearCache();                        // wipe the whole cache
static byte[]? CreateThumbnail(byte[] image, int h = 120, int w = 120);

CachedImage

byte[]? Data { get; set; }
bool   Loaded();          // has non-empty data
int    Size();            // byte length (0 if empty)
byte[]? ToByteArray();
Image? ToImage();              // decode to System.Drawing.Image — WinForms (null on failure)
BitmapImage? ToBitmapImage();  // decode to WPF BitmapImage, frozen & thread-safe (null on failure)

StorageType

enum StorageType { FILE, DB }

Caching backends

SQLite (StorageType.DB)

  • Single file BatchImageLoaderLibraryCache.sqlite in the working directory.
  • Schema is versioned; an older incompatible cache is reset automatically on first run.
  • WAL journal mode + busy_timeout for safe concurrent access; one pooled connection per operation.
  • Cache key is (url, variant), so several thumbnail sizes of one URL are stored side by side.

Filesystem (StorageType.FILE)

  • Files are written to a cache directory, named {sha1(url)}_{variant}.jpg.
  • The original URL is stored in an NTFS Alternate Data Stream, used by LoadFromCache() to rebuild the in-memory index.
  • NTFS only — breaks on exFAT/FAT, network shares, or after archiving that strips ADS.

How it works

  1. GetImageFromUrl(url) returns a Task<CachedImage> from a concurrent dictionary keyed by URL. The first caller starts the load; everyone else (now or later) awaits the same task — so each URL loads once, with no busy-waiting and no risk of a stuck waiter.
  2. The loader checks the persistent cache. On a miss it downloads via the shared HttpClient, optionally builds a thumbnail, and saves the result.
  3. A failed download returns the embedded 404 placeholder for that session but is not written to disk, so the next run retries.
  4. A SemaphoreSlim caps how many downloads run at once.

Notes & limitations

  • Windows-only (GDI+ thumbnails, NTFS ADS for the FILE backend).
  • Single global instance — one configuration per process; not designed for multiple independent loaders or unit-test isolation.
  • In-memory results are kept for the process lifetime (no eviction); fine for large-memory machines, mind it for very large batches.
  • Thumbnails are resized without preserving aspect ratio.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net6.0-windows7.0 is compatible.  net7.0-windows was computed.  net8.0-windows was computed.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.9 97 6/28/2026
1.0.8 96 6/28/2026
1.0.6 106 6/15/2026
1.0.5 103 6/8/2026
1.0.4 100 6/8/2026
1.0.3 102 6/8/2026
1.0.2 94 6/8/2026
1.0.1 98 6/8/2026