Skip to content

Commit a1b8421

Browse files
Update to ImageSharp v3 builds
1 parent d91883f commit a1b8421

13 files changed

+96
-114
lines changed

Diff for: .gitattributes

+3-2
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,19 @@
6464
# Set explicit file behavior to:
6565
# treat as text
6666
# normalize to Unix-style line endings and
67-
# use a union merge when resoling conflicts
67+
# use a union merge when resolving conflicts
6868
###############################################################################
6969
*.csproj text eol=lf merge=union
7070
*.dbproj text eol=lf merge=union
7171
*.fsproj text eol=lf merge=union
7272
*.ncrunchproject text eol=lf merge=union
7373
*.vbproj text eol=lf merge=union
74+
*.shproj text eol=lf merge=union
7475
###############################################################################
7576
# Set explicit file behavior to:
7677
# treat as text
7778
# normalize to Windows-style line endings and
78-
# use a union merge when resoling conflicts
79+
# use a union merge when resolving conflicts
7980
###############################################################################
8081
*.sln text eol=crlf merge=union
8182
###############################################################################

Diff for: samples/ImageSharp.Web.Sample/Startup.cs

+39-53
Original file line numberDiff line numberDiff line change
@@ -30,52 +30,46 @@ public class Startup
3030
/// </summary>
3131
/// <param name="services">The collection of service descriptors.</param>
3232
public void ConfigureServices(IServiceCollection services)
33-
{
34-
services.AddImageSharp()
35-
.SetRequestParser<QueryCollectionRequestParser>()
36-
.Configure<PhysicalFileSystemCacheOptions>(options =>
37-
{
38-
options.CacheRootPath = null;
39-
options.CacheFolder = "is-cache";
40-
options.CacheFolderDepth = 8;
41-
})
42-
.SetCache<PhysicalFileSystemCache>()
43-
.SetCacheKey<UriRelativeLowerInvariantCacheKey>()
44-
.SetCacheHash<SHA256CacheHash>()
45-
.Configure<PhysicalFileSystemProviderOptions>(options =>
46-
{
47-
options.ProviderRootPath = null;
48-
})
49-
.AddProvider<PhysicalFileSystemProvider>()
50-
.AddProcessor<ResizeWebProcessor>()
51-
.AddProcessor<FormatWebProcessor>()
52-
.AddProcessor<BackgroundColorWebProcessor>()
53-
.AddProcessor<QualityWebProcessor>()
54-
.AddProcessor<AutoOrientWebProcessor>();
33+
=> services.AddImageSharp()
34+
.SetRequestParser<QueryCollectionRequestParser>()
35+
.Configure<PhysicalFileSystemCacheOptions>(options =>
36+
{
37+
options.CacheRootPath = null;
38+
options.CacheFolder = "is-cache";
39+
options.CacheFolderDepth = 8;
40+
})
41+
.SetCache<PhysicalFileSystemCache>()
42+
.SetCacheKey<UriRelativeLowerInvariantCacheKey>()
43+
.SetCacheHash<SHA256CacheHash>()
44+
.Configure<PhysicalFileSystemProviderOptions>(options => options.ProviderRootPath = null)
45+
.AddProvider<PhysicalFileSystemProvider>()
46+
.AddProcessor<ResizeWebProcessor>()
47+
.AddProcessor<FormatWebProcessor>()
48+
.AddProcessor<BackgroundColorWebProcessor>()
49+
.AddProcessor<QualityWebProcessor>()
50+
.AddProcessor<AutoOrientWebProcessor>();
5551

56-
// Add the default service and options.
57-
//
58-
// services.AddImageSharp();
52+
// Add the default service and options.
53+
//
54+
// services.AddImageSharp();
5955

60-
// Or add the default service and custom options.
61-
//
62-
// this.ConfigureDefaultServicesAndCustomOptions(services);
56+
// Or add the default service and custom options.
57+
//
58+
// this.ConfigureDefaultServicesAndCustomOptions(services);
6359

64-
// Or we can fine-grain control adding the default options and configure all other services.
65-
//
66-
// this.ConfigureCustomServicesAndDefaultOptions(services);
60+
// Or we can fine-grain control adding the default options and configure all other services.
61+
//
62+
// this.ConfigureCustomServicesAndDefaultOptions(services);
6763

68-
// Or we can fine-grain control adding custom options and configure all other services
69-
// There are also factory methods for each builder that will allow building from configuration files.
70-
//
71-
// this.ConfigureCustomServicesAndCustomOptions(services);
72-
}
64+
// Or we can fine-grain control adding custom options and configure all other services
65+
// There are also factory methods for each builder that will allow building from configuration files.
66+
//
67+
// this.ConfigureCustomServicesAndCustomOptions(services);
7368

