ImageWizard.Core 3.8.0

dotnet add package ImageWizard.Core --version 3.8.0
NuGet\Install-Package ImageWizard.Core -Version 3.8.0
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="ImageWizard.Core" Version="3.8.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ImageWizard.Core --version 3.8.0
#r "nuget: ImageWizard.Core, 3.8.0"
#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.
// Install ImageWizard.Core as a Cake Addin
#addin nuget:?package=ImageWizard.Core&version=3.8.0

// Install ImageWizard.Core as a Cake Tool
#tool nuget:?package=ImageWizard.Core&version=3.8.0

ImageWizard

A ASP.NET Core service / middleware to resize your images on the fly as alternative for thumbor.

License: MIT NuGet Docker

Demo: imagewizard.net

Features

  • loader:
    • Http (streaming mode)
    • File (use IFileProvider)
    • YouTube (get thumbnail)
    • Gravatar
    • OpenGraph
  • caches:
    • File
    • Distributed cache
    • MongoDB
  • image filters: resize, crop, rotate,..
  • common image effects like grayscale and blur are available
  • create your custom data filter
  • pdf filters: page-to-image for documents
  • url is protected by a HMACSHA256 signature to prevent DDoS attacks
  • can handle the device pixel ratio (DPR)
  • support for cache control and ETag
  • enable range processing by http request
  • use RecyclableMemoryStream for smarter memory management (IStreamPool)
  • cleanup service

Example

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

Loader

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

Cache

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

Pipeline

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

How to use it

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"));

Internal services

  • ICacheKey
  • ICacheHash
  • ICacheLock
  • IUrlSignature
  • IStreamPool

Create custom filter

  • add a public method which is marked with the filter attribute
    • at url level are the following types possible for method overloading:
      • integer ("0")
      • floating-point number ("0.0")
      • bool ("True" or "False")
      • enum (value)
      • string ('Hello')
 public 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)));
        }
    }

Register filter:

services.AddImageWizard()
	.AddImageSharp(c => c.WithFilter<BackgroundColorFilter>());

URL segments:

"/backgroundcolor(255,255,255)/"
"/backgroundcolor(1.0,1.0,1.0)/"

How to use the DPR (device pixel ratio) attribute

  • use dpr filter to set the value or enable the client hints
  • all parameter with DPR attribute will be multiplied by the DPR factor
 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

How to use optional parameters

  • use rather method overloading if possible
  • if all parameter have default values you can set all parameters by name

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)/"

ASP.NET Core UrlBuilder

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()" />

Processing pipelines

ImageSharp

Image transformations
  • resize(size)
  • resize(width,height)
  • resize(width,height,mode)
    • mode: min, max, crop, pad, stretch
  • resize(width,height,mode,anchor)
    • anchor: center, top, bottom, left, right, topleft, topright, bottomleft, bottomright
  • crop(width,height)
    • int for absolute values, 0.0 to 1.0 for relative values
  • crop(x,y,width,height)
    • int for absolute values, 0.0 to 1.0 for relative values
  • backgroundcolor(r,g,b)
    • int (0 to 255) or float (0.0 to 1.0)
  • backgroundcolor(r,g,b,a)
    • int (0 to 255) or float (0.0 to 1.0)
  • flip(type)
    • type: horizontal, vertical
  • rotate(value)
    • value: 90, 180 or 270
  • grayscale()
  • grayscale(amount)
    • amount: 0.0 to 1.0
  • blackwhite()
  • blur()
  • invert()
  • brightness(value)
  • contrast(value)
  • autoorient()
  • drawtext(text='Hello',size=24,x=0.5,y=0.5)
    • string: raw ('Hello') or base64url (SGVsbG8)
Output formats
  • jpg()
  • jpg(quality)
  • png()
  • gif()
  • tga()
  • bmp()
  • webp()
  • webp(quality)
Special options
  • dpr(value) //set allowed device pixel ratio

SkiaSharp

Image transformations
  • resize(width,height)
  • resize(width,height,mode)
    • mode: min, max, crop, pad, stretch
  • crop(width,height)
    • 0.0 to 1.0 for relative values
  • crop(x,y,width,height)
    • 0.0 to 1.0 for relative values
  • flip(type)
    • type: horizontal, vertical
  • rotate(value)
    • value: 0.0 to 360.0
  • grayscale()
  • blur()
  • blur(radius)
  • drawtext(text='Hello',size=24,x=0.5,y=0.5)
    • string: raw ('Hello') or base64url (SGVsbG8)
Output formats
  • jpg()
  • jpg(quality)
  • png()
  • gif()
  • bmp()
  • webp()

DocNET

DocNET transformations
  • pagetoimage(pageindex)
  • pagetoimage(pageindex,width,height)
  • subpages(pageFromIndex, pageToIndex)

SvgNet

SVG transformations
  • removesize()
  • blur()
  • blur(deviation)
    • value: float
  • rotate(angle)
    • value: float

Plugin for Piranha CMS 8.0

ImageWizard.Piranha NuGet

Useful to resize imagefields.

<img src="@Url.ImageWizard().Fetch(Model.Body).Resize(900,900).Grayscale().Blur().BuildUrl()">

Docker

Docker

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 Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (10)

Showing the top 5 NuGet packages that depend on ImageWizard.Core:

Package Downloads
ImageWizard.MongoDB

Package Description

ImageWizard.ImageSharp

Package Description

ImageWizard.SvgNet

Package Description

ImageWizard.Analytics

Package Description

ImageWizard.Azure

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.8.0 744 12/12/2023
3.7.5 1,097 5/7/2023
3.7.4 2,112 11/18/2022
3.7.3 1,704 10/28/2022
3.7.2 1,685 10/28/2022
3.7.1 2,302 7/17/2022
3.7.0 1,923 6/25/2022
3.6.0 2,001 4/11/2022
3.5.1 2,076 3/13/2022
3.5.0 1,853 2/25/2022
3.4.0 1,831 2/9/2022
3.2.0 1,961 1/30/2022
3.0.1 1,690 1/10/2022
3.0.0 1,148 1/2/2022
2.2.0 2,174 11/8/2021
2.1.9 1,747 6/5/2021
2.1.8 1,453 6/2/2021
2.1.7 1,569 3/6/2021
2.1.6 1,924 2/8/2021
2.1.5 1,492 11/11/2020
2.1.2 1,995 6/21/2020
2.1.1 1,734 5/20/2020
2.1.0 1,766 5/20/2020
2.0.3 1,579 5/14/2020
2.0.2 1,671 5/7/2020
2.0.1 1,702 5/6/2020
2.0.0 1,179 5/6/2020
1.5.7 1,493 4/16/2020
1.5.6 1,478 4/8/2020
1.5.4 1,503 2/5/2020
1.5.2 1,316 2/5/2020
1.5.1 1,112 2/5/2020
1.5.0 1,057 2/5/2020
1.4.1 1,390 12/8/2019
1.4.0 1,226 12/7/2019
1.3.1 1,177 12/7/2019
1.3.0 1,289 11/3/2019
1.2.2 1,277 9/7/2019
1.2.1 1,122 8/15/2019
1.2.0 1,288 8/13/2019
1.1.6 1,285 7/17/2019
1.1.5 1,315 7/3/2019
1.1.4 1,123 6/30/2019
1.1.3 1,301 6/29/2019
1.1.2 1,137 6/29/2019
1.1.1 1,090 6/29/2019
1.1.0 1,134 6/29/2019
1.0.0 1,116 6/28/2019