Git Product home page Git Product logo

imagesharp.web's Introduction

SixLabors.ImageSharp.Web
SixLabors.ImageSharp.Web

Build Status Code coverage License: Six Labors Split GitHub issues

GitHub stars GitHub forks Twitter

ImageSharp.Web is a high-performance ASP.NET Core middleware leveraging the ImageSharp graphics library to allow on-the-fly image manipulation via URL based commands.

License

Support Six Labors

Support the efforts of the development of the Six Labors projects.

Documentation

  • Detailed documentation for the ImageSharp.Web API is available. This includes additional conceptual documentation to help you get started.

Questions

Code of Conduct

This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information, see the .NET Foundation Code of Conduct.

Installation

Install stable releases via Nuget; development releases are available via Feedz.io.

Package Name Release (NuGet) Nightly (Feedz.io)
SixLabors.ImageSharp.Web NuGet feedz.io

Manual build

If you prefer, you can compile ImageSharp.Web yourself (please do and help!)

Alternatively, you can work from command line and/or with a lightweight editor on both Linux/Unix and Windows:

To clone ImageSharp.Web locally, click the "Clone in [YOUR_OS]" button above or run the following git commands:

git clone https://github.com/SixLabors/ImageSharp.Web

If working with Windows please ensure that you have enabled log file paths in git (run as Administrator).

git config --system core.longpaths true

This repository contains git submodules. To add the submodules to the project, navigate to the repository root and type:

git submodule update --init --recursive

Running the Tests

The unit tests require Azurite Azure Storage Emulator and s3rver in order to run.

On Windows to install and run the server as a background process run the following command

npm install -g azurite
start /B azurite --loose

npm install -g s3rver
start /B s3rver -d .

On Linux

sudo npm install -g azurite
sudo azurite --loose &

sudo npm install -g s3rver
sudo s3rver -d . &

How can you help?

Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our Contribution Guide before opening a PR.

The ImageSharp.Web Team

imagesharp.web's People

Contributors

andyfelton-equatedigital avatar andymac4182 avatar antonfirsov avatar brianpopow avatar c1rus avatar daniel15 avatar deanmarcussen avatar dependabot[bot] avatar dlemstra avatar jevgenigeurtsen avatar jhdrn avatar jimbobsquarepants avatar jrunestone avatar jz5 avatar kroymann avatar lahma avatar markciliavincenti avatar marklagendijk avatar mathieu79fi avatar mdupras avatar meixger avatar pandorax100 avatar phyxionnl avatar piedone avatar ronaldbarendse avatar sandcastle avatar sebastienros avatar stefannikolei avatar tocsoft avatar wagich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imagesharp.web's Issues

ImageSharp.Web always returning original image when a static content folder is specified

Description

Hi I'm trying ImageSharp.Web for the first time so, bear with me.
I created a fresh .Net Core 2.2 project and added the default configuration like you have on your documentation. In this scenario it works like it's supposed to but as soon as you change your static content folder it always returns the original unmodified image.

Steps to Reproduce

Scenario 1 (this works).
Use this Configure method (ommited the ConfigureServices method).

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();

        app.UseImageSharp();
        app.UseStaticFiles();
    }

Scenario 2 (this always returns the original image).

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc();

        app.UseImageSharp();
        app.UseStaticFiles(new StaticFileOptions
        {
            FileProvider = new PhysicalFileProvider("c:\\ImageSharpTest"),
            RequestPath = "/StaticFiles"
        });
    }

Checked the folder permissions and I have read and write permissions.

System Configuration

  • ImageSharp.Web version: 1.0.1
  • Environment (Windows 10, VisualStudio 2019):
  • .NET Framework version: .Net Core 2.2

ImageSharp.Web

Description

This issue is designed to capture the architecture and tasks required to build an extensible library for parsing URL API instructions and caching the result.

Feel free to discuss below. We'll assign specific issues for functional components as we determine them.

Basic Requirements

  • Asp.NET Core Middleware to capture valid requests
  • Extensible configuration for Caching, ImageServices, and Processing. Must be secure.
  • IImageService implementations for physical file system and remote images.
  • IDistributedCache implementation for physical file system that can be switched out for Redis, Azure, etc. How do we handle cleanup, Response codes?
  • Fast, low collision hashing of URL for cache implementations.

Pipeline

The following gives an overall summary of the image processing pipeline.

  1. Request is intercepted by Middleware (Authorisation?)
  2. IImageService is assigned using URL prefix pattern matching (Regex?)
  3. IImageService determines validity of request and attempts to return stream containing image.
  4. IDistributedCache implementation checks if file exists. (Redirect if exists?)
  5. Not cached? URL querystring params are parsed for matching processor.
  6. Image is processed by matches via fluent API.
  7. Result is cached and image served.
  8. Cleanup of expired cached files. (How?, When?)

Edit

Updated Requirements and Pipeline below

Basic Requirements

  • Asp.NET Core Middleware to capture valid requests
  • Extensible configuration for Parsing, Resolving, Processing, and Caching. Must be secure
  • Configuration for handling EXIF metadata Managed via OnBeforeSave
  • IRequestParser implementation for parsing requests for command string that can be switched out
  • IImageResolver implementation collection for physical file system that
  • Extensible CommandParser implementation for converting commands into real values for processing.
  • IImageWebProcessor for Resize
  • IImageWebProcessor for Quality Managed by configuring individual formats.
  • IImageWebProcessor for Format
  • IImageWebProcessor for BackgroundColor
  • IImageCache implementation for physical file system that can be switched out for Azure, etc.
  • Fast, low collision hashing of URL for cache implementations
  • ILogger based logging
  • TagHelper for generating img, picture markup Out of scope.

Pipeline

The following gives an overall summary of the image processing pipeline.

  1. Request is intercepted by Middleware
  2. IUriParser extracts commands; if not found, exit
  3. IImageResolver is assigned using Match() method
  4. IImageResolver determines validity of request and attempts to return stream containing image.
  5. IImageCache implementation checks if file exists. (Returns correct response)
  6. Not cached? URL querystring params are parsed for matching processor.
  7. IImageWebProcessor implementations process the image
  8. Result is cached and image served.

copied from SixLabors/ImageSharp#216

Processing does not use query string parameter order

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

According to the documentation processing operations should use the order in which they are supplied in the query string, but this is currently not the case. Instead, it loops through all processors in the order they are registered and calls the Process method on each one (even when none of the commands for that processor are provided):

public static FormattedImage Process(
this FormattedImage source,
ILogger logger,
IEnumerable<IImageWebProcessor> processors,
IDictionary<string, string> commands,
CommandParser commandParser,
CultureInfo culture)
{
if (commands.Count != 0)
{
foreach (IImageWebProcessor processor in processors)
{
source = processor.Process(source, logger, commands, commandParser, culture);
}
}
return source;
}

This probably wasn't noticed before, because the order in which the built-in processors are called doesn't affect the end-result (ResizeWebProcessor, FormatWebProcessor, BackgroundColorWebProcessor and JpegQualityWebProcessor all affect different aspects of an image). All processors also include a check before mutating the image, so that ensured there were no side-effects by always invoking them.

Umbraco required a custom processor to crop images using coordinates (representing a crop box/rectangle), but adding that after the default built-in processors would result in cropping the already resized image, instead of using the original.

Steps to Reproduce

You can use the CropWebProcessor from umbraco/Umbraco-CMS#10623 to test this issue (or create a similar simple one):

  • Only adding the processor (after the default ones) ends up with wrongly cropped/resized images;
  • Removing the ResizeWebProcessor, adding the custom processor and then re-adding it again will correctly crop before resizing.

Suggested solution

The ImageSharpMiddleware already keeps track of all known processing commands, filters unknown ones from the current request and short-circuits when there are none. This would mean only the above Process extension method will need to be updated.

Besides invoking the processor in the order they are provided in the query string, we need to ensure they aren't invoked for every command (e.g. twice when using ?width=200&height=200). This can be done by tracking the all commands used by a processor:

var processedCommands = new List<string>();
foreach (KeyValuePair<string, string> command in commands)
{
    if (processedCommands.Contains(command.Key, StringComparer.OrdinalIgnoreCase))
    {
        // Skip commands already used by a processor
        continue;
    }

    foreach (IImageWebProcessor processor in processors.Where(p => p.Commands.Contains(command.Key, StringComparer.OrdinalIgnoreCase)))
    {
        source = processor.Process(source, logger, commands, commandParser, culture);

        processedCommands.AddRange(processor.Commands);
    }
}

Or by tracking available processors and remove them after invoking:

var availableProcessors = processors.ToList();
foreach (KeyValuePair<string, string> command in commands)
{
    foreach (IImageWebProcessor processor in availableProcessors.Where(p => p.Commands.Contains(command.Key, StringComparer.OrdinalIgnoreCase)).ToList())
    {
        source = processor.Process(source, logger, commands, commandParser, culture);

        // Prevent invoking the processor again
        availableProcessors.Remove(processor);
    }
}

I haven't tested the above code, but it should give a good start for a PR/fix and might be something to benchmark/compare against each other.

Other notes

The current API (using IDictionary<string, string> commands) combines duplicate query string keys, making it impossible to run processors more than once using different commands, e.g. resize width to 200, crop and then resize the cropped version to a height of 300 (there are definitely better examples to illustrate the use case).

This might be because QueryHelpers.ParseQuery() is used, which creates an IDictionary<string, StringValues> and thereby already loses the order of duplicate query string keys. Because the StringValues are then converted into a single string (joining multiple values with a comma), you might end up with invalid values (e.g. ?width=100&width=200 will result in 100,200, which gets interpreted as 100200 when used as resize width)!

Also something to note: the cache key only uses known processor commands, so adding cache busting parameters (e.g. rnd or v) doesn't currently work. There is a CacheBusterWebProcessor, but that's only used/added for tests. Changing the order does though, so that part should already work as expected!

System Configuration

  • ImageSharp.Web version: 1.0.3
  • Other Six Labors packages and versions: ImageSharp 1.0.3
  • Environment (Operating system, version and so on): Windows 10 (21H1 64-bit)
  • .NET Framework version: .NET 5
  • Additional information: Umbraco 9.0.0-rc001

Potential Memory Leak - LargeArrayPool growing large

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I noticed our application that is hosting the ImageSharp.Web middleware has grown to fill a large percentage of both machines it is on. After analysing a dump file with dotMemory it appears most of the memory is being used by largeArrayPool in ArrayPoolMemoryManager I have a feeling this is something I am doing wrong in one of the pieces I have replaced.

image

It seems to be mostly in a single set of buffers.

Steps to Reproduce

The only non standard part of the middleware is preventing caching

public class NoCacheImageCache : IImageCache
    {
        public Task<CachedInfo> IsExpiredAsync(HttpContext context, string key, DateTime minDateUtc)
        {
            return Task.FromResult(new CachedInfo(true, DateTimeOffset.UtcNow, 0));
        }

        public Task<IByteBuffer> GetAsync(string key)
        {
            return null;
        }

        public Task<DateTimeOffset> SetAsync(string key, IByteBuffer value)
        {
            return Task.FromResult(DateTimeOffset.UtcNow);
        }

        public IDictionary<string, string> Settings { get; set; } = new Dictionary<string, string>();
    }

and loading the files from s3

public class S3FileSystemResolver : IImageResolver
    {
        private readonly IS3Storage _s3Storage;
        private readonly Serilog.ILogger _logger;
        private readonly IBufferManager _bufferManager;

        public S3FileSystemResolver(IS3Storage s3Storage, Serilog.ILogger logger, IBufferManager bufferManager)
        {
            _s3Storage = s3Storage;
            _logger = logger;
            _bufferManager = bufferManager;
        }
        public Task<bool> IsValidRequestAsync(HttpContext context, ILogger logger)
        {
            var displayUrl = context.Request.Path;

            return Task.FromResult(Path.GetExtension(displayUrl).EndsWith(".jpg") ||
                                   Path.GetExtension(displayUrl).EndsWith(".png"));
        }

        public async Task<IByteBuffer> ResolveImageAsync(HttpContext context, ILogger logger)
        {
            var bucketName = _s3Storage.BucketNameFor<ImageAsset>();
            var displayUrl = context.Request.Path;
            _logger.Information("Getting image for {ImageUri}", displayUrl);
            var imageId = Path.GetFileNameWithoutExtension(displayUrl);
            _logger.Debug("Image id is {ImageId}", imageId);

            var imageData = await _s3Storage.DownloadBytes(bucketName, $"{imageId}.png");

            if (imageData == null)
            {
                _logger.Debug("No image found for {ImageId}", imageId);
                return null;
            }

            _logger.Debug("Found image {ImageId}", imageId);

            var buffer = _bufferManager.Allocate(imageData.Length);

            imageData.CopyTo(buffer.Array, 0);

            return buffer;
        }

        public Func<HttpContext, bool> Match { get; set; } = _ => true;
        public IDictionary<string, string> Settings { get; set; } = new Dictionary<string, string>();
    }

and setting of the PNG Encoder

public class PngEncoderProcessor : IImageWebProcessor
    {
        public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands)
        {
            var extension = commands.GetValueOrDefault(PngColorTypeCommand);

            if (extension.IsNotNullOrWhiteSpace() && Enum.TryParse<PngColorType>(extension, out var pngColorType))
            {
                image.Image.GetConfiguration().ImageFormatsManager.SetEncoder(ImageFormats.Png,
                    new PngEncoder { PngColorType = pngColorType });
            }
            else
            {
                image.Image.GetConfiguration().ImageFormatsManager.SetEncoder(ImageFormats.Png,
                    new PngEncoder { PngColorType = PngColorType.Palette });
            }

            return image;
        }

        /// <summary>
        /// The command constant for format
        /// </summary>
        private const string PngColorTypeCommand = "pngcolortype";

        /// <summary>
        /// The reusable collection of commands
        /// </summary>
        private static readonly IEnumerable<string> PngEncoderCommands
            = new[] { PngColorTypeCommand };

        public IEnumerable<string> Commands => PngEncoderCommands;
    }
services.AddImageSharpCore()
                    .SetRequestParser<QueryCollectionRequestParser>()
                    .SetBufferManager<PooledBufferManager>()
                    .SetCache<NoCacheImageCache>()
                    .SetCacheHash<CacheHash>()
                    .SetAsyncKeyLock<AsyncKeyLock>()
                    .AddResolver<S3FileSystemResolver>()
                    .AddProcessor<ResizeWebProcessor>()
                    .AddProcessor<FormatWebProcessor>()
                    .AddProcessor<BackgroundColorWebProcessor>()
                    .AddProcessor<PngEncoderProcessor>();

System Configuration

  • ImageSharp.Web version: 1.0.0-dev001425
  • Other SixLabors packages and versions: SixLabors.ImageSharp.Web 1.0.0-dev000087
  • Environment (Operating system, version and so on): Windows
  • .NET Framework version: .NET Core 2.1
  • Additional information:

Unhandled exception thrown by application when using a specific image with extreme height

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

When inserting the attached image, it refuses to show and produces the following fail in VS Debug Console;

Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HM9FH4P35QNA", Request id "0HM9FH4P35QNA:00000003": An unhandled exception was thrown by the application.
      SixLabors.ImageSharp.UnknownImageFormatException: Image cannot be loaded. Available decoders:
       - JPEG : JpegDecoder
       - PNG : PngDecoder
       - BMP : BmpDecoder
       - TGA : TgaDecoder
       - GIF : GifDecoder
      
         at SixLabors.ImageSharp.Image.Load[TPixel](Configuration configuration, Stream stream, IImageFormat& format)
         at SixLabors.ImageSharp.Web.FormattedImage.Load(Configuration configuration, Stream source)
         at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.<>c__DisplayClass18_0.<<ProcessRequestAsync>b__0>d.MoveNext()
      --- End of stack trace from previous location ---
         at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.<>c__DisplayClass18_0.<<ProcessRequestAsync>b__0>d.MoveNext()
      --- End of stack trace from previous location ---
         at SixLabors.ImageSharp.Web.Middleware.ConcurrentDictionaryExtensions.GetOrAddAsync[TKey,TValue](ConcurrentDictionary`2 dictionary, TKey key, Func`2 valueFactory)
         at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary`2 commands)
         at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Steps to Reproduce

b5035dcb-22ee-4098-8ccc-b1d53a4fec52_download
Attempt to use the attached image with, in my case, "?height=600&width=600&rmode=max", although other dimensions also have the same issue.

System Configuration

  • ImageSharp.Web version: 1.0.3
  • Other ImageSharp.Web packages and versions:
  • Environment (Operating system, version and so on): Windows 10 Pro - 10.0.19041 Build 19041
  • .NET Framework version: ASP.NET Core 5.0
  • Additional information:

Refactor to support aspnetcore middleware and httpmodule versions

We want to refactor the code so that we produce 3 packages.

  1. SixLabors.ImageSharp.Web.Core - the core processing engine with its own abstractions around the http request to normalise request formats between core and systemweb (should be netstandard only)
  2. SixLabors.ImageSharp.Web.AspNetCore - the aspnet core middleware piece, this includes the extension methods for configuring in an aspnetcore style + the a middleware dispacher that calls out to the SixLabors.ImageSharp.Web.Core after translating the request context into an ImageRequestContext and handling the response.
  3. SixLabors.ImageSharp.Web.SystemWeb - the full framework HttpModule based implementation like other version responsible for translating between HttpContext and ImageRequestContext and calling the processing pipeline.

This will allow us to reach older installations targeting full framework and also would provide a transition option for those user using the older ImageProcessor.Web library allowing ImageProcessor.Web and ImageProcessor to be able to be mothballed as users would now have a transition option.

Exception on simple usage

The library version I am using is 1.0.0-beta0003. I am using ASP.NET Core 2.1 with standard configuration.

services.AddImageSharp();
    <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />

exception

cache path isn't valid

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

ImageSharp.Web is no longer working in asp.net 3.0 (full release version). the error is:

ArgumentException: The path in 'value' must start with '/'. (Parameter 'value')
Microsoft.AspNetCore.Http.PathString..ctor(string value)
Microsoft.AspNetCore.Hosting.StaticWebAssets.StaticWebAssetsFileProvider.StartsWithBasePath(string subpath, out PathString rest)
Microsoft.AspNetCore.Hosting.StaticWebAssets.StaticWebAssetsFileProvider.GetFileInfo(string subpath)
Microsoft.Extensions.FileProviders.CompositeFileProvider.GetFileInfo(string subpath)
SixLabors.ImageSharp.Web.Caching.PhysicalFileSystemCache.GetAsync(string key)
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, bool processRequest, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary<string, string> commands)
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

the fix for this issue is straightforward, in PhysicalFileSystemCache.cs on line 75 there's a call:

string path = this.ToFilePath(key);

the bug occurs when this path doesn't start with forward slash "/". as you can see from the stack trace of the error, the path eventually gets passed to the Microsoft.AspNetCore.Http.PathString constructor which expects the path to start with forward slash.

EDIT: i initially reported that this was no longer an issue for PhysicalFileSystemProvider in the full 3.0 release but this isn't the case - it's still an issue. it was only working because of my change to ensure the path started with "/". once i got rid of my changes the issue resurfaced. of course both physical and azure provider both use the same caching mechanism and it's the PhysicalFileSystemCache that's causing the issue.

Steps to Reproduce

i'd link you to my project but you'd have to setup so many things to get it running it might be easier to just create a new asp.net 3.0 project and try to resize an image.

System Configuration

  • ImageSharp.Web version: 1.0.0-beta0009
  • Other SixLabors packages and versions:
    imagesharp 1.0.0-beta0007
    imagesharp.drawing 1.0.0-beta0007
    imagesharp.web.providers.azure 1.0.0-beta0009
  • Environment (Operating system, version and so on):
    windows 10
  • .NET Framework version:
    .net core 3.0
  • Additional information:

error when extacting container name from path in Azure Blob Store provider

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I'm using RC-1 with the azure blob store provider and getting a 404 on any images stored on Azure (local images work fine). I think the issue lines on line 92 of AzureBlobStorageImageProvider.cs.

When extracting the container key from the URL, instead of

string nameToMatch = index != -1 ? path.Substring(index) : path;

should it not be

string nameToMatch = index != -1 ? path.Substring(0 ,index) : path;

to extract the first portion of the path?

I've copied the code for the Azure provider directly into my project and made the above change and it's resolved my issue so i'm reasonably confident in the above.

Steps to Reproduce

Attempt to resize an image stored on an Azure blob

System Configuration

  • ImageSharp.Web version: RC-1
  • Other ImageSharp packages and versions:
  • Environment (Operating system, version and so on): Windows 10
  • .NET Framework version: dotnet core 3.1
  • Additional information:

macOS: Intellisense problems with include paths

Prerequisites

Install ImageSharp.Web-master on a Mac. Start Visual Studio with ImageSharp.Web.sln

Description

Open ImageSharp.Web-master/samples/ImageSharp.Web.Sample/Startup.cs .

Any reference to ImageSharp classes are red-lined.

If you change line 12 of ImageSharp.Web-master/samples/ImageSharp.Web.Sample/Startup.cs/⁨ImageSharp.Web.Sample⁩.csproj
from
<ProjectReference Include="..\..\src\ImageSharp.Web\/ImageSharp.Web.csproj" />
to
<ProjectReference Include="../../src/ImageSharp.Web/ImageSharp.Web.csproj" />

the problem is solved.

System Configuration

  • ImageSharp.Web version: 1.0.0-beta6
  • Other SixLabors packages and versions:
  • Environment (Operating system, version and so on): macOS 10.14.2
  • .NET Core version: 2.1.2
  • Additional information: VS Community for Mac 7.7.3

ImageSharp.Web.Caching.AsyncKeyLock.GetDoorman: System.NullReferenceException

Description

System.NullReferenceException: Object reference not set to an instance of an object.

at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at SixLabors.ImageSharp.Web.Caching.AsyncKeyLock.GetDoorman(String key) in ImageSharp.Web\Caching\AsyncKeyLock.cs:line 85
at SixLabors.ImageSharp.Web.Caching.AsyncKeyLock.ReaderLockAsync(String key) in ImageSharp.Web\Caching\AsyncKeyLock.cs:line 47
at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context) in ImageSharp.Web\Middleware\ImageSharpMiddleware.cs:line 187

MissingMethodException when running on .NET Core 2.0

The usage of EntityTagHeaderValue is like this:

this.fileEtag = new EntityTagHeaderValue($"{'\"'}{Convert.ToString(etagHash, 16)}{'\"'}");

When an application using ImageSharp.Web is using a newer version of Microsoft.Net.Http.Headers, literally 2.0.0, then this constructor is not available anymore as it has been converted to a StringSegment.
It results in a MissingMethodException whenever the middleware is used.

There are two solutions:

  • Target 2.0.0 only and reference the new packages
  • Multi-target 1.4 and 2.0.0 with a conditional statement to switch to the other implementation

Please advise on your preferred solution and I will implement it. At this point I personally don't think supporting 1.4 still makes sense as you released after 2.0.

Bug in default implementation of cache hash creation?

Hi,
I ran into caching issues while adding this middleware into my app, all matched urls (which are in the form of /imagepool/3a47ac8a-c95c-4a6c-a96c-94613d3f567a.ext) returned the same image, the one which was accessed first. Adding a processing parameter caused the correct image being loaded, but again trying to load other images with the same parameters returned the firstly accessed image.

So I took a look at the default CacheHash implementation and to me it looks like the hash is generated from the empty(?) buffer from the pool. Seems the url-value is only used to get the extension and the size of the buffer, thus if the hash is calculated from a buffer of zeroes(?) it only changes if the buffer size changes. After switching to my own implementation of the CacheHash everything worked as expected.

byte[] hash = hashAlgorithm.ComputeHash(buffer.Array, 0, byteCount);

Missing content root folder triggers an exception

Repro: Delete the wwwroot folder, and see this exception

ArgumentNullException: Value cannot be null. Parameter name: path1 System.IO.Path.Combine(string path1, string path2) SixLabors.ImageSharp.Web.Caching.PhysicalFileSystemCache+<SetAsync>d__12.MoveNext()

Ideally the exception should be more descriptive. Or just be no-op without an exception.

Clarify ImageMetaData Last Modified Time / etag value

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Cheers for all the fixes over the weekend @JimBobSquarePants .

I'm just doing some integration work with ImageSharp and OrchardCore at the moment and wanted to clarify the behaviour of the ImageMetaData LastModifiedDate, which is used to generate the etag.

The comments all say that it's based on the date the source file was modified

/// <param name="lastWriteTimeUtc">The date and time in coordinated universal time (UTC) since the source file was last modified.</param>

but in ImageSharpMiddleware when creating the cached image metadata it uses DateTime.UtcNow, rather than the last modified date of the source image.

cachedImageMetadata = new ImageMetaData(DateTime.UtcNow, image.Format.DefaultMimeType, maxAge);

Unless I've missed something somewhere else?

I can't decide if I prefer it this way, or not, but figured I should clarify if it's intended / unintended?

API suggestion for IImageResolver and IImageCache

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Problem

Currently cached images are loaded into memory unnecessarily: it should be enough to copy the file/azure blob/redis/memory etc. stream into response.Body without reading the full contents.

Solution

IImageCache.GetAsync(...), IImageCache.SetAsync(...) and IImageResolver.ResolveImageAsync() should work with a dedicated abstract ICachedImage object instead of an in-memory buffer:

public interface ICachedImage
{
    Stream OpenRead();
    Stream OpenWrite();
}

For me it seems this API can cover all the use cases which are being solved with in-memory buffers at the moment:

  • Read and write FormattedImage
  • Copy contents to and from other streams (eg. response.Body, MemoryStream)

ImageSharp.Web.Sample yields System.MissingMethodException on macOS

Prerequisites

Install ImageSharp.Web-master on a Mac. Start Visual Studio with ImageSharp.Web.sln

Description

Build ImageSharp.Web.Sample (see ticket #53 on errors).
Run it.
The demo page looks quite poor like this

All requests for an image result in an exception like:

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:2646/imagesharp-logo.png?width=300&bgcolor=FFFF00 �[40m�[32minfo�[39m�[22m�[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:2646/imagesharp-logo.png?width=300&bgcolor=FFFF00 Exception thrown: 'System.MissingMethodException' in SixLabors.ImageSharp.Web.dll Exception thrown: 'System.NotSupportedException' in SixLabors.ImageSharp.Web.dll Exception thrown: 'System.MissingMethodException' in System.Private.CoreLib.dll Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 4214.771ms 500 text/html; charset=utf-8 �[40m�[32minfo�[39m�[22m�[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 4214.771ms 500 text/html; charset=utf-8 �[40m�[32minfo�[39m�[22m�[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:2646/imagesharp-logo.png?width=300&bgcolor=128,28,32 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:2646/imagesharp-logo.png?width=300&bgcolor=128,28,32 �[41m�[30mfail�[39m�[22m�[49m: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request. System.MissingMethodException: Method not found: 'Void Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(System.String)'. at SixLabors.ImageSharp.Web.Middleware.ImageContext.ComputeLastModified() at SixLabors.ImageSharp.Web.Middleware.ImageContext.ComprehendRequestHeaders(DateTimeOffset lastModified, Int64 length) in .../ImageSharp.Web-master/src/ImageSharp.Web/Middleware/ImageContext.cs:line 103 at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.SendResponse(ImageContext imageContext, String key, Stream stream, ImageMetaData metadata) in .../ImageSharp.Web-master/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs:line 279 at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context) in .../ImageSharp.Web-master/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs:line 203 at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) Exception thrown: 'System.MissingMethodException' in SixLabors.ImageSharp.Web.dll Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:Error: An unhandled exception has occurred while executing the request.

System Configuration

  • ImageSharp.Web version: 1.0.0-beta6
  • Other SixLabors packages and versions:
    packages/sixlabors.core/1.0.0-beta0006/lib/netcoreapp2.0/SixLabors.Core.dll packages/sixlabors.imagesharp/1.0.0-beta0005/lib/netcoreapp2.1/SixLabors.ImageSharp.dll
  • Environment (Operating system, version and so on): macOS 10.14.2
  • .NET Core version: 2.1.2
  • Additional information: VS Community for Mac 7.7.3

SixLabors.ImageSharp.ImageFormatException: Bad method for ZLIB header: cmf=80 when loading png image

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

When using Umbraco 9 on Azure Web Apps using Azure Storage to save media I get the following exception in ImageSharp:

SixLabors.ImageSharp.ImageFormatException: Bad method for ZLIB header: cmf=80

   at SixLabors.ImageSharp.Formats.Png.Zlib.ZlibInflateStream.InitializeInflateStream(Boolean isCriticalChunk)

   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.ReadScanlines[TPixel](PngChunk chunk, ImageFrame`1 image, PngMetadata pngMetadata)

   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.Decode[TPixel](BufferedReadStream stream, CancellationToken cancellationToken)

   at SixLabors.ImageSharp.Formats.ImageDecoderUtilities.Decode[TPixel](IImageDecoderInternals decoder, Configuration configuration, Stream stream, Func`3 largeImageExceptionFactory)

   at SixLabors.ImageSharp.Formats.Png.PngDecoder.Decode[TPixel](Configuration configuration, Stream stream)

   at SixLabors.ImageSharp.Image.Decode[TPixel](Stream stream, Configuration config)

   at SixLabors.ImageSharp.Image.<>c__DisplayClass133_0`1.<Load>b__0(Stream s)

   at SixLabors.ImageSharp.Image.WithSeekableStream[T](Configuration configuration, Stream stream, Func`2 action)

   at SixLabors.ImageSharp.Image.Load[TPixel](Configuration configuration, Stream stream, IImageFormat& format)

   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.<>c__DisplayClass18_0.<<ProcessRequestAsync>b__0>d.MoveNext()

--- End of stack trace from previous location ---

   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.<>c__DisplayClass18_0.<<ProcessRequestAsync>b__0>d.MoveNext()

--- End of stack trace from previous location ---

   at SixLabors.ImageSharp.Web.Middleware.ConcurrentDictionaryExtensions.GetOrAddAsync[TKey,TValue](ConcurrentDictionary`2 dictionary, TKey key, Func`2 valueFactory)

   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary`2 commands)

   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)

   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)

   at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\projects\dotnet\src\MiniProfiler.AspNetCore\MiniProfilerMiddleware.cs:line 121

   at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)

   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()

--- End of stack trace from previous location ---

   at Umbraco.Cms.Web.Common.Middleware.PreviewAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)

   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()

--- End of stack trace from previous location ---

   at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestLoggingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)

   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()

--- End of stack trace from previous location ---

   at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()

This issue seems to only be caused when using Azure/Azure storage. When running on localhost with Azure Storage emulator as media storage the image does load without problems.

Steps to Reproduce

Not available as I don't know exactly in what circumstances the issues occur. I do know this images doesn't show up when using query parameters on our development environment running in the configuration mentioned below: https://www.wearetriple.com/media/qfsl0o2c/vodafone-header-image-triple.png

System Configuration

Azure Web App S1 tier
Standard LRS Tier Azure Storage
.Net 6

  • ImageSharp version: 1.0.4
  • Other ImageSharp packages and versions: SixLabors.ImageSharp.Web.Providers.Azure 1.0.3
  • Environment (Operating system, version and so on): Azure Web App running Windows
  • .NET Framework version: .Net 6
  • Additional information: I use Umbraco 9 as cms.

Image in cache is created for non supported formats

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exists in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

If you request an image with an unsupported image type, an image is created in the cache. This way it is easier to DDOS the system.

Steps to Reproduce

-Add ImageSharp.Web to your asp.net core application
-Request an image with an unsupported type
-See in the console that a new image in the cache is created.

System Configuration

  • ImageSharp.Web version: 1.04
  • Other Six Labors packages and versions: 1.04
  • Environment (Operating system, version and so on): Windows 10 Pro 20H2 19042.1348
  • .NET Framework version: .NET Core 5.0
  • Additional information:

I temporarily solved the problem by the following code:

            services.AddImageSharp(x => 
            {
                x.OnParseCommandsAsync = c =>
                {
                    if (c.Commands.Count == 0)
                    {
                        return Task.CompletedTask;
                    }

                    // It's a good idea to have this to provide very basic security. 
                    // We can safely use the static resize processor properties. 
                    uint width = c.Parser.ParseValue<uint>(
                        c.Commands.GetValueOrDefault(ResizeWebProcessor.Width),
                        c.Culture);

                    uint height = c.Parser.ParseValue<uint>(
                        c.Commands.GetValueOrDefault(ResizeWebProcessor.Height),
                        c.Culture);

                    if (width > 4000 && height > 4000)
                    {
                        c.Commands.Remove(ResizeWebProcessor.Width);
                        c.Commands.Remove(ResizeWebProcessor.Height);
                    }


                    //If file extension is not supported, remove command.
                    {
                        string extension = c.Commands.GetValueOrDefault(FormatWebProcessor.Format);

                        SixLabors.ImageSharp.Formats.IImageFormat format = x.Configuration.ImageFormatsManager.FindFormatByFileExtension(extension);

                        if (format == null)
                        {
                            c.Commands.Remove(FormatWebProcessor.Format);
                        }
                    }

                    return Task.CompletedTask;
                };

            });

Pooling output stream buffer

In the ImageSharpMiddleware class, the following comment currently exists:

// TODO: How to prevent the allocation in outStream? Passing a pooled buffer won't let stream grow if needed.

This could be achieved by a custom MemoryStream-esque implementation that grows the buffer by using an array pool or a buffer manager rather than allocating on the heap. (MemoryStream performs this allocation in its Capacity property, which makes it a poor candidate for inheriting and changing that specific behaviour, so we'd effectively have to roll our own Stream to prevent said allocation)

I reckon in high-performance scenarios the difference between having a pooled vs allocated output stream could be significant.

Is this middleware component part of the official release, and would it be worth it to invest the time to optimise this part of the middleware? If so, I could have a stab at it.

Issue with multiple requests on different threads against the same image

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I implemented ImageSharp.Web to leverage resizing on a website. Some page templates on this site feature the same image, in different sizes, in close succession. I noticed that the image that was resolved first in the group, sometimes became reused for the second request. This lead to the site returning the same image for two distinct query strings. I then dug a bit deeper and managed to reproduce the issue in an automated test. Please have a look at this.

Steps to Reproduce

  1. Set up a test project with Microsoft.AspNetCore.TestHost, NUnit, NUnit3TestAdapter and SixLabors.ImageSharp.Web installed.
  2. Paste this gist into a file ResizerTests.cs.
  3. Provide an image to be copied to the output for images/product.jpg (has to be wider than 400px).
  4. Note that running the test with client.GetAsync(...) produces unique image sizes, Task.Run(() => client.GetAsync(...)) does not.

System Configuration

  • ImageSharp.Web version: 1.0.5
  • Other Six Labors packages and versions: ImageSharp 1.0.4
  • Environment (Operating system, version and so on): Win10 x64 21H2, 16GB RAM
  • .NET Framework version: .NET 5.0

Log levels for Success and Failures should be tuned

Hi
The current log levels defined here: LoggerExtensions.cs
Are not defined in the best possible way to allow filtering unneeded log messages: Failures and Success all use Information or Debug level.

Can we tune this so that:

  1. Error is logged with Error level.
  2. Failure is logged as Warning level.
  3. the rest is logged at Debug or Trace level depending on the how much they are in the 'hot' path.

We can make a pull request if you agree with the mentioned levels above.

Response body is sometimes empty when processing multiple identical queries

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I'm brand new to the ImageSharp codebase, so apologies if this is user error.

Some requests seem to be getting responses with a 200 status code, but a ContentLength of 0 and an empty body. It seems this is mostly in cases where the same request is hitting the server a few times around the same sort of time.

Steps to Reproduce

I've had a go at modifying one of the existing tests to assert the ContentLength is not 0, and it does fail for me, please see below.

AzureBlobStorageCacheServerTests

        [Theory]
        [InlineData(TestConstants.PhysicalTestImage)]
        [InlineData(TestConstants.AzureTestImage)]
        public async Task CanProcessMultipleIdenticalQueriesAsync(string url)
        {
            Task[] tasks = Enumerable.Range(0, 100).Select(i => Task.Run(async () =>
            {
                var command = i % 2 == 0 ? Command : Command2;
                using HttpResponseMessage response = await this.HttpClient.GetAsync(url + command);
                Assert.NotNull(response);
                Assert.True(response.IsSuccessStatusCode);
                // I have added this additional assertion below. If I modify the enumerable range to (0, 2), the test passes
                // If I leave the enumerable alone and generate a new width in each iteration, the test eventually passes
                // It seems to be only multiple identical requests which have the issue
                Assert.True(response.Content.Headers.ContentLength > 0);
            })).ToArray();

            var all = Task.WhenAll(tasks);
            await all;
            Assert.True(all.IsCompletedSuccessfully);
        }

I have a vague notion that we could be hitting imageContext.SendAsync fewer times than ProcessRequestAsync in the ImageSharpMiddleware, which makes me a little suspicious the issue could lie within some of the static caching in this middleware.

System Configuration

The test above is failing for me in VS2019 16.9.3.

  • ImageSharp.Web version:
    Current master branch, but repro'd in 1.0.2 of SixLabors.ImageSharp.Web and SixLabors.ImageSharp.Web.Providers.Azure in a dev environment to prompt the initial investigation
  • Environment (Operating system, version and so on):
  • Windows 10 Version 10.0.19041 Build 19041
  • .NET Framework version:
  • Modified test is failing on netcoreapp2.1 and 3.1

The UTC time represented when the offset is applied must be between year 0 and 10,000

Description

I configured ImageSharp.Web as described in the (very light) documentation with the very minimal configuration (AddImageSharp and UseImageSharp). I also place a file (a.jpg) in the wwwroot folder of my app. When I access "/a.jpg", the image is displayed correctly, however, when I access "/a.jpg?width=100", I get the following error:

System.ArgumentOutOfRangeException: The UTC time represented when the offset is applied must be between year 0 and 10,000. (Parameter 'offset')
   at System.DateTimeOffset.ValidateDate(DateTime dateTime, TimeSpan offset)
   at System.DateTimeOffset..ctor(DateTime dateTime)
   at System.DateTimeOffset.op_Implicit(DateTime dateTime)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.SendResponseAsync(ImageContext imageContext, String key, ImageCacheMetadata metadata, IImageCacheResolver cacheResolver)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary`2 commands)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)

Steps to Reproduce

Simply configure ImageSharp as described in the documentation.

System Configuration

  • ImageSharp.Web version: 1.0.3
  • Environment (Operating system, version and so on): Windows 10
  • .NET Framework version: .NET 6 - Preview 4

BackgroundColorWebProcessor does not work

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

The BackgroundColorWebProcessor doesn't work. It doesn't matter if you try to set a hex or rgb value, you will still get the same result.

Steps to Reproduce

/imagesharp-logo.png?width=315&bgcolor=red

FIX

instead of Rgba32 converter (that by the way is not registered in the CommandParser) we should use the Color Converter

public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands)
{
	//Rgba32 background = CommandParser.Instance.ParseValue<Rgba32>(commands.GetValueOrDefault(Color)); 
	Color background = CommandParser.Instance.ParseValue<Color>(commands.GetValueOrDefault(Color));
	if (background != default)
	{
		image.Image.Mutate(x => x.BackgroundColor(background));
	}

	return image;
}

System Configuration

  • ImageSharp.Web version: 1.0.0-rc0001
  • Other ImageSharp packages and versions: SixLabors.ImageSharp.Web.Providers.Azure (1.0.0-rc0002)
  • Environment (Operating system, version and so on): Win10 x64 Prof
  • .NET Framework version: netcoreapp 3.1
  • Additional information: VS2019

AzureBlobStorageImageProvider extremely poor performance

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Using the new AzureBlobStorageImageProvider is extremely slow.

Steps to Reproduce

            services.AddImageSharpCore ()
                .SetRequestParser<QueryCollectionRequestParser> ()
                .Configure<PhysicalFileSystemCacheOptions> (options => {
                    options.CacheFolder = "/tmp/pn-cache";
                })
                .SetCache<PhysicalFileSystemCache> ()
                .SetCacheHash<CacheHash> ()
                .AddProvider<AzureBlobStorageImageProvider> (AzureProviderFactory)
                .Configure<AzureBlobStorageImageProviderOptions> (options => {
                    options.ConnectionString = connectionString;
                    options.ContainerName = containerName;
                })
                .AddProcessor<ResizeWebProcessor> ();

where AzureProviderFactory is

private static AzureBlobStorageImageProvider AzureProviderFactory (IServiceProvider provider) {
            var containerName = provider.GetRequiredService<IOptions<ImageFileStorageSettings>> ().Value.ContainerName;

            return new AzureBlobStorageImageProvider (
                provider.GetRequiredService<IOptions<AzureBlobStorageImageProviderOptions>> (),
                provider.GetRequiredService<FormatUtilities> ()) {
                Match = context => {
                    return context.Request.Path.StartsWithSegments ($"/{containerName}");
                }
            };
        }

System Configuration

Ubuntu 19.04 and CoreOS running docker and Kubernetes in Azure Container Service.

  • ImageSharp.Web version: latest
  • Other SixLabors packages and versions:
  • Environment (Operating system, version and so on):
  • .NET Framework version:
  • Additional information:

I believe the issue is that ImageSharpMiddleware calls

IImageResolver sourceImageResolver = await provider.GetAsync(context).ConfigureAwait(false);

before checking the cache and in the case of the AzureBlobStorageImageProvider this causes a CloudBlockBlob to be instantiated and ExistsAsync() to be called. This kills performance especially when many images are being loaded at once.

On the other hand, I might just be doing it all wrong..

AddProvider -> implementationFactory throws exception on Startup

Prerequisites

  • [ y] I have written a descriptive issue title
  • [ y] I have verified that I am running the latest version of ImageSharp.Web
  • [ y] I have verified if the problem exist in both DEBUG and RELEASE mode
  • [ y] I have searched open and closed issues to ensure it has not already been reported

Description

Using the AddProvider() builder extension with an implementation factory throws an exception.

System.ArgumentException
  HResult=0x80070057
  Message=Implementation type cannot be 'SixLabors.ImageSharp.Web.Providers.IImageProvider' because it is indistinguishable from other services registered for 'SixLabors.ImageSharp.Web.Providers.IImageProvider'.
Parameter name: descriptor
  Source=Microsoft.Extensions.DependencyInjection.Abstractions
  StackTrace:
   at Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.TryAddEnumerable(IServiceCollection services, ServiceDescriptor descriptor)
   at SixLabors.ImageSharp.Web.DependencyInjection.ImageSharpCoreBuilderExtensions.AddProvider(IImageSharpCoreBuilder builder, Func`2 implementationFactory) in E:\Sites\ImageSharp.Web\src\ImageSharp.Web\DependencyInjection\ImageSharpCoreBuilderExtensions.cs:line 156
   at SixLabors.ImageSharp.Web.Sample.Startup.ConfigureServices(IServiceCollection services) in E:\Sites\ImageSharp.Web\samples\ImageSharp.Web.Sample\Startup.cs:line 22

