Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 38 additions & 47 deletions src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,9 @@ private async Task Invoke(HttpContext httpContext, bool retry)
}

await this.ProcessRequestAsync(
httpContext,
imageCommandContext,
sourceImageResolver,
new ImageContext(httpContext, this.options),
commands,
retry);
}

Expand All @@ -278,12 +277,14 @@ private static void SetBadRequest(HttpContext httpContext)
}

private async Task ProcessRequestAsync(
HttpContext httpContext,
ImageCommandContext imageCommandContext,
IImageResolver sourceImageResolver,
ImageContext imageContext,
CommandCollection commands,
bool retry)
{
HttpContext httpContext = imageCommandContext.Context;
CommandCollection commands = imageCommandContext.Commands;

// Create a hashed cache key
string key = this.cacheHash.Create(
this.cacheKey.Create(httpContext, commands),
Expand Down Expand Up @@ -344,55 +345,45 @@ private async Task ProcessRequestAsync(
{
DecoderOptions decoderOptions = new() { Configuration = this.options.Configuration };

// TODO: We need some way to set options based upon processors.
await this.options.OnBeforeLoadAsync.Invoke(httpContext, decoderOptions);
// TODO: Do we need some way to set options based upon processors?
await this.options.OnBeforeLoadAsync.Invoke(imageCommandContext, decoderOptions);

// No commands? We simply copy the stream across.
if (commands.Count == 0)
FormattedImage? image = null;
try
{
await inStream.CopyToAsync(outStream);
outStream.Position = 0;
format = await Image.DetectFormatAsync(decoderOptions, outStream);
}
else
{
FormattedImage? image = null;
try
// Now we can finally process the image.
// We first sort the processor collection by command order then use that collection to determine whether the decoded image pixel format
// explicitly requires an alpha component in order to allow correct processing.
//
// The non-generic variant will decode to the correct pixel format based upon the encoded image metadata which can yield
// massive memory savings.
IReadOnlyList<(int Index, IImageWebProcessor Processor)> sortedProcessors = this.processors.OrderBySupportedCommands(commands);
bool requiresAlpha = sortedProcessors.RequiresTrueColorPixelFormat(commands, this.commandParser, this.parserCulture);

if (requiresAlpha)
{
// Now we can finally process the image.
// We first sort the processor collection by command order then use that collection to determine whether the decoded image pixel format
// explicitly requires an alpha component in order to allow correct processing.
//
// The non-generic variant will decode to the correct pixel format based upon the encoded image metadata which can yield
// massive memory savings.
IReadOnlyList<(int Index, IImageWebProcessor Processor)> sortedProcessors = this.processors.OrderBySupportedCommands(commands);
bool requiresAlpha = sortedProcessors.RequiresTrueColorPixelFormat(commands, this.commandParser, this.parserCulture);

if (requiresAlpha)
{
image = await FormattedImage.LoadAsync<Rgba32>(decoderOptions, inStream);
}
else
{
image = await FormattedImage.LoadAsync(decoderOptions, inStream);
}

image.Process(
this.logger,
sortedProcessors,
commands,
this.commandParser,
this.parserCulture);

await this.options.OnBeforeSaveAsync.Invoke(image);

image.Save(outStream);
format = image.Format;
image = await FormattedImage.LoadAsync<Rgba32>(decoderOptions, inStream);
}
finally
else
{
image?.Dispose();
image = await FormattedImage.LoadAsync(decoderOptions, inStream);
}

image.Process(
this.logger,
sortedProcessors,
commands,
this.commandParser,
this.parserCulture);

await this.options.OnBeforeSaveAsync.Invoke(image);

image.Save(outStream);
format = image.Format;
}
finally
{
image?.Dispose();
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class ImageSharpMiddlewareOptions
};

private Func<ImageCommandContext, Task> onParseCommandsAsync = _ => Task.CompletedTask;
private Func<HttpContext, DecoderOptions, Task> onBeforeLoadAsync = (_, _) => Task.CompletedTask;
private Func<ImageCommandContext, DecoderOptions, Task> onBeforeLoadAsync = (_, _) => Task.CompletedTask;
private Func<FormattedImage, Task> onBeforeSaveAsync = _ => Task.CompletedTask;
private Func<ImageProcessingContext, Task> onProcessedAsync = _ => Task.CompletedTask;
private Func<HttpContext, Task> onPrepareResponseAsync = _ => Task.CompletedTask;
Expand Down Expand Up @@ -118,7 +118,7 @@ public Func<ImageCommandContext, Task> OnParseCommandsAsync
/// Gets or sets the method that can be used to used to augment decoder options.
/// This is called before the image is decoded and loaded for processing.
/// </summary>
public Func<HttpContext, DecoderOptions, Task> OnBeforeLoadAsync
public Func<ImageCommandContext, DecoderOptions, Task> OnBeforeLoadAsync
{
get => this.onBeforeLoadAsync;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected void ConfigureServices(IServiceCollection services)
return onParseCommandsAsync.Invoke(context);
};

Func<HttpContext, DecoderOptions, Task> onBeforeLoadAsync = options.OnBeforeLoadAsync;
Func<ImageCommandContext, DecoderOptions, Task> onBeforeLoadAsync = options.OnBeforeLoadAsync;

options.OnBeforeLoadAsync = (context, decoderOptions) =>
{
Expand Down