diff --git a/.editorconfig b/.editorconfig
index 06e698247..0e4883082 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -368,8 +368,6 @@ csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
-csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_for_built_in_types = never
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = false:warning
-
-csharp_prefer_simple_using_statement = false:silent
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 40878c575..f1d4afef4 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -334,6 +334,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests.ProfilingS
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{2aa31a1f-142c-43f4-8687-09abca4b3a26}*SharedItemsImports = 5
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/shared-infrastructure b/shared-infrastructure
index 36b2d55f5..8dfef29f1 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 36b2d55f5bb0d91024955bd26ba220ee41cc96e5
+Subproject commit 8dfef29f1838da76be9596f1a2f1be6d93e453d3
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 2c13e469f..a78a75d42 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -34,4 +34,6 @@
+
+
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 68d4f8949..055a6803e 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -52,4 +52,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
index 971bff322..5d8668257 100644
--- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
@@ -2,9 +2,11 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Memory;
+#if !SUPPORTS_SPAN_STREAM
+using System.Buffers;
+#endif
namespace SixLabors.ImageSharp
{
diff --git a/src/ImageSharp/Common/Helpers/Guard.Numeric.cs b/src/ImageSharp/Common/Helpers/Guard.Numeric.cs
new file mode 100644
index 000000000..72262e0b9
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/Guard.Numeric.cs
@@ -0,0 +1,1154 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors
+{
+ ///
+ /// Provides methods to protect against invalid parameters.
+ ///
+ internal static partial class Guard
+ {
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(byte value, byte max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(byte value, byte max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(byte value, byte min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(byte value, byte min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(byte value, byte min, byte max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(sbyte value, sbyte max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(sbyte value, sbyte max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(sbyte value, sbyte min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(sbyte value, sbyte min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(sbyte value, sbyte min, sbyte max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(short value, short max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(short value, short max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(short value, short min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(short value, short min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(short value, short min, short max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(ushort value, ushort max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(ushort value, ushort max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(ushort value, ushort min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(ushort value, ushort min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(ushort value, ushort min, ushort max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(char value, char max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(char value, char max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(char value, char min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(char value, char min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(char value, char min, char max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(int value, int max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(int value, int max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(int value, int min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(int value, int min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(int value, int min, int max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(uint value, uint max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(uint value, uint max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(uint value, uint min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(uint value, uint min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(uint value, uint min, uint max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(float value, float max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(float value, float max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(float value, float min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(float value, float min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(float value, float min, float max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(long value, long max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(long value, long max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(long value, long min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(long value, long min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(long value, long min, long max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(ulong value, ulong max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(ulong value, ulong max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(ulong value, ulong min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(ulong value, ulong min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(ulong value, ulong min, ulong max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(double value, double max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(double value, double max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(double value, double min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(double value, double min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(double value, double min, double max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+
+ ///
+ /// Ensures that the specified value is less than a maximum value.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThan(decimal value, decimal max, string parameterName)
+ {
+ if (value >= max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is less than or equal to a maximum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeLessThanOrEqualTo(decimal value, decimal max, string parameterName)
+ {
+ if (value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThan(decimal value, decimal min, string parameterName)
+ {
+ if (value <= min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value
+ /// and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeGreaterThanOrEqualTo(decimal value, decimal min, string parameterName)
+ {
+ if (value < min)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName);
+ }
+ }
+
+ ///
+ /// Verifies that the specified value is greater than or equal to a minimum value and less than
+ /// or equal to a maximum value and throws an exception if it is not.
+ ///
+ /// The target value, which should be validated.
+ /// The minimum value.
+ /// The maximum value.
+ /// The name of the parameter that is to be checked.
+ ///
+ /// is less than the minimum value of greater than the maximum value.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MustBeBetweenOrEqualTo(decimal value, decimal min, decimal max, string parameterName)
+ {
+ if (value < min || value > max)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName);
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index 1d215d286..3ab1b199a 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -22,7 +22,7 @@ namespace SixLabors
{
if (!value.GetType().GetTypeInfo().IsValueType)
{
- ThrowArgumentException("Type must be a struct.", parameterName);
+ ThrowHelper.ThrowArgumentException("Type must be a struct.", parameterName);
}
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs
index c9d631da0..06c4b3fc6 100644
--- a/src/ImageSharp/Formats/Gif/GifConstants.cs
+++ b/src/ImageSharp/Formats/Gif/GifConstants.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Collections.Generic;
using System.Text;
@@ -21,11 +22,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
public const string FileVersion = "89a";
- ///
- /// The ASCII encoded bytes used to identify the GIF file.
- ///
- internal static readonly byte[] MagicNumber = Encoding.ASCII.GetBytes(FileType + FileVersion);
-
///
/// The extension block introducer !.
///
@@ -51,11 +47,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
public const string NetscapeApplicationIdentification = "NETSCAPE2.0";
- ///
- /// The ASCII encoded application identification bytes.
- ///
- internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.ASCII.GetBytes(NetscapeApplicationIdentification);
-
///
/// The Netscape looping application sub block size.
///
@@ -110,5 +101,25 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The collection of file extensions that equate to a Gif.
///
public static readonly IEnumerable FileExtensions = new[] { "gif" };
+
+ ///
+ /// Gets the ASCII encoded bytes used to identify the GIF file (combining and ).
+ ///
+ internal static ReadOnlySpan MagicNumber => new[]
+ {
+ (byte)'G', (byte)'I', (byte)'F',
+ (byte)'8', (byte)'9', (byte)'a'
+ };
+
+ ///
+ /// Gets the ASCII encoded application identification bytes (representing ).
+ ///
+ internal static ReadOnlySpan NetscapeApplicationIdentificationBytes => new[]
+ {
+ (byte)'N', (byte)'E', (byte)'T',
+ (byte)'S', (byte)'C', (byte)'A',
+ (byte)'P', (byte)'E',
+ (byte)'2', (byte)'.', (byte)'0'
+ };
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index dcd0be34b..a591eaf3b 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
///
/// The stream to write to.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteHeader(Stream stream) => stream.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length);
+ private void WriteHeader(Stream stream) => stream.Write(GifConstants.MagicNumber);
///
/// Writes the logical screen descriptor to the stream.
diff --git a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
index 8af5b81c2..5e26370ba 100644
--- a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
+++ b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs
@@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
buffer[0] = GifConstants.ApplicationBlockSize;
// Write NETSCAPE2.0
- GifConstants.NetscapeApplicationIdentificationBytes.AsSpan().CopyTo(buffer.Slice(1, 11));
+ GifConstants.NetscapeApplicationIdentificationBytes.CopyTo(buffer.Slice(1, 11));
// Application Data ----
buffer[12] = 3; // Application block length (always 3)
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
index 54633a5d7..87b486ea6 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
@@ -1,8 +1,7 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
@@ -12,24 +11,38 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
internal static class ProfileResolver
{
///
- /// Describes the JFIF specific markers.
+ /// Gets the JFIF specific markers.
///
- public static readonly byte[] JFifMarker = Encoding.ASCII.GetBytes("JFIF\0");
+ public static ReadOnlySpan JFifMarker => new[]
+ {
+ (byte)'J', (byte)'F', (byte)'I', (byte)'F', (byte)'\0'
+ };
///
- /// Describes the ICC specific markers.
+ /// Gets the ICC specific markers.
///
- public static readonly byte[] IccMarker = Encoding.ASCII.GetBytes("ICC_PROFILE\0");
+ public static ReadOnlySpan IccMarker => new[]
+ {
+ (byte)'I', (byte)'C', (byte)'C', (byte)'_',
+ (byte)'P', (byte)'R', (byte)'O', (byte)'F',
+ (byte)'I', (byte)'L', (byte)'E', (byte)'\0'
+ };
///
- /// Describes the EXIF specific markers.
+ /// Gets the EXIF specific markers.
///
- public static readonly byte[] ExifMarker = Encoding.ASCII.GetBytes("Exif\0\0");
+ public static ReadOnlySpan ExifMarker => new[]
+ {
+ (byte)'E', (byte)'x', (byte)'i', (byte)'f', (byte)'\0', (byte)'\0'
+ };
///
- /// Describes Adobe specific markers .
+ /// Gets the Adobe specific markers .
///
- public static readonly byte[] AdobeMarker = Encoding.ASCII.GetBytes("Adobe");
+ public static ReadOnlySpan AdobeMarker => new[]
+ {
+ (byte)'A', (byte)'d', (byte)'o', (byte)'b', (byte)'e'
+ };
///
/// Returns a value indicating whether the passed bytes are a match to the profile identifier.
@@ -43,4 +56,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
&& bytesToCheck.Slice(0, profileIdentifier.Length).SequenceEqual(profileIdentifier);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
index 059e2052b..669abad28 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
@@ -34,12 +34,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public fixed byte Data[Size];
///
- /// Unzig maps from the zigzag ordering to the natural ordering. For example,
- /// unzig[3] is the column and row of the fourth element in zigzag order. The
- /// value is 16, which means first column (16%8 == 0) and third row (16/8 == 2).
+ /// Gets the unzigs map, which maps from the zigzag ordering to the natural ordering.
+ /// For example, unzig[3] is the column and row of the fourth element in zigzag order.
+ /// The value is 16, which means first column (16%8 == 0) and third row (16/8 == 2).
///
- private static readonly byte[] Unzig =
- new byte[Size]
+ private static ReadOnlySpan Unzig => new byte[]
{
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
@@ -75,8 +74,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public static ZigZag CreateUnzigTable()
{
ZigZag result = default;
- byte* unzigPtr = result.Data;
- Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, Size);
+ ref byte sourceRef = ref MemoryMarshal.GetReference(Unzig);
+ ref byte destinationRef = ref Unsafe.AsRef(result.Data);
+
+ Unzig.CopyTo(new Span(result.Data, Size));
+
return result;
}
diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs
index 632460ec4..247bb3c75 100644
--- a/src/ImageSharp/Formats/Png/PngConstants.cs
+++ b/src/ImageSharp/Formats/Png/PngConstants.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Collections.Generic;
using System.Text;
@@ -36,21 +37,6 @@ namespace SixLabors.ImageSharp.Formats.Png
///
public static readonly IEnumerable FileExtensions = new[] { "png" };
- ///
- /// The header bytes identifying a Png.
- ///
- public static readonly byte[] HeaderBytes =
- {
- 0x89, // Set the high bit.
- 0x50, // P
- 0x4E, // N
- 0x47, // G
- 0x0D, // Line ending CRLF
- 0x0A, // Line ending CRLF
- 0x1A, // EOF
- 0x0A // LF
- };
-
///
/// The header bytes as a big-endian coded ulong.
///
@@ -77,5 +63,20 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The minimum length of a keyword in a text chunk is 1 byte.
///
public const int MinTextKeywordLength = 1;
+
+ ///
+ /// Gets the header bytes identifying a Png.
+ ///
+ public static ReadOnlySpan HeaderBytes => new byte[]
+ {
+ 0x89, // Set the high bit.
+ 0x50, // P
+ 0x4E, // N
+ 0x47, // G
+ 0x0D, // Line ending CRLF
+ 0x0A, // Line ending CRLF
+ 0x1A, // EOF
+ 0x0A // LF
+ };
}
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 8dbfc25d7..2d8d66c33 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Png
IndexedImageFrame quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image);
this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized);
- stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length);
+ stream.Write(PngConstants.HeaderBytes);
this.WriteHeaderChunk(stream);
this.WritePaletteChunk(stream, quantized);
diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
index e8dd8a520..543a1fe30 100644
--- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
+++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs
@@ -36,12 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private const int EofSymbol = 256;
- // The lengths of the bit length codes are sent in order of decreasing
- // probability, to avoid transmitting the lengths for unused bit length codes.
- private static readonly int[] BitLengthOrder = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
-
- private static readonly byte[] Bit4Reverse = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-
private static readonly short[] StaticLCodes;
private static readonly byte[] StaticLLength;
private static readonly short[] StaticDCodes;
@@ -128,6 +122,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer;
}
+ ///
+ /// Gets the lengths of the bit length codes are sent in order of decreasing probability, to avoid transmitting the lengths for unused bit length codes.
+ ///
+ private static ReadOnlySpan BitLengthOrder => new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ private static ReadOnlySpan Bit4Reverse => new byte[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+
///
/// Gets the pending buffer to use.
///
@@ -158,6 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.Pending.WriteBits(this.literalTree.NumCodes - 257, 5);
this.Pending.WriteBits(this.distTree.NumCodes - 1, 5);
this.Pending.WriteBits(blTreeCodes - 4, 4);
+
for (int rank = 0; rank < blTreeCodes; rank++)
{
this.Pending.WriteBits(this.blTree.Length[BitLengthOrder[rank]], 3);
@@ -250,6 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.blTree.BuildTree();
int blTreeCodes = 4;
+
for (int i = 18; i > blTreeCodes; i--)
{
if (this.blTree.Length[BitLengthOrder[i]] > 0)
@@ -363,10 +366,30 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
[MethodImpl(InliningOptions.ShortMethod)]
public static short BitReverse(int toReverse)
{
- return (short)(Bit4Reverse[toReverse & 0xF] << 12
- | Bit4Reverse[(toReverse >> 4) & 0xF] << 8
- | Bit4Reverse[(toReverse >> 8) & 0xF] << 4
- | Bit4Reverse[toReverse >> 12]);
+ /* Use unsafe offsetting and manually validate the input index to reduce the
+ * total number of conditional branches. There are two main cases to test here:
+ * 1. In the first 3, the input value (or some combination of it) is combined
+ * with & 0xF, which results in a maximum value of 0xF no matter what the
+ * input value was. That is 15, which is always in range for the target span.
+ * As a result, no input validation is needed at all in this case.
+ * 2. There are two cases where the input value might cause an invalid access:
+ * when it is either negative, or greater than 15 << 12. We can test both
+ * conditions in a single pass by casting the input value to uint and right
+ * shifting it by 12, which also preserves the sign. If it is a negative
+ * value (2-complement), the test will fail as the uint cast will result
+ * in a much larger value. If the value was simply too high, the test will
+ * fail as expected. We can't simply check whether the value is lower than
+ * 15 << 12, because higher values are acceptable in the first 3 accesses.
+ * Doing this reduces the total number of index checks from 4 down to just 1. */
+ int toReverseRightShiftBy12 = toReverse >> 12;
+ Guard.MustBeLessThanOrEqualTo((uint)toReverseRightShiftBy12, 15, nameof(toReverse));
+
+ ref byte bit4ReverseRef = ref MemoryMarshal.GetReference(Bit4Reverse);
+
+ return (short)(Unsafe.Add(ref bit4ReverseRef, toReverse & 0xF) << 12
+ | Unsafe.Add(ref bit4ReverseRef, (toReverse >> 4) & 0xF) << 8
+ | Unsafe.Add(ref bit4ReverseRef, (toReverse >> 8) & 0xF) << 4
+ | Unsafe.Add(ref bit4ReverseRef, toReverseRightShiftBy12));
}
///
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index be0e9032b..24d4f4a00 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -37,6 +37,16 @@
+
+
+ True
+ True
+ Guard.Numeric.tt
+
+
True
True
@@ -202,6 +212,10 @@
DefaultPixelBlenders.Generated.cs
TextTemplatingFileGenerator
+
+ Guard.Numeric.cs
+ TextTemplatingFileGenerator
+
@@ -209,5 +223,4 @@
-
diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs
index c7112c47a..c58b224e4 100644
--- a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs
+++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs
@@ -1,11 +1,13 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
+
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal static class ExifConstants
{
- public static readonly byte[] LittleEndianByteOrderMarker =
+ public static ReadOnlySpan LittleEndianByteOrderMarker => new byte[]
{
(byte)'I',
(byte)'I',
@@ -13,7 +15,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
0x00,
};
- public static readonly byte[] BigEndianByteOrderMarker =
+ public static ReadOnlySpan BigEndianByteOrderMarker => new byte[]
{
(byte)'M',
(byte)'M',
@@ -21,4 +23,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
0x2A
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
index c068461b2..b00813730 100644
--- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
+++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
@@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
int i = 0;
// The byte order marker for little-endian, followed by the number 42 and a 0
- ExifConstants.LittleEndianByteOrderMarker.AsSpan().CopyTo(result.AsSpan(start: i));
+ ExifConstants.LittleEndianByteOrderMarker.CopyTo(result.AsSpan(start: i));
i += ExifConstants.LittleEndianByteOrderMarker.Length;
uint ifdOffset = ((uint)i - startIndex) + 4U;
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
index 94127432b..8184f1577 100644
--- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
@@ -13,7 +13,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
-
///
/// Returns the result of the "NormalSrc" compositing equation.
///
@@ -419,7 +418,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "MultiplySrc" compositing equation.
///
@@ -825,7 +823,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "AddSrc" compositing equation.
///
@@ -1231,7 +1228,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "SubtractSrc" compositing equation.
///
@@ -1637,7 +1633,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "ScreenSrc" compositing equation.
///
@@ -2043,7 +2038,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "DarkenSrc" compositing equation.
///
@@ -2449,7 +2443,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "LightenSrc" compositing equation.
///
@@ -2855,7 +2848,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "OverlaySrc" compositing equation.
///
@@ -3261,7 +3253,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
return dest;
}
-
///
/// Returns the result of the "HardLightSrc" compositing equation.
///
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
index 433ac4567..ce2e406d4 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
@@ -139,14 +139,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
private sealed class Octree
{
- ///
- /// Mask used when getting the appropriate pixels for a given node.
- ///
- private static readonly byte[] Mask = new byte[]
- {
- 0b10000000, 0b1000000, 0b100000, 0b10000, 0b1000, 0b100, 0b10, 0b1
- };
-
///
/// The root of the Octree
///
@@ -183,6 +175,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.previousNode = null;
}
+ ///
+ /// Gets the mask used when getting the appropriate pixels for a given node.
+ ///
+ private static ReadOnlySpan Mask => new byte[]
+ {
+ 0b10000000,
+ 0b1000000,
+ 0b100000,
+ 0b10000,
+ 0b1000,
+ 0b100,
+ 0b10,
+ 0b1
+ };
+
///
/// Gets or sets the number of leaves in the tree
///
@@ -530,8 +537,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetColorIndex(ref Rgba32 color, int level)
{
+ DebugGuard.MustBeLessThan(level, Mask.Length, nameof(level));
+
int shift = 7 - level;
- byte mask = Mask[level];
+ ref byte maskRef = ref MemoryMarshal.GetReference(Mask);
+ byte mask = Unsafe.Add(ref maskRef, level);
+
return ((color.R & mask) >> shift)
| ((color.G & mask) >> (shift - 1))
| ((color.B & mask) >> (shift - 2));
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
index c908abc50..fb09065b0 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Text;
@@ -19,25 +19,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[Fact]
public void ProfileResolverHasCorrectJFifMarker()
{
- Assert.Equal(JFifMarker, ProfileResolver.JFifMarker);
+ Assert.Equal(JFifMarker, ProfileResolver.JFifMarker.ToArray());
}
[Fact]
public void ProfileResolverHasCorrectExifMarker()
{
- Assert.Equal(ExifMarker, ProfileResolver.ExifMarker);
+ Assert.Equal(ExifMarker, ProfileResolver.ExifMarker.ToArray());
}
[Fact]
public void ProfileResolverHasCorrectIccMarker()
{
- Assert.Equal(IccMarker, ProfileResolver.IccMarker);
+ Assert.Equal(IccMarker, ProfileResolver.IccMarker.ToArray());
}
[Fact]
public void ProfileResolverHasCorrectAdobeMarker()
{
- Assert.Equal(AdobeMarker, ProfileResolver.AdobeMarker);
+ Assert.Equal(AdobeMarker, ProfileResolver.AdobeMarker.ToArray());
}
[Fact]
@@ -76,4 +76,4 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.False(ProfileResolver.IsProfile(AdobeMarker, ProfileResolver.IccMarker));
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs
index 0b2274581..9ea6a305c 100644
--- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs
+++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.AddFrame((ImageFrame)null);
});
- Assert.StartsWith("Value cannot be null.", ex.Message);
+ Assert.StartsWith("Parameter \"frame\" must be not null.", ex.Message);
}
[Fact]
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.AddFrame(data);
});
- Assert.StartsWith("Value cannot be null.", ex.Message);
+ Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message);
}
[Fact]
@@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.AddFrame(new Rgba32[0]);
});
- Assert.StartsWith("Value 0 must be greater than or equal to 100.", ex.Message);
+ Assert.StartsWith($"Parameter \"data\" ({typeof(int)}) must be greater than or equal to {100}, was {0}", ex.Message);
}
[Fact]
@@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.InsertFrame(1, null);
});
- Assert.StartsWith("Value cannot be null.", ex.Message);
+ Assert.StartsWith("Parameter \"frame\" must be not null.", ex.Message);
}
[Fact]
diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs
index b0008d394..08e6f8e1f 100644
--- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs
+++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.AddFrame(null);
});
- Assert.StartsWith("Value cannot be null.", ex.Message);
+ Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message);
}
[Fact]
@@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests
this.Collection.InsertFrame(1, null);
});
- Assert.StartsWith("Value cannot be null.", ex.Message);
+ Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message);
}
[Fact]
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
index 79bf76545..7069b0346 100644
--- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
+++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
@@ -394,7 +394,7 @@ namespace SixLabors.ImageSharp.Tests
public void ProfileToByteArray()
{
// Arrange
- byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker;
+ byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker.ToArray();
ExifProfile expectedProfile = CreateExifProfile();
var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList();