diff --git a/.gitattributes b/.gitattributes
index 2fdea90e..ff4ec940 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -64,18 +64,19 @@
# Set explicit file behavior to:
# treat as text
# normalize to Unix-style line endings and
-# use a union merge when resoling conflicts
+# use a union merge when resolving conflicts
###############################################################################
*.csproj text eol=lf merge=union
*.dbproj text eol=lf merge=union
*.fsproj text eol=lf merge=union
*.ncrunchproject text eol=lf merge=union
*.vbproj text eol=lf merge=union
+*.shproj text eol=lf merge=union
###############################################################################
# Set explicit file behavior to:
# treat as text
# normalize to Windows-style line endings and
-# use a union merge when resoling conflicts
+# use a union merge when resolving conflicts
###############################################################################
*.sln text eol=crlf merge=union
###############################################################################
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 97aafb97..78220623 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -189,9 +189,15 @@ jobs:
shell: pwsh
run: ./ci-pack.ps1
- - name: MyGet Publish
+ - name: Feedz Publish
shell: pwsh
run: |
- dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v2/package
- dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v3/index.json
- # TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org
+ dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.FEEDZ_TOKEN}} -s https://f.feedz.io/sixlabors/sixlabors/nuget/index.json --skip-duplicate
+ dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.FEEDZ_TOKEN}} -s https://f.feedz.io/sixlabors/sixlabors/symbols --skip-duplicate
+
+ - name: NuGet Publish
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ shell: pwsh
+ run: |
+ dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json --skip-duplicate
+ dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json --skip-duplicate
diff --git a/README.md b/README.md
index 0ded0990..189b9788 100644
--- a/README.md
+++ b/README.md
@@ -45,11 +45,11 @@ For more information, see the [.NET Foundation Code of Conduct](https://dotnetfo
### Installation
-Install stable releases via Nuget; development releases are available via MyGet.
+Install stable releases via Nuget; development releases are available via Feedz.io.
-| Package Name | Release (NuGet) | Nightly (MyGet) |
+| Package Name | Release (NuGet) | Nightly (Feedz.io) |
|--------------------------------|-----------------|-----------------|
-| `SixLabors.ImageSharp.Web` | [](https://www.nuget.org/packages/SixLabors.ImageSharp.Web/) | [](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp.Web) |
+| `SixLabors.ImageSharp.Web` | [](https://www.nuget.org/packages/SixLabors.ImageSharp.Web/) | [](https://f.feedz.io/sixlabors/sixlabors/nuget/index.json) |
## Manual build
diff --git a/ci-pack.ps1 b/ci-pack.ps1
index 09f45347..55c69fb5 100644
--- a/ci-pack.ps1
+++ b/ci-pack.ps1
@@ -3,4 +3,4 @@ dotnet clean -c Release
$repositoryUrl = "https://github.com/$env:GITHUB_REPOSITORY"
# Building for packing and publishing.
-dotnet pack -c Release --output "$PSScriptRoot/artifacts" /p:RepositoryUrl=$repositoryUrl
+dotnet pack -c Release -p:PackageOutputPath="$PSScriptRoot/artifacts" -p:RepositoryUrl=$repositoryUrl
diff --git a/samples/ImageSharp.Web.Sample/Startup.cs b/samples/ImageSharp.Web.Sample/Startup.cs
index eaf01e31..a01e8c07 100644
--- a/samples/ImageSharp.Web.Sample/Startup.cs
+++ b/samples/ImageSharp.Web.Sample/Startup.cs
@@ -30,50 +30,44 @@ public class Startup
///
/// The collection of service descriptors.
public void ConfigureServices(IServiceCollection services)
- {
- services.AddImageSharp()
- .SetRequestParser()
- .Configure(options =>
- {
- options.CacheRootPath = null;
- options.CacheFolder = "is-cache";
- options.CacheFolderDepth = 8;
- })
- .SetCache()
- .SetCacheKey()
- .SetCacheHash()
- .Configure(options =>
- {
- options.ProviderRootPath = null;
- })
- .AddProvider()
- .AddProcessor()
- .AddProcessor()
- .AddProcessor()
- .AddProcessor()
- .AddProcessor();
+ => services.AddImageSharp()
+ .SetRequestParser()
+ .Configure(options =>
+ {
+ options.CacheRootPath = null;
+ options.CacheFolder = "is-cache";
+ options.CacheFolderDepth = 8;
+ })
+ .SetCache()
+ .SetCacheKey()
+ .SetCacheHash()
+ .Configure(options => options.ProviderRootPath = null)
+ .AddProvider()
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor();
- // Add the default service and options.
- //
- // services.AddImageSharp();
+ // Add the default service and options.
+ //
+ // services.AddImageSharp();
- // Or add the default service and custom options.
- //
- // this.ConfigureDefaultServicesAndCustomOptions(services);
+ // Or add the default service and custom options.
+ //
+ // this.ConfigureDefaultServicesAndCustomOptions(services);
- // Or we can fine-grain control adding the default options and configure all other services.
- //
- // this.ConfigureCustomServicesAndDefaultOptions(services);
+ // Or we can fine-grain control adding the default options and configure all other services.
+ //
+ // this.ConfigureCustomServicesAndDefaultOptions(services);
- // Or we can fine-grain control adding custom options and configure all other services
- // There are also factory methods for each builder that will allow building from configuration files.
- //
- // this.ConfigureCustomServicesAndCustomOptions(services);
- }
+ // Or we can fine-grain control adding custom options and configure all other services
+ // There are also factory methods for each builder that will allow building from configuration files.
+ //
+ // this.ConfigureCustomServicesAndCustomOptions(services);
private void ConfigureDefaultServicesAndCustomOptions(IServiceCollection services)
- {
- services.AddImageSharp(options =>
+ => services.AddImageSharp(options =>
{
options.Configuration = Configuration.Default;
options.BrowserMaxAge = TimeSpan.FromDays(7);
@@ -84,18 +78,14 @@ private void ConfigureDefaultServicesAndCustomOptions(IServiceCollection service
options.OnProcessedAsync = _ => Task.CompletedTask;
options.OnPrepareResponseAsync = _ => Task.CompletedTask;
});
- }
private void ConfigureCustomServicesAndDefaultOptions(IServiceCollection services)
- {
- services.AddImageSharp()
- .RemoveProcessor()
- .RemoveProcessor();
- }
+ => services.AddImageSharp()
+ .RemoveProcessor()
+ .RemoveProcessor();
private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services)
- {
- services.AddImageSharp(options =>
+ => services.AddImageSharp(options =>
{
options.Configuration = Configuration.Default;
options.BrowserMaxAge = TimeSpan.FromDays(7);
@@ -107,10 +97,7 @@ private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services
options.OnPrepareResponseAsync = _ => Task.CompletedTask;
})
.SetRequestParser()
- .Configure(options =>
- {
- options.CacheFolder = "different-cache";
- })
+ .Configure(options => options.CacheFolder = "different-cache")
.SetCache()
.SetCacheKey()
.SetCacheHash()
@@ -121,7 +108,6 @@ private void ConfigureCustomServicesAndCustomOptions(IServiceCollection services
.AddProcessor()
.AddProcessor()
.AddProcessor();
- }
///
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
diff --git a/shared-infrastructure b/shared-infrastructure
index 6c52486c..9a6cf00d 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 6c52486c512357475cbb92bbb7c4c0af4d85b1db
+Subproject commit 9a6cf00d9a3d482bb08211dd8309f4724a2735cb
diff --git a/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs b/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs
index 772cc42d..e311ae86 100644
--- a/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs
+++ b/src/ImageSharp.Web.Providers.AWS/AmazonS3ClientFactory.cs
@@ -18,6 +18,7 @@ internal static class AmazonS3ClientFactory
///
/// A new .
///
+ /// Invalid configuration.
public static AmazonS3Client CreateClient(IAWSS3BucketClientOptions options)
{
if (!string.IsNullOrWhiteSpace(options.Endpoint))
@@ -33,14 +34,14 @@ public static AmazonS3Client CreateClient(IAWSS3BucketClientOptions options)
{
// AccessSecret can be empty.
Guard.NotNullOrWhiteSpace(options.Region, nameof(options.Region));
- var region = RegionEndpoint.GetBySystemName(options.Region);
+ RegionEndpoint region = RegionEndpoint.GetBySystemName(options.Region);
AmazonS3Config config = new() { RegionEndpoint = region, UseAccelerateEndpoint = options.UseAccelerateEndpoint };
SetTimeout(config, options.Timeout);
return new AmazonS3Client(options.AccessKey, options.AccessSecret, config);
}
else if (!string.IsNullOrWhiteSpace(options.Region))
{
- var region = RegionEndpoint.GetBySystemName(options.Region);
+ RegionEndpoint region = RegionEndpoint.GetBySystemName(options.Region);
AmazonS3Config config = new() { RegionEndpoint = region, UseAccelerateEndpoint = options.UseAccelerateEndpoint };
SetTimeout(config, options.Timeout);
return new AmazonS3Client(config);
diff --git a/src/ImageSharp.Web/AsyncHelper.cs b/src/ImageSharp.Web/AsyncHelper.cs
index 8bc52d93..3ba68fcb 100644
--- a/src/ImageSharp.Web/AsyncHelper.cs
+++ b/src/ImageSharp.Web/AsyncHelper.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
diff --git a/src/ImageSharp.Web/Caching/HexEncoder.cs b/src/ImageSharp.Web/Caching/HexEncoder.cs
index 7687cc3f..acf72787 100644
--- a/src/ImageSharp.Web/Caching/HexEncoder.cs
+++ b/src/ImageSharp.Web/Caching/HexEncoder.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/ImageSharp.Web/Caching/ICacheHash.cs b/src/ImageSharp.Web/Caching/ICacheHash.cs
index bf262d0e..26324709 100644
--- a/src/ImageSharp.Web/Caching/ICacheHash.cs
+++ b/src/ImageSharp.Web/Caching/ICacheHash.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Caching;
diff --git a/src/ImageSharp.Web/Caching/ICacheKey.cs b/src/ImageSharp.Web/Caching/ICacheKey.cs
index 2a23d42a..d7d3ae43 100644
--- a/src/ImageSharp.Web/Caching/ICacheKey.cs
+++ b/src/ImageSharp.Web/Caching/ICacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Caching/IImageCache.cs b/src/ImageSharp.Web/Caching/IImageCache.cs
index bdd22c6b..1ac8e5cd 100644
--- a/src/ImageSharp.Web/Caching/IImageCache.cs
+++ b/src/ImageSharp.Web/Caching/IImageCache.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using SixLabors.ImageSharp.Web.Resolvers;
@@ -17,7 +16,7 @@ public interface IImageCache
///
/// The cache key.
/// The .
- Task GetAsync(string key);
+ Task GetAsync(string key);
///
/// Sets the value associated with the specified key.
diff --git a/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs b/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs
index e3abe213..64b56e0b 100644
--- a/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs
+++ b/src/ImageSharp.Web/Caching/LegacyV1CacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Text;
diff --git a/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs b/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs
index 8e9e7494..dbb1cf16 100644
--- a/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs
+++ b/src/ImageSharp.Web/Caching/LruCache/ConcurrentTLruCache{TKey,TValue}.cs
@@ -1,8 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Web.Caching;
@@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Web.Caching;
/// 6. When cold is full, cold tail is moved to warm head or removed from dictionary on depending on WasAccessed.
///
internal class ConcurrentTLruCache
+ where TKey : notnull
{
private readonly ConcurrentDictionary> dictionary;
@@ -97,9 +98,9 @@ public ConcurrentTLruCache(int concurrencyLevel, int capacity, IEqualityComparer
/// The key of the value to get.
/// When this method returns, contains the object from the cache that has the specified key, or the default value of the type if the operation failed.
/// if the key was found in the cache; otherwise, .
- public bool TryGet(TKey key, out TValue value)
+ public bool TryGet(TKey key, [NotNullWhen(true)] out TValue? value)
{
- if (this.dictionary.TryGetValue(key, out LongTickCountLruItem item))
+ if (this.dictionary.TryGetValue(key, out LongTickCountLruItem? item))
{
return this.GetOrDiscard(item, out value);
}
@@ -111,7 +112,7 @@ public bool TryGet(TKey key, out TValue value)
// AggressiveInlining forces the JIT to inline policy.ShouldDiscard(). For LRU policy
// the first branch is completely eliminated due to JIT time constant propogation.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool GetOrDiscard(LongTickCountLruItem item, out TValue value)
+ private bool GetOrDiscard(LongTickCountLruItem item, out TValue? value)
{
if (this.policy.ShouldDiscard(item))
{
@@ -135,7 +136,7 @@ private bool GetOrDiscard(LongTickCountLruItem item, out TValue va
/// in the cache, or the new value if the key was not in the dictionary.
public TValue GetOrAdd(TKey key, Func valueFactory)
{
- if (this.TryGet(key, out TValue value))
+ if (this.TryGet(key, out TValue? value))
{
return value;
}
@@ -164,7 +165,7 @@ public TValue GetOrAdd(TKey key, Func valueFactory)
/// A task that represents the asynchronous operation.
public async Task GetOrAddAsync(TKey key, Func> valueFactory)
{
- if (this.TryGet(key, out TValue value))
+ if (this.TryGet(key, out TValue? value))
{
return value;
}
@@ -202,7 +203,7 @@ public bool TryRemove(TKey key)
// and it will not be marked as removed. If key 1 is fetched while LruItem1* is still in the queue, there will
// be two queue entries for key 1, and neither is marked as removed. Thus when LruItem1 * ages out, it will
// incorrectly remove 1 from the dictionary, and this cycle can repeat.
- if (this.dictionary.TryGetValue(key, out LongTickCountLruItem existing))
+ if (this.dictionary.TryGetValue(key, out LongTickCountLruItem? existing))
{
if (existing.WasRemoved)
{
@@ -219,7 +220,7 @@ public bool TryRemove(TKey key)
existing.WasRemoved = true;
}
- if (this.dictionary.TryRemove(key, out LongTickCountLruItem removedItem))
+ if (this.dictionary.TryRemove(key, out LongTickCountLruItem? removedItem))
{
// Mark as not accessed, it will later be cycled out of the queues because it can never be fetched
// from the dictionary. Note: Hot/Warm/Cold count will reflect the removed item until it is cycled
@@ -261,7 +262,7 @@ private void CycleHot()
{
Interlocked.Decrement(ref this.hotCount);
- if (this.hotQueue.TryDequeue(out LongTickCountLruItem item))
+ if (this.hotQueue.TryDequeue(out LongTickCountLruItem? item))
{
ItemDestination where = this.policy.RouteHot(item);
this.Move(item, where);
@@ -279,7 +280,7 @@ private void CycleWarm()
{
Interlocked.Decrement(ref this.warmCount);
- if (this.warmQueue.TryDequeue(out LongTickCountLruItem item))
+ if (this.warmQueue.TryDequeue(out LongTickCountLruItem? item))
{
ItemDestination where = this.policy.RouteWarm(item);
@@ -308,7 +309,7 @@ private void CycleCold()
{
Interlocked.Decrement(ref this.coldCount);
- if (this.coldQueue.TryDequeue(out LongTickCountLruItem item))
+ if (this.coldQueue.TryDequeue(out LongTickCountLruItem? item))
{
ItemDestination where = this.policy.RouteCold(item);
@@ -354,7 +355,7 @@ private void Move(LongTickCountLruItem item, ItemDestination where
break;
}
- if (this.dictionary.TryRemove(item.Key, out LongTickCountLruItem removedItem))
+ if (this.dictionary.TryRemove(item.Key, out LongTickCountLruItem? removedItem))
{
item.WasRemoved = true;
if (removedItem.Value is IDisposable d)
diff --git a/src/ImageSharp.Web/Caching/LruCache/LongTickCountLruItem{TKey,TValue}.cs b/src/ImageSharp.Web/Caching/LruCache/LongTickCountLruItem{TKey,TValue}.cs
index 7bd0a76d..58cb46eb 100644
--- a/src/ImageSharp.Web/Caching/LruCache/LongTickCountLruItem{TKey,TValue}.cs
+++ b/src/ImageSharp.Web/Caching/LruCache/LongTickCountLruItem{TKey,TValue}.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Caching;
diff --git a/src/ImageSharp.Web/Caching/LruCache/TLruLongTicksPolicy{TKey,TValue}.cs b/src/ImageSharp.Web/Caching/LruCache/TLruLongTicksPolicy{TKey,TValue}.cs
index 30f28b4f..d6994ec5 100644
--- a/src/ImageSharp.Web/Caching/LruCache/TLruLongTicksPolicy{TKey,TValue}.cs
+++ b/src/ImageSharp.Web/Caching/LruCache/TLruLongTicksPolicy{TKey,TValue}.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Diagnostics;
using System.Runtime.CompilerServices;
diff --git a/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs b/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs
index ff0847e0..34fe94a3 100644
--- a/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs
+++ b/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -77,17 +76,17 @@ internal static string GetCacheRoot(PhysicalFileSystemCacheOptions cacheOptions,
}
///
- public Task GetAsync(string key)
+ public Task GetAsync(string key)
{
string path = Path.Combine(this.cacheRootPath, ToFilePath(key, this.cacheFolderDepth));
FileInfo metaFileInfo = new(ToMetaDataFilePath(path));
if (!metaFileInfo.Exists)
{
- return Task.FromResult(null);
+ return Task.FromResult(null);
}
- return Task.FromResult(new PhysicalFileSystemCacheResolver(metaFileInfo, this.formatUtilities));
+ return Task.FromResult(new PhysicalFileSystemCacheResolver(metaFileInfo, this.formatUtilities));
}
///
@@ -96,10 +95,10 @@ public async Task SetAsync(string key, Stream stream, ImageCacheMetadata metadat
string path = Path.Combine(this.cacheRootPath, ToFilePath(key, this.cacheFolderDepth));
string imagePath = this.ToImageFilePath(path, metadata);
string metaPath = ToMetaDataFilePath(path);
- string directory = Path.GetDirectoryName(path);
+ string? directory = Path.GetDirectoryName(path);
// Ensure cache directory is created before creating files
- if (!Directory.Exists(directory))
+ if (!Directory.Exists(directory) && directory is not null)
{
Directory.CreateDirectory(directory);
}
diff --git a/src/ImageSharp.Web/Caching/PhysicalFileSystemCacheOptions.cs b/src/ImageSharp.Web/Caching/PhysicalFileSystemCacheOptions.cs
index ad09f177..ec2d2410 100644
--- a/src/ImageSharp.Web/Caching/PhysicalFileSystemCacheOptions.cs
+++ b/src/ImageSharp.Web/Caching/PhysicalFileSystemCacheOptions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Caching;
@@ -21,7 +20,7 @@ public class PhysicalFileSystemCacheOptions
/// application content files; commonly 'wwwroot'.
///
///
- public string CacheRootPath { get; set; }
+ public string? CacheRootPath { get; set; }
///
/// Gets or sets the cache folder name.
diff --git a/src/ImageSharp.Web/Caching/SHA256CacheHash.cs b/src/ImageSharp.Web/Caching/SHA256CacheHash.cs
index f0d3f16d..7eeae17a 100644
--- a/src/ImageSharp.Web/Caching/SHA256CacheHash.cs
+++ b/src/ImageSharp.Web/Caching/SHA256CacheHash.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Buffers;
using System.Runtime.CompilerServices;
@@ -33,7 +32,7 @@ public SHA256CacheHash(IOptions options)
public string Create(string value, uint length)
{
int byteCount = Encoding.ASCII.GetByteCount(value);
- byte[] buffer = null;
+ byte[]? buffer = null;
try
{
diff --git a/src/ImageSharp.Web/Caching/UriAbsoluteCacheKey.cs b/src/ImageSharp.Web/Caching/UriAbsoluteCacheKey.cs
index 74ed4c59..ea9f126a 100644
--- a/src/ImageSharp.Web/Caching/UriAbsoluteCacheKey.cs
+++ b/src/ImageSharp.Web/Caching/UriAbsoluteCacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Caching/UriAbsoluteLowerInvariantCacheKey.cs b/src/ImageSharp.Web/Caching/UriAbsoluteLowerInvariantCacheKey.cs
index 1c78b30f..2e3069d4 100644
--- a/src/ImageSharp.Web/Caching/UriAbsoluteLowerInvariantCacheKey.cs
+++ b/src/ImageSharp.Web/Caching/UriAbsoluteLowerInvariantCacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Caching/UriRelativeCacheKey.cs b/src/ImageSharp.Web/Caching/UriRelativeCacheKey.cs
index cefe8dd0..01d08740 100644
--- a/src/ImageSharp.Web/Caching/UriRelativeCacheKey.cs
+++ b/src/ImageSharp.Web/Caching/UriRelativeCacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Caching/UriRelativeLowerInvariantCacheKey.cs b/src/ImageSharp.Web/Caching/UriRelativeLowerInvariantCacheKey.cs
index 1071c333..77e423eb 100644
--- a/src/ImageSharp.Web/Caching/UriRelativeLowerInvariantCacheKey.cs
+++ b/src/ImageSharp.Web/Caching/UriRelativeLowerInvariantCacheKey.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/CaseHandlingUriBuilder.cs b/src/ImageSharp.Web/CaseHandlingUriBuilder.cs
index f257fa08..e3418820 100644
--- a/src/ImageSharp.Web/CaseHandlingUriBuilder.cs
+++ b/src/ImageSharp.Web/CaseHandlingUriBuilder.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Buffers;
using System.Runtime.CompilerServices;
diff --git a/src/ImageSharp.Web/CommandHandling.cs b/src/ImageSharp.Web/CommandHandling.cs
index 02f2e19b..2e436ea6 100644
--- a/src/ImageSharp.Web/CommandHandling.cs
+++ b/src/ImageSharp.Web/CommandHandling.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Commands/CommandCollection.cs b/src/ImageSharp.Web/Commands/CommandCollection.cs
index 1718384e..16747d48 100644
--- a/src/ImageSharp.Web/Commands/CommandCollection.cs
+++ b/src/ImageSharp.Web/Commands/CommandCollection.cs
@@ -1,8 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Collections.ObjectModel;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Web.Commands;
@@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Web.Commands;
///
/// Represents an ordered collection of processing commands.
///
-public sealed class CommandCollection : KeyedCollection>
+public sealed class CommandCollection : KeyedCollection>
{
///
/// Initializes a new instance of the class.
@@ -32,7 +32,7 @@ public IEnumerable Keys
{
get
{
- foreach (KeyValuePair item in this)
+ foreach (KeyValuePair item in this)
{
yield return this.GetKeyForItem(item);
}
@@ -54,7 +54,7 @@ public IEnumerable Keys
{
get
{
- if (!this.TryGetValue(key, out string value))
+ if (!this.TryGetValue(key, out string? value))
{
ThrowKeyNotFound();
}
@@ -64,7 +64,7 @@ public IEnumerable Keys
set
{
- if (this.TryGetValue(key, out KeyValuePair item))
+ if (this.TryGetValue(key, out KeyValuePair item))
{
this.SetItem(this.IndexOf(item), new(key, value));
}
@@ -107,12 +107,12 @@ public IEnumerable Keys
/// an element with the specified key; otherwise, .
///
/// is null.
- public bool TryGetValue(string key, out string value)
+ public bool TryGetValue(string key, [NotNullWhen(true)] out string? value)
{
- if (this.TryGetValue(key, out KeyValuePair keyValue))
+ if (this.TryGetValue(key, out KeyValuePair keyValue))
{
value = keyValue.Value;
- return true;
+ return value is not null;
}
value = default;
@@ -138,7 +138,7 @@ public int FindIndex(Predicate match)
Guard.NotNull(match, nameof(match));
int index = 0;
- foreach (KeyValuePair item in this)
+ foreach (KeyValuePair item in this)
{
if (match(item.Key))
{
@@ -162,7 +162,7 @@ public int FindIndex(Predicate match)
///
public int IndexOf(string key)
{
- if (this.TryGetValue(key, out KeyValuePair item))
+ if (this.TryGetValue(key, out KeyValuePair item))
{
return this.IndexOf(item);
}
@@ -172,8 +172,9 @@ public int IndexOf(string key)
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected override string GetKeyForItem(KeyValuePair item) => item.Key;
+ protected override string GetKeyForItem(KeyValuePair item) => item.Key;
[MethodImpl(MethodImplOptions.NoInlining)]
+ [DoesNotReturn]
private static void ThrowKeyNotFound() => throw new KeyNotFoundException();
}
diff --git a/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs b/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs
index 6d6752ca..126c990a 100644
--- a/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs
+++ b/src/ImageSharp.Web/Commands/CommandCollectionExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Commands;
@@ -15,9 +14,9 @@ public static class CommandCollectionExtensions
/// The collection instance.
/// The key of the value to get.
/// The value associated with the specified key or the default value.
- public static string GetValueOrDefault(this CommandCollection collection, string key)
+ public static string? GetValueOrDefault(this CommandCollection collection, string key)
{
- collection.TryGetValue(key, out KeyValuePair result);
+ collection.TryGetValue(key, out KeyValuePair result);
return result.Value;
}
}
diff --git a/src/ImageSharp.Web/Commands/CommandParser.cs b/src/ImageSharp.Web/Commands/CommandParser.cs
index e527510a..4bd0f534 100644
--- a/src/ImageSharp.Web/Commands/CommandParser.cs
+++ b/src/ImageSharp.Web/Commands/CommandParser.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Runtime.CompilerServices;
@@ -36,12 +36,12 @@ public CommandParser(IEnumerable converters)
///
/// The converted instance or the default.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public T ParseValue(string value, CultureInfo culture)
+ public T? ParseValue(string? value, CultureInfo culture)
{
DebugGuard.NotNull(culture, nameof(culture));
Type type = typeof(T);
- ICommandConverter converter = Array.Find(this.converters, x => x.Type.Equals(type));
+ ICommandConverter? converter = Array.Find(this.converters, x => x.Type.Equals(type));
if (converter != null)
{
@@ -59,7 +59,7 @@ public T ParseValue(string value, CultureInfo culture)
converter = Array.Find(this.converters, x => x.Type.Equals(typeof(Enum)));
if (converter != null)
{
- return (T)((ICommandConverter
- private static readonly Regex HexColorRegex = new("([0-9a-fA-F]{3}){1,2}", RegexOptions.Compiled);
+ private static readonly Regex HexColorRegex = new("([0-9a-fA-F][^,;.-]\\B{3}){1,2}", RegexOptions.Compiled);
///
/// The number color regex.
@@ -35,16 +34,22 @@ public sealed class ColorConverter : ICommandConverter
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Color ConvertFrom(CommandParser parser, CultureInfo culture, string value, Type propertyType)
+ public Color ConvertFrom(CommandParser parser, CultureInfo culture, string? value, Type propertyType)
{
if (string.IsNullOrWhiteSpace(value))
{
return default;
}
- // Numeric r,g,b - r,g,b,a
- char separator = culture.TextInfo.ListSeparator[0];
+ // Named colors
+ IDictionary table = ColorConstantsTable.Value;
+ if (table.TryGetValue(value, out Color color))
+ {
+ return color;
+ }
+ // Numeric r,g,b - r,g,b,a
+ char separator = ConverterUtility.GetListSeparator(culture);
if (value.IndexOf(separator) != -1)
{
string[] components = value.Split(separator);
@@ -60,9 +65,9 @@ public Color ConvertFrom(CommandParser parser, CultureInfo culture, string value
if (convert)
{
- List rgba = parser.ParseValue>(value, culture);
+ List? rgba = parser.ParseValue>(value, culture);
- return rgba.Count switch
+ return rgba?.Count switch
{
4 => Color.FromRgba(rgba[0], rgba[1], rgba[2], rgba[3]),
3 => Color.FromRgb(rgba[0], rgba[1], rgba[2]),
@@ -77,9 +82,7 @@ public Color ConvertFrom(CommandParser parser, CultureInfo culture, string value
return Color.ParseHex(value);
}
- // Named colors
- IDictionary table = ColorConstantsTable.Value;
- return table.TryGetValue(value, out Color color) ? color : default;
+ return default;
}
private static IDictionary InitializeColorConstantsTable()
@@ -90,7 +93,7 @@ private static IDictionary InitializeColorConstantsTable()
{
if (field.FieldType == typeof(Color))
{
- table[field.Name] = (Color)field.GetValue(null);
+ table[field.Name] = (Color)field.GetValue(null)!;
}
}
diff --git a/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs b/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs
new file mode 100644
index 00000000..c924e35c
--- /dev/null
+++ b/src/ImageSharp.Web/Commands/Converters/ConverterUtility.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Web.Commands.Converters;
+internal static class ConverterUtility
+{
+ ///
+ /// Gets the that is used by the given culture to separate items in a list.
+ ///
+ /// The culture.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static char GetListSeparator(CultureInfo culture)
+ => MemoryMarshal.GetReference(culture.TextInfo.ListSeparator);
+}
diff --git a/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs b/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs
index 764a68a3..b74ae4d5 100644
--- a/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs
+++ b/src/ImageSharp.Web/Commands/Converters/EnumConverter.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Runtime.CompilerServices;
@@ -22,10 +21,10 @@ public sealed class EnumConverter : ICommandConverter
/// This allows us to reuse the same converter for infinite enum types.
///
[MethodImpl(MethodImplOptions.NoInlining)]
- public object ConvertFrom(
+ public object? ConvertFrom(
CommandParser parser,
CultureInfo culture,
- string value,
+ string? value,
Type propertyType)
{
if (string.IsNullOrWhiteSpace(value))
@@ -35,7 +34,7 @@ public object ConvertFrom(
try
{
- char separator = culture.TextInfo.ListSeparator[0];
+ char separator = ConverterUtility.GetListSeparator(culture);
if (value.IndexOf(separator) != -1)
{
long convertedValue = 0;
@@ -64,5 +63,8 @@ public object ConvertFrom(
/// The .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string[] GetStringArray(string input, char separator)
+
+ // TODO: Can we use StringSplit Enumerator here?
+ // https://github.com/dotnet/runtime/issues/934
=> input.Split(separator).Select(s => s.Trim()).ToArray();
}
diff --git a/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs b/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs
index 7b7e750a..f81c75e5 100644
--- a/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs
+++ b/src/ImageSharp.Web/Commands/Converters/ICommandConverter.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
@@ -35,5 +34,5 @@ public interface ICommandConverter : ICommandConverter
/// The to convert.
/// The property type that the converter will convert to.
/// The conversion cannot be performed.
- T ConvertFrom(CommandParser parser, CultureInfo culture, string value, Type propertyType);
+ T? ConvertFrom(CommandParser parser, CultureInfo culture, string? value, Type propertyType);
}
diff --git a/src/ImageSharp.Web/Commands/Converters/IntegralNumberConverter{T}.cs b/src/ImageSharp.Web/Commands/Converters/IntegralNumberConverter{T}.cs
index 5c49e141..3fb27fb4 100644
--- a/src/ImageSharp.Web/Commands/Converters/IntegralNumberConverter{T}.cs
+++ b/src/ImageSharp.Web/Commands/Converters/IntegralNumberConverter{T}.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
@@ -20,7 +19,7 @@ public sealed class IntegralNumberConverter : ICommandConverter
public T ConvertFrom(
CommandParser parser,
CultureInfo culture,
- string value,
+ string? value,
Type propertyType)
{
if (string.IsNullOrWhiteSpace(value)
diff --git a/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs b/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs
index 4b2fdd3a..5a1e35ca 100644
--- a/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs
+++ b/src/ImageSharp.Web/Commands/Converters/ListConverter{T}.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Runtime.CompilerServices;
@@ -21,10 +20,10 @@ public sealed class ListConverter : ICommandConverter>
public List ConvertFrom(
CommandParser parser,
CultureInfo culture,
- string value,
+ string? value,
Type propertyType)
{
- var result = new List();
+ List result = new();
if (string.IsNullOrWhiteSpace(value))
{
return result;
@@ -32,8 +31,8 @@ public List ConvertFrom(
foreach (string pill in GetStringArray(value, culture))
{
- T item = parser.ParseValue(pill, culture);
- if (item != null)
+ T? item = parser.ParseValue(pill, culture);
+ if (item is not null)
{
result.Add(item);
}
@@ -45,7 +44,10 @@ public List ConvertFrom(
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string[] GetStringArray(string input, CultureInfo culture)
{
- char separator = culture.TextInfo.ListSeparator[0];
+ char separator = ConverterUtility.GetListSeparator(culture);
+
+ // TODO: Can we use StringSplit Enumerator here?
+ // https://github.com/dotnet/runtime/issues/934
return input.Split(separator).Select(s => s.Trim()).ToArray();
}
}
diff --git a/src/ImageSharp.Web/Commands/Converters/SimpleCommandConverter{T}.cs b/src/ImageSharp.Web/Commands/Converters/SimpleCommandConverter{T}.cs
index d02359a9..399e3120 100644
--- a/src/ImageSharp.Web/Commands/Converters/SimpleCommandConverter{T}.cs
+++ b/src/ImageSharp.Web/Commands/Converters/SimpleCommandConverter{T}.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Runtime.CompilerServices;
@@ -19,10 +18,10 @@ public sealed class SimpleCommandConverter : ICommandConverter
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public T ConvertFrom(
+ public T? ConvertFrom(
CommandParser parser,
CultureInfo culture,
- string value,
+ string? value,
Type propertyType)
{
if (string.IsNullOrWhiteSpace(value))
@@ -31,7 +30,7 @@ public T ConvertFrom(
}
Type t = typeof(T);
- Type u = Nullable.GetUnderlyingType(t);
+ Type? u = Nullable.GetUnderlyingType(t);
if (u != null)
{
diff --git a/src/ImageSharp.Web/Commands/IRequestParser.cs b/src/ImageSharp.Web/Commands/IRequestParser.cs
index 4d4d418a..73aede92 100644
--- a/src/ImageSharp.Web/Commands/IRequestParser.cs
+++ b/src/ImageSharp.Web/Commands/IRequestParser.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
diff --git a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs
index f4215369..6386ee7d 100644
--- a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs
+++ b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParser.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
@@ -41,8 +40,8 @@ public CommandCollection ParseRequestCommands(HttpContext context)
}
StringValues query = queryCollection[QueryKey];
- string requestedPreset = query[query.Count - 1];
- if (this.presets.TryGetValue(requestedPreset, out CommandCollection collection))
+ string? requestedPreset = query[^1];
+ if (requestedPreset is not null && this.presets.TryGetValue(requestedPreset, out CommandCollection? collection))
{
return collection;
}
@@ -66,7 +65,11 @@ private static CommandCollection ParsePreset(string unparsedPresetValue)
foreach (KeyValuePair pair in parsed)
{
// Use the indexer for both set and query. This replaces any previously parsed values.
- transformed[pair.Key] = pair.Value[pair.Value.Count - 1];
+ string? value = pair.Value[^1];
+ if (value is not null)
+ {
+ transformed[pair.Key] = value;
+ }
}
return transformed;
diff --git a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs
index f12934f3..7c40e8a4 100644
--- a/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs
+++ b/src/ImageSharp.Web/Commands/PresetOnlyQueryCollectionRequestParserOptions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs b/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs
index 9edf4ea4..420fc019 100644
--- a/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs
+++ b/src/ImageSharp.Web/Commands/QueryCollectionRequestParser.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
@@ -26,7 +25,11 @@ public CommandCollection ParseRequestCommands(HttpContext context)
foreach (KeyValuePair pair in query)
{
// Use the indexer for both set and query. This replaces any previously parsed values.
- transformed[pair.Key] = pair.Value[pair.Value.Count - 1];
+ string? value = pair.Value[^1];
+ if (value is not null)
+ {
+ transformed[pair.Key] = value;
+ }
}
return transformed;
diff --git a/src/ImageSharp.Web/Commands/TypeConstants.cs b/src/ImageSharp.Web/Commands/TypeConstants.cs
index e7a0d2b6..c6460de5 100644
--- a/src/ImageSharp.Web/Commands/TypeConstants.cs
+++ b/src/ImageSharp.Web/Commands/TypeConstants.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs b/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs
index e3bdaf9c..e2f896dc 100644
--- a/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs
+++ b/src/ImageSharp.Web/DependencyInjection/ApplicationBuilderExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Builder;
using SixLabors.ImageSharp.Web.Middleware;
diff --git a/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs b/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs
index 34a2701d..f1935af9 100644
--- a/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs
+++ b/src/ImageSharp.Web/DependencyInjection/IImageSharpBuilder.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs b/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs
index ac44dfe8..58da1137 100644
--- a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs
+++ b/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilder.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs b/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs
index d696f015..8c4a17bb 100644
--- a/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs
+++ b/src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -205,7 +204,7 @@ public static IImageSharpBuilder InsertProvider(this IImageSharpBuild
public static IImageSharpBuilder RemoveProvider(this IImageSharpBuilder builder)
where TProvider : class, IImageProvider
{
- ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageProvider) && x.GetImplementationType() == typeof(TProvider));
+ ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageProvider) && x.GetImplementationType() == typeof(TProvider));
if (descriptor != null)
{
builder.Services.Remove(descriptor);
@@ -264,7 +263,7 @@ public static IImageSharpBuilder AddProcessor(this IImageSharpBuilde
public static IImageSharpBuilder RemoveProcessor(this IImageSharpBuilder builder)
where TProcessor : class, IImageWebProcessor
{
- ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageWebProcessor) && x.GetImplementationType() == typeof(TProcessor));
+ ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageWebProcessor) && x.GetImplementationType() == typeof(TProcessor));
if (descriptor != null)
{
builder.Services.Remove(descriptor);
@@ -323,7 +322,7 @@ public static IImageSharpBuilder AddConverter(this IImageSharpBuilde
public static IImageSharpBuilder RemoveConverter(this IImageSharpBuilder builder)
where TConverter : class, ICommandConverter
{
- ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(ICommandConverter) && x.GetImplementationType() == typeof(TConverter));
+ ServiceDescriptor? descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(ICommandConverter) && x.GetImplementationType() == typeof(TConverter));
if (descriptor != null)
{
builder.Services.Remove(descriptor);
@@ -374,7 +373,7 @@ public static IImageSharpBuilder Configure(this IImageSharpBuilder bui
return builder;
}
- private static Type GetImplementationType(this ServiceDescriptor descriptor)
+ private static Type? GetImplementationType(this ServiceDescriptor descriptor)
=> descriptor.ImplementationType
?? descriptor.ImplementationInstance?.GetType()
?? descriptor.ImplementationFactory?.GetType().GenericTypeArguments[1];
diff --git a/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs b/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs
index 31fcd6ac..92729e1f 100644
--- a/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/ImageSharp.Web/DependencyInjection/ServiceCollectionExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.DependencyInjection;
using SixLabors.ImageSharp.Web.Caching;
diff --git a/src/ImageSharp.Web/ExifOrientationUtilities.cs b/src/ImageSharp.Web/ExifOrientationUtilities.cs
index 15e0d336..dab77e8c 100644
--- a/src/ImageSharp.Web/ExifOrientationUtilities.cs
+++ b/src/ImageSharp.Web/ExifOrientationUtilities.cs
@@ -1,11 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
-using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Web;
diff --git a/src/ImageSharp.Web/FormatUtilities.cs b/src/ImageSharp.Web/FormatUtilities.cs
index 174950b8..4e9cba52 100644
--- a/src/ImageSharp.Web/FormatUtilities.cs
+++ b/src/ImageSharp.Web/FormatUtilities.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Options;
@@ -51,7 +51,7 @@ public FormatUtilities(IOptions options)
/// if the uri contains an extension; otherwise, .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetExtensionFromUri(string uri, out string extension)
+ public bool TryGetExtensionFromUri(string uri, [NotNullWhen(true)] out string? extension)
{
extension = null;
int query = uri.IndexOf('?');
@@ -60,7 +60,7 @@ public bool TryGetExtensionFromUri(string uri, out string extension)
if (query > -1)
{
if (uri.Contains(FormatWebProcessor.Format, StringComparison.OrdinalIgnoreCase)
- && QueryHelpers.ParseQuery(uri.Substring(query)).TryGetValue(FormatWebProcessor.Format, out StringValues ext))
+ && QueryHelpers.ParseQuery(uri[query..]).TryGetValue(FormatWebProcessor.Format, out StringValues ext))
{
// We have a query but is it a valid one?
ReadOnlySpan extSpan = ext[0].AsSpan();
@@ -86,7 +86,7 @@ public bool TryGetExtensionFromUri(string uri, out string extension)
int extensionIndex;
if ((extensionIndex = path.LastIndexOf('.')) != -1)
{
- ReadOnlySpan pathExtension = path.Slice(extensionIndex + 1);
+ ReadOnlySpan pathExtension = path[(extensionIndex + 1)..];
foreach (string e in this.extensions)
{
diff --git a/src/ImageSharp.Web/FormattedImage.cs b/src/ImageSharp.Web/FormattedImage.cs
index 4a270918..65c82df2 100644
--- a/src/ImageSharp.Web/FormattedImage.cs
+++ b/src/ImageSharp.Web/FormattedImage.cs
@@ -1,12 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
-using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
-using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Web;
@@ -41,14 +39,15 @@ private FormattedImage(Image image, IImageFormat format, bool keepOpen)
{
this.Image = image;
this.imageFormatsManager = image.GetConfiguration().ImageFormatsManager;
- this.Format = format;
+ this.format = format;
+ this.encoder = this.imageFormatsManager.GetEncoder(format);
this.keepOpen = keepOpen;
}
///
/// Gets the decoded image.
///
- public Image Image { get; private set; }
+ public Image Image { get; }
///
/// Gets or sets the format.
@@ -64,7 +63,7 @@ public IImageFormat Format
}
this.format = value;
- this.encoder = this.imageFormatsManager.FindEncoder(value);
+ this.encoder = this.imageFormatsManager.GetEncoder(value);
}
}
@@ -82,7 +81,7 @@ public IImageEncoder Encoder
}
// The given type should match the format encoder.
- IImageEncoder reference = this.imageFormatsManager.FindEncoder(this.Format);
+ IImageEncoder reference = this.imageFormatsManager.GetEncoder(this.Format);
if (reference.GetType() != value.GetType())
{
ThrowInvalid(nameof(value));
@@ -96,26 +95,29 @@ public IImageEncoder Encoder
/// Create a new instance of the class from the given stream.
///
/// The pixel format.
- /// The configuration.
+ /// The general decoder options.
/// The source.
/// A representing the asynchronous operation.
- internal static async Task LoadAsync(Configuration configuration, Stream source)
+ internal static async Task LoadAsync(DecoderOptions options, Stream source)
where TPixel : unmanaged, IPixel
{
- (Image image, IImageFormat format) = await Image.LoadWithFormatAsync(configuration, source);
- return new FormattedImage(image, format, false);
+ // TODO: We want to be able to apply decoder options per request.
+ // For example. If a resize command has been passed with no extra resampling options
+ // then we should apply those changes on decode. This will allow memory savings and performance improvements.
+ Image image = await Image.LoadAsync(options, source);
+ return new FormattedImage(image, image.Metadata.DecodedImageFormat!, false);
}
///
/// Create a new instance of the class from the given stream.
///
- /// The configuration.
+ /// The general decoder options.
/// The source.
/// A representing the asynchronous operation.
- internal static async Task LoadAsync(Configuration configuration, Stream source)
+ internal static async Task LoadAsync(DecoderOptions options, Stream source)
{
- (Image image, IImageFormat format) = await Image.LoadWithFormatAsync(configuration, source);
- return new FormattedImage(image, format, false);
+ Image image = await Image.LoadAsync(options, source);
+ return new FormattedImage(image, image.Metadata.DecodedImageFormat!, false);
}
///
@@ -141,8 +143,7 @@ public bool TryGetExifOrientation(out ushort value)
value = ExifOrientationMode.Unknown;
if (this.Image.Metadata.ExifProfile != null)
{
- IExifValue orientation = this.Image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
- if (orientation is null)
+ if (!this.Image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out IExifValue? orientation))
{
return false;
}
@@ -171,13 +172,12 @@ public void Dispose()
if (!this.keepOpen)
{
this.Image?.Dispose();
- this.Image = null;
}
}
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [DoesNotReturn]
private static void ThrowNull(string name) => throw new ArgumentNullException(name);
- [MethodImpl(MethodImplOptions.NoInlining)]
+ [DoesNotReturn]
private static void ThrowInvalid(string name) => throw new ArgumentException(name);
}
diff --git a/src/ImageSharp.Web/HMACUtilities.cs b/src/ImageSharp.Web/HMACUtilities.cs
index eb9d497a..f90d8c52 100644
--- a/src/ImageSharp.Web/HMACUtilities.cs
+++ b/src/ImageSharp.Web/HMACUtilities.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Buffers;
using System.Runtime.CompilerServices;
@@ -70,7 +69,7 @@ public static unsafe string ComputeHMACSHA512(string value, byte[] secret)
private static unsafe string CreateHMAC(string value, HMAC hmac)
{
int byteCount = Encoding.ASCII.GetByteCount(value);
- byte[] buffer = null;
+ byte[]? buffer = null;
try
{
diff --git a/src/ImageSharp.Web/ImageCacheMetadata.cs b/src/ImageSharp.Web/ImageCacheMetadata.cs
index 0e1ce20d..d871fd8d 100644
--- a/src/ImageSharp.Web/ImageCacheMetadata.cs
+++ b/src/ImageSharp.Web/ImageCacheMetadata.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Runtime.CompilerServices;
@@ -98,23 +97,24 @@ public ImageCacheMetadata(
public static ImageCacheMetadata FromDictionary(IDictionary dictionary)
{
// DateTime.TryParse(null) == DateTime.MinValue so no need for conditional;
- dictionary.TryGetValue(SourceLastModifiedKey, out string sourceLastWriteTimeUtcString);
+ dictionary.TryGetValue(SourceLastModifiedKey, out string? sourceLastWriteTimeUtcString);
DateTime.TryParse(sourceLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime sourceLastWriteTimeUtc);
- dictionary.TryGetValue(CacheLastModifiedKey, out string cacheLastWriteTimeUtcString);
+ dictionary.TryGetValue(CacheLastModifiedKey, out string? cacheLastWriteTimeUtcString);
DateTime.TryParse(cacheLastWriteTimeUtcString, null, DateTimeStyles.RoundtripKind, out DateTime cacheLastWriteTimeUtc);
- dictionary.TryGetValue(ContentTypeKey, out string contentType);
+ dictionary.TryGetValue(ContentTypeKey, out string? contentType);
+ Guard.NotNull(contentType);
// int.TryParse(null) == 0 and we want to return TimeSpan.MinValue not TimeSpan.Zero
TimeSpan cacheControlMaxAge = TimeSpan.MinValue;
- if (dictionary.TryGetValue(CacheControlKey, out string cacheControlMaxAgeString))
+ if (dictionary.TryGetValue(CacheControlKey, out string? cacheControlMaxAgeString))
{
_ = int.TryParse(cacheControlMaxAgeString, out int maxAge);
cacheControlMaxAge = TimeSpan.FromSeconds(maxAge);
}
- dictionary.TryGetValue(ContentLengthKey, out string contentLengthString);
+ dictionary.TryGetValue(ContentLengthKey, out string? contentLengthString);
_ = long.TryParse(contentLengthString, out long contentLength);
return new ImageCacheMetadata(
@@ -135,7 +135,7 @@ public static async Task ReadAsync(Stream stream)
Dictionary dictionary = new();
using (StreamReader reader = new(stream, Encoding.UTF8))
{
- string line;
+ string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
int idx = line.IndexOf(':');
@@ -160,7 +160,7 @@ public bool Equals(ImageCacheMetadata other)
&& this.ContentLength == other.ContentLength;
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> obj is ImageCacheMetadata data && this.Equals(data);
///
diff --git a/src/ImageSharp.Web/ImageMetadata.cs b/src/ImageSharp.Web/ImageMetadata.cs
index 9ff37df7..ba2d5462 100644
--- a/src/ImageSharp.Web/ImageMetadata.cs
+++ b/src/ImageSharp.Web/ImageMetadata.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Runtime.CompilerServices;
@@ -90,7 +89,7 @@ public bool Equals(ImageMetadata other)
&& this.ContentLength == other.ContentLength;
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> obj is ImageMetadata data && this.Equals(data);
///
diff --git a/src/ImageSharp.Web/ImageSharp.Web.csproj b/src/ImageSharp.Web/ImageSharp.Web.csproj
index 26986650..a4f69af8 100644
--- a/src/ImageSharp.Web/ImageSharp.Web.csproj
+++ b/src/ImageSharp.Web/ImageSharp.Web.csproj
@@ -45,7 +45,7 @@
-
+
diff --git a/src/ImageSharp.Web/ImageSharpRequestAuthorizationUtilities.cs b/src/ImageSharp.Web/ImageSharpRequestAuthorizationUtilities.cs
index 18a5c502..7c1aede5 100644
--- a/src/ImageSharp.Web/ImageSharpRequestAuthorizationUtilities.cs
+++ b/src/ImageSharp.Web/ImageSharpRequestAuthorizationUtilities.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.AspNetCore.Http;
@@ -96,7 +95,7 @@ public void StripUnknownCommands(CommandCollection commands)
/// The uri to compute the code from.
/// The command collection handling.
/// The computed HMAC.
- public string ComputeHMAC(string uri, CommandHandling handling)
+ public string? ComputeHMAC(string uri, CommandHandling handling)
=> this.ComputeHMAC(new Uri(uri, UriKind.RelativeOrAbsolute), handling);
///
@@ -105,7 +104,7 @@ public string ComputeHMAC(string uri, CommandHandling handling)
/// The uri to compute the code from.
/// The command collection handling.
/// The computed HMAC.
- public Task ComputeHMACAsync(string uri, CommandHandling handling)
+ public Task ComputeHMACAsync(string uri, CommandHandling handling)
=> this.ComputeHMACAsync(new Uri(uri, UriKind.RelativeOrAbsolute), handling);
///
@@ -114,7 +113,7 @@ public Task ComputeHMACAsync(string uri, CommandHandling handling)
/// The uri to compute the code from.
/// The command collection handling.
/// The computed HMAC.
- public string ComputeHMAC(Uri uri, CommandHandling handling)
+ public string? ComputeHMAC(Uri uri, CommandHandling handling)
{
ToComponents(
uri,
@@ -131,7 +130,7 @@ public string ComputeHMAC(Uri uri, CommandHandling handling)
/// The uri to compute the code from.
/// The command collection handling.
/// The computed HMAC.
- public Task ComputeHMACAsync(Uri uri, CommandHandling handling)
+ public Task ComputeHMACAsync(Uri uri, CommandHandling handling)
{
ToComponents(
uri,
@@ -150,7 +149,7 @@ public Task ComputeHMACAsync(Uri uri, CommandHandling handling)
/// The querystring.
/// The command collection handling.
/// The computed HMAC.
- public string ComputeHMAC(HostString host, PathString path, QueryString queryString, CommandHandling handling)
+ public string? ComputeHMAC(HostString host, PathString path, QueryString queryString, CommandHandling handling)
=> this.ComputeHMAC(host, path, queryString, new(QueryHelpers.ParseQuery(queryString.Value)), handling);
///
@@ -161,7 +160,7 @@ public string ComputeHMAC(HostString host, PathString path, QueryString queryStr
/// The querystring.
/// The command collection handling.
/// The computed HMAC.
- public Task ComputeHMACAsync(HostString host, PathString path, QueryString queryString, CommandHandling handling)
+ public Task ComputeHMACAsync(HostString host, PathString path, QueryString queryString, CommandHandling handling)
=> this.ComputeHMACAsync(host, path, queryString, new(QueryHelpers.ParseQuery(queryString.Value)), handling);
///
@@ -173,7 +172,7 @@ public Task ComputeHMACAsync(HostString host, PathString path, QueryStri
/// The query collection.
/// The command collection handling.
/// The computed HMAC.
- public string ComputeHMAC(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
+ public string? ComputeHMAC(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
=> this.ComputeHMAC(this.ToHttpContext(host, path, queryString, query), handling);
///
@@ -185,7 +184,7 @@ public string ComputeHMAC(HostString host, PathString path, QueryString queryStr
/// The query collection.
/// The command collection handling.
/// The computed HMAC.
- public Task ComputeHMACAsync(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
+ public Task ComputeHMACAsync(HostString host, PathString path, QueryString queryString, QueryCollection query, CommandHandling handling)
=> this.ComputeHMACAsync(this.ToHttpContext(host, path, queryString, query), handling);
///
@@ -194,7 +193,7 @@ public Task ComputeHMACAsync(HostString host, PathString path, QueryStri
/// The request HTTP context.
/// The command collection handling.
/// The computed HMAC.
- public string ComputeHMAC(HttpContext context, CommandHandling handling)
+ public string? ComputeHMAC(HttpContext context, CommandHandling handling)
=> AsyncHelper.RunSync(() => this.ComputeHMACAsync(context, handling));
///
@@ -203,7 +202,7 @@ public string ComputeHMAC(HttpContext context, CommandHandling handling)
/// The request HTTP context.
/// The command collection handling.
/// The computed HMAC.
- public async Task ComputeHMACAsync(HttpContext context, CommandHandling handling)
+ public async Task ComputeHMACAsync(HttpContext context, CommandHandling handling)
{
byte[] secret = this.options.HMACSecretKey;
if (secret is null || secret.Length == 0)
diff --git a/src/ImageSharp.Web/Middleware/ImageCommandContext.cs b/src/ImageSharp.Web/Middleware/ImageCommandContext.cs
index 0bb06af9..228347f0 100644
--- a/src/ImageSharp.Web/Middleware/ImageCommandContext.cs
+++ b/src/ImageSharp.Web/Middleware/ImageCommandContext.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.AspNetCore.Http;
diff --git a/src/ImageSharp.Web/Middleware/ImageContext.cs b/src/ImageSharp.Web/Middleware/ImageContext.cs
index f34058b1..697dc5e7 100644
--- a/src/ImageSharp.Web/Middleware/ImageContext.cs
+++ b/src/ImageSharp.Web/Middleware/ImageContext.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
@@ -23,7 +22,7 @@ internal struct ImageContext
private DateTimeOffset fileLastModified;
private long fileLength;
- private EntityTagHeaderValue fileEtag;
+ private EntityTagHeaderValue? fileEtag;
private PreconditionState ifMatchState;
private PreconditionState ifNoneMatchState;
diff --git a/src/ImageSharp.Web/Middleware/ImageProcessingContext.cs b/src/ImageSharp.Web/Middleware/ImageProcessingContext.cs
index a03a5508..53c0c3d1 100644
--- a/src/ImageSharp.Web/Middleware/ImageProcessingContext.cs
+++ b/src/ImageSharp.Web/Middleware/ImageProcessingContext.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Commands;
diff --git a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs
index d964f218..9b9e9b2b 100644
--- a/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs
+++ b/src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Diagnostics;
using System.Globalization;
@@ -10,7 +9,6 @@
using Microsoft.Extensions.Options;
using Microsoft.IO;
using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Web.Caching;
using SixLabors.ImageSharp.Web.Commands;
using SixLabors.ImageSharp.Web.Processors;
@@ -34,7 +32,7 @@ private static readonly ConcurrentTLruCache SourceMetadat
///
/// Used to temporarily store cache resolver reads to reduce the overhead of cache lookups.
///
- private static readonly ConcurrentTLruCache CacheResolverLru
+ private static readonly ConcurrentTLruCache CacheResolverLru
= new(1024, TimeSpan.FromSeconds(30));
///
@@ -187,7 +185,7 @@ public ImageSharpMiddleware(
private async Task Invoke(HttpContext httpContext, bool retry)
{
// Get the correct provider for the request
- IImageProvider provider = null;
+ IImageProvider? provider = null;
foreach (IImageProvider resolver in this.providers)
{
if (resolver.Match(httpContext))
@@ -209,7 +207,7 @@ private async Task Invoke(HttpContext httpContext, bool retry)
// First check for a HMAC token and capture before the command is stripped out.
byte[] secret = this.options.HMACSecretKey;
bool checkHMAC = false;
- string token = null;
+ string? token = null;
if (secret?.Length > 0)
{
checkHMAC = true;
@@ -220,7 +218,7 @@ private async Task Invoke(HttpContext httpContext, bool retry)
ImageCommandContext imageCommandContext = new(httpContext, commands, this.commandParser, this.parserCulture);
// At this point we know that this is an image request so should attempt to compute a validating HMAC.
- string hmac = null;
+ string? hmac = null;
if (checkHMAC && token != null)
{
// Generate and cache a HMAC to validate against based upon the current valid commands from the request.
@@ -255,7 +253,7 @@ private async Task Invoke(HttpContext httpContext, bool retry)
}
}
- IImageResolver sourceImageResolver = await provider.GetAsync(httpContext);
+ IImageResolver? sourceImageResolver = await provider.GetAsync(httpContext);
if (sourceImageResolver is null)
{
@@ -313,7 +311,7 @@ private async Task ProcessRequestAsync(
// Enter an asynchronous write worker which prevents multiple writes and delays any reads for the same request.
// This reduces the overheads of unnecessary processing.
- RecyclableMemoryStream outStream = null;
+ RecyclableMemoryStream? outStream = null;
try
{
Task takeLockTask = this.asyncKeyLock.WriterLockAsync(key);
@@ -347,16 +345,21 @@ private async Task ProcessRequestAsync(
using (Stream inStream = await sourceImageResolver.OpenReadAsync())
{
+ 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);
+
// No commands? We simply copy the stream across.
if (commands.Count == 0)
{
await inStream.CopyToAsync(outStream);
outStream.Position = 0;
- format = await Image.DetectFormatAsync(this.options.Configuration, outStream);
+ format = await Image.DetectFormatAsync(decoderOptions, outStream);
}
else
{
- FormattedImage image = null;
+ FormattedImage? image = null;
try
{
// Now we can finally process the image.
@@ -370,11 +373,11 @@ private async Task ProcessRequestAsync(
if (requiresAlpha)
{
- image = await FormattedImage.LoadAsync(this.options.Configuration, inStream);
+ image = await FormattedImage.LoadAsync(decoderOptions, inStream);
}
else
{
- image = await FormattedImage.LoadAsync(this.options.Configuration, inStream);
+ image = await FormattedImage.LoadAsync(decoderOptions, inStream);
}
image.Process(
@@ -438,7 +441,7 @@ private async Task ProcessRequestAsync(
}
}
- private static ValueTask StreamDisposeAsync(Stream stream)
+ private static ValueTask StreamDisposeAsync(Stream? stream)
{
if (stream is null)
{
@@ -460,12 +463,12 @@ private async Task IsNewOrUpdatedAsync(
// Check to see if the cache contains this image.
// If not, we return early. No further checks necessary.
- (IImageCacheResolver ImageCacheResolver, ImageCacheMetadata ImageCacheMetadata) cachedImage = await
+ (IImageCacheResolver? ImageCacheResolver, ImageCacheMetadata ImageCacheMetadata) cachedImage = await
CacheResolverLru.GetOrAddAsync(
key,
async k =>
{
- IImageCacheResolver resolver = await this.cache.GetAsync(k);
+ IImageCacheResolver? resolver = await this.cache.GetAsync(k);
ImageCacheMetadata metadata = default;
if (resolver != null)
{
@@ -503,8 +506,8 @@ private async Task SendResponseAsync(
ImageContext imageContext,
string key,
ImageCacheMetadata metadata,
- IImageCacheResolver cacheResolver,
- Stream stream,
+ IImageCacheResolver? cacheResolver,
+ Stream? stream,
bool retry)
{
imageContext.ComprehendRequestHeaders(metadata.CacheLastWriteTimeUtc, metadata.ContentLength);
@@ -531,6 +534,8 @@ private async Task SendResponseAsync(
{
try
{
+ Guard.NotNull(cacheResolver);
+
using Stream cacheStream = await cacheResolver.OpenReadAsync();
await imageContext.SendAsync(cacheStream, metadata);
}
diff --git a/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs b/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs
index ebb294e8..a1753f35 100644
--- a/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs
+++ b/src/ImageSharp.Web/Middleware/ImageSharpMiddlewareOptions.cs
@@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.AspNetCore.Http;
using Microsoft.IO;
+using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Web.Commands;
using SixLabors.ImageSharp.Web.Providers;
@@ -27,6 +27,7 @@ public class ImageSharpMiddlewareOptions
};
private Func onParseCommandsAsync = _ => Task.CompletedTask;
+ private Func onBeforeLoadAsync = (_, _) => Task.CompletedTask;
private Func onBeforeSaveAsync = _ => Task.CompletedTask;
private Func onProcessedAsync = _ => Task.CompletedTask;
private Func onPrepareResponseAsync = _ => Task.CompletedTask;
@@ -113,6 +114,21 @@ public Func 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.
+ ///
+ public Func OnBeforeLoadAsync
+ {
+ get => this.onBeforeLoadAsync;
+
+ set
+ {
+ Guard.NotNull(value, nameof(this.OnBeforeLoadAsync));
+ this.onBeforeLoadAsync = value;
+ }
+ }
+
///
/// Gets or sets the additional method that can be used for final manipulation before the image is saved.
/// This is called after image has been processed, but before the image has been saved to the output stream for caching.
diff --git a/src/ImageSharp.Web/Middleware/ImageWorkerResult.cs b/src/ImageSharp.Web/Middleware/ImageWorkerResult.cs
index f15a66a4..ee25c663 100644
--- a/src/ImageSharp.Web/Middleware/ImageWorkerResult.cs
+++ b/src/ImageSharp.Web/Middleware/ImageWorkerResult.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using SixLabors.ImageSharp.Web.Resolvers;
@@ -27,7 +26,7 @@ public ImageWorkerResult(ImageMetadata sourceImageMetadata, ImageCacheMetadata c
this.Resolver = resolver;
}
- public ImageWorkerResult(ImageCacheMetadata cacheImageMetadata, IImageCacheResolver resolver)
+ public ImageWorkerResult(ImageCacheMetadata cacheImageMetadata, IImageCacheResolver? resolver)
{
this.IsNewOrUpdated = false;
this.SourceImageMetadata = default;
@@ -41,5 +40,5 @@ public ImageWorkerResult(ImageCacheMetadata cacheImageMetadata, IImageCacheResol
public ImageCacheMetadata CacheImageMetadata { get; }
- public IImageCacheResolver Resolver { get; }
+ public IImageCacheResolver? Resolver { get; }
}
diff --git a/src/ImageSharp.Web/Middleware/LoggerExtensions.cs b/src/ImageSharp.Web/Middleware/LoggerExtensions.cs
index 84195f02..7f158e8a 100644
--- a/src/ImageSharp.Web/Middleware/LoggerExtensions.cs
+++ b/src/ImageSharp.Web/Middleware/LoggerExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.Logging;
@@ -12,10 +11,10 @@ namespace SixLabors.ImageSharp.Web.Middleware;
internal static class LoggerExtensions
{
private static readonly Action LogProcessingErrorAction;
- private static readonly Action LogResolveFailedAction;
- private static readonly Action LogServedAction;
- private static readonly Action LogPathNotModifiedAction;
- private static readonly Action LogPreconditionFailedAction;
+ private static readonly Action LogResolveFailedAction;
+ private static readonly Action LogServedAction;
+ private static readonly Action LogPathNotModifiedAction;
+ private static readonly Action LogPreconditionFailedAction;
///
/// Initializes static members of the class.
diff --git a/src/ImageSharp.Web/PathUtilities.cs b/src/ImageSharp.Web/PathUtilities.cs
index e3f6ef6b..719b2e27 100644
--- a/src/ImageSharp.Web/PathUtilities.cs
+++ b/src/ImageSharp.Web/PathUtilities.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web;
diff --git a/src/ImageSharp.Web/Processors/AutoOrientWebProcessor.cs b/src/ImageSharp.Web/Processors/AutoOrientWebProcessor.cs
index 392d58a5..fc081169 100644
--- a/src/ImageSharp.Web/Processors/AutoOrientWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/AutoOrientWebProcessor.cs
@@ -1,10 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
-using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Web.Commands;
namespace SixLabors.ImageSharp.Web.Processors;
diff --git a/src/ImageSharp.Web/Processors/BackgroundColorWebProcessor.cs b/src/ImageSharp.Web/Processors/BackgroundColorWebProcessor.cs
index 7fd82474..549fa716 100644
--- a/src/ImageSharp.Web/Processors/BackgroundColorWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/BackgroundColorWebProcessor.cs
@@ -1,10 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
-using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Web.Commands;
namespace SixLabors.ImageSharp.Web.Processors;
diff --git a/src/ImageSharp.Web/Processors/FormatWebProcessor.cs b/src/ImageSharp.Web/Processors/FormatWebProcessor.cs
index f8665dc4..f8093018 100644
--- a/src/ImageSharp.Web/Processors/FormatWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/FormatWebProcessor.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
@@ -50,16 +49,12 @@ public FormattedImage Process(
CommandParser parser,
CultureInfo culture)
{
- string extension = commands.GetValueOrDefault(Format);
+ string? extension = commands.GetValueOrDefault(Format);
- if (!string.IsNullOrWhiteSpace(extension))
+ if (!string.IsNullOrWhiteSpace(extension)
+ && this.options.Configuration.ImageFormatsManager.TryFindFormatByFileExtension(extension, out IImageFormat? format))
{
- IImageFormat format = this.options.Configuration.ImageFormatsManager.FindFormatByFileExtension(extension);
-
- if (format != null)
- {
- image.Format = format;
- }
+ image.Format = format;
}
return image;
diff --git a/src/ImageSharp.Web/Processors/IImageWebProcessor.cs b/src/ImageSharp.Web/Processors/IImageWebProcessor.cs
index 6e1f8a85..df0cdb22 100644
--- a/src/ImageSharp.Web/Processors/IImageWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/IImageWebProcessor.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
diff --git a/src/ImageSharp.Web/Processors/QualityWebProcessor.cs b/src/ImageSharp.Web/Processors/QualityWebProcessor.cs
index 76af983f..37d8e9da 100644
--- a/src/ImageSharp.Web/Processors/QualityWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/QualityWebProcessor.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
@@ -45,24 +44,30 @@ public FormattedImage Process(
if (image.Format is JpegFormat)
{
- var reference =
+ JpegEncoder reference =
(JpegEncoder)image.Image
.GetConfiguration()
.ImageFormatsManager
- .FindEncoder(image.Format);
+ .GetEncoder(image.Format);
if (quality != reference.Quality)
{
- image.Encoder = new JpegEncoder() { Quality = quality, ColorType = reference.ColorType };
+ image.Encoder = new JpegEncoder()
+ {
+ Quality = quality,
+ Interleaved = reference.Interleaved,
+ ColorType = reference.ColorType,
+ SkipMetadata = reference.SkipMetadata
+ };
}
}
else if (image.Format is WebpFormat)
{
- var reference =
+ WebpEncoder reference =
(WebpEncoder)image.Image
.GetConfiguration()
.ImageFormatsManager
- .FindEncoder(image.Format);
+ .GetEncoder(image.Format);
image.Encoder = new WebpEncoder()
{
@@ -76,6 +81,7 @@ public FormattedImage Process(
TransparentColorMode = reference.TransparentColorMode,
NearLossless = reference.NearLossless,
NearLosslessQuality = reference.NearLosslessQuality,
+ SkipMetadata = reference.SkipMetadata
};
}
}
diff --git a/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs b/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs
index 37a53a67..74e504b6 100644
--- a/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs
+++ b/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs
@@ -1,12 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using System.Numerics;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
-using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.ImageSharp.Web.Commands;
@@ -87,7 +85,7 @@ public FormattedImage Process(
CommandParser parser,
CultureInfo culture)
{
- ResizeOptions options = GetResizeOptions(image, commands, parser, culture);
+ ResizeOptions? options = GetResizeOptions(image, commands, parser, culture);
if (options != null)
{
@@ -107,7 +105,7 @@ public FormattedImage Process(
/// The to use as the current parsing culture.
///
/// The .
- internal static ResizeOptions GetResizeOptions(
+ internal static ResizeOptions? GetResizeOptions(
FormattedImage image,
CommandCollection commands,
CommandParser parser,
@@ -127,15 +125,18 @@ internal static ResizeOptions GetResizeOptions(
return null;
}
+ ResizeMode mode = GetMode(commands, parser, culture);
+
return new()
{
Size = size,
CenterCoordinates = GetCenter(orientation, commands, parser, culture),
Position = GetAnchor(orientation, commands, parser, culture),
- Mode = GetMode(commands, parser, culture),
+ Mode = mode,
Compand = GetCompandMode(commands, parser, culture),
Sampler = GetSampler(commands),
- PadColor = parser.ParseValue(commands.GetValueOrDefault(Color), culture)
+ PadColor = parser.ParseValue(commands.GetValueOrDefault(Color), culture),
+ TargetRectangle = mode is ResizeMode.Manual ? new Rectangle(0, 0, size.Width, size.Height) : null
};
}
@@ -165,7 +166,12 @@ private static Size ParseSize(
CommandParser parser,
CultureInfo culture)
{
- float[] coordinates = parser.ParseValue(commands.GetValueOrDefault(Xy), culture);
+ float[]? coordinates = parser.ParseValue(commands.GetValueOrDefault(Xy), culture);
+
+ if (coordinates is null)
+ {
+ return null;
+ }
if (coordinates.Length != 2)
{
@@ -200,7 +206,7 @@ private static bool GetCompandMode(
private static IResampler GetSampler(CommandCollection commands)
{
- string sampler = commands.GetValueOrDefault(Sampler);
+ string? sampler = commands.GetValueOrDefault(Sampler);
if (sampler != null)
{
diff --git a/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs b/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs
index 4c568b0a..ada16b3d 100644
--- a/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs
+++ b/src/ImageSharp.Web/Processors/WebProcessingExtensions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Globalization;
using Microsoft.Extensions.Logging;
diff --git a/src/ImageSharp.Web/Providers/FileProviderImageProvider.cs b/src/ImageSharp.Web/Providers/FileProviderImageProvider.cs
index c7dc3a5b..96f55441 100644
--- a/src/ImageSharp.Web/Providers/FileProviderImageProvider.cs
+++ b/src/ImageSharp.Web/Providers/FileProviderImageProvider.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
@@ -51,14 +50,18 @@ public virtual bool IsValidRequest(HttpContext context)
=> this.formatUtilities.TryGetExtensionFromUri(context.Request.GetDisplayUrl(), out _);
///
- public Task GetAsync(HttpContext context)
+ public Task GetAsync(HttpContext context)
{
- IFileInfo fileInfo = this.fileProvider.GetFileInfo(context.Request.Path.Value);
- if (!fileInfo.Exists)
+ string? path = context.Request.Path.Value;
+ if (path is not null)
{
- return Task.FromResult(null);
+ IFileInfo fileInfo = this.fileProvider.GetFileInfo(path);
+ if (fileInfo.Exists)
+ {
+ return Task.FromResult(new FileProviderImageResolver(fileInfo));
+ }
}
- return Task.FromResult(new FileProviderImageResolver(fileInfo));
+ return Task.FromResult(null);
}
}
diff --git a/src/ImageSharp.Web/Providers/IImageProvider.cs b/src/ImageSharp.Web/Providers/IImageProvider.cs
index a25e7525..6de0c68d 100644
--- a/src/ImageSharp.Web/Providers/IImageProvider.cs
+++ b/src/ImageSharp.Web/Providers/IImageProvider.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Http;
using SixLabors.ImageSharp.Web.Resolvers;
@@ -36,5 +35,5 @@ public interface IImageProvider
///
/// The current HTTP request context.
/// The .
- Task GetAsync(HttpContext context);
+ Task GetAsync(HttpContext context);
}
diff --git a/src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs b/src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs
index dddfe2f2..7634e20f 100644
--- a/src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs
+++ b/src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
diff --git a/src/ImageSharp.Web/Providers/PhysicalFileSystemProviderOptions.cs b/src/ImageSharp.Web/Providers/PhysicalFileSystemProviderOptions.cs
index f7b6f42e..57aaa99f 100644
--- a/src/ImageSharp.Web/Providers/PhysicalFileSystemProviderOptions.cs
+++ b/src/ImageSharp.Web/Providers/PhysicalFileSystemProviderOptions.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Providers;
@@ -21,7 +20,7 @@ public class PhysicalFileSystemProviderOptions
/// application content files; commonly 'wwwroot'.
///
///
- public string ProviderRootPath { get; set; }
+ public string? ProviderRootPath { get; set; }
///
/// Gets or sets the processing behavior. Defaults to .
diff --git a/src/ImageSharp.Web/Providers/WebRootImageProvider.cs b/src/ImageSharp.Web/Providers/WebRootImageProvider.cs
index 5c928dc3..a469dd11 100644
--- a/src/ImageSharp.Web/Providers/WebRootImageProvider.cs
+++ b/src/ImageSharp.Web/Providers/WebRootImageProvider.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.AspNetCore.Hosting;
diff --git a/src/ImageSharp.Web/Resolvers/FileProviderImageResolver.cs b/src/ImageSharp.Web/Resolvers/FileProviderImageResolver.cs
index af0c6bb0..d4d6f0f1 100644
--- a/src/ImageSharp.Web/Resolvers/FileProviderImageResolver.cs
+++ b/src/ImageSharp.Web/Resolvers/FileProviderImageResolver.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using Microsoft.Extensions.FileProviders;
diff --git a/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs b/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs
index 2d2b784a..b629bb86 100644
--- a/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs
+++ b/src/ImageSharp.Web/Resolvers/IImageCacheResolver.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Resolvers;
diff --git a/src/ImageSharp.Web/Resolvers/IImageResolver.cs b/src/ImageSharp.Web/Resolvers/IImageResolver.cs
index 935702b9..72d6dfb0 100644
--- a/src/ImageSharp.Web/Resolvers/IImageResolver.cs
+++ b/src/ImageSharp.Web/Resolvers/IImageResolver.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
namespace SixLabors.ImageSharp.Web.Resolvers;
diff --git a/src/ImageSharp.Web/Resolvers/PhysicalFileSystemCacheResolver.cs b/src/ImageSharp.Web/Resolvers/PhysicalFileSystemCacheResolver.cs
index 6494079b..ab6f4936 100644
--- a/src/ImageSharp.Web/Resolvers/PhysicalFileSystemCacheResolver.cs
+++ b/src/ImageSharp.Web/Resolvers/PhysicalFileSystemCacheResolver.cs
@@ -1,6 +1,5 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Web.Caching;
diff --git a/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs b/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs
index de4b8919..706c8f31 100644
--- a/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs
+++ b/tests/ImageSharp.Web.Tests/Processors/AutoOrientWebProcessorTests.cs
@@ -26,17 +26,17 @@ public void AutoOrientWebProcessor_UpdatesOrientation()
const ushort tl = 1;
const ushort br = 3;
- using var image = new Image(1, 1);
+ using Image image = new(1, 1);
image.Metadata.ExifProfile = new();
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, br);
- IExifValue orientation = image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
+ Assert.True(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out IExifValue orientation));
Assert.Equal(br, orientation.Value);
- using var formatted = new FormattedImage(image, PngFormat.Instance);
+ using FormattedImage formatted = new(image, PngFormat.Instance);
new AutoOrientWebProcessor().Process(formatted, null, commands, parser, culture);
- orientation = image.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
+ Assert.True(image.Metadata.ExifProfile.TryGetValue(ExifTag.Orientation, out orientation));
Assert.Equal(tl, orientation.Value);
}
}
diff --git a/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs b/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs
index 66ed89eb..982fb5ea 100644
--- a/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs
+++ b/tests/ImageSharp.Web.Tests/Processors/FormattedImageTests.cs
@@ -12,8 +12,8 @@ public class FormattedImageTests
[Fact]
public void ConstructorSetsProperties()
{
- using var image = new Image(1, 1);
- using var formatted = new FormattedImage(image, JpegFormat.Instance);
+ using Image image = new(1, 1);
+ using FormattedImage formatted = new(image, JpegFormat.Instance);
Assert.NotNull(formatted.Image);
Assert.Equal(image, formatted.Image);
@@ -28,8 +28,8 @@ public void ConstructorSetsProperties()
[Fact]
public void CanSetFormat()
{
- using var image = new Image(1, 1);
- using var formatted = new FormattedImage(image, JpegFormat.Instance);
+ using Image image = new(1, 1);
+ using FormattedImage formatted = new(image, JpegFormat.Instance);
Assert.NotNull(formatted.Format);
Assert.Equal(JpegFormat.Instance, formatted.Format);
@@ -44,8 +44,8 @@ public void CanSetFormat()
[Fact]
public void CanSetEncoder()
{
- using var image = new Image(1, 1);
- using var formatted = new FormattedImage(image, PngFormat.Instance);
+ using Image image = new(1, 1);
+ using FormattedImage formatted = new(image, PngFormat.Instance);
Assert.NotNull(formatted.Format);
Assert.Equal(PngFormat.Instance, formatted.Format);
@@ -56,14 +56,14 @@ public void CanSetEncoder()
formatted.Format = JpegFormat.Instance;
Assert.Equal(typeof(JpegEncoder), formatted.Encoder.GetType());
- JpegColorType current = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault();
+ JpegEncodingColor current = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault();
- Assert.Equal(JpegColorType.YCbCrRatio420, current);
- formatted.Encoder = new JpegEncoder { ColorType = JpegColorType.YCbCrRatio444 };
+ Assert.Equal(JpegEncodingColor.YCbCrRatio420, current);
+ formatted.Encoder = new JpegEncoder { ColorType = JpegEncodingColor.YCbCrRatio444 };
- JpegColorType replacement = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault();
+ JpegEncodingColor replacement = ((JpegEncoder)formatted.Encoder).ColorType.GetValueOrDefault();
Assert.NotEqual(current, replacement);
- Assert.Equal(JpegColorType.YCbCrRatio444, replacement);
+ Assert.Equal(JpegEncodingColor.YCbCrRatio444, replacement);
}
}
diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs
index 5af0560e..bbfb8a5d 100644
--- a/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs
+++ b/tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs
@@ -44,7 +44,7 @@ private static async Task InitializeAWSStorageAsync(IServiceProvider services, A
{
try
{
- var putBucketRequest = new PutBucketRequest
+ PutBucketRequest putBucketRequest = new()
{
BucketName = bucketOptions.BucketName,
BucketRegion = bucketOptions.Region,
@@ -57,7 +57,7 @@ private static async Task InitializeAWSStorageAsync(IServiceProvider services, A
{
// CI tests are run in parallel and can sometimes return a
// false negative for the existance of a bucket.
- if (string.Equals(e.ErrorCode, "BucketAlreadyExists"))
+ if (string.Equals(e.ErrorCode, "BucketAlreadyExists", StringComparison.Ordinal))
{
return;
}
@@ -84,14 +84,14 @@ private static async Task InitializeAWSStorageAsync(IServiceProvider services, A
using Stream stream = file.CreateReadStream();
// Set the max-age property so we get coverage for testing in our AWS provider.
- var cacheControl = new CacheControlHeaderValue
+ CacheControlHeaderValue cacheControl = new()
{
Public = true,
MaxAge = TimeSpan.FromDays(7),
MustRevalidate = true
};
- var putRequest = new PutObjectRequest()
+ PutObjectRequest putRequest = new()
{
BucketName = bucketOptions.BucketName,
Key = TestConstants.ImagePath,
diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/ServerTestBase.cs b/tests/ImageSharp.Web.Tests/TestUtilities/ServerTestBase.cs
index f9fa82a2..6d8b5e83 100644
--- a/tests/ImageSharp.Web.Tests/TestUtilities/ServerTestBase.cs
+++ b/tests/ImageSharp.Web.Tests/TestUtilities/ServerTestBase.cs
@@ -42,7 +42,7 @@ public async Task CanProcessAndResolveImageAsync()
string url = this.ImageSource;
string ext = Path.GetExtension(url);
- IImageFormat format = Configuration.Default.ImageFormatsManager.FindFormatByFileExtension(ext);
+ Assert.True(Configuration.Default.ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format));
// First response
HttpResponseMessage response = await this.HttpClient.GetAsync(url + await this.AugmentCommandAsync(this.Fixture.Commands[0]));
@@ -52,11 +52,10 @@ public async Task CanProcessAndResolveImageAsync()
Assert.True(response.Content.Headers.ContentLength > 0);
Assert.Equal(format.DefaultMimeType, response.Content.Headers.ContentType.MediaType);
- (Image Image, IImageFormat Format) actual = await Image.LoadWithFormatAsync(await response.Content.ReadAsStreamAsync());
- using Image image = actual.Image;
+ using Image image = await Image.LoadAsync(await response.Content.ReadAsStreamAsync());
Assert.Equal(Width, image.Width);
- Assert.Equal(format, actual.Format);
+ Assert.Equal(format, image.Metadata.DecodedImageFormat);
response.Dispose();
@@ -68,16 +67,15 @@ public async Task CanProcessAndResolveImageAsync()
Assert.True(response.Content.Headers.ContentLength > 0);
Assert.Equal(format.DefaultMimeType, response.Content.Headers.ContentType.MediaType);
- (Image Image, IImageFormat Format) cachedActual = await Image.LoadWithFormatAsync(await response.Content.ReadAsStreamAsync());
- using Image cached = cachedActual.Image;
+ using Image cached = await Image.LoadAsync(await response.Content.ReadAsStreamAsync());
Assert.Equal(Width, cached.Width);
- Assert.Equal(format, actual.Format);
+ Assert.Equal(format, image.Metadata.DecodedImageFormat);
response.Dispose();
// 304 response
- var request = new HttpRequestMessage
+ HttpRequestMessage request = new()
{
RequestUri = new Uri(url + await this.AugmentCommandAsync(this.Fixture.Commands[0])),
Method = HttpMethod.Get,
@@ -133,7 +131,7 @@ public async Task CanProcessMultipleIdenticalQueriesAsync()
Assert.True(response.Content.Headers.ContentLength > 0);
})).ToArray();
- var all = Task.WhenAll(tasks);
+ Task all = Task.WhenAll(tasks);
await all;
Assert.True(all.IsCompletedSuccessfully);
}
diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/TestConstants.cs b/tests/ImageSharp.Web.Tests/TestUtilities/TestConstants.cs
index bc1ba269..26c64845 100644
--- a/tests/ImageSharp.Web.Tests/TestUtilities/TestConstants.cs
+++ b/tests/ImageSharp.Web.Tests/TestUtilities/TestConstants.cs
@@ -8,7 +8,7 @@ public static class TestConstants
public const string AzureConnectionString = "UseDevelopmentStorage=true";
public const string AzureContainerName = "azure";
public const string AzureCacheContainerName = "is-cache";
- public const string AWSEndpoint = "http://127.0.0.1:4568/";
+ public const string AWSEndpoint = "http://localhost:4568/";
public const string AWSRegion = "eu-west-2";
public const string AWSBucketName = "aws";
public const string AWSCacheBucketName = "aws-cache";
diff --git a/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs b/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs
index 12ed053d..a9f68eed 100644
--- a/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs
+++ b/tests/ImageSharp.Web.Tests/TestUtilities/TestServerFixture.cs
@@ -7,6 +7,7 @@
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Web.DependencyInjection;
using SixLabors.ImageSharp.Web.Middleware;
@@ -67,6 +68,16 @@ protected void ConfigureServices(IServiceCollection services)
return onParseCommandsAsync.Invoke(context);
};
+ Func onBeforeLoadAsync = options.OnBeforeLoadAsync;
+
+ options.OnBeforeLoadAsync = (context, decoderOptions) =>
+ {
+ Assert.NotNull(context);
+ Assert.NotNull(decoderOptions);
+
+ return onBeforeLoadAsync.Invoke(context, decoderOptions);
+ };
+
Func onProcessedAsync = options.OnProcessedAsync;
options.OnProcessedAsync = context =>