Steps to Reproduce

Add the following code to the samples project Startup

                .AddProvider(sp => new PhysicalFileSystemProvider(
                    sp.GetRequiredService<IOptions<ImageSharpMiddlewareOptions>>(),
                    sp.GetRequiredService<IHostingEnvironment>(),
                    sp.GetRequiredService<MemoryAllocator>()))

System Configuration

Clone of ImageSharp.Web

ImageSharp.Web.Caching.AsyncKeyLock.GetDoorman: System.InvalidOperationException

Description

System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.

Steps to Reproduce

   at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
   at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
   at SixLabors.ImageSharp.Web.Caching.AsyncKeyLock.GetDoorman(String key) in ImageSharp.Web\Caching\AsyncKeyLock.cs:line 76
   at SixLabors.ImageSharp.Web.Caching.AsyncKeyLock.ReaderLockAsync(String key) in ImageSharp.Web\Caching\AsyncKeyLock.cs:line 47
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context) in ImageSharp.Web\Middleware\ImageSharpMiddleware.cs:line 187

System Configuration

  • ImageSharp.Web version: master
  • Other SixLabors packages and versions:
    SixLabors.ImageSharp 1.0.0-dev002697
  • Environment (Operating system, version and so on):
    Windows Server 2012 Standard
  • .NET Framework version:
    .Net Core 2.1

could not be resolved

I have some additional static folders set up

            app.UseImageSharp();    // Add the image processing middleware.

            app.UseHttpsRedirection();  // wwwroot
            app.UseStaticFiles(new StaticFileOptions {
                OnPrepareResponse = ctx => {
                    ctx.Context.Response.Headers.Append(
                        "Cache-Control", $"public, max-age={cacheMaxAge}");
                }
            });

            // Public folder
            app.UseStaticFiles(new StaticFileOptions {
                OnPrepareResponse = ctx => {
                    ctx.Context.Response.Headers.Append(
                        "Cache-Control", $"public, max-age={cacheMaxAge}");
                },
                FileProvider = new PhysicalFileProvider(
                Path.Combine(Directory.GetCurrentDirectory(), "Public")),
                RequestPath = "/Public",
            });

The wwwroot folder works fine, but how to support the "Public" folder?

error console:

SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware[2]
      The image 'https://localhost:5001/Public/news/67a8376d-6bcc-4d32-b191-7c728a02df67/source.png?width=200&height=50&rsampler=nearest&rmode=stretch' could not be resolved

Originally posted by @Alerinos in #144

AsyncKeyLock fails intermittently.

I've seen this pop up a few times intermittently during testing. I'm more than a little concerned that this means our AsyncKeyLock does not do what it should which is to prevent cache reads while writing.

I'm gonna need help here investigating. Tests explicitly use a single instance of the server and cache and it always works on my machine.

cc/ @kroymann @sebastienros

A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:11.2043310]     CanProcessAndResolveImage(url: "http://localhost/azure/SubFolder/imagesharp-logo.p"...) [FAIL]
  X CanProcessAndResolveImage(url: "http://localhost/azure/SubFolder/imagesharp-logo.p"...) [577ms]
  Error Message:
   System.IO.IOException : The process cannot access the file 'D:\a\ImageSharp.Web\ImageSharp.Web\artifacts\bin\tests\ImageSharp.Web.Tests\Release\netcoreapp3.1\is-cache\b\2\d\5\5\2\9\b\f\e\c\d\b2d5529bfecd.png' because it is being used by another process.
  Stack Trace:
     at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
   at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
   at System.IO.File.Create(String path)
   at SixLabors.ImageSharp.Web.Caching.PhysicalFileSystemCache.SetAsync(String key, Stream stream, ImageCacheMetadata metadata) in /_/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs:line 128
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary`2 commands) in /_/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs:line 306
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.ProcessRequestAsync(HttpContext context, IImageResolver sourceImageResolver, ImageContext imageContext, IDictionary`2 commands) in /_/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs:line 318
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context) in /_/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs:line 215
   at Microsoft.AspNetCore.TestHost.HttpContextBuilder.<>c__DisplayClass23_0.<<SendAsync>g__RunRequestAsync|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.TestHost.ClientHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at SixLabors.ImageSharp.Web.Tests.Processing.PhysicalFileSystemCacheServerTests.CanProcessAndResolveImage(String url) in D:\a\ImageSharp.Web\ImageSharp.Web\tests\ImageSharp.Web.Tests\Processing\PhysicalFileSystemCacheServerTests.cs:line 70
