![]() |
VOOZH | about |
dotnet add package ImageWizard.Core --version 3.11.2
NuGet\Install-Package ImageWizard.Core -Version 3.11.2
<PackageReference Include="ImageWizard.Core" Version="3.11.2" />
<PackageVersion Include="ImageWizard.Core" Version="3.11.2" />Directory.Packages.props
<PackageReference Include="ImageWizard.Core" />Project file
paket add ImageWizard.Core --version 3.11.2
#r "nuget: ImageWizard.Core, 3.11.2"
#:package ImageWizard.Core@3.11.2
#addin nuget:?package=ImageWizard.Core&version=3.11.2Install as a Cake Addin
#tool nuget:?package=ImageWizard.Core&version=3.11.2Install as a Cake Tool
A ASP.NET Core service / middleware to resize your images on the fly as alternative for thumbor.
👁 License: MIT
👁 NuGet
👁 Docker
Demo: imagewizard.net
https://localhost/image/cGiAwFYGYWx0SzO0YyCidWIfkdlUYrVgBwbm7bcTOjE/resize(200,200)/grayscale()/jpg(90)/fetch/https://upload.wikimedia.org/wikipedia/commons/b/b7/Europe_topography_map.png
| Description | Url segment |
|---|---|
| base path | "image" |
| signature based on HMACSHA256 | "cGiAwFYGYWx0SzO0YyCidWIfkdlUYrVgBwbm7bcTOjE" or "unsafe" (if enabled) |
| any filters | "resize(200,200)/grayscale()/jpg(90)" |
| loader type | "fetch" |
| loader source | https://upload.wikimedia.org/wikipedia/commons/b/b7/Europe_topography_map.png |
| Name | Loader type | Loader source | NuGet |
|---|---|---|---|
| Http loader | fetch | absolute or relative url | 👁 NuGet |
| File loader | file | relative path to file | 👁 NuGet |
| YouTube loader | youtube | video id | 👁 NuGet |
| Gravatar loader | gravatar | encoded email address | 👁 NuGet |
| OpenGraph loader | opengraph | absolute url | 👁 NuGet |
| Azure loader | azure | relative path to file | 👁 NuGet |
| PuppeteerSharp loader | screenshot | absolute url | 👁 NuGet |
| Name | Description | NuGet |
|---|---|---|
| File cache | Meta and blob file path based on cache id. | 👁 NuGet |
| Distributed cache | MS SQL, Redis | 👁 NuGet |
| MongoDB cache | Use GridFS | 👁 NuGet |
| Name | Mime type | NuGet |
|---|---|---|
| ImageSharp | image/jpeg, image/png, image/gif, image/bmp, image/webp, image/tga | 👁 NuGet |
| SkiaSharp | image/jpeg, image/png, image/gif, image/bmp, image/webp | 👁 NuGet |
| SvgNet | image/svg+xml | 👁 NuGet |
| DocNET | application/pdf | 👁 NuGet |
services.AddImageWizard();
//or
services.AddImageWizard(options =>
{
options.AllowUnsafeUrl = true;
options.AllowedDPR = new double[] { 1.0, 1.5, 2.0, 3.0, 4.0 };
options.Key = new byte[64] { .. };
options.UseETag = true;
options.CacheControl.IsEnabled = true;
options.CacheControl.MaxAge = TimeSpan.FromDays(365);
options.CacheControl.MustRevalidate = false;
options.CacheControl.Public = true;
options.CacheControl.NoCache = false;
options.CacheControl.NoStore = false;
//select automatically the compatible mime type by request header
options.UseAcceptHeader = true;
options.RefreshLastAccessInterval = TimeSpan.FromMinutes(1);
options.FallbackHandler = (state, url, cachedData) =>
{
//use the existing cached data if available?
if (cachedData != null)
{
return cachedData;
}
//load fallback image
FileInfo fallbackImage = state switch
{
LoaderResultState.NotFound => new FileInfo(@"notfound.jpg"),
LoaderResultState.Failed => new FileInfo(@"failed.jpg"),
_ => throw new Exception()
};
if (fallbackImage.Exists == false)
{
return null;
}
//convert FileInfo to CachedData
return fallbackImage.ToCachedData();
};
})
//registers ImageSharp pipeline for specified mime types
.AddImageSharp(c => c
.WithMimeTypes(MimeTypes.WebP, MimeTypes.Jpeg, MimeTypes.Png, MimeTypes.Gif)
.WithOptions(x =>
{
x.ImageMaxHeight = 4000;
x.ImageMaxWidth = 4000;
})
//Adds your custom filters
.WithFilter<BlurFilter>()
//Executes custom action before the pipeline is started.
.WithPreProcessing(x =>
{
x.Image.Mutate(m => m.AutoOrient());
})
//Executes custom action after the pipeline is finished.
.WithPostProcessing(x =>
{
//blurs all images
x.Image.Mutate(m => m.Blur());
//overrides target format (Jpeg to WebP)
if (x.ImageFormat is JpegFormat)
{
x.ImageFormat = new WebPFormat() { Lossless = false };
}
//overrides target format (Png to WebP)
else if (x.ImageFormat is PngFormat)
{
x.ImageFormat = new WebPFormat() { Lossless = true };
}
//overrides metadata
x.Image.Metadata.ExifProfile = new ExifProfile();
x.Image.Metadata.ExifProfile.SetValue(ExifTag.Copyright, "ImageWizard");
}))
//.AddSkiaSharp()
.AddSvgNet()
.AddDocNET()
//uses file cache (relative or absolute path)
.SetFileCache(options => options.Folder = "FileCache")
//or MongoDB cache
.SetMongoDBCache(options => options.Hostname = "localhost")
//or distributed cache
.SetDistributedCache()
//adds some loaders
.AddFileLoader(options => options.Folder = "FileStorage")
.AddHttpLoader(options =>
{
//checks every time for a new version of the original image.
options.RefreshMode = LoaderRefreshMode.EveryTime;
//sets base url for relative urls
options.DefaultBaseUrl = "https://mydomain";
//allows only relative urls
//(use base url from request or DefaultBaseUrl from options)
options.AllowAbsoluteUrls = false;
//allows only specified hosts
options.AllowedHosts = new [] { "mydomain" };
//adds custom http header like apikey to prevent
//that user can download the original image
options.SetHeader("ApiKey", "123456");
})
.AddYoutubeLoader()
.AddGravatarLoader()
.AddOpenGraphLoader()
.AddAnalytics()
//Adds a background service which removes cached data based on defined CleanupReason.
//The cache needs to implements ICleanupCache.
.AddCleanupService(x =>
{
//Duration between the cleanup actions. (Default: 1 day)
x.Interval = TimeSpan.FromMinutes(1);
//Removes cached data which are older than defined duration.
x.OlderThan(TimeSpan.FromMinutes(2));
//Removes cached data which are last used since defined duration.
x.LastUsedSince(TimeSpan.FromMinutes(2));
//Removes cached data which are expired (based on the loader result).
x.Expired();
})
;
//default path ("/image")
//use middleware
app.UseImageWizard(x =>
{
//default path ("/analytics")
x.MapAnalytics();
});
//or use endpoint
app.Endpoints(e => e.MapImageWizard("/image"));
public partial class BackgroundColorFilter : ImageSharpFilter
{
//use dependency injection
public BackgroundColorFilter(ILogger<BackgroundColorFilter> logger)
{
//...
}
[Filter]
public void BackgroundColor(byte r, byte g, byte b)
{
Context.Image.Mutate(m => m.BackgroundColor(new Rgba32(r, g, b)));
}
[Filter]
public void BackgroundColor(float r, float g, float b)
{
Context.Image.Mutate(m => m.BackgroundColor(new Rgba32(r, g, b)));
}
}
The source generator creates the following code:
public partial class BackgroundColorFilter : IFilterFactory
{
public static IEnumerable<IFilterAction> Create()
{
return [
new FilterAction<BackgroundColorFilter>("backgroundcolor", new Regex(@"^\((?<r>-?\d+),(?<g>-?\d+),(?<b>-?\d+)\)$"), (filter, group) => { byte r = byte.Parse(group["r"].ValueSpan, CultureInfo.InvariantCulture);byte g = byte.Parse(group["g"].ValueSpan, CultureInfo.InvariantCulture);byte b = byte.Parse(group["b"].ValueSpan, CultureInfo.InvariantCulture);filter.BackgroundColor(r,g,b); }),
new FilterAction<BackgroundColorFilter>("backgroundcolor", new Regex(@"^\((?<r>-?\d+\.\d+),(?<g>-?\d+\.\d+),(?<b>-?\d+\.\d+)\)$"), (filter, group) => { float r = float.Parse(group["r"].ValueSpan, CultureInfo.InvariantCulture);float g = float.Parse(group["g"].ValueSpan, CultureInfo.InvariantCulture);float b = float.Parse(group["b"].ValueSpan, CultureInfo.InvariantCulture);filter.BackgroundColor(r,g,b); }),
];
}
}
Register filter:
services.AddImageWizard()
.AddImageSharp(c => c.WithFilter<BackgroundColorFilter>());
URL segments:
"/backgroundcolor(255,255,255)/"
"/backgroundcolor(1.0,1.0,1.0)/"
public class ResizeFilter : ImageSharpFilter
{
[Filter]
public void Resize([DPR]int width, [DPR]int height)
{
Context.Image.Mutate(m => m.Resize(width, height));
}
}
URL segment:
"/dpr(2.0)/resize(200,100)/" //calls resize filter with the resolution 400 x 200
or
"/resize(200,100)/" + client hints
Response header:
Content-DPR: 2
Example:
public class TextFilter : ImageSharpFilter
{
[Filter]
public void DrawText(int x = 0, int y = 0, string text = "", int size = 12, string font = "Arial")
{
Context.Image.Mutate(m =>
{
m.DrawText(
text,
new Font(SystemFonts.Find(font), size),
Rgba32.Black,
new PointF(x, y));
});
}
}
URL segment:
"/drawtext(text='Hello',x=10,y=20)/"
https://www.nuget.org/packages/ImageWizard.Client/
Example:
Add settings to the appsettings.json
"ImageWizard": {
"BaseUrl": "https://<your-domain>/image",
"Key": "DEMO-KEY---PLEASE-CHANGE-THIS-KEY---PLEASE-CHANGE-THIS-KEY---PLEASE-CHANGE-THIS-KEY---==",
"Enabled": true
}
Register settings to services
services.Configure<ImageWizardClientSettings>(Configuration.GetSection("ImageWizard"));
services.AddImageWizardClient();
//or
services.AddImageWizardClient(options =>
{
options.BaseUrl = "https://<your-domain>/image";
options.Key = "..";
options.Enabled = true;
options.UseUnsafeUrl = false;
});
Create url with fluent api
@Url
.ImageWizard()
//use HTTP loader
.Fetch("https://<your-domain>/test/picture.jpg")
//fetch local file from wwwroot folder (with fingerprint)
.FetchLocal("picture.jpg")
//or file loader
.File("test/picture.jpg")
//or azure
.Azure("image.jpg")
.AsImage()
.Resize(160,140,ResizeMode.Max)
.Blur()
.Grayscale()
.Jpg(90)
.BuildUrl()
Use dependency injection
@IImageWizardUrlBuilder UrlBuilder
<img src="@UrlBuilder.FetchLocalFile("picture.jpg").AsImage().Resize(400, 200, ResizeMode.Max).Grayscale().BuildUrl()" />
Use IUrlHelper
<img src="@Url.ImageWizard().FetchLocalFile("picture.jpg").AsImage().Resize(400, 200, ResizeMode.Max).Grayscale().BuildUrl()" />
ImageWizard.Piranha 👁 NuGet
Useful to resize imagefields.
<img src="@Url.ImageWizard().Fetch(Model.Body).Resize(900,900).Grayscale().Blur().BuildUrl()">
static:
image: usercode/imagewizard
container_name: imagewizard
restart: always
networks:
- default
volumes:
- file_cache:/data
environment:
- General__Key=DEMO+KEY+++PLEASE+CHANGE+THIS+KEY+++PLEASE+CHANGE+THIS+KEY+++PLEASE+CHANGE+THIS+KEY+++==
- General__AllowUnsafeUrl=false
- General__UseAcceptHeader=false
- General__UseETag=true
- General__AllowedDPR__0=1.0
- General__AllowedDPR__1=1.5
- General__AllowedDPR__2=2.0
- General__AllowedDPR__3=3.0
- General__CacheControl__IsEnabled=true
- General__CacheControl__Public=true
- General__CacheControl__MaxAge=60
- General__CacheControl__MustRevalidate=false
- General__CacheControl__NoCache=false
- General__CacheControl__NoStore=false
- FileCache__Folder=/cache
- FileLoader__Folder=/data
- HttpLoader__DefaultBaseUrl=https://domain.tld
- HttpLoader__AllowAbsoluteUrls=false
- HttpLoader__AllowedHosts__0=domain.tld
- HttpLoader__Headers__0__Name=ApiKey
- HttpLoader__Headers__0__Value=123
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 5 NuGet packages that depend on ImageWizard.Core:
| Package | Downloads |
|---|---|
|
ImageWizard.MongoDB
Package Description |
|
|
DragonFly.ImageWizard
Headless CMS based on ASP.NET Core and Blazor |
|
|
ImageWizard.ImageSharp
Package Description |
|
|
ImageWizard.SvgNet
Package Description |
|
|
ImageWizard.Analytics
Package Description |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.11.2 | 591 | 8/6/2025 |
| 3.11.1 | 694 | 7/21/2025 |
| 3.10.0 | 1,513 | 7/26/2024 |
| 3.8.0 | 1,604 | 12/12/2023 |
| 3.7.5 | 1,795 | 5/7/2023 |
| 3.7.4 | 2,743 | 11/18/2022 |
| 3.7.3 | 2,075 | 10/28/2022 |
| 3.7.2 | 2,046 | 10/28/2022 |
| 3.7.1 | 2,781 | 7/17/2022 |
| 3.7.0 | 2,303 | 6/25/2022 |
| 3.6.0 | 2,382 | 4/11/2022 |
| 3.5.1 | 2,485 | 3/13/2022 |
| 3.5.0 | 2,251 | 2/25/2022 |
| 3.4.0 | 2,187 | 2/9/2022 |
| 3.2.0 | 2,348 | 1/30/2022 |
| 3.0.1 | 2,056 | 1/10/2022 |
| 3.0.0 | 1,510 | 1/2/2022 |
| 2.2.0 | 2,671 | 11/8/2021 |
| 2.1.9 | 2,133 | 6/5/2021 |
| 2.1.8 | 1,839 | 6/2/2021 |