7469
private void ConfigureDefaultServicesAndCustomOptions(IServiceCollection services)
75-
{
76-
services.AddImageSharp(options =>
70+
=> services.AddImageSharp(options =>
7771
{
78-
options.Configuration = Configuration.Default;
72+
options.DecoderOptions = new();
7973
options.BrowserMaxAge = TimeSpan.FromDays(7);
8074
options.CacheMaxAge = TimeSpan.FromDays(365);
8175
options.CacheHashLength = 8;
@@ -84,20 +78,16 @@ private void ConfigureDefaultServicesAndCustomOptions(IServiceCollection service
8478
options.OnProcessedAsync = _ => Task.CompletedTask;
8579
options.OnPrepareResponseAsync = _ => Task.CompletedTask;
8680
});
87-
}
8881

8982
private void ConfigureCustomServicesAndDefaultOptions(IServiceCollection services)
90-
{
91-
services.AddImageSharp()
92-
.RemoveProcessor<FormatWebProcessor>()
93-
.RemoveProcessor<BackgroundColorWebProcessor>();
94-
}
83+
=> services.AddImageSharp()
84+
.RemoveProcessor<FormatWebProcessor>()
85+
.RemoveProcessor<BackgroundColorWebProcessor>();
9586

9687
private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services)
97-
{
98-
services.AddImageSharp(options =>
88+
=> services.AddImageSharp(options =>
9989
{
100-
options.Configuration = Configuration.Default;
90+
options.DecoderOptions = new();
10191
options.BrowserMaxAge = TimeSpan.FromDays(7);
10292
options.CacheMaxAge = TimeSpan.FromDays(365);
10393
options.CacheHashLength = 8;
@@ -107,10 +97,7 @@ private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services
10797
options.OnPrepareResponseAsync = _ => Task.CompletedTask;
10898
})
10999
.SetRequestParser<QueryCollectionRequestParser>()
110-
.Configure<PhysicalFileSystemCacheOptions>(options =>
111-
{
112-
options.CacheFolder = "different-cache";
113-
})
100+
.Configure<PhysicalFileSystemCacheOptions>(options => options.CacheFolder = "different-cache")
114101
.SetCache<PhysicalFileSystemCache>()
115102
.SetCacheKey<UriRelativeLowerInvariantCacheKey>()
116103
.SetCacheHash<SHA256CacheHash>()
@@ -121,7 +108,6 @@ private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services
121108
.AddProcessor<FormatWebProcessor>()
122109
.AddProcessor<BackgroundColorWebProcessor>()
123110
.AddProcessor<QualityWebProcessor>();
124-
}
125111

126112
/// <summary>
127113
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

Diff for: shared-infrastructure

Diff for: src/ImageSharp.Web/FormatUtilities.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public FormatUtilities(IOptions<ImageSharpMiddlewareOptions> options)
2828
{
2929
Guard.NotNull(options, nameof(options));
3030

31-
foreach (IImageFormat imageFormat in options.Value.Configuration.ImageFormats)
31+
foreach (IImageFormat imageFormat in options.Value.DecoderOptions.Configuration.ImageFormats)
3232
{
3333
string[] extensions = imageFormat.FileExtensions.ToArray();
3434

@@ -60,7 +60,7 @@ public bool TryGetExtensionFromUri(string uri, out string extension)
6060
if (query > -1)
6161
{
6262
if (uri.Contains(FormatWebProcessor.Format, StringComparison.OrdinalIgnoreCase)
63-
&& QueryHelpers.ParseQuery(uri.Substring(query)).TryGetValue(FormatWebProcessor.Format, out StringValues ext))
63+
&& QueryHelpers.ParseQuery(uri[query..]).TryGetValue(FormatWebProcessor.Format, out StringValues ext))
6464
{
6565
// We have a query but is it a valid one?
6666
ReadOnlySpan<char> extSpan = ext[0].AsSpan();
@@ -86,7 +86,7 @@ public bool TryGetExtensionFromUri(string uri, out string extension)
8686
int extensionIndex;
8787
if ((extensionIndex = path.LastIndexOf('.')) != -1)
8888
{
89-
ReadOnlySpan<char> pathExtension = path.Slice(extensionIndex + 1);
89+
ReadOnlySpan<char> pathExtension = path[(extensionIndex + 1)..];
9090

9191
foreach (string e in this.extensions)
9292
{

Diff for: src/ImageSharp.Web/FormattedImage.cs

+14-13
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using SixLabors.ImageSharp.Advanced;
77
using SixLabors.ImageSharp.Formats;
88
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
9-
using SixLabors.ImageSharp.PixelFormats;
109

1110
namespace SixLabors.ImageSharp.Web;
1211

@@ -64,7 +63,7 @@ public IImageFormat Format
6463
}
6564

6665
this.format = value;
67-
this.encoder = this.imageFormatsManager.FindEncoder(value);
66+
this.encoder = this.imageFormatsManager.GetEncoder(value);
6867
}
6968
}
7069

@@ -82,7 +81,7 @@ public IImageEncoder Encoder
8281
}
8382

8483
// The given type should match the format encoder.
85-
IImageEncoder reference = this.imageFormatsManager.FindEncoder(this.Format);
84+
IImageEncoder reference = this.imageFormatsManager.GetEncoder(this.Format);
8685
if (reference.GetType() != value.GetType())
8786
{
8887
ThrowInvalid(nameof(value));
@@ -96,26 +95,29 @@ public IImageEncoder Encoder
9695
/// Create a new instance of the <see cref="FormattedImage"/> class from the given stream.
9796
/// </summary>
9897
/// <typeparam name="TPixel">The pixel format.</typeparam>
99-
/// <param name="configuration">The configuration.</param>
98+
/// <param name="options">The general decoder options.</param>
10099
/// <param name="source">The source.</param>
101100
/// <returns>A <see cref="Task{FormattedImage}"/> representing the asynchronous operation.</returns>
102-
internal static async Task<FormattedImage> LoadAsync<TPixel>(Configuration configuration, Stream source)
101+
internal static async Task<FormattedImage> LoadAsync<TPixel>(DecoderOptions options, Stream source)
103102
where TPixel : unmanaged, IPixel<TPixel>
104103
{
105-
(Image<TPixel> image, IImageFormat format) = await Image.LoadWithFormatAsync<TPixel>(configuration, source);
106-
return new FormattedImage(image, format, false);
104+
// TODO: We want to be able to apply decoder options per request.
105+
// For example. If a resize command has been passed with no extra resampling options
106+
// then we should apply those changes on decode. This will allow memory savings and performance improvements.
107+
Image<TPixel> image = await Image.LoadAsync<TPixel>(options, source);
108+
return new FormattedImage(image, image.Metadata.DecodedImageFormat, false);
107109
}
108110

109111
/// <summary>
110112
/// Create a new instance of the <see cref="FormattedImage"/> class from the given stream.
111113
/// </summary>
112-
/// <param name="configuration">The configuration.</param>
114+
/// <param name="options">The general decoder options.</param>
113115
/// <param name="source">The source.</param>
114116
/// <returns>A <see cref="Task{FormattedImage}"/> representing the asynchronous operation.</returns>
115-
internal static async Task<FormattedImage> LoadAsync(Configuration configuration, Stream source)
117+
internal static async Task<FormattedImage> LoadAsync(DecoderOptions options, Stream source)
116118
{
117-
(Image image, IImageFormat format) = await Image.LoadWithFormatAsync(configuration, source);
118-
return new FormattedImage(image, format, false);
119+
Image image = await Image.LoadAsync(options, source);
120+
return new FormattedImage(image, image.Metadata.DecodedImageFormat, false);
119121
}
120122

121123
/// <summary>
@@ -141,8 +143,7 @@ public bool TryGetExifOrientation(out ushort value)
141143
value = ExifOrientationMode.Unknown;
142144
if (this.Image.Metadata.ExifProfile != null)
143145
{
144-
IExifValue<ushort> orientation = this.Image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
145-
if (orientation is null)
146+
if (!this.Image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out IExifValue<ushort> orientation))
146147
{
147148
return false;
148149
}

Diff for: src/ImageSharp.Web/ImageSharp.Web.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<ItemGroup>
4646
<FrameworkReference Include="Microsoft.AspNetCore.App" />
4747
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.2.0" />
48-
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
48+
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.0-alpha.0.95" />
4949
</ItemGroup>
5050

5151
<Import Project="..\..\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems" Label="Shared" />

Diff for: src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Microsoft.Extensions.Options;
1111
using Microsoft.IO;
1212
using SixLabors.ImageSharp.Formats;
13-
using SixLabors.ImageSharp.PixelFormats;
1413
using SixLabors.ImageSharp.Web.Caching;
1514
using SixLabors.ImageSharp.Web.Commands;
1615
using SixLabors.ImageSharp.Web.Processors;
@@ -352,7 +351,7 @@ private async Task ProcessRequestAsync(
352351
{
353352
await inStream.CopyToAsync(outStream);
354353
outStream.Position = 0;
355-
format = await Image.DetectFormatAsync(this.options.Configuration, outStream);
354+
format = await Image.DetectFormatAsync(this.options.DecoderOptions, outStream);
356355
}
357356
else
358357
{
@@ -370,11 +369,11 @@ private async Task ProcessRequestAsync(
370369

371370
if (requiresAlpha)
372371
{
373-
image = await FormattedImage.LoadAsync<Rgba32>(this.options.Configuration, inStream);
372+
image = await FormattedImage.LoadAsync<Rgba32>(this.options.DecoderOptions, inStream);
374373
}
375374
else
376375
{
377-
image = await FormattedImage.LoadAsync(this.options.Configuration, inStream);
376+
image = await FormattedImage.LoadAsync(this.options.DecoderOptions, inStream);
378377
}
379378

380379
image.Process(

Diff for: src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Globalization;
66
using Microsoft.AspNetCore.Http;
77
using Microsoft.IO;
8+
using SixLabors.ImageSharp.Formats;
89
using SixLabors.ImageSharp.Web.Commands;
910
using SixLabors.ImageSharp.Web.Providers;
1011

@@ -32,9 +33,9 @@ public class ImageSharpMiddlewareOptions
3233
private Func<HttpContext, Task> onPrepareResponseAsync = _ => Task.CompletedTask;
3334

3435
/// <summary>
35-
/// Gets or sets the base library configuration.
36+
/// Gets or sets the default decoder options.
3637
/// </summary>
37-
public Configuration Configuration { get; set; } = Configuration.Default;
38+
public DecoderOptions DecoderOptions { get; set; } = new();
3839

3940
/// <summary>
4041
/// Gets or sets the recyclable memorystream manager used for managing pooled stream

Diff for: src/ImageSharp.Web/Processors/FormatWebProcessor.cs

+3-7
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,10 @@ public FormattedImage Process(
5252
{
5353
string extension = commands.GetValueOrDefault(Format);
5454

55-
if (!string.IsNullOrWhiteSpace(extension))
55+
if (!string.IsNullOrWhiteSpace(extension)
56+
&& this.options.DecoderOptions.Configuration.ImageFormatsManager.TryFindFormatByFileExtension(extension, out IImageFormat format))
5657
{
57-
IImageFormat format = this.options.Configuration.ImageFormatsManager.FindFormatByFileExtension(extension);
58-
59-
if (format != null)
60-
{
61-
image.Format = format;
62-
}
58+
image.Format = format;
6359
}
6460

6561
return image;

Diff for: src/ImageSharp.Web/Processors/QualityWebProcessor.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ public FormattedImage Process(
4545

4646
if (image.Format is JpegFormat)
4747
{
48-
var reference =
48+
JpegEncoder reference =
4949
(JpegEncoder)image.Image
5050
.GetConfiguration()
5151
.ImageFormatsManager
52-
.FindEncoder(image.Format);
52+
.GetEncoder(image.Format);
5353

5454
if (quality != reference.Quality)
5555
{
@@ -58,11 +58,11 @@ public FormattedImage Process(
5858
}
5959
else if (image.Format is WebpFormat)
6060
{
61-
var reference =
61+
WebpEncoder reference =
6262
(WebpEncoder)image.Image
6363
.GetConfiguration()
6464
.ImageFormatsManager
65-
.FindEncoder(image.Format);
65+
.GetEncoder(image.Format);
6666

6767
image.Encoder = new WebpEncoder()
6868
{

Diff for: tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ public void AutoOrientWebProcessor_UpdatesOrientation()
2626

2727
const ushort tl = 1;
2828
const ushort br = 3;
29-
using var image = new Image<Rgba32>(1, 1);
29+
using Image<Rgba32> image = new(1, 1);
3030
image.Metadata.ExifProfile = new();
3131
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, br);
3232

33-
IExifValue<ushort> orientation = image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
33+
Assert.True(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out IExifValue<ushort> orientation));
3434
Assert.Equal(br, orientation.Value);
3535

36-
using var formatted = new FormattedImage(image, PngFormat.Instance);
36+
using FormattedImage formatted = new(image, PngFormat.Instance);
3737
new AutoOrientWebProcessor().Process(formatted, null, commands, parser, culture);
3838

39-
orientation = image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
39+
Assert.True(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out orientation));
4040
Assert.Equal(tl, orientation.Value);
4141
}
4242
}

0 commit comments

Comments
 (0)