--- End of stack trace from previous location where exception was thrown ---

Race condition can lead to dead-lock in AsyncKeyLock

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

I was reviewing the latest AsyncKeyLock/Doorman implementation and have found a race condition that could cause a caller to be blocked forever waiting to receive the lock, or could potentially cause a reader and writer to execute concurrently. Here are the problematic flows:

How to get permanently stuck waiting for the lock

  1. Thread A begins releasing a writer lock (with no waiting readers or writers)
  2. Thread B attempts to obtain the lock (and gets stuck waiting to lock the Doorman.waitingWriters queue)
  3. Thread A finishes releasing the writer lock. It leaves the Doorman.status field set to -1, and removes the Doorman from the ConcurrentDictionary as it believes nobody is waiting.
  4. Thread B continues, observes that the Doorman.status field is -1, and then adds itself to a waiting queue that will never be released.

How to cause a reader and writer to execute concurrently on the same key

  1. Thread A begins releasing a reader lock (again with no waiting readers or writers)
  2. Thread B attempts to obtain the writer lock
  3. Thread A finishes releasing the reader lock, and incorrectly removes the lock from the ConcurrentDictionary as it believes nobody is waiting.
  4. Thread B continues and observes that the Doorman status is 0 so it takes the writer lock and proceeds.
  5. Thread C attempts to take reader lock. Since the Doorman in use by thread B is no longer stored in the ConcurrentDictionary, thread C creates creates a new Doorman using the same key. Now Thread B and Thread C are holding two different locks for the same key.

Dicussion

There are two problems here:

  1. The status field is not getting set back to 0 when the final writer releases the lock.
  2. The act of obtaining the Doorman from the dictionary and then adding a reference to that Doorman (thus preventing it from being removed from the dictionary) must be atomic. I've been trying to think of a way to do this using lock-free programming and have not yet come up with a solution. Unfortunately, I think this will require going back to a locking paradigm.

Full .net Framework support?

Prerequisites

Install latest Imagesharp.Web beta 0.3
reg service inside startup.cs with:
services.AddImageSharp();

Description

Nothing happens when trying to call ?height=100 on any images from wwwroot.

Steps to Reproduce

Download startup template for asp.net boilerplate here: https://aspnetboilerplate.com/
Set full .NET framework.
Add own connectionstring
Add nuget package imagesharp.web
Add services registration

System Configuration

.net core 2.1
full framework 4.6.1

Im still new to Core could anyone explain to me what version i should use when using a combination of core and framework.

Thank you for an excellent library i used imageprocessor.web quite alot, woul be very lovely to get this working with abp's new template.

Question: Missing Configuration? Querystrings not applying.

Hi,

I recently discovered this package and from the looks of it, is exactly what i need for a .net core project. I'm testing it out on a fresh .Net Core 2.0 project and have installed via nuget the package and configured the Startup.cs's ConfigurationServices appropriately, by adding the line services.AddImageSharp(); and have even added inside of the Configure(IApplication app, IHotingEnvironment) the line app.UseImageSharpe() Following this i went to test it out by appending a simple crop query string to an image <img src="~/images/banner1.svg?width=100&height=100" alt="ASP.NET" class="img-responsive" /> and nothing seems to be taking any effect, the image remains the same. Is this a matter of further configuration or some issue? any help would be greatly appreciated, thanks!

UnauthorizedAccessException on Web Server

Description

UnauthorizedAccessException when accessing images on web server. Works locally.

UnauthorizedAccessException: Access to the path '~path~\wwwroot\is-cache\2\8\b\3\8\7\f\6\8\b\0\8' is denied.

    System.IO.__Error.WinIOError(int errorCode, string maybeFullPath)
    System.IO.Directory.InternalCreateDirectory(string fullPath, string path, object dirSecurityObj, bool checkHost)
    System.IO.Directory.InternalCreateDirectoryHelper(string path, bool checkHost)
    System.IO.Directory.CreateDirectory(string path)
    SixLabors.ImageSharp.Web.Caching.PhysicalFileSystemCache.SetAsync(string key, Stream stream, ImageMetaData metadata)
    SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Steps to Reproduce

Configuration for startup.cs class.
ConfigureServices method:

services.AddImageSharp();

Configure method:

app.UseImageSharp();
app.UseStaticFiles();

System Configuration

ImageSharp.Web v1.0.0-beta0007
Windows Server 2012 R2
.NET Framework version: 4.7.2
AspNetCore v2.2.0

Incorrect CI Version Numbers.

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

The nightly versions numbers are not generating the expected value. 1.0.0-ci0010 is currently the latest but is lower than 1.0.0-ci0032 published in November.

The ImageSharp repo is working well so we should copy that.

RemoveProvider Builder Extensions don't work

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web (Yes this time!)
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

The ImageSharpCoreBuilderExtensions.RemoveProvider<TProvider> helper extensions don't work.

Steps to Reproduce

Call .RemoveProvider and then check the Service Collection afterwards.

Fix

The ServiceCollection is an ICollection so Remove needs to find the instance that exists of the ServiceDescriptor rather than a new instance created by ServiceDescriptor.Singleton<IImageProvider, TProvider>()

Example (from the ServiceCollectionDescriptorExtensions.Replace method)

            var registeredServiceDescriptor = collection.FirstOrDefault(s => s.ServiceType == descriptor.ServiceType);
            if (registeredServiceDescriptor != null)
            {
                collection.Remove(registeredServiceDescriptor);
            }

Implementation factories are different again, as it doesn't register the TImplementationType when creating a ServiceDescriptor so you need to examine the factory return type

            var registeredServiceDescriptor = services.FirstOrDefault(x => 
                x.ServiceType == typeof(IImageProvider) && 
                x.Lifetime == ServiceLifetime.Singleton &&
                x.ImplementationFactory.Method.ReturnType == typeof(TProvider));
            if (registeredServiceDescriptor != null)
            {
                collection.Remove(registeredServiceDescriptor);
            }

BlobStorageImageProvider won't work anymore without query parameters

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Since merging pull request #73 "Return on no commands", the ImageSharpMiddleware directly hands off request processing to the next middleware in the pipeline when there aren't any commands found.

This prevents any provider fetching images from a remote source (as the Azure Blob Storage Provider does) from running in a "pass-through" scenario without any transforms. Only images present on the filesystem still work, because the StaticFileMiddleware handles those requests.

It would be extremely unfortunate to need a second, separate middleware to handle those requests given that it would need to completely duplicate the functionality of the already present provider.

Steps to Reproduce

  • Default config with AzureBlobStorageImageProvider set as image provider
  • Access image URL without any query parameters

System Configuration

  • ASP.NET Core 3.0 Preview 9
  • SixLabors.ImageSharp.Web 1.0.0-dev000227

Under heavy load the LRUCache can fail to retrieve image metadata

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Under heavy load the LRUCache may return what seems to be an empty ImageCacheMetadata (when I say empty, it is not null, but has no apparent values).

This results in a dictionary error when trying to read the format utilities in PhysicalFileSystemCacheResolver

               string path = Path.ChangeExtension(
                this.metaFileInfo.PhysicalPath,
                this.formatUtilities.GetExtensionFromContentType(this.metadata.ContentType));

Steps to Reproduce

deanmarcussen@dean ImageSharp.Web % ~/Scripts/bombardier -c 100 -d 5s -k "http://localhost:2646/imagesharp-logo.png?width=300"
Bombarding http://localhost:2646/imagesharp-logo.png?width=300 for 5s using 100 connection(s)
[=============================================================================================================================================================================] 5s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec      3314.89    1101.36    5268.09
  Latency       30.18ms    22.94ms   468.19ms
  HTTP codes:
    1xx - 0, 2xx - 16654, 3xx - 0, 4xx - 0, 5xx - 7
    others - 0
  Throughput:    18.61MB/s

On this run 7 500 errors, corresponding to this exception

2021-02-26 08:09:33.2911|1|ERROR|Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware|An unhandled exception has occurred while executing the request. System.ArgumentNullException: Value cannot be null. (Parameter 'key')
   at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at SixLabors.ImageSharp.Web.Resolvers.PhysicalFileSystemCacheResolver.OpenReadAsync() in /Users/deanmarcussen/Projects/ImageSharp.Web/src/ImageSharp.Web/Caching/PhysicalFileSystemCacheResolver.cs:line 44
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.SendResponseAsync(ImageContext imageContext, 

... truncated for brevity.

I can so far trace this back to

                            // Now resolve the cached image metadata storing the result.
                            ImageCacheMetadata cachedImageMetadata = await cachedImageResolver.GetMetaDataAsync();
                            // ImageCacheMetadata cachedImageMetadata = await
                            //     CacheMetadataLru.GetOrAddAsync(
                            //         key,
                            //         _ => cachedImageResolver.GetMetaDataAsync());

where removing the LRU cache resolves the issue (and obviously goes a lot slower!)

Have not had time yet to dig into what's going on with the LRU cache, i.e. where the GetOrAddAsync might be going wrong.

But from initial look, it might be the issue where GetOrAdd is not thread safe, and there's a race going on.

This is why Lazy was used in the other implementation for the Workers though I've since read there might be better alternatives.

Where did the LRU implementation come from?
Any chance it's been updated since?

System Configuration

Current repro is on macos, core3, latest pull from with the sample project, but also reported on gitter w / OrchardCore in production on IIS Windows Server 2016.

Intermittent build failures on Travis.

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Ever since we merged the Lock Free PR #34 we've had intermittent build failures on Travis where tests simply time out. It could be a poorly written test, it could be something more sinister. We should investigate.

/cc @sebastienros

https://travis-ci.org/SixLabors/ImageSharp.Web/builds

Build failure on macOS

Prerequisites

Install ImageSharp.Web-master on a Mac. Start Visual Studio with ImageSharp.Web.sln

Description

Building ImageSharp.Web does not produce a target netstandard2.0 as wanted by
corresponding line 7 in *.csproj:
<TargetFrameworks>netstandard1.4;netstandard2.0</TargetFrameworks>

Only target netstandard1.4 is built.

That leads to an error when building ImageSharp.Web.Sample application. This application refers to netstandard2.0 target.

Changing line 7 in *.csproj:
<TargetFrameworks>netstandard2.0</TargetFrameworks>
solves the problem.

(same problem in ImageSharp.Web.Test.csproj)

System Configuration

  • ImageSharp.Web version: 1.0.0-beta6
  • Other SixLabors packages and versions:
  • Environment (Operating system, version and so on): macOS 10.14.2
  • .NET Core version: 2.1.2
  • Additional information: VS Community for Mac 7.7.3

IImageProviders created as singletons?

Looks like I cannot inject an EF Core context into an IImageProvider as the lifecycles are not compatible:

System.InvalidOperationException: Cannot consume scoped service 'MyWebApp.Data.ApplicationDbContext' from singleton 'SixLabors.ImageSharp.Web.Providers.IImageProvider'.

I was trying to implement a provider and resolver to display images by id/guid and need to access the database to fetch the actual storage location. But seems it is not possible atm, or am I missing something?

PNG decoding from Azure blob stream throws "ImageFormatException: Bad method for ZLIB header: cmf=251"

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

PNG decoding of 3 problematic images (included in the project) directly from an Azure blob stream throws ImageFormatException: Bad method for ZLIB header: cmf=251. This issue is resolved by reading the entire blob stream, copying it to a MemoryStream, and returning the MemoryStream (as seen in CustomAzureBlobStorageImageResolver.cs).

Steps to Reproduce

Download project (ImageSharp.Web.Png.DecodeExceptionRepro.zip), create "img" container in Azure blob storage (by default the project connects to a local Azure storage emulator), upload the 3 images in the Images folder to blob storage, run the project & request the first image with the following URL: http://localhost:5020/img/1.png?width=512. This should result in the exception. Requesting the other 2 images should result in the exception as well.

Now, stop running the project, open Startup.cs, modify ConfigureServices to use CustomAzureBlobStorageImageProvider (which returns a MemoryStream instead of an Azure blob stream) instead of AzureBlobStorageImageProvider. Re-run & re-request the URL. It should work.

The Custom... classes are based on code in master branch of this repo, with slight modifications marked by // CHANGED comments.

The .png files are valid according to pngcheck.

System Configuration

  • ImageSharp.Web version: v1.0.0-beta0009
  • Other ImageSharp packages and versions: SixLabors.ImageSharp.Web.Providers.Azure v1.0.0-beta0009
  • Environment (Operating system, version and so on): Windows 10 Home 64-bit (10.0, Build 18362)
  • .NET Framework version: .NET Core 3.1
  • Additional information: Microsoft Visual Studio Professional 2019 - Version 16.4.0

High level ideals for image server/middleware

This is a discussion post around features that I'd like to see long term in a Mvc Core image server/middleware.

Currently, this project is built around a URL based API which has limitations and doesn't cover the gamut of what we need to serve the best image for a given situation:

We need different image formats based on the client Accept header:

  • WebP - Chrome / Opera
  • JpegXR - Edge
  • Jpeg2000/JP2 - Safari
  • Everything else

(Note that Safari does not announce support for Jpeg2000, but it is apparently supported)

We need different sizes based on the device pixel ration (DPR), Viewport-Width and intended display Width. These are announced with Client Hints on supported browsers:

We need to set cache headers appropriately when varying by all of these things.

We also want to simplify the amount of work we need to do to handle images in markup with Tag Helpers.

We may want to add an Accepts-CH header to the response to indicate that we honour Client Hints automatically via TagHelperComponents.

We'd like to automatically handle srcset attribute generation on img tags.

We'd like to automatically generate markup for picture elements to simplify the markup generated.

Longer term, further API's are being discussed such as Network Information - this info could allow us to serve 1x images to higher DPI displays if their connection (downlink) appears to be poor or their EffectiveConnectionType is 2g (for example).

And we also need to handle the source imagery probably not being ideal either (i.e, all the existing options for cropping a certain way, etc.)

I'm just kicking the tin can around at the moment with some ideas in my head. Maybe this is a SixLabors.Web thing - maybe it's something completely different. I just wanted to open up a discussion at this stage.

All the best! ❤️

Cache image reponses are not disposed

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Web
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

There is a couple of reported memory related issues, and while I know there is some tracking in ImageSharp itself about releasing retained resources, there looks to be another issue here (easily resolved) regarding stream usage.

Reported here on Orchard Core OrchardCMS/OrchardCore#9060
and likely related to this discussion #161

Performance testing locally this causes memory usage to grow dramatically - got as high as 15Gb before I stopped it.

Collecting manually doesn't drop it, so I suspect that's why there's reported app service failures.

Steps to Reproduce

This line doesn't dispose of the cache file streams

await imageContext.SendAsync(stream ?? await cacheResolver.OpenReadAsync(), metadata);

adding a dispose

                    using (var stream = await cacheResolver.OpenReadAsync())
                    {
                        await imageContext.SendAsync(stream, metadata);
                    }

and everything gets collected when the GC runs, and memory usage is as one would expect.

I've seen some (difficult to reproduce) issues with file locks on the cache images, but I am hoping this might explain those as well.

Off for the covid jab in a minute, so pr to come

System Configuration

Just locally.

Can not add ImageSharp service to StartUp.cs in VS 2017

Prerequisites

In was able to successfully install ImageSharp.Web in VS 2017 with the command:
install-package SixLabors.ImageSharp.Web -version 1.0.0-beta0005 However, when I tried to add the line:
services.AddImageSharp(); to StartUp.cs, VS 2017 did not recognize the name space - I got an intellisense error and was unable to proceed. This seems to be the same as the problems reported in issue #190 except for the fact that I am using the package manager command line to install.

Steps to Reproduce

I tried this in both an existing project and a brand-new one.

System Configuration

Windows 10 VS2017 vanilla - latest version

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.