diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..0392d3e02
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,93 @@
+[*.cs]
+# Use soft tabs (spaces) for indentation
+indent_style = space
+
+# Indent switch case contents
+csharp_indent_case_contents = true
+
+# Indent switch labels
+csharp_indent_switch_labels = true
+
+# Place catch statements on a new line
+csharp_new_line_before_catch = true
+
+# Place else statements on a new line
+csharp_new_line_before_else = true
+
+# Require finally statements to be on a new line after the closing brace
+csharp_new_line_before_finally = true
+
+# Require braces to be on a new line for types, properties, lambdas, object_collection_array_initializers, methods, control_blocks, and accessors (also known as "Allman" style)
+csharp_new_line_before_open_brace = types, properties, lambdas, object_collection_array_initializers, methods, control_blocks, accessors
+
+# Sort System.* using directives alphabetically, and place them before other usings
+dotnet_sort_system_directives_first = true
+
+# Require NO space between a cast and the value
+csharp_space_after_cast = false
+
+# Require a space before the colon for bases or interfaces in a type declaration
+csharp_space_after_colon_in_inheritance_clause = true
+
+# Require a space after a keyword in a control flow statement such as a for loop
+csharp_space_after_keywords_in_control_flow_statements = true
+
+# Require a space before the colon for bases or interfaces in a type declaration
+csharp_space_before_colon_in_inheritance_clause = true
+
+# Remove space within empty argument list parentheses
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+
+# Remove space between method call name and opening parenthesis
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+
+# Do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
+csharp_space_between_method_call_parameter_list_parentheses = false
+
+# Remove space within empty parameter list parentheses for a method declaration
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+
+# Place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+
+# Leave code block on single line
+csharp_preserve_single_line_blocks = true
+
+# Prefer expression-bodied members for accessors
+csharp_style_expression_bodied_accessors = true:suggestion
+
+# Prefer expression-bodied members for constructors
+csharp_style_expression_bodied_constructors = true:suggestion
+
+# Prefer expression-bodied members for indexers
+csharp_style_expression_bodied_indexers = true:suggestion
+
+# Prefer expression-bodied members for methods
+csharp_style_expression_bodied_methods = true:suggestion
+
+# Prefer expression-bodied members for properties
+csharp_style_expression_bodied_properties = true:suggestion
+
+# Prefer out variables to be declared inline in the argument list of a method call when possible
+csharp_style_inlined_variable_declaration = true:suggestion
+
+# Prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Prefer explicit type over var to declare variables with built-in system types such as int
+csharp_style_var_for_built_in_types = false:suggestion
+
+# Prefer var when the type is already mentioned on the right-hand side of a declaration expression
+csharp_style_var_when_type_is_apparent = true:suggestion
+
+# Prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+
+# Prefer fields to be prefaced with this. in C# or Me. in Visual Basic
+dotnet_style_qualification_for_field = true:suggestion
+
+# Prefer methods to be prefaced with this. in C# or Me. in Visual Basic
+dotnet_style_qualification_for_method = true:suggestion
+
+# Prefer properties to be prefaced with this. in C# or Me. in Visual Basic
+dotnet_style_qualification_for_property = true:suggestion
diff --git a/ImageProcessor.sln b/ImageProcessor.sln
index 8fc6482a2..e49199a71 100644
--- a/ImageProcessor.sln
+++ b/ImageProcessor.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2026
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{5368AF57-74ED-4499-BCCD-38BCB18C4629}"
EndProject
@@ -34,13 +34,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{4E1AB050
build\build.ps1 = build\build.ps1
EndProjectSection
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Readme", "Readme", "{1F68939E-8BBE-4D09-98B5-68B06BBDE68E}"
- ProjectSection(SolutionItems) = preProject
- LICENSE = LICENSE
- README.md = README.md
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Nuspecs", "Nuspecs", "{E0B81C77-6E29-4500-9E9F-F0B72EBE8241}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{E0B81C77-6E29-4500-9E9F-F0B72EBE8241}"
ProjectSection(SolutionItems) = preProject
build\NuSpecs\ImageProcessor.nuspec = build\NuSpecs\ImageProcessor.nuspec
build\NuSpecs\ImageProcessor.Plugins.Cair.nuspec = build\NuSpecs\ImageProcessor.Plugins.Cair.nuspec
@@ -81,6 +75,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ImageProcessor.Web.Plugins.
build\content\ImageProcessor.Web.Plugins.AmazonS3Cache\config\imageprocessor\cache.config.transform = build\content\ImageProcessor.Web.Plugins.AmazonS3Cache\config\imageprocessor\cache.config.transform
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57BBD0FE-E8BB-45EF-B7EE-EB7669192D0D}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ .gitattributes = .gitattributes
+ .gitignore = .gitignore
+ LICENSE = LICENSE
+ NuGet.config = NuGet.config
+ README.md = README.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
All|Any CPU = All|Any CPU
@@ -167,6 +171,7 @@ Global
{633B1C4C-4823-47BE-9A01-A665F3118C8C} = {0E113662-D6E2-473E-92BA-6005EB412C00}
{ADAF0E0D-0CE9-45C2-AF95-70443273C468} = {0E113662-D6E2-473E-92BA-6005EB412C00}
{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7} = {0E113662-D6E2-473E-92BA-6005EB412C00}
+ {4E1AB050-8CC4-4099-80AF-7FF2BFC000E9} = {57BBD0FE-E8BB-45EF-B7EE-EB7669192D0D}
{E0B81C77-6E29-4500-9E9F-F0B72EBE8241} = {4E1AB050-8CC4-4099-80AF-7FF2BFC000E9}
{A74AE40C-5374-4B15-BEBF-94D74C16AC3A} = {0E113662-D6E2-473E-92BA-6005EB412C00}
{19517DBA-58AA-4294-97BF-0D02902749B4} = {4E1AB050-8CC4-4099-80AF-7FF2BFC000E9}
diff --git a/ImageProcessor.sln.DotSettings b/ImageProcessor.sln.DotSettings
deleted file mode 100644
index a2833a2b2..000000000
--- a/ImageProcessor.sln.DotSettings
+++ /dev/null
@@ -1,6 +0,0 @@
-
- ASCII
- CORS
- IO
- SHA
- SRGB
\ No newline at end of file
diff --git a/Nuget.config b/NuGet.config
similarity index 60%
rename from Nuget.config
rename to NuGet.config
index 00e302a4d..554c2f634 100644
--- a/Nuget.config
+++ b/NuGet.config
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec b/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec
index e7fe1260f..92948a9f2 100644
--- a/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec
+++ b/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec
@@ -22,7 +22,7 @@
en-GB
Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF
-
+
diff --git a/build/NuSpecs/ImageProcessor.Web.nuspec b/build/NuSpecs/ImageProcessor.Web.nuspec
index 835a7e0c3..ef29e2489 100644
--- a/build/NuSpecs/ImageProcessor.Web.nuspec
+++ b/build/NuSpecs/ImageProcessor.Web.nuspec
@@ -25,7 +25,7 @@
Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF
-
+
diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec
index 02531031d..4e4ea9247 100644
--- a/build/NuSpecs/ImageProcessor.nuspec
+++ b/build/NuSpecs/ImageProcessor.nuspec
@@ -23,6 +23,11 @@
James Jackson-South
en-GB
Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff Fluent Animated EXIF
+
+
+
+
+
diff --git a/build/build.ps1 b/build/build.ps1
index b0d49529b..14e886689 100644
--- a/build/build.ps1
+++ b/build/build.ps1
@@ -8,7 +8,7 @@ $nugetOutput = Join-Path $binPath "NuGets";
# Projects (NuGet dependencies are handled in the nuspec files themselves)
$imageprocessor = @{
name = "ImageProcessor"
- version = "2.8.0"
+ version = "2.9.0"
folder = Join-Path $buildPath "src\ImageProcessor"
output = Join-Path $binPath "ImageProcessor\lib\net452"
csproj = "ImageProcessor.csproj"
@@ -17,7 +17,7 @@ $imageprocessor = @{
$imageProcessorPluginsCair = @{
name = "ImageProcessor.Plugins.Cair"
- version = "1.3.0"
+ version = "1.3.1"
folder = Join-Path $buildPath "src\ImageProcessor.Plugins.Cair"
output = Join-Path $binPath "ImageProcessor.Plugins.Cair\lib\net452"
csproj = "ImageProcessor.Plugins.Cair.csproj"
@@ -35,7 +35,7 @@ $imageProcessorPluginsWebP = @{
$imageprocessorWeb = @{
name = "ImageProcessor.Web"
- version = "4.11.0"
+ version = "4.12.0"
folder = Join-Path $buildPath "src\ImageProcessor.Web"
output = Join-Path $binPath "ImageProcessor.Web\lib\net452"
csproj = "ImageProcessor.Web.csproj"
@@ -49,7 +49,7 @@ $imageprocessorWebConfig = @{
$imageProcessorWebPluginsAzureBlobCache = @{
name = "ImageProcessor.Web.Plugins.AzureBlobCache"
- version = "1.6.0"
+ version = "1.7.0"
folder = Join-Path $buildPath "src\ImageProcessor.Web.Plugins.AzureBlobCache"
output = Join-Path $binPath "ImageProcessor.Web.Plugins.AzureBlobCache\lib\net452"
csproj = "ImageProcessor.Web.Plugins.AzureBlobCache.csproj"
@@ -58,7 +58,7 @@ $imageProcessorWebPluginsAzureBlobCache = @{
$imageProcessorWebPluginsAmazonS3Cache = @{
name = "ImageProcessor.Web.Plugins.AmazonS3Cache"
- version = "1.1.0"
+ version = "1.2.0"
folder = Join-Path $buildPath "src\ImageProcessor.Web.Plugins.AmazonS3Cache"
output = Join-Path $binPath "ImageProcessor.Web.Plugins.AmazonS3Cache\lib\net452"
csproj = "ImageProcessor.Web.Plugins.AmazonS3Cache.csproj"
@@ -67,7 +67,7 @@ $imageProcessorWebPluginsAmazonS3Cache = @{
$imageProcessorWebPluginsPostProcessor = @{
name = "ImageProcessor.Web.Plugins.PostProcessor"
- version = "1.5.0"
+ version = "2.0.0"
folder = Join-Path $buildPath "src\ImageProcessor.Web.Plugins.PostProcessor"
output = Join-Path $binPath "ImageProcessor.Web.Plugins.PostProcessor\lib\net452"
csproj = "ImageProcessor.Web.Plugins.PostProcessor.csproj"
diff --git a/build/content/ImageProcessor.Plugins.WebP/web.config.transform b/build/content/ImageProcessor.Plugins.WebP/web.config.transform
index aaa15b857..70b5d667f 100644
--- a/build/content/ImageProcessor.Plugins.WebP/web.config.transform
+++ b/build/content/ImageProcessor.Plugins.WebP/web.config.transform
@@ -2,7 +2,7 @@
-
+
diff --git a/build/content/ImageProcessor.Web.Config/web.config.transform b/build/content/ImageProcessor.Web.Config/web.config.transform
index 6acc1eafd..75bf362f0 100644
--- a/build/content/ImageProcessor.Web.Config/web.config.transform
+++ b/build/content/ImageProcessor.Web.Config/web.config.transform
@@ -2,12 +2,11 @@
-
-
-
+
+
+
-
diff --git a/build/content/ImageProcessor.Web.Plugins.AmazonS3Cache/config/imageprocessor/cache.config.transform b/build/content/ImageProcessor.Web.Plugins.AmazonS3Cache/config/imageprocessor/cache.config.transform
index 6a6cb898f..c0315678f 100644
--- a/build/content/ImageProcessor.Web.Plugins.AmazonS3Cache/config/imageprocessor/cache.config.transform
+++ b/build/content/ImageProcessor.Web.Plugins.AmazonS3Cache/config/imageprocessor/cache.config.transform
@@ -4,7 +4,7 @@
-
+
@@ -16,4 +16,3 @@
-
diff --git a/build/content/ImageProcessor.Web.Plugins.AzureBlobCache/config/imageprocessor/cache.config.transform b/build/content/ImageProcessor.Web.Plugins.AzureBlobCache/config/imageprocessor/cache.config.transform
index ea3d82bc4..e0e2c4758 100644
--- a/build/content/ImageProcessor.Web.Plugins.AzureBlobCache/config/imageprocessor/cache.config.transform
+++ b/build/content/ImageProcessor.Web.Plugins.AzureBlobCache/config/imageprocessor/cache.config.transform
@@ -2,16 +2,15 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
diff --git a/build/content/ImageProcessor.Web/web.config.transform b/build/content/ImageProcessor.Web/web.config.transform
index bdee7b510..872fe9124 100644
--- a/build/content/ImageProcessor.Web/web.config.transform
+++ b/build/content/ImageProcessor.Web/web.config.transform
@@ -3,13 +3,13 @@
-
+
-
+
diff --git a/src/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj b/src/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj
index 7ff8c49dd..377af60a4 100644
--- a/src/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj
+++ b/src/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj
@@ -38,6 +38,9 @@
+
+ ..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll
+
@@ -62,6 +65,7 @@
+
diff --git a/src/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs b/src/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs
index 4fd5f4f1b..1b8e3f613 100644
--- a/src/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs
+++ b/src/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs
@@ -10,18 +10,14 @@
namespace ImageProcessor.Plugins.Cair.Imaging
{
+ using System;
using System.Drawing;
///
/// Encapsulates the properties required to resize an image using content aware resizing.
///
- public class ContentAwareResizeLayer
+ public class ContentAwareResizeLayer : IEquatable
{
- ///
- /// The expected output type.
- ///
- private OutputType outputType = OutputType.Cair;
-
///
/// Initializes a new instance of the class.
///
@@ -33,6 +29,11 @@ public ContentAwareResizeLayer(Size size)
this.Size = size;
}
+ ///
+ /// Gets or sets the size.
+ ///
+ public Size Size { get; set; }
+
///
/// Gets or sets the content aware resize convolution type (Default ContentAwareResizeConvolutionType.Prewitt).
///
@@ -46,23 +47,7 @@ public ContentAwareResizeLayer(Size size)
///
/// Gets or sets the expected output type.
///
- public OutputType OutputType
- {
- get
- {
- return this.outputType;
- }
-
- set
- {
- this.outputType = value;
- }
- }
-
- ///
- /// Gets or sets the size.
- ///
- public Size Size { get; set; }
+ public OutputType OutputType { get; set; } = OutputType.Cair;
///
/// Gets or sets the the file path to a bitmap file that provides weight indicators specified using
@@ -88,54 +73,36 @@ public OutputType OutputType
public int Timeout { get; set; } = 60000;
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- ContentAwareResizeLayer resizeLayer = obj as ContentAwareResizeLayer;
-
- if (resizeLayer == null)
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is ContentAwareResizeLayer contentAwareResizeLayer && this.Equals(contentAwareResizeLayer);
- return this.Size == resizeLayer.Size
- && this.ConvolutionType == resizeLayer.ConvolutionType
- && this.EnergyFunction == resizeLayer.EnergyFunction
- && this.OutputType == resizeLayer.OutputType
- && this.Parallelize == resizeLayer.Parallelize
- && this.Timeout == resizeLayer.Timeout
- && this.WeightPath == resizeLayer.WeightPath;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(ContentAwareResizeLayer other) => other != null
+ && this.Size == other.Size
+ && this.ConvolutionType == other.ConvolutionType
+ && this.EnergyFunction == other.EnergyFunction
+ && this.OutputType == other.OutputType
+ && this.WeightPath == other.WeightPath
+ && this.Parallelize == other.Parallelize
+ && this.Timeout == other.Timeout;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = (int)this.ConvolutionType;
- hashCode = (hashCode * 397) ^ (int)this.EnergyFunction;
- hashCode = (hashCode * 397) ^ this.Parallelize.GetHashCode();
- hashCode = (hashCode * 397) ^ (int)this.OutputType;
- hashCode = (hashCode * 397) ^ this.Timeout;
- hashCode = (hashCode * 397) ^ this.Size.GetHashCode();
- hashCode = (hashCode * 397) ^ (this.WeightPath != null ? this.WeightPath.GetHashCode() : 0);
- return hashCode;
- }
- }
+ public override int GetHashCode() => (this.Size, this.ConvolutionType, this.EnergyFunction, this.OutputType, this.WeightPath, this.Parallelize, this.Timeout).GetHashCode();
}
}
diff --git a/src/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs b/src/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs
index 9a550feaa..49070aabc 100644
--- a/src/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Plugins.Cair/Properties/AssemblyInfo.cs
@@ -40,5 +40,5 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.2.0")]
-[assembly: AssemblyFileVersion("1.0.2.0")]
+[assembly: AssemblyVersion("1.3.1.00000")]
+[assembly: AssemblyFileVersion("1.3.1.00000")]
diff --git a/src/ImageProcessor.Plugins.Cair/packages.config b/src/ImageProcessor.Plugins.Cair/packages.config
new file mode 100644
index 000000000..8653b8e4c
--- /dev/null
+++ b/src/ImageProcessor.Plugins.Cair/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs b/src/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs
index 3c931f96f..464306624 100644
--- a/src/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs
@@ -40,5 +40,5 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.6.0")]
-[assembly: AssemblyFileVersion("1.0.6.0")]
+[assembly: AssemblyVersion("1.3.0.00000")]
+[assembly: AssemblyFileVersion("1.3.0.00000")]
diff --git a/src/ImageProcessor.Web.Plugins.AmazonS3Cache/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.Plugins.AmazonS3Cache/Properties/AssemblyInfo.cs
index b93dd013a..327867e5e 100644
--- a/src/ImageProcessor.Web.Plugins.AmazonS3Cache/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Web.Plugins.AmazonS3Cache/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-// --------------------------------------------------------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) James Jackson-South.
// Licensed under the Apache License, Version 2.0.
@@ -18,7 +18,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ImageProcessor.Web.Plugins.AmazonS3Cache")]
-[assembly: AssemblyCopyright("Copyright © James Jackson-South")]
+[assembly: AssemblyCopyright("Copyright © James Jackson-South")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -39,6 +39,6 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+// [assembly: AssemblyVersion("1.7.0.00000")]
+[assembly: AssemblyVersion("1.7.0.00000")]
+[assembly: AssemblyFileVersion("1.7.0.00000")]
diff --git a/src/ImageProcessor.Web.Plugins.AzureBlobCache/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.Plugins.AzureBlobCache/Properties/AssemblyInfo.cs
index 07f67664d..11a70398c 100644
--- a/src/ImageProcessor.Web.Plugins.AzureBlobCache/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Web.Plugins.AzureBlobCache/Properties/AssemblyInfo.cs
@@ -40,5 +40,5 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.3.1.0")]
-[assembly: AssemblyFileVersion("1.3.1.0")]
+[assembly: AssemblyVersion("1.7.0.00000")]
+[assembly: AssemblyFileVersion("1.7.0.00000")]
diff --git a/src/ImageProcessor.Web.Plugins.PostProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.Plugins.PostProcessor/Properties/AssemblyInfo.cs
index ec35b4441..a57980769 100644
--- a/src/ImageProcessor.Web.Plugins.PostProcessor/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Web.Plugins.PostProcessor/Properties/AssemblyInfo.cs
@@ -41,7 +41,7 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.2.3.0")]
-[assembly: AssemblyFileVersion("1.2.3.0")]
+[assembly: AssemblyVersion("2.0.0.00000")]
+[assembly: AssemblyFileVersion("2.0.0.00000")]
-[assembly: InternalsVisibleTo("ImageProcessor.Web.UnitTests")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("ImageProcessor.Web.UnitTests")]
diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs
index 2488037fb..fb201ace9 100644
--- a/src/ImageProcessor.Web/Caching/DiskCache.cs
+++ b/src/ImageProcessor.Web/Caching/DiskCache.cs
@@ -211,64 +211,62 @@ public override Task TrimCacheAsync()
this.ScheduleCacheTrimmer(token =>
{
- string rootDirectory = Path.GetDirectoryName(this.CachedPath);
-
+ var rootDirectory = Path.GetDirectoryName(this.CachedPath);
if (rootDirectory != null)
{
- // Jump up to the parent branch to clean through the cache.
- // UNC folders can throw exceptions if the file doesn't exist.
- IEnumerable directories = SafeEnumerateDirectories(validatedAbsoluteCachePath).Reverse();
-
+ // Jump up to the parent branch to clean through the cache
+ // UNC folders can throw exceptions if the file doesn't exist
+ var directories = SafeEnumerateDirectories(validatedAbsoluteCachePath).Reverse().ToList();
foreach (string directory in directories)
{
- if (!Directory.Exists(directory))
- {
- continue;
- }
-
if (token.IsCancellationRequested)
{
break;
}
- IEnumerable files = Directory.EnumerateFiles(directory)
- .Select(f => new FileInfo(f))
- .OrderBy(f => f.CreationTimeUtc);
- int count = files.Count();
-
- foreach (FileInfo fileInfo in files)
+ try
{
- if (token.IsCancellationRequested)
- {
- break;
- }
-
- try
+ var files = Directory.EnumerateFiles(directory).Select(f => new FileInfo(f)).OrderBy(f => f.CreationTimeUtc).ToList();
+ var count = files.Count;
+ foreach (var fileInfo in files)
{
- // If the group count is equal to the max count minus 1 then we know we
- // have reduced the number of items below the maximum allowed.
- // We'll cleanup any orphaned expired files though.
- if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1)
+ if (token.IsCancellationRequested)
{
break;
}
- // Remove from the cache and delete each CachedImage.
- CacheIndexer.Remove(fileInfo.Name);
- fileInfo.Delete();
- count--;
- }
- catch (Exception ex)
- {
- // Log it but skip to the next file.
- ImageProcessorBootstrapper.Instance.Logger.Log($"Unable to clean cached file: {fileInfo.FullName}, {ex.Message}");
+ try
+ {
+ // If the group count is equal to the max count minus 1 then we know we have reduced the number of items below the maximum allowed
+ // We'll cleanup any orphaned expired files though
+ if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1)
+ {
+ break;
+ }
+
+ // Remove from the cache and delete each CachedImage
+ CacheIndexer.Remove(fileInfo.Name);
+ fileInfo.Delete();
+ count--;
+ }
+ catch (Exception ex)
+ {
+ // Log it but skip to the next file
+ ImageProcessorBootstrapper.Instance.Logger.Log($"Unable to clean cached file: {fileInfo.FullName}, {ex.Message}");
+ }
}
}
+ catch (Exception ex)
+ {
+ // Log it but skip to the next directory
+ ImageProcessorBootstrapper.Instance.Logger.Log($"Unable to clean cached directory: {directory}, {ex.Message}");
+ }
- // If the directory is empty of files delete it to remove the FCN.
+ // If the directory is empty of files delete it to remove the FCN
this.RecursivelyDeleteEmptyDirectories(directory, validatedAbsoluteCachePath, token);
}
}
+
return Task.FromResult(0);
});
diff --git a/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointConverter.cs b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointConverter.cs
index 4c5d5d717..6bd8f7a60 100644
--- a/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointConverter.cs
+++ b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointConverter.cs
@@ -36,7 +36,7 @@ public override object ConvertFrom(CultureInfo culture, object value, Type prope
{
object result = base.ConvertFrom(culture, value, propertyType);
- return result is int[] list ? new Point(list[0], list[1]) : result;
+ return result is int[] list && list.Length == 2 ? new Point(list[0], list[1]) : result;
}
}
}
diff --git a/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointFConverter.cs b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointFConverter.cs
new file mode 100644
index 000000000..7cb1dca28
--- /dev/null
+++ b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/PointFConverter.cs
@@ -0,0 +1,42 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright (c) James Jackson-South.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// The point converter.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Web.Helpers
+{
+ using System;
+ using System.Drawing;
+ using System.Globalization;
+
+ ///
+ /// The PointF converter.
+ ///
+ public class PointFConverter : GenericArrayTypeConverter
+ {
+ ///
+ /// Converts the given object to the type of this converter, using the specified context and culture
+ /// information.
+ ///
+ ///
+ /// An that represents the converted value.
+ ///
+ ///
+ /// The to use as the current culture.
+ ///
+ /// The to convert.
+ /// The property type that the converter will convert to.
+ /// The conversion cannot be performed.
+ public override object ConvertFrom(CultureInfo culture, object value, Type propertyType)
+ {
+ object result = base.ConvertFrom(culture, value, propertyType);
+
+ return result is float[] list && list.Length == 2 ? new PointF(list[0], list[1]) : result;
+ }
+ }
+}
diff --git a/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/SizeConverter.cs b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/SizeConverter.cs
index 98d38c23b..8e579f49e 100644
--- a/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/SizeConverter.cs
+++ b/src/ImageProcessor.Web/Helpers/QuerystringParser/Converters/SizeConverter.cs
@@ -36,7 +36,7 @@ public override object ConvertFrom(CultureInfo culture, object value, Type prope
{
object result = base.ConvertFrom(culture, value, propertyType);
- return result is int[] list ? new Size(list[0], list[1]) : result;
+ return result is int[] list && list.Length == 2 ? new Size(list[0], list[1]) : result;
}
}
}
diff --git a/src/ImageProcessor.Web/Helpers/QuerystringParser/QueryParamParser.cs b/src/ImageProcessor.Web/Helpers/QuerystringParser/QueryParamParser.cs
index 9e5bbb665..272d463f7 100644
--- a/src/ImageProcessor.Web/Helpers/QuerystringParser/QueryParamParser.cs
+++ b/src/ImageProcessor.Web/Helpers/QuerystringParser/QueryParamParser.cs
@@ -22,13 +22,13 @@ namespace ImageProcessor.Web.Helpers
public sealed class QueryParamParser
{
///
- /// A new instance of the class.
+ /// A new instance of the class.
/// with lazy initialization.
///
private static readonly Lazy Lazy = new Lazy(() => new QueryParamParser());
///
- /// Prevents a default instance of the class from being created.
+ /// Prevents a default instance of the class from being created.
///
private QueryParamParser()
{
@@ -42,25 +42,22 @@ private QueryParamParser()
}
///
- /// Gets the current instance.
+ /// Gets the current instance.
///
+ ///
+ /// The instance.
+ ///
public static QueryParamParser Instance => Lazy.Value;
///
/// Parses the given string value converting it to the given type.
///
- ///
- /// The value to parse.
- ///
- ///
- /// The to use as the current culture.
- /// If not set will parse using
- ///
- ///
- /// The to convert the string to.
- ///
+ /// The to convert the string to.
+ /// The value to parse.
+ /// The to use as the current culture.
+ /// If not set will parse using
///
- /// The .
+ /// The .
///
public T ParseValue(string value, CultureInfo culture = null)
{
@@ -72,6 +69,12 @@ public T ParseValue(string value, CultureInfo culture = null)
Type type = typeof(T);
IQueryParamConverter converter = QueryTypeDescriptor.GetConverter(type);
+ if (converter == null && Nullable.GetUnderlyingType(type) is Type underlyingType)
+ {
+ type = underlyingType;
+ converter = QueryTypeDescriptor.GetConverter(type);
+ }
+
try
{
// ReSharper disable once AssignNullToNotNullAttribute
@@ -87,12 +90,8 @@ public T ParseValue(string value, CultureInfo culture = null)
///
/// Adds a type converter to the parser.
///
- ///
- /// The to add a converter for.
- ///
- ///
- /// The type of to add.
- ///
+ /// The to add a converter for.
+ /// The type of to add.
public void AddTypeConverter(Type type, Type converterType) => QueryTypeDescriptor.AddConverter(type, converterType);
///
@@ -108,15 +107,19 @@ public T ParseValue(string value, CultureInfo culture = null)
///
/// Adds point converters.
///
- private void AddPointConverters() => this.AddTypeConverter(typeof(Point), typeof(PointConverter));
+ private void AddPointConverters()
+ {
+ this.AddTypeConverter(typeof(Point), typeof(PointConverter));
+ this.AddTypeConverter(typeof(PointF), typeof(PointFConverter));
+ }
///
- /// Adds point converters.
+ /// Adds size converters.
///
private void AddSizeConverters() => this.AddTypeConverter(typeof(Size), typeof(SizeConverter));
///
- /// Add the generic converters
+ /// Add the generic converters.
///
private void AddGenericConverters()
{
diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj
index 720e0c83c..897a404f8 100644
--- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj
+++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj
@@ -72,6 +72,7 @@
+
diff --git a/src/ImageProcessor.Web/Processors/Resize.cs b/src/ImageProcessor.Web/Processors/Resize.cs
index 36d4f6208..10fe2a464 100644
--- a/src/ImageProcessor.Web/Processors/Resize.cs
+++ b/src/ImageProcessor.Web/Processors/Resize.cs
@@ -75,16 +75,19 @@ public int MatchRegexIndex(string queryString)
ResizeMode mode = QueryParamParser.Instance.ParseValue(queryCollection["mode"]);
AnchorPosition position = QueryParamParser.Instance.ParseValue(queryCollection["anchor"]);
bool upscale = queryCollection["upscale"] == null || QueryParamParser.Instance.ParseValue(queryCollection["upscale"]);
- float[] center = queryCollection["center"] != null
- ? QueryParamParser.Instance.ParseValue(queryCollection["center"]) :
- new float[] { };
+ PointF? center = QueryParamParser.Instance.ParseValue(queryCollection["center"]);
+ if (center.HasValue)
+ {
+ // Swap X/Y for backwards compatibility
+ center = new PointF(center.Value.Y, center.Value.X);
+ }
this.Processor.DynamicParameter = new ResizeLayer(size)
{
ResizeMode = mode,
AnchorPosition = position,
Upscale = upscale,
- CenterCoordinates = center
+ Center = center
};
// Correctly parse any restrictions.
diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs
index c6ea053e4..5f3bd5a65 100644
--- a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs
@@ -41,7 +41,7 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("4.8.7.0")]
-[assembly: AssemblyFileVersion("4.8.7.0")]
+[assembly: AssemblyVersion("4.12.0.00000")]
+[assembly: AssemblyFileVersion("4.12.0.00000")]
[assembly: InternalsVisibleTo("ImageProcessor.Web.UnitTests")]
diff --git a/src/ImageProcessor/Common/Extensions/FloatExtensions.cs b/src/ImageProcessor/Common/Extensions/FloatExtensions.cs
index ab0a80ecc..b7067046f 100644
--- a/src/ImageProcessor/Common/Extensions/FloatExtensions.cs
+++ b/src/ImageProcessor/Common/Extensions/FloatExtensions.cs
@@ -32,6 +32,6 @@ public static class FloatExtensions
///
/// The .
///
- public static byte ToByte(this float value) => Convert.ToByte(ImageMaths.Clamp(value, 0, 255));
+ public static byte ToByte(this float value) => Convert.ToByte(ImageMaths.Clamp(value, byte.MinValue, byte.MaxValue));
}
}
diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs
index b5c0f14d8..8837c9381 100644
--- a/src/ImageProcessor/ImageFactory.cs
+++ b/src/ImageProcessor/ImageFactory.cs
@@ -75,7 +75,7 @@ public class ImageFactory : IDisposable
/// Whether to preserve exif metadata. Defaults to false.
///
public ImageFactory(bool preserveExifData = false)
- : this(preserveExifData, true)
+ : this(preserveExifData, false)
{
}
@@ -119,7 +119,7 @@ public ImageFactory(MetaDataMode metaDataMode, bool fixGamma)
}
///
- /// Finalizes an instance of the ImageFactory class.
+ /// Finalizes an instance of the class.
///
///
/// Use C# destructor syntax for finalization code.
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 1ad521cdb..aad9be49c 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -42,6 +42,9 @@
+
+ ..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll
+
@@ -148,6 +151,7 @@
+
@@ -202,5 +206,8 @@
+
+
+
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Colors/CmykColor.cs b/src/ImageProcessor/Imaging/Colors/CmykColor.cs
index 1dbf47b4b..5a1f3d8d1 100644
--- a/src/ImageProcessor/Imaging/Colors/CmykColor.cs
+++ b/src/ImageProcessor/Imaging/Colors/CmykColor.cs
@@ -247,54 +247,49 @@ public override string ToString()
}
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// Another object to compare to.
public override bool Equals(object obj) => obj is CmykColor cmykColor && this.Equals(cmykColor);
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
- /// true if the current object is equal to the parameter; otherwise, false.
- public bool Equals(CmykColor other)
- {
- Color thisColor = this;
- Color otherColor = other;
- return thisColor.Equals(otherColor);
- }
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(CmykColor other) =>
+ this.C == other.C
+ && this.M == other.M
+ && this.Y == other.Y
+ && this.K == other.K;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- Color thisColor = this;
- return thisColor.GetHashCode();
- }
+ public override int GetHashCode() => (this.C, this.M, this.Y, this.K).GetHashCode();
///
/// Checks the range of the given value to ensure that it remains within the acceptable boundaries.
///
- ///
- /// The value to check.
- ///
+ /// The value to check.
///
- /// The sanitized .
+ /// The sanitized .
///
private static float Clamp(float value) => ImageMaths.Clamp(value, 0, 100);
///
- /// Returns a value indicating whether the current instance is empty.
+ /// Determines whether this instance is empty.
///
///
- /// The true if this instance is empty; otherwise, false.
+ /// true if this instance is empty; otherwise, false.
///
private bool IsEmpty()
{
diff --git a/src/ImageProcessor/Imaging/Colors/Color32.cs b/src/ImageProcessor/Imaging/Colors/Color32.cs
index 4e01e031e..0e989c481 100644
--- a/src/ImageProcessor/Imaging/Colors/Color32.cs
+++ b/src/ImageProcessor/Imaging/Colors/Color32.cs
@@ -86,47 +86,29 @@ public Color32(int argb)
public Color Color => Color.FromArgb(this.A, this.R, this.G, this.B);
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// Another object to compare to.
public override bool Equals(object obj) => obj is Color32 color32 && this.Equals(color32);
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
- /// true if the current object is equal to the parameter; otherwise, false.
- public bool Equals(Color32 other) => this.Argb.Equals(other.Argb);
-
- ///
- /// Returns the hash code for this instance.
- ///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// true if the current object is equal to the parameter; otherwise, false.
///
- public override int GetHashCode() => this.GetHashCode(this);
+ public bool Equals(Color32 other) => this.Argb == other.Argb;
///
- /// Returns the hash code for the given instance.
+ /// Returns a hash code for this instance.
///
- ///
- /// The instance of to return the hash code for.
- ///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- private int GetHashCode(Color32 obj)
- {
- unchecked
- {
- int hashCode = obj.B.GetHashCode();
- hashCode = (hashCode * 397) ^ obj.G.GetHashCode();
- hashCode = (hashCode * 397) ^ obj.R.GetHashCode();
- return (hashCode * 397) ^ obj.A.GetHashCode();
- }
- }
+ public override int GetHashCode() => this.Argb.GetHashCode();
}
}
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Colors/HSLAColor.cs b/src/ImageProcessor/Imaging/Colors/HSLAColor.cs
index 23e9483ff..d47f8eb79 100644
--- a/src/ImageProcessor/Imaging/Colors/HSLAColor.cs
+++ b/src/ImageProcessor/Imaging/Colors/HSLAColor.cs
@@ -242,37 +242,34 @@ public override string ToString()
}
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// Another object to compare to.
public override bool Equals(object obj) => obj is HslaColor hslaColor && this.Equals(hslaColor);
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
- /// true if the current object is equal to the parameter; otherwise, false.
- public bool Equals(HslaColor other)
- {
- Color thisColor = this;
- Color otherColor = other;
- return thisColor.Equals(otherColor);
- }
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(HslaColor other) =>
+ this.H == other.H
+ && this.S == other.S
+ && this.L == other.L
+ && this.A == other.A;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- Color thisColor = this;
- return thisColor.GetHashCode();
- }
+ public override int GetHashCode() => (this.H, this.S, this.L, this.A).GetHashCode();
///
/// Gets the color component from the given hue values.
diff --git a/src/ImageProcessor/Imaging/Colors/RGBAColor.cs b/src/ImageProcessor/Imaging/Colors/RGBAColor.cs
index 3a4bd6e3a..defa82056 100644
--- a/src/ImageProcessor/Imaging/Colors/RGBAColor.cs
+++ b/src/ImageProcessor/Imaging/Colors/RGBAColor.cs
@@ -190,36 +190,33 @@ public override string ToString()
}
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// Another object to compare to.
public override bool Equals(object obj) => obj is RgbaColor rgbaColor && this.Equals(rgbaColor);
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
- /// true if the current object is equal to the parameter; otherwise, false.
- public bool Equals(RgbaColor other)
- {
- Color thisColor = this;
- Color otherColor = other;
- return thisColor.Equals(otherColor);
- }
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(RgbaColor other) =>
+ this.R == other.R
+ && this.G == other.G
+ && this.B == other.B
+ && this.A == other.A;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- Color thisColor = this;
- return thisColor.GetHashCode();
- }
+ public override int GetHashCode() => (this.R, this.G, this.B, this.A).GetHashCode();
}
}
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Colors/YCbCrColor.cs b/src/ImageProcessor/Imaging/Colors/YCbCrColor.cs
index 7c969c001..957e6cede 100644
--- a/src/ImageProcessor/Imaging/Colors/YCbCrColor.cs
+++ b/src/ImageProcessor/Imaging/Colors/YCbCrColor.cs
@@ -168,37 +168,33 @@ public override string ToString()
}
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// Another object to compare to.
public override bool Equals(object obj) => obj is YCbCrColor yCbCrColor && this.Equals(yCbCrColor);
///
/// Indicates whether the current object is equal to another object of the same type.
///
/// An object to compare with this object.
- /// true if the current object is equal to the parameter; otherwise, false.
- public bool Equals(YCbCrColor other)
- {
- Color thisColor = this;
- Color otherColor = other;
- return thisColor.Equals(otherColor);
- }
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(YCbCrColor other) =>
+ this.Y == other.Y
+ && this.Cb == other.Cb
+ && this.Cr == other.Cr;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- Color thisColor = this;
- return thisColor.GetHashCode();
- }
+ public override int GetHashCode() => (this.Y, this.Cb, this.Cr).GetHashCode();
///
/// Returns a value indicating whether the current instance is empty.
diff --git a/src/ImageProcessor/Imaging/CropLayer.cs b/src/ImageProcessor/Imaging/CropLayer.cs
index f1fdee181..7582201e8 100644
--- a/src/ImageProcessor/Imaging/CropLayer.cs
+++ b/src/ImageProcessor/Imaging/CropLayer.cs
@@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging
///
/// Encapsulates the properties required to crop an image.
///
- public class CropLayer
+ public class CropLayer : IEquatable
{
///
/// Initializes a new instance of the class.
@@ -31,9 +31,24 @@ public class CropLayer
///
public CropLayer(float left, float top, float right, float bottom, CropMode cropMode = CropMode.Percentage)
{
- if (left < 0 || top < 0 || right < 0 || bottom < 0)
+ if (left < 0)
{
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(left));
+ }
+
+ if (top < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(top));
+ }
+
+ if (right < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(right));
+ }
+
+ if (bottom < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(bottom));
}
this.Left = left;
@@ -69,47 +84,34 @@ public CropLayer(float left, float top, float right, float bottom, CropMode crop
public CropMode CropMode { get; set; }
///
- /// Determines whether the specified , is
- /// equal to this instance.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The to compare with this instance.
- ///
+ /// The to compare with this instance.
///
- /// true if the specified is equal to
- /// this instance; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is CropLayer cropLayer))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is CropLayer cropLayer && this.Equals(cropLayer);
- // Define the tolerance for variation in their values
- return Math.Abs(this.Top - cropLayer.Top) <= Math.Abs(this.Top * .0001)
- && Math.Abs(this.Right - cropLayer.Right) <= Math.Abs(this.Right * .0001)
- && Math.Abs(this.Bottom - cropLayer.Bottom) <= Math.Abs(this.Bottom * .0001)
- && Math.Abs(this.Left - cropLayer.Left) <= Math.Abs(this.Left * .0001)
- && this.CropMode.Equals(cropLayer.CropMode);
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(CropLayer other) => other != null
+ && this.Left == other.Left
+ && this.Top == other.Top
+ && this.Right == other.Right
+ && this.Bottom == other.Bottom
+ && this.CropMode == other.CropMode;
///
- /// Serves as a hash function for a particular type.
+ /// Returns a hash code for this instance.
///
///
- /// A hash code for the current .
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Left.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Top.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Right.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Bottom.GetHashCode();
- return (hashCode * 397) ^ (int)this.CropMode;
- }
- }
+ public override int GetHashCode() => (this.Left, this.Top, this.Right, this.Bottom, this.CropMode).GetHashCode();
}
}
diff --git a/src/ImageProcessor/Imaging/FastBitmap.cs b/src/ImageProcessor/Imaging/FastBitmap.cs
index 02b0bd2b4..d9c2080fc 100644
--- a/src/ImageProcessor/Imaging/FastBitmap.cs
+++ b/src/ImageProcessor/Imaging/FastBitmap.cs
@@ -20,7 +20,7 @@ namespace ImageProcessor.Imaging
///
/// Allows fast access to 's pixel data.
///
- public unsafe class FastBitmap : IDisposable
+ public unsafe class FastBitmap : IDisposable, IEquatable
{
///
/// The integral representation of the 8bppIndexed pixel format.
@@ -400,27 +400,29 @@ public void Dispose()
}
///
- /// Determines whether the specified is equal to the current .
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if the specified object is equal to the current object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// The object to compare with the current object.
- public override bool Equals(object obj)
- {
- if (!(obj is FastBitmap fastBitmap))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is FastBitmap fastBitmap && this.Equals(fastBitmap);
- return this.bitmap == fastBitmap.bitmap;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(FastBitmap other) => other != null
+ && this.bitmap == other.bitmap;
///
- /// Serves as a hash function for a particular type.
+ /// Returns a hash code for this instance.
///
///
- /// A hash code for the current .
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode() => this.bitmap.GetHashCode();
diff --git a/src/ImageProcessor/Imaging/Filters/Photo/MatrixFilterBase.cs b/src/ImageProcessor/Imaging/Filters/Photo/MatrixFilterBase.cs
index 9bb760f83..7c37cb4f4 100644
--- a/src/ImageProcessor/Imaging/Filters/Photo/MatrixFilterBase.cs
+++ b/src/ImageProcessor/Imaging/Filters/Photo/MatrixFilterBase.cs
@@ -10,13 +10,14 @@
namespace ImageProcessor.Imaging.Filters.Photo
{
+ using System;
using System.Drawing;
using System.Drawing.Imaging;
///
/// The matrix filter base contains equality methods.
///
- public abstract class MatrixFilterBase : IMatrixFilter
+ public abstract class MatrixFilterBase : IMatrixFilter, IEquatable
{
///
/// Gets the for this filter instance.
@@ -29,41 +30,88 @@ public abstract class MatrixFilterBase : IMatrixFilter
/// The current image to process
/// The new image to return
///
- /// The processed .
+ /// The processed .
///
public abstract Bitmap TransformImage(Image source, Image destination);
///
- /// Determines whether the specified , is equal to this instance.
+ /// Determines whether the specified , is equal to this instance.
///
- /// The to compare with this instance.
+ /// The to compare with this instance.
///
- /// true if the specified is equal to this instance; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is IMatrixFilter filter))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is IMatrixFilter matrixFilter && this.Equals(matrixFilter);
- return this.GetType().Name == filter.GetType().Name
- && this.Matrix.Equals(filter.Matrix);
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(IMatrixFilter other) => other != null
+ && this.GetType() == other.GetType()
+ && (this.Matrix == null || other.Matrix == null ? this.Matrix == other.Matrix : (
+ this.Matrix.Matrix00 == other.Matrix.Matrix00
+ && this.Matrix.Matrix01 == other.Matrix.Matrix01
+ && this.Matrix.Matrix02 == other.Matrix.Matrix02
+ && this.Matrix.Matrix03 == other.Matrix.Matrix03
+ && this.Matrix.Matrix04 == other.Matrix.Matrix04
+ && this.Matrix.Matrix10 == other.Matrix.Matrix10
+ && this.Matrix.Matrix11 == other.Matrix.Matrix11
+ && this.Matrix.Matrix12 == other.Matrix.Matrix12
+ && this.Matrix.Matrix13 == other.Matrix.Matrix13
+ && this.Matrix.Matrix14 == other.Matrix.Matrix14
+ && this.Matrix.Matrix20 == other.Matrix.Matrix20
+ && this.Matrix.Matrix21 == other.Matrix.Matrix21
+ && this.Matrix.Matrix22 == other.Matrix.Matrix22
+ && this.Matrix.Matrix23 == other.Matrix.Matrix23
+ && this.Matrix.Matrix24 == other.Matrix.Matrix24
+ && this.Matrix.Matrix30 == other.Matrix.Matrix30
+ && this.Matrix.Matrix31 == other.Matrix.Matrix31
+ && this.Matrix.Matrix32 == other.Matrix.Matrix32
+ && this.Matrix.Matrix33 == other.Matrix.Matrix33
+ && this.Matrix.Matrix34 == other.Matrix.Matrix34
+ && this.Matrix.Matrix40 == other.Matrix.Matrix40
+ && this.Matrix.Matrix41 == other.Matrix.Matrix41
+ && this.Matrix.Matrix42 == other.Matrix.Matrix42
+ && this.Matrix.Matrix43 == other.Matrix.Matrix43
+ && this.Matrix.Matrix44 == other.Matrix.Matrix44
+ ));
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.GetType().Name.GetHashCode();
- return (hashCode * 397) ^ this.Matrix.GetHashCode();
- }
- }
+ public override int GetHashCode() => (
+ this.GetType(),
+ this.Matrix?.Matrix00,
+ this.Matrix?.Matrix01,
+ this.Matrix?.Matrix02,
+ this.Matrix?.Matrix03,
+ this.Matrix?.Matrix04,
+ this.Matrix?.Matrix10,
+ this.Matrix?.Matrix11,
+ this.Matrix?.Matrix12,
+ this.Matrix?.Matrix13,
+ this.Matrix?.Matrix14,
+ this.Matrix?.Matrix20,
+ this.Matrix?.Matrix21,
+ this.Matrix?.Matrix22,
+ this.Matrix?.Matrix23,
+ this.Matrix?.Matrix24,
+ this.Matrix?.Matrix30,
+ this.Matrix?.Matrix31,
+ this.Matrix?.Matrix32,
+ this.Matrix?.Matrix33,
+ this.Matrix?.Matrix34,
+ this.Matrix?.Matrix40,
+ this.Matrix?.Matrix41,
+ this.Matrix?.Matrix42,
+ this.Matrix?.Matrix43,
+ this.Matrix?.Matrix44).GetHashCode();
}
}
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs
index d5e582243..4651b865c 100644
--- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs
+++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs
@@ -18,7 +18,7 @@ namespace ImageProcessor.Imaging.Formats
///
/// The supported format base. Implement this class when building a supported format.
///
- public abstract class FormatBase : ISupportedImageFormat
+ public abstract class FormatBase : ISupportedImageFormat, IEquatable
{
///
/// Initializes a new instance of the class.
@@ -123,36 +123,31 @@ public virtual Image Save(string path, Image image, long bitDepth)
}
///
- /// Determines whether the specified , is equal to this instance.
+ /// Determines whether the specified , is equal to this instance.
///
- /// The to compare with this instance.
+ /// The to compare with this instance.
///
- /// true if the specified is equal to this instance; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is ISupportedImageFormat format))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is ISupportedImageFormat format && this.Equals(format);
- return this.MimeType.Equals(format.MimeType) && this.IsIndexed.Equals(format.IsIndexed);
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(ISupportedImageFormat other) => other != null
+ && this.MimeType == other.MimeType
+ && this.IsIndexed == other.IsIndexed;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.MimeType.GetHashCode();
- hashCode = (hashCode * 397) ^ this.IsIndexed.GetHashCode();
- return (hashCode * 397) ^ this.Quality;
- }
- }
+ public override int GetHashCode() => (this.MimeType, this.IsIndexed).GetHashCode();
}
}
diff --git a/src/ImageProcessor/Imaging/GaussianLayer.cs b/src/ImageProcessor/Imaging/GaussianLayer.cs
index 15d45b15a..55668d397 100644
--- a/src/ImageProcessor/Imaging/GaussianLayer.cs
+++ b/src/ImageProcessor/Imaging/GaussianLayer.cs
@@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging
///
/// A Gaussian layer for applying sharpening and blurring methods to an image.
///
- public class GaussianLayer
+ public class GaussianLayer : IEquatable
{
///
/// The size.
@@ -131,43 +131,32 @@ public int Threshold
}
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is GaussianLayer gaussianLayer))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is GaussianLayer gaussianLayer && this.Equals(gaussianLayer);
- return this.Size == gaussianLayer.Size
- && Math.Abs(this.Sigma - gaussianLayer.Sigma) < 0.0001
- && this.Threshold == gaussianLayer.Threshold;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(GaussianLayer other) => other != null
+ && this.Size == other.Size
+ && this.Sigma == other.Sigma
+ && this.Threshold == other.Threshold;
///
- /// Serves as a hash function for a particular type.
+ /// Returns a hash code for this instance.
///
///
- /// A hash code for the current .
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Size;
- hashCode = (hashCode * 397) ^ this.Size.GetHashCode();
- return (hashCode * 397) ^ this.Threshold;
- }
- }
+ public override int GetHashCode() => (this.Size, this.Sigma, this.Threshold).GetHashCode();
}
}
diff --git a/src/ImageProcessor/Imaging/Helpers/Adjustments.cs b/src/ImageProcessor/Imaging/Helpers/Adjustments.cs
index bf60cd9ab..1a42df3b5 100644
--- a/src/ImageProcessor/Imaging/Helpers/Adjustments.cs
+++ b/src/ImageProcessor/Imaging/Helpers/Adjustments.cs
@@ -13,6 +13,7 @@ namespace ImageProcessor.Imaging.Helpers
using System;
using System.Drawing;
using System.Drawing.Imaging;
+ using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
@@ -329,7 +330,7 @@ private static byte[] GetLinearBytes()
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
- ramp[x] = (255f * SRGBToLinear(x / 255f)).ToByte();
+ ramp[x] = ((255 * SRGBToLinear(x / 255D)) + .5).ToByte();
}
return ramp;
@@ -347,7 +348,7 @@ private static byte[] GetSRGBBytes()
byte[] ramp = new byte[256];
for (int x = 0; x < 256; ++x)
{
- ramp[x] = (255f * LinearToSRGB(x / 255f)).ToByte();
+ ramp[x] = ((255 * LinearToSRGB(x / 255D)) + .5).ToByte();
}
return ramp;
@@ -362,16 +363,15 @@ private static byte[] GetSRGBBytes()
///
/// The .
///
- private static float SRGBToLinear(float signal)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static double SRGBToLinear(double signal)
{
- const float a = 0.055f;
-
if (signal <= 0.04045)
{
- return signal / 12.92f;
+ return signal / 12.92;
}
- return (float)Math.Pow((signal + a) / (1 + a), 2.4);
+ return Math.Pow((signal + 0.055) / 1.055, 2.4);
}
///
@@ -381,18 +381,17 @@ private static float SRGBToLinear(float signal)
///
/// The signal value to convert.
///
- /// The .
+ /// The .
///
- private static float LinearToSRGB(float signal)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static double LinearToSRGB(double signal)
{
- const float a = 0.055f;
-
- if (signal <= 0.0031308)
+ if (signal <= (0.04045 / 12.92))
{
- return signal * 12.92f;
+ return signal * 12.92;
}
- return ((float)((1 + a) * Math.Pow(signal, 0.4166667F))) - a;
+ return (1.055 * Math.Pow(signal, 1.0 / 2.4)) - 0.055;
}
}
}
diff --git a/src/ImageProcessor/Imaging/Helpers/GraphicsHelper.cs b/src/ImageProcessor/Imaging/Helpers/GraphicsHelper.cs
index 8c1360fb9..bc8eac7c6 100644
--- a/src/ImageProcessor/Imaging/Helpers/GraphicsHelper.cs
+++ b/src/ImageProcessor/Imaging/Helpers/GraphicsHelper.cs
@@ -28,15 +28,15 @@ public static void SetGraphicsOptions(Graphics graphics, bool blending = false,
{
// Highest quality resampling algorithm.
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
-
- // Ensure pixel offset is set.
- graphics.PixelOffsetMode = PixelOffsetMode.Half;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
if (smoothing)
{
// We want smooth edges when drawing.
graphics.SmoothingMode = SmoothingMode.AntiAlias;
}
+
if (blending || smoothing)
{
// Best combination for blending pixels.
diff --git a/src/ImageProcessor/Imaging/ImageLayer.cs b/src/ImageProcessor/Imaging/ImageLayer.cs
index 99bd9e57a..578dc04f7 100644
--- a/src/ImageProcessor/Imaging/ImageLayer.cs
+++ b/src/ImageProcessor/Imaging/ImageLayer.cs
@@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging
///
/// Encapsulates the properties required to add an image layer to an image.
///
- public class ImageLayer : IDisposable
+ public class ImageLayer : IDisposable, IEquatable
{
///
/// A value indicating whether this instance of the given entity has been disposed.
@@ -51,46 +51,34 @@ public class ImageLayer : IDisposable
public Point? Position { get; set; }
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is ImageLayer imageLayer))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is ImageLayer imageLayer && this.Equals(imageLayer);
- return this.Image == imageLayer.Image
- && this.Size == imageLayer.Size
- && this.Opacity == imageLayer.Opacity
- && this.Position == imageLayer.Position;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(ImageLayer other) => other != null
+ && this.Image == other.Image
+ && this.Size == other.Size
+ && this.Opacity == other.Opacity
+ && this.Position == other.Position;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Image.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Size.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Opacity;
- return (hashCode * 397) ^ this.Position.GetHashCode();
- }
- }
+ public override int GetHashCode() => (this.Image, this.Size, this.Opacity, this.Position).GetHashCode();
///
/// Disposes the object and frees resources for the Garbage Collector.
diff --git a/src/ImageProcessor/Imaging/MetaData/Rational.cs b/src/ImageProcessor/Imaging/MetaData/Rational.cs
index 32bd97adf..499842290 100644
--- a/src/ImageProcessor/Imaging/MetaData/Rational.cs
+++ b/src/ImageProcessor/Imaging/MetaData/Rational.cs
@@ -1000,27 +1000,20 @@ public int CompareTo(object obj)
public override string ToString() => Convert.ToString(this, CultureInfo.InvariantCulture);
///
- /// Indicates whether this instance and a specified object are equal.
+ /// Determines whether the specified , is equal to this instance.
///
+ /// The to compare with this instance.
///
- /// true if and this instance are the same type and represent the same value;
- /// otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- /// The object to compare with the current instance.
public override bool Equals(object obj) => this.CompareTo(obj) == 0;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- // Adapted from Anonymous Type: { uint Numerator, uint Denominator }
- int num = 0x1fb8d67d;
- num = (-1521134295 * num) + EqualityComparer.Default.GetHashCode(this.numerator);
- return (-1521134295 * num) + EqualityComparer.Default.GetHashCode(this.denominator);
- }
+ public override int GetHashCode() => (this.Numerator, this.Denominator).GetHashCode();
}
}
diff --git a/src/ImageProcessor/Imaging/ResizeHelper.cs b/src/ImageProcessor/Imaging/ResizeHelper.cs
new file mode 100644
index 000000000..1a726a1fe
--- /dev/null
+++ b/src/ImageProcessor/Imaging/ResizeHelper.cs
@@ -0,0 +1,394 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright (c) James Jackson-South.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Resizes an image to the given dimensions.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+using System.Drawing;
+
+namespace ImageProcessor.Imaging
+{
+ ///
+ /// Provides methods to help calculate the target rectangle when resizing using the
+ /// enumeration.
+ ///
+ internal static class ResizeHelper
+ {
+ ///
+ /// Calculates the target location and bounds to perform the resize operation against.
+ ///
+ /// The source image size.
+ /// The resize options.
+ /// The target width.
+ /// The target height.
+ ///
+ /// The tuple representing the location and the bounds.
+ ///
+ public static (Size, Rectangle) CalculateTargetLocationAndBounds(
+ Size sourceSize,
+ ResizeLayer options,
+ int width,
+ int height)
+ {
+ if (width <= 0 && height <= 0)
+ {
+ ThrowInvalid($"Target width {width} and height {height} must be greater than zero.");
+ }
+
+ switch (options.ResizeMode)
+ {
+ case ResizeMode.Crop:
+ return CalculateCropRectangle(sourceSize, options, width, height);
+ case ResizeMode.Pad:
+ return CalculatePadRectangle(sourceSize, options, width, height);
+ case ResizeMode.BoxPad:
+ return CalculateBoxPadRectangle(sourceSize, options, width, height);
+ case ResizeMode.Max:
+ return CalculateMaxRectangle(sourceSize, width, height);
+ case ResizeMode.Min:
+ return CalculateMinRectangle(sourceSize, width, height);
+
+ // Last case ResizeMode.Stretch:
+ default:
+ return (new Size(width, height), new Rectangle(0, 0, width, height));
+ }
+ }
+
+ private static (Size, Rectangle) CalculateBoxPadRectangle(
+ Size source,
+ ResizeLayer options,
+ int width,
+ int height)
+ {
+ if (width <= 0 || height <= 0)
+ {
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
+ }
+
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = Math.Abs(height / (float)sourceHeight);
+ float percentWidth = Math.Abs(width / (float)sourceWidth);
+
+ int boxPadHeight = height > 0 ? height : (int)Math.Round(sourceHeight * percentWidth);
+ int boxPadWidth = width > 0 ? width : (int)Math.Round(sourceWidth * percentHeight);
+
+ // Only calculate if upscaling.
+ if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight)
+ {
+ int destinationX;
+ int destinationY;
+ int destinationWidth = sourceWidth;
+ int destinationHeight = sourceHeight;
+ width = boxPadWidth;
+ height = boxPadHeight;
+
+ switch (options.AnchorPosition)
+ {
+ case AnchorPosition.Left:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = 0;
+ break;
+ case AnchorPosition.Right:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPosition.TopRight:
+ destinationY = 0;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPosition.Top:
+ destinationY = 0;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ case AnchorPosition.TopLeft:
+ destinationY = 0;
+ destinationX = 0;
+ break;
+ case AnchorPosition.BottomRight:
+ destinationY = height - sourceHeight;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPosition.Bottom:
+ destinationY = height - sourceHeight;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ case AnchorPosition.BottomLeft:
+ destinationY = height - sourceHeight;
+ destinationX = 0;
+ break;
+ default:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ }
+
+ return (new Size(width, height),
+ new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
+ }
+
+ // Switch to pad mode to downscale and calculate from there.
+ return CalculatePadRectangle(source, options, width, height);
+ }
+
+ private static (Size, Rectangle) CalculateCropRectangle(
+ Size source,
+ ResizeLayer options,
+ int width,
+ int height)
+ {
+ float ratio;
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+
+ int targetX = 0;
+ int targetY = 0;
+ int targetWidth = width;
+ int targetHeight = height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = Math.Abs(height / (float)sourceHeight);
+ float percentWidth = Math.Abs(width / (float)sourceWidth);
+
+ if (percentHeight < percentWidth)
+ {
+ ratio = percentWidth;
+
+ if (options.Center is var center && center.HasValue)
+ {
+ float centerRatio = -(ratio * sourceHeight) * center.Value.Y;
+ targetY = (int)Math.Round(centerRatio + (height / 2F));
+
+ if (targetY > 0)
+ {
+ targetY = 0;
+ }
+
+ if (targetY < (int)Math.Round(height - (sourceHeight * ratio)))
+ {
+ targetY = (int)Math.Round(height - (sourceHeight * ratio));
+ }
+ }
+ else
+ {
+ switch (options.AnchorPosition)
+ {
+ case AnchorPosition.Top:
+ case AnchorPosition.TopLeft:
+ case AnchorPosition.TopRight:
+ targetY = 0;
+ break;
+ case AnchorPosition.Bottom:
+ case AnchorPosition.BottomLeft:
+ case AnchorPosition.BottomRight:
+ targetY = (int)Math.Round(height - (sourceHeight * ratio));
+ break;
+ default:
+ targetY = (int)Math.Round((height - (sourceHeight * ratio)) / 2F);
+ break;
+ }
+ }
+
+ targetHeight = (int)Math.Ceiling(sourceHeight * percentWidth);
+ }
+ else
+ {
+ ratio = percentHeight;
+
+ if (options.Center is var center && center.HasValue)
+ {
+ float centerRatio = -(ratio * sourceWidth) * center.Value.X;
+ targetX = (int)Math.Round(centerRatio + (width / 2F));
+
+ if (targetX > 0)
+ {
+ targetX = 0;
+ }
+
+ if (targetX < (int)Math.Round(width - (sourceWidth * ratio)))
+ {
+ targetX = (int)Math.Round(width - (sourceWidth * ratio));
+ }
+ }
+ else
+ {
+ switch (options.AnchorPosition)
+ {
+ case AnchorPosition.Left:
+ case AnchorPosition.TopLeft:
+ case AnchorPosition.BottomLeft:
+ targetX = 0;
+ break;
+ case AnchorPosition.Right:
+ case AnchorPosition.TopRight:
+ case AnchorPosition.BottomRight:
+ targetX = (int)Math.Round(width - (sourceWidth * ratio));
+ break;
+ default:
+ targetX = (int)Math.Round((width - (sourceWidth * ratio)) / 2F);
+ break;
+ }
+ }
+
+ targetWidth = (int)Math.Ceiling(sourceWidth * percentHeight);
+ }
+
+ // Target image width and height can be different to the rectangle width and height.
+ return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight));
+ }
+
+ private static (Size, Rectangle) CalculateMaxRectangle(
+ Size source,
+ int width,
+ int height)
+ {
+ int targetWidth = width;
+ int targetHeight = height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = Math.Abs(height / (float)source.Height);
+ float percentWidth = Math.Abs(width / (float)source.Width);
+
+ // Integers must be cast to floats to get needed precision
+ float ratio = height / (float)width;
+ float sourceRatio = source.Height / (float)source.Width;
+
+ if (sourceRatio < ratio)
+ {
+ targetHeight = (int)Math.Round(source.Height * percentWidth);
+ }
+ else
+ {
+ targetWidth = (int)Math.Round(source.Width * percentHeight);
+ }
+
+ // Replace the size to match the rectangle.
+ return (new Size(targetWidth, targetHeight), new Rectangle(0, 0, targetWidth, targetHeight));
+ }
+
+ private static (Size, Rectangle) CalculateMinRectangle(
+ Size source,
+ int width,
+ int height)
+ {
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+ int targetWidth = width;
+ int targetHeight = height;
+
+ // Don't upscale
+ if (width > sourceWidth || height > sourceHeight)
+ {
+ return (new Size(sourceWidth, sourceHeight), new Rectangle(0, 0, sourceWidth, sourceHeight));
+ }
+
+ // Find the shortest distance to go.
+ int widthDiff = sourceWidth - width;
+ int heightDiff = sourceHeight - height;
+
+ if (widthDiff < heightDiff)
+ {
+ float sourceRatio = (float)sourceHeight / sourceWidth;
+ targetHeight = (int)Math.Round(width * sourceRatio);
+ }
+ else if (widthDiff > heightDiff)
+ {
+ float sourceRatioInverse = (float)sourceWidth / sourceHeight;
+ targetWidth = (int)Math.Round(height * sourceRatioInverse);
+ }
+ else
+ {
+ if (height > width)
+ {
+ float percentWidth = Math.Abs(width / (float)sourceWidth);
+ targetHeight = (int)Math.Round(sourceHeight * percentWidth);
+ }
+ else
+ {
+ float percentHeight = Math.Abs(height / (float)sourceHeight);
+ targetWidth = (int)Math.Round(sourceWidth * percentHeight);
+ }
+ }
+
+ // Replace the size to match the rectangle.
+ return (new Size(targetWidth, targetHeight), new Rectangle(0, 0, targetWidth, targetHeight));
+ }
+
+ private static (Size, Rectangle) CalculatePadRectangle(
+ Size sourceSize,
+ ResizeLayer options,
+ int width,
+ int height)
+ {
+ float ratio;
+ int sourceWidth = sourceSize.Width;
+ int sourceHeight = sourceSize.Height;
+
+ int targetX = 0;
+ int targetY = 0;
+ int targetWidth = width;
+ int targetHeight = height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = Math.Abs(height / (float)sourceHeight);
+ float percentWidth = Math.Abs(width / (float)sourceWidth);
+
+ if (percentHeight < percentWidth)
+ {
+ ratio = percentHeight;
+ targetWidth = (int)Math.Round(sourceWidth * percentHeight);
+
+ switch (options.AnchorPosition)
+ {
+ case AnchorPosition.Left:
+ case AnchorPosition.TopLeft:
+ case AnchorPosition.BottomLeft:
+ targetX = 0;
+ break;
+ case AnchorPosition.Right:
+ case AnchorPosition.TopRight:
+ case AnchorPosition.BottomRight:
+ targetX = (int)Math.Round(width - (sourceWidth * ratio));
+ break;
+ default:
+ targetX = (int)Math.Round((width - (sourceWidth * ratio)) / 2F);
+ break;
+ }
+ }
+ else
+ {
+ ratio = percentWidth;
+ targetHeight = (int)Math.Round(sourceHeight * percentWidth);
+
+ switch (options.AnchorPosition)
+ {
+ case AnchorPosition.Top:
+ case AnchorPosition.TopLeft:
+ case AnchorPosition.TopRight:
+ targetY = 0;
+ break;
+ case AnchorPosition.Bottom:
+ case AnchorPosition.BottomLeft:
+ case AnchorPosition.BottomRight:
+ targetY = (int)Math.Round(height - (sourceHeight * ratio));
+ break;
+ default:
+ targetY = (int)Math.Round((height - (sourceHeight * ratio)) / 2F);
+ break;
+ }
+ }
+
+ // Target image width and height can be different to the rectangle width and height.
+ return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight));
+ }
+
+ private static void ThrowInvalid(string message) => throw new InvalidOperationException(message);
+ }
+}
diff --git a/src/ImageProcessor/Imaging/ResizeLayer.cs b/src/ImageProcessor/Imaging/ResizeLayer.cs
index 1c3b81271..94c01d7e2 100644
--- a/src/ImageProcessor/Imaging/ResizeLayer.cs
+++ b/src/ImageProcessor/Imaging/ResizeLayer.cs
@@ -10,6 +10,7 @@
namespace ImageProcessor.Imaging
{
+ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
@@ -17,37 +18,20 @@ namespace ImageProcessor.Imaging
///
/// Encapsulates the properties required to resize an image.
///
- public class ResizeLayer
+ ///
+ public class ResizeLayer : IEquatable
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- ///
- /// The containing the width and height to set the image to.
- ///
- ///
- /// The resize mode to apply to resized image. (Default ResizeMode.Pad)
- ///
- ///
- /// The to apply to resized image. (Default AnchorPosition.Center)
- ///
- ///
- /// Whether to allow up-scaling of images. (Default true)
- ///
- ///
- /// The center coordinates (Default null)
- ///
- ///
- /// The maximum size to resize an image to.
- /// Used to restrict resizing based on calculated resizing
- ///
- ///
- /// The range of sizes to restrict resizing an image to.
- /// Used to restrict resizing based on calculated resizing
- ///
- ///
- /// The anchor point (Default null)
- ///
+ /// The containing the width and height to resize the image to.
+ /// The resize mode to apply to the resized image.
+ /// The anchor position to apply to the resized image.
+ /// Whether to allow up-scaling of images.
+ /// The center coordinates (Y,X).
+ /// The maximum size to resize an image to. Used to restrict resizing based on calculated resizing.
+ /// The range of sizes to restrict resizing an image to. Used to restrict resizing based on calculated resizing.
+ /// The anchor point.
public ResizeLayer(
Size size,
ResizeMode resizeMode = ResizeMode.Pad,
@@ -62,107 +46,138 @@ public ResizeLayer(
this.Upscale = upscale;
this.ResizeMode = resizeMode;
this.AnchorPosition = anchorPosition;
- this.CenterCoordinates = centerCoordinates ?? new float[] { };
+ if (centerCoordinates != null && centerCoordinates.Length == 2)
+ {
+ this.Center = new PointF(centerCoordinates[1], centerCoordinates[0]);
+ }
this.MaxSize = maxSize;
- this.RestrictedSizes = restrictedSizes ?? new List();
+ this.RestrictedSizes = restrictedSizes;
this.AnchorPoint = anchorPoint;
}
///
/// Gets or sets the size.
///
+ ///
+ /// The size.
+ ///
public Size Size { get; set; }
///
- /// Gets or sets the max size.
+ /// Gets or sets the maximum size.
///
+ ///
+ /// The maximum size.
+ ///
public Size? MaxSize { get; set; }
///
- /// Gets or sets the restricted range of sizes. to restrict resizing methods to.
+ /// Gets or sets the restricted range of sizes to restrict resizing methods to.
///
+ ///
+ /// The restricted sizes.
+ ///
public List RestrictedSizes { get; set; }
///
/// Gets or sets the resize mode.
///
+ ///
+ /// The resize mode.
+ ///
public ResizeMode ResizeMode { get; set; }
///
/// Gets or sets the anchor position.
///
+ ///
+ /// The anchor position.
+ ///
public AnchorPosition AnchorPosition { get; set; }
///
/// Gets or sets a value indicating whether to allow up-scaling of images.
- /// For this is always true.
+ /// For this is always true.
///
+ ///
+ /// true if up-scaling is allowed; otherwise, false.
+ ///
public bool Upscale { get; set; }
///
- /// Gets or sets the center coordinates.
+ /// Gets or sets the center coordinates (Y,X).
+ ///
+ ///
+ /// The center coordinates (Y,X).
+ ///
+ [Obsolete("Use the Center property instead.")]
+ public float[] CenterCoordinates
+ {
+ get
+ {
+ return this.Center is PointF center ? new float[] { center.Y, center.X } : null;
+ }
+ set
+ {
+ if (value != null && value.Length == 2)
+ {
+ this.Center = new PointF(value[1], value[0]);
+ }
+ else
+ {
+ this.Center = null;
+ }
+ }
+ }
+
+ ///
+ /// Gets the center coordinates as .
///
- public float[] CenterCoordinates { get; set; }
+ ///
+ /// The center coordinates as .
+ ///
+ public PointF? Center { get; set; }
///
/// Gets or sets the anchor point.
///
+ ///
+ /// The anchor point.
+ ///
public Point? AnchorPoint { get; set; }
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is ResizeLayer resizeLayer))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is ResizeLayer resizeLayer && this.Equals(resizeLayer);
- return this.Size == resizeLayer.Size
- && this.ResizeMode == resizeLayer.ResizeMode
- && this.AnchorPosition == resizeLayer.AnchorPosition
- && this.Upscale == resizeLayer.Upscale
- && ((this.CenterCoordinates != null
- && resizeLayer.CenterCoordinates != null
- && this.CenterCoordinates.SequenceEqual(resizeLayer.CenterCoordinates))
- || (this.CenterCoordinates == resizeLayer.CenterCoordinates))
- && this.MaxSize == resizeLayer.MaxSize
- && ((this.RestrictedSizes != null
- && resizeLayer.RestrictedSizes != null
- && this.RestrictedSizes.SequenceEqual(resizeLayer.RestrictedSizes))
- || (this.RestrictedSizes == resizeLayer.RestrictedSizes))
- && this.AnchorPoint == resizeLayer.AnchorPoint;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(ResizeLayer other) => other != null
+ && this.Size == other.Size
+ && this.MaxSize == other.MaxSize
+ && (this.RestrictedSizes == null || other.RestrictedSizes == null ? this.RestrictedSizes == other.RestrictedSizes : this.RestrictedSizes.SequenceEqual(other.RestrictedSizes))
+ && this.ResizeMode == other.ResizeMode
+ && this.AnchorPosition == other.AnchorPosition
+ && this.Upscale == other.Upscale
+ && this.Center == other.Center
+ && this.AnchorPoint == other.AnchorPoint;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Size.GetHashCode();
- hashCode = (hashCode * 397) ^ this.MaxSize.GetHashCode();
- hashCode = (hashCode * 397) ^ (this.RestrictedSizes?.GetHashCode() ?? 0);
- hashCode = (hashCode * 397) ^ (int)this.ResizeMode;
- hashCode = (hashCode * 397) ^ (int)this.AnchorPosition;
- hashCode = (hashCode * 397) ^ this.Upscale.GetHashCode();
- hashCode = (hashCode * 397) ^ (this.CenterCoordinates?.GetHashCode() ?? 0);
- return (hashCode * 397) ^ this.AnchorPoint.GetHashCode();
- }
- }
+ public override int GetHashCode() => (this.Size, this.MaxSize, this.ResizeMode, this.AnchorPosition, this.Upscale, this.Center, this.AnchorPoint).GetHashCode();
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageProcessor/Imaging/Resizer.cs b/src/ImageProcessor/Imaging/Resizer.cs
index cdfef07e7..1b53f89d5 100644
--- a/src/ImageProcessor/Imaging/Resizer.cs
+++ b/src/ImageProcessor/Imaging/Resizer.cs
@@ -10,17 +10,16 @@
namespace ImageProcessor.Imaging
{
+ using ImageProcessor.Common.Exceptions;
+ using ImageProcessor.Common.Extensions;
+ using ImageProcessor.Imaging.Formats;
+ using ImageProcessor.Imaging.Helpers;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
- using ImageProcessor.Common.Exceptions;
- using ImageProcessor.Common.Extensions;
- using ImageProcessor.Imaging.Formats;
- using ImageProcessor.Imaging.Helpers;
-
///
/// Provides methods to resize images.
///
@@ -65,472 +64,54 @@ public class Resizer
///
/// The resized .
///
- public Bitmap ResizeImage(Image source, bool linear)
- {
- int width = this.ResizeLayer.Size.Width;
- int height = this.ResizeLayer.Size.Height;
- ResizeMode mode = this.ResizeLayer.ResizeMode;
- AnchorPosition anchor = this.ResizeLayer.AnchorPosition;
- bool upscale = this.ResizeLayer.Upscale;
- float[] centerCoordinates = this.ResizeLayer.CenterCoordinates;
- int maxWidth = this.ResizeLayer.MaxSize?.Width ?? int.MaxValue;
- int maxHeight = this.ResizeLayer.MaxSize?.Height ?? int.MaxValue;
- List restrictedSizes = this.ResizeLayer.RestrictedSizes;
- Point? anchorPoint = this.ResizeLayer.AnchorPoint;
-
- return this.ResizeImage(source, width, height, maxWidth, maxHeight, restrictedSizes, mode, anchor, upscale, centerCoordinates, linear, anchorPoint);
- }
-
- ///
- /// Gets an image resized using the composite color space without any gamma correction adjustments.
- ///
- /// The source image.
- /// The width to resize to.
- /// The height to resize to.
- /// The destination rectangle.
- ///
- /// The .
- ///
- protected virtual Bitmap ResizeComposite(Image source, int width, int height, Rectangle destination)
- {
- var resized = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
- resized.SetResolution(source.HorizontalResolution, source.VerticalResolution);
-
- using (var graphics = Graphics.FromImage(resized))
- {
- GraphicsHelper.SetGraphicsOptions(graphics);
- using (var attributes = new ImageAttributes())
- {
- attributes.SetWrapMode(WrapMode.TileFlipXY);
- graphics.DrawImage(source, destination, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
- }
- }
-
- return resized;
- }
-
- ///
- /// Gets an image resized using the linear color space with gamma correction adjustments.
- ///
- /// The source image.
- /// The width to resize to.
- /// The height to resize to.
- /// The destination rectangle.
- ///
- /// The .
- ///
- protected virtual Bitmap ResizeLinear(Image source, int width, int height, Rectangle destination) => this.ResizeLinear(source, width, height, destination, this.AnimationProcessMode);
-
- ///
- /// Gets an image resized using the linear color space with gamma correction adjustments.
- ///
- /// The source image.
- /// The width to resize to.
- /// The height to resize to.
- /// The destination rectangle.
- /// The process mode for frames in animated images.
- ///
- /// The .
- ///
- protected virtual Bitmap ResizeLinear(Image source, int width, int height, Rectangle destination, AnimationProcessMode animationProcessMode)
- {
- // Adjust the gamma value so that the image is in the linear color space.
- Bitmap linear = Adjustments.ToLinear(source.Copy(animationProcessMode));
-
- var resized = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
- resized.SetResolution(source.HorizontalResolution, source.VerticalResolution);
-
- using (var graphics = Graphics.FromImage(resized))
- {
- GraphicsHelper.SetGraphicsOptions(graphics);
- using (var attributes = new ImageAttributes())
- {
- attributes.SetWrapMode(WrapMode.TileFlipXY);
- graphics.DrawImage(linear, destination, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
- }
- }
-
- // Return to composite color space.
- resized = Adjustments.ToSRGB(resized);
-
- linear.Dispose();
- return resized;
- }
-
- ///
- /// Resizes the given image.
- ///
- /// The source to resize
- /// The width to resize the image to.
- /// The height to resize the image to.
- /// The default max width to resize the image to.
- /// The default max height to resize the image to.
- /// A containing image resizing restrictions.
- /// The mode with which to resize the image.
- /// The anchor position to place the image at.
- /// Whether to allow up-scaling of images. (Default true)
- ///
- /// If the resize mode is crop, you can set a specific center coordinate, use as alternative to anchorPosition
- ///
- /// Whether to resize the image using the linear color space.
- ///
- /// If resize mode is box pad, you can set a specific anchor coordinate, use as alternative to anchorPosition.
- ///
- ///
- /// The resized .
- ///
- private Bitmap ResizeImage(
+ public Bitmap ResizeImage(
Image source,
- int width,
- int height,
- int maxWidth,
- int maxHeight,
- List restrictedSizes,
- ResizeMode resizeMode = ResizeMode.Pad,
- AnchorPosition anchorPosition = AnchorPosition.Center,
- bool upscale = true,
- float[] centerCoordinates = null,
- bool linear = false,
- Point? anchorPoint = null)
+ bool linear)
{
Bitmap newImage = null;
try
{
- int sourceWidth = source.Width;
- int sourceHeight = source.Height;
-
- int destinationWidth = width;
- int destinationHeight = height;
-
- maxWidth = maxWidth > 0 ? maxWidth : int.MaxValue;
- maxHeight = maxHeight > 0 ? maxHeight : int.MaxValue;
-
- // Fractional variants for preserving aspect ratio.
- double percentHeight = Math.Abs(height / (double)sourceHeight);
- double percentWidth = Math.Abs(width / (double)sourceWidth);
-
- int destinationX = 0;
- int destinationY = 0;
-
- // Change the destination rectangle coordinates if box padding.
- if (resizeMode == ResizeMode.BoxPad)
+ Size sourceSize = source.Size;
+ int targetWidth = this.ResizeLayer.Size.Width;
+ int targetHeight = this.ResizeLayer.Size.Height;
+ int maxWidth = this.ResizeLayer.MaxSize?.Width ?? int.MaxValue;
+ int maxHeight = this.ResizeLayer.MaxSize?.Height ?? int.MaxValue;
+
+ // Ensure size is populated across both dimensions.
+ // These dimensions are used to calculate the final dimensions determined by the mode algorithm.
+ // If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio.
+ // If it is not possible to keep aspect ratio, make sure at least the minimum is is kept.
+ const int Min = 1;
+ if (targetWidth == 0 && targetHeight > 0)
{
- int boxPadHeight = height > 0 ? height : Convert.ToInt32(sourceHeight * percentWidth);
- int boxPadWidth = width > 0 ? width : Convert.ToInt32(sourceWidth * percentHeight);
-
- // Only calculate if upscaling.
- if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight)
- {
- destinationWidth = sourceWidth;
- destinationHeight = sourceHeight;
- width = boxPadWidth;
- height = boxPadHeight;
-
- upscale = true;
-
- if (anchorPoint.HasValue)
- {
- if (anchorPoint.Value.Y < 0)
- {
- destinationY = 0;
- }
- else if (anchorPoint.Value.Y + sourceHeight > boxPadHeight)
- {
- destinationY = boxPadHeight - sourceHeight;
- }
- else
- {
- destinationY = anchorPoint.Value.Y;
- }
-
- if (anchorPoint.Value.X < 0)
- {
- destinationX = 0;
- }
- else if (anchorPoint.Value.X + sourceWidth > boxPadWidth)
- {
- destinationX = boxPadWidth - sourceWidth;
- }
- else
- {
- destinationX = anchorPoint.Value.X;
- }
- }
- else
- {
- switch (anchorPosition)
- {
- case AnchorPosition.Left:
- destinationY = (height - sourceHeight) / 2;
- destinationX = 0;
- break;
- case AnchorPosition.Right:
- destinationY = (height - sourceHeight) / 2;
- destinationX = width - sourceWidth;
- break;
- case AnchorPosition.TopRight:
- destinationY = 0;
- destinationX = width - sourceWidth;
- break;
- case AnchorPosition.Top:
- destinationY = 0;
- destinationX = (width - sourceWidth) / 2;
- break;
- case AnchorPosition.TopLeft:
- destinationY = 0;
- destinationX = 0;
- break;
- case AnchorPosition.BottomRight:
- destinationY = height - sourceHeight;
- destinationX = width - sourceWidth;
- break;
- case AnchorPosition.Bottom:
- destinationY = height - sourceHeight;
- destinationX = (width - sourceWidth) / 2;
- break;
- case AnchorPosition.BottomLeft:
- destinationY = height - sourceHeight;
- destinationX = 0;
- break;
- default:
- destinationY = (height - sourceHeight) / 2;
- destinationX = (width - sourceWidth) / 2;
- break;
- }
- }
- }
- else
- {
- // Switch to pad mode to downscale and calculate from there.
- resizeMode = ResizeMode.Pad;
- }
+ targetWidth = (int)Math.Max(Min, Math.Round(sourceSize.Width * targetHeight / (float)sourceSize.Height));
}
- // Change the destination rectangle coordinates if padding and
- // there has been a set width and height.
- if (resizeMode == ResizeMode.Pad && width > 0 && height > 0)
+ if (targetHeight == 0 && targetWidth > 0)
{
- double ratio;
-
- if (percentHeight < percentWidth)
- {
- ratio = percentHeight;
- destinationWidth = Convert.ToInt32(sourceWidth * percentHeight);
-
- switch (anchorPosition)
- {
- case AnchorPosition.Left:
- case AnchorPosition.TopLeft:
- case AnchorPosition.BottomLeft:
- destinationX = 0;
- break;
- case AnchorPosition.Right:
- case AnchorPosition.TopRight:
- case AnchorPosition.BottomRight:
- destinationX = (int)(width - (sourceWidth * ratio));
- break;
- default:
- destinationX = Convert.ToInt32((width - (sourceWidth * ratio)) / 2);
- break;
- }
- }
- else
- {
- ratio = percentWidth;
- destinationHeight = Convert.ToInt32(sourceHeight * percentWidth);
-
- switch (anchorPosition)
- {
- case AnchorPosition.Top:
- case AnchorPosition.TopLeft:
- case AnchorPosition.TopRight:
- destinationY = 0;
- break;
- case AnchorPosition.Bottom:
- case AnchorPosition.BottomLeft:
- case AnchorPosition.BottomRight:
- destinationY = (int)(height - (sourceHeight * ratio));
- break;
- default:
- destinationY = (int)((height - (sourceHeight * ratio)) / 2);
- break;
- }
- }
+ targetHeight = (int)Math.Max(Min, Math.Round(sourceSize.Height * targetWidth / (float)sourceSize.Width));
}
- // Change the destination rectangle coordinates if cropping and
- // there has been a set width and height.
- if (resizeMode == ResizeMode.Crop && width > 0 && height > 0)
- {
- double ratio;
-
- if (percentHeight < percentWidth)
- {
- ratio = percentWidth;
-
- if (centerCoordinates?.Length > 0)
- {
- double center = -(ratio * sourceHeight) * centerCoordinates[0];
- destinationY = (int)center + (height / 2);
-
- if (destinationY > 0)
- {
- destinationY = 0;
- }
-
- if (destinationY < (int)(height - (sourceHeight * ratio)))
- {
- destinationY = (int)(height - (sourceHeight * ratio));
- }
- }
- else
- {
- switch (anchorPosition)
- {
- case AnchorPosition.Top:
- case AnchorPosition.TopLeft:
- case AnchorPosition.TopRight:
- destinationY = 0;
- break;
- case AnchorPosition.Bottom:
- case AnchorPosition.BottomLeft:
- case AnchorPosition.BottomRight:
- destinationY = (int)(height - (sourceHeight * ratio));
- break;
- default:
- destinationY = (int)((height - (sourceHeight * ratio)) / 2);
- break;
- }
- }
-
- destinationHeight = (int)Math.Ceiling(sourceHeight * percentWidth);
- }
- else
- {
- ratio = percentHeight;
-
- if (centerCoordinates?.Length > 0)
- {
- double center = -(ratio * sourceWidth) * centerCoordinates[1];
- destinationX = (int)center + (width / 2);
-
- if (destinationX > 0)
- {
- destinationX = 0;
- }
-
- if (destinationX < (int)(width - (sourceWidth * ratio)))
- {
- destinationX = (int)(width - (sourceWidth * ratio));
- }
- }
- else
- {
- switch (anchorPosition)
- {
- case AnchorPosition.Left:
- case AnchorPosition.TopLeft:
- case AnchorPosition.BottomLeft:
- destinationX = 0;
- break;
- case AnchorPosition.Right:
- case AnchorPosition.TopRight:
- case AnchorPosition.BottomRight:
- destinationX = (int)(width - (sourceWidth * ratio));
- break;
- default:
- destinationX = (int)((width - (sourceWidth * ratio)) / 2);
- break;
- }
- }
-
- destinationWidth = (int)Math.Ceiling(sourceWidth * percentHeight);
- }
- }
+ (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(source.Size, this.ResizeLayer, targetWidth, targetHeight);
- // Constrain the image to fit the maximum possible height or width.
- if (resizeMode == ResizeMode.Max)
- {
- // If either is 0, we don't need to figure out orientation
- if (width > 0 && height > 0)
- {
- // Integers must be cast to doubles to get needed precision
- double ratio = (double)height / width;
- double sourceRatio = (double)sourceHeight / sourceWidth;
-
- if (sourceRatio < ratio)
- {
- height = 0;
- }
- else
- {
- width = 0;
- }
- }
- }
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+ int width = size.Width;
+ int height = size.Height;
+ bool upscale = this.ResizeLayer.Upscale;
- // Resize the image until the shortest side reaches the set given dimension.
- if (resizeMode == ResizeMode.Min)
+ if (ResizeLayer.ResizeMode == ResizeMode.Min)
{
- height = height > 0 ? height : Convert.ToInt32(sourceHeight * percentWidth);
- width = width > 0 ? width : Convert.ToInt32(sourceWidth * percentHeight);
-
- double sourceRatio = (double)sourceHeight / sourceWidth;
-
// Ensure we can't upscale.
maxHeight = sourceHeight;
maxWidth = sourceWidth;
upscale = false;
-
- // Find the shortest distance to go.
- int widthDiff = sourceWidth - width;
- int heightDiff = sourceHeight - height;
-
- if (widthDiff < heightDiff)
- {
- destinationHeight = Convert.ToInt32(width * sourceRatio);
- height = destinationHeight;
- destinationWidth = width;
- }
- else if (widthDiff > heightDiff)
- {
- destinationHeight = height;
- destinationWidth = Convert.ToInt32(height / sourceRatio);
- width = destinationWidth;
- }
- else
- {
- if (height > width)
- {
- destinationHeight = Convert.ToInt32(sourceHeight * percentWidth);
- height = destinationHeight;
- }
- else if (width > height)
- {
- destinationWidth = Convert.ToInt32(sourceWidth * percentHeight);
- width = destinationWidth;
- }
- else
- {
- destinationWidth = width;
- destinationHeight = height;
- }
- }
}
- // If height or width is not passed we assume that the standard ratio is to be kept.
- if (height == 0)
- {
- destinationHeight = Convert.ToInt32(sourceHeight * percentWidth);
- height = destinationHeight;
- }
-
- if (width == 0)
- {
- destinationWidth = Convert.ToInt32(sourceWidth * percentHeight);
- width = destinationWidth;
- }
+ maxWidth = maxWidth > 0 ? maxWidth : int.MaxValue;
+ maxHeight = maxHeight > 0 ? maxHeight : int.MaxValue;
+ List restrictedSizes = this.ResizeLayer.RestrictedSizes;
// Restrict sizes
if (restrictedSizes?.Count > 0)
@@ -560,15 +141,15 @@ private Bitmap ResizeImage(
if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight)
{
// Exit if upscaling is not allowed.
- if ((width > sourceWidth || height > sourceHeight) && !upscale && resizeMode != ResizeMode.Stretch)
+ if ((width > sourceWidth || height > sourceHeight)
+ && !upscale
+ && this.ResizeLayer.ResizeMode != ResizeMode.Stretch)
{
return (Bitmap)source;
}
- // Do the resize.
- var destination = new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight);
-
- newImage = linear ? this.ResizeLinear(source, width, height, destination, this.AnimationProcessMode) : this.ResizeComposite(source, width, height, destination);
+ newImage = linear ? this.ResizeLinear(source, width, height, rectangle, this.AnimationProcessMode)
+ : this.ResizeComposite(source, width, height, rectangle);
// Reassign the image.
source.Dispose();
@@ -584,5 +165,103 @@ private Bitmap ResizeImage(
return (Bitmap)source;
}
+
+ ///
+ /// Gets an image resized using the composite color space without any gamma correction adjustments.
+ ///
+ /// The source image.
+ /// The target width to resize to.
+ /// The target height to resize to.
+ /// The destination rectangle.
+ ///
+ /// The .
+ ///
+ protected virtual Bitmap ResizeComposite(Image source, int width, int height, Rectangle destination)
+ {
+ var resized = new Bitmap(width, height, source.PixelFormat);
+ resized.SetResolution(source.HorizontalResolution, source.VerticalResolution);
+
+ using (var graphics = Graphics.FromImage(resized))
+ {
+ GraphicsHelper.SetGraphicsOptions(graphics);
+ using (var attributes = new ImageAttributes())
+ {
+ attributes.SetWrapMode(WrapMode.TileFlipXY);
+ graphics.DrawImage(
+ source,
+ destination,
+ 0,
+ 0,
+ source.Width,
+ source.Height,
+ GraphicsUnit.Pixel,
+ attributes);
+ }
+ }
+
+ return resized;
+ }
+
+ ///
+ /// Gets an image resized using the linear color space with gamma correction adjustments.
+ ///
+ /// The source image.
+ /// The width to resize to.
+ /// The height to resize to.
+ /// The destination rectangle.
+ ///
+ /// The .
+ ///
+ protected virtual Bitmap ResizeLinear(Image source, int targetWidth, int targetHeight, Rectangle destination)
+ => this.ResizeLinear(source, targetWidth, targetHeight, destination, this.AnimationProcessMode);
+
+ ///
+ /// Gets an image resized using the linear color space with gamma correction adjustments.
+ ///
+ /// The source image.
+ /// The width to resize to.
+ /// The height to resize to.
+ /// The destination rectangle.
+ /// The process mode for frames in animated images.
+ ///
+ /// The .
+ ///
+ protected virtual Bitmap ResizeLinear(
+ Image source,
+ int width,
+ int height,
+ Rectangle destination,
+ AnimationProcessMode animationProcessMode)
+ {
+ // Adjust the gamma value so that the image is in the linear color space.
+ Bitmap linear = Adjustments.ToLinear(source.Copy(animationProcessMode));
+
+ var resized = new Bitmap(width, height, source.PixelFormat);
+ resized.SetResolution(source.HorizontalResolution, source.VerticalResolution);
+
+ using (var graphics = Graphics.FromImage(resized))
+ {
+ GraphicsHelper.SetGraphicsOptions(graphics);
+ using (var attributes = new ImageAttributes())
+ {
+ attributes.SetWrapMode(WrapMode.TileFlipXY);
+ graphics.DrawImage(
+ linear,
+ destination,
+ 0,
+ 0,
+ source.Width,
+ source.Height,
+ GraphicsUnit.Pixel,
+ attributes);
+ }
+ }
+
+ // Return to composite color space.
+ resized = Adjustments.ToSRGB(resized);
+
+ linear.Dispose();
+ return resized;
+ }
}
}
diff --git a/src/ImageProcessor/Imaging/RoundedCornerLayer.cs b/src/ImageProcessor/Imaging/RoundedCornerLayer.cs
index 3e4e3017c..69442befc 100644
--- a/src/ImageProcessor/Imaging/RoundedCornerLayer.cs
+++ b/src/ImageProcessor/Imaging/RoundedCornerLayer.cs
@@ -10,10 +10,12 @@
namespace ImageProcessor.Imaging
{
+ using System;
+
///
/// Encapsulates the properties required to add rounded corners to an image.
///
- public class RoundedCornerLayer
+ public class RoundedCornerLayer : IEquatable
{
///
/// Initializes a new instance of the class.
@@ -68,45 +70,34 @@ public RoundedCornerLayer(int radius, bool topLeft = true, bool topRight = true,
public bool BottomRight { get; set; }
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is RoundedCornerLayer rounded))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is RoundedCornerLayer roundedCornerLayer && this.Equals(roundedCornerLayer);
- return this.Radius == rounded.Radius
- && this.TopLeft == rounded.TopLeft && this.TopRight == rounded.TopRight
- && this.BottomLeft == rounded.BottomLeft && this.BottomRight == rounded.BottomRight;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(RoundedCornerLayer other) => other != null
+ && this.Radius == other.Radius
+ && this.TopLeft == other.TopLeft
+ && this.TopRight == other.TopRight
+ && this.BottomLeft == other.BottomLeft
+ && this.BottomRight == other.BottomRight;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Radius;
- hashCode = (hashCode * 397) ^ this.TopLeft.GetHashCode();
- hashCode = (hashCode * 397) ^ this.TopRight.GetHashCode();
- hashCode = (hashCode * 397) ^ this.BottomLeft.GetHashCode();
- return (hashCode * 397) ^ this.BottomRight.GetHashCode();
- }
- }
+ public override int GetHashCode() => (this.Radius, this.TopLeft, this.TopRight, this.BottomLeft, this.BottomRight).GetHashCode();
}
}
diff --git a/src/ImageProcessor/Imaging/TextLayer.cs b/src/ImageProcessor/Imaging/TextLayer.cs
index 049fa92af..837299c18 100644
--- a/src/ImageProcessor/Imaging/TextLayer.cs
+++ b/src/ImageProcessor/Imaging/TextLayer.cs
@@ -18,7 +18,7 @@ namespace ImageProcessor.Imaging
///
/// Encapsulates the properties required to add a layer of text to an image.
///
- public class TextLayer : IDisposable
+ public class TextLayer : IDisposable, IEquatable
{
///
/// A value indicating whether this instance of the given entity has been disposed.
@@ -96,58 +96,40 @@ public class TextLayer : IDisposable
public bool RightToLeft { get; set; }
///
- /// Returns a value that indicates whether the specified object is an
- /// object that is equivalent to
- /// this object.
+ /// Determines whether the specified , is equal to this instance.
///
- ///
- /// The object to test.
- ///
+ /// The to compare with this instance.
///
- /// True if the given object is an object that is equivalent to
- /// this object; otherwise, false.
+ /// true if the specified is equal to this instance; otherwise, false.
///
- public override bool Equals(object obj)
- {
- if (!(obj is TextLayer textLayer))
- {
- return false;
- }
+ public override bool Equals(object obj) => obj is TextLayer textLayer && this.Equals(textLayer);
- return this.Text == textLayer.Text
- && this.FontColor == textLayer.FontColor
- && this.FontFamily.Equals(textLayer.FontFamily)
- && this.FontSize == textLayer.FontSize
- && this.Style == textLayer.Style
- && this.DropShadow == textLayer.DropShadow
- && this.Opacity == textLayer.Opacity
- && this.Position == textLayer.Position
- && this.Vertical == textLayer.Vertical
- && this.RightToLeft == textLayer.RightToLeft;
- }
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ ///
+ /// true if the current object is equal to the parameter; otherwise, false.
+ ///
+ public bool Equals(TextLayer other) => other != null
+ && this.Text == other.Text
+ && this.FontColor == other.FontColor
+ && (this.FontFamily == null || other.FontFamily == null ? this.FontFamily == other.FontFamily : this.FontFamily.Equals(other.FontFamily))
+ && this.FontSize == other.FontSize
+ && this.Style == other.Style
+ && this.Opacity == other.Opacity
+ && this.Position == other.Position
+ && this.DropShadow == other.DropShadow
+ && this.Vertical == other.Vertical
+ && this.RightToLeft == other.RightToLeft;
///
- /// Returns the hash code for this instance.
+ /// Returns a hash code for this instance.
///
///
- /// A 32-bit signed integer that is the hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.Text?.GetHashCode() ?? 0;
- hashCode = (hashCode * 397) ^ this.DropShadow.GetHashCode();
- hashCode = (hashCode * 397) ^ (this.FontFamily?.GetHashCode() ?? 0);
- hashCode = (hashCode * 397) ^ (int)this.Style;
- hashCode = (hashCode * 397) ^ this.FontColor.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Opacity;
- hashCode = (hashCode * 397) ^ this.FontSize;
- hashCode = (hashCode * 397) ^ this.Position.GetHashCode();
- hashCode = (hashCode * 397) ^ this.Vertical.GetHashCode();
- return (hashCode * 397) ^ this.RightToLeft.GetHashCode();
- }
- }
+ public override int GetHashCode() => (this.Text, this.FontColor, this.FontFamily, this.FontSize, this.Style, this.Opacity, this.Position, this.DropShadow, this.Vertical, this.RightToLeft).GetHashCode();
///
/// Disposes the object and frees resources for the Garbage Collector.
diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs
index ae53745fc..6f896c314 100644
--- a/src/ImageProcessor/Processors/Resize.cs
+++ b/src/ImageProcessor/Processors/Resize.cs
@@ -77,7 +77,7 @@ public Image ProcessImage(ImageFactory factory)
// Augment the layer with the extra information.
resizeLayer.RestrictedSizes = this.RestrictedSizes;
- var maxSize = new Size();
+ Size maxSize = default;
int.TryParse(this.Settings["MaxWidth"], NumberStyles.Any, CultureInfo.InvariantCulture, out int maxWidth);
int.TryParse(this.Settings["MaxHeight"], NumberStyles.Any, CultureInfo.InvariantCulture, out int maxHeight);
diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs
index 3feaec74d..46c2ad6e0 100644
--- a/src/ImageProcessor/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor/Properties/AssemblyInfo.cs
@@ -41,8 +41,8 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.5.6.0")]
-[assembly: AssemblyFileVersion("2.5.6.0")]
+[assembly: AssemblyVersion("2.9.0.00000")]
+[assembly: AssemblyFileVersion("2.9.0.00000")]
[assembly: InternalsVisibleTo("ImageProcessor.UnitTests")]
[assembly: InternalsVisibleTo("ImageProcessor.Web")]
diff --git a/src/ImageProcessor/packages.config b/src/ImageProcessor/packages.config
new file mode 100644
index 000000000..8653b8e4c
--- /dev/null
+++ b/src/ImageProcessor/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/ImageProcessor.Playground/Program.cs b/tests/ImageProcessor.Playground/Program.cs
index 225f798cd..74e59d8eb 100644
--- a/tests/ImageProcessor.Playground/Program.cs
+++ b/tests/ImageProcessor.Playground/Program.cs
@@ -68,7 +68,8 @@ public static void Main(string[] args)
try
{
imageFactory.Load(inStream)
- .Crop(new Rectangle(0, 0, imageFactory.Image.Width / 2, imageFactory.Image.Height / 2))
+ .Resize(new Size(426, 0))
+ //.Crop(new Rectangle(0, 0, imageFactory.Image.Width / 2, imageFactory.Image.Height / 2))
.Save(Path.GetFullPath(Path.Combine(outPath, fileInfo.Name)));
}
catch (Exception ex)
diff --git a/tests/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/tests/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
index 31e5fc607..049a87497 100644
--- a/tests/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
+++ b/tests/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
@@ -1008,7 +1008,7 @@ public void ResizeIsApplied()
// Check we min correctly using the shortest size.
imageFactory.Resize(minLayer);
Assert.AreEqual(imageFactory.Image.Size, new Size(400, 300));
- imageFactory.Save(OutputPath + "resize-crop-" + i + ".jpg");
+ imageFactory.Save(OutputPath + "resize-min-" + i + ".jpg");
// Check padding with only a single dimension specified (width)
imageFactory.Resize(paddedSingleDimensionWidthLayer);
diff --git a/tests/ImageProcessor.UnitTests/Images/792.jpeg b/tests/ImageProcessor.UnitTests/Images/792.jpeg
new file mode 100644
index 000000000..4e0112eb9
Binary files /dev/null and b/tests/ImageProcessor.UnitTests/Images/792.jpeg differ
diff --git a/tests/ImageProcessor.UnitTests/Images/format-Penguins.tif b/tests/ImageProcessor.UnitTests/Images/format-Penguins.tif
index c789aaec2..8a79fd09a 100644
Binary files a/tests/ImageProcessor.UnitTests/Images/format-Penguins.tif and b/tests/ImageProcessor.UnitTests/Images/format-Penguins.tif differ
diff --git a/tests/ImageProcessor.UnitTests/Imaging/Filters/Photo/MatrixFilterBaseTests.cs b/tests/ImageProcessor.UnitTests/Imaging/Filters/Photo/MatrixFilterBaseTests.cs
index d5b76bb3f..c87f8afdf 100644
--- a/tests/ImageProcessor.UnitTests/Imaging/Filters/Photo/MatrixFilterBaseTests.cs
+++ b/tests/ImageProcessor.UnitTests/Imaging/Filters/Photo/MatrixFilterBaseTests.cs
@@ -29,7 +29,7 @@ public static void MatrixFilterBaseImplementsEqualsBasedOnMatrixPropertyVariant(
VariantFilterBase first = new VariantFilterBase();
VariantFilterBase second = new VariantFilterBase();
- first.Equals(second).Should().BeFalse();
+ first.Equals(second).Should().BeTrue();
}
internal static ColorMatrix InvariantColorMatrix = new ColorMatrix(new[]
diff --git a/tests/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs b/tests/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs
index ca47f7782..2a0f83e5e 100644
--- a/tests/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs
+++ b/tests/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs
@@ -273,30 +273,18 @@ public void TestResizeRegex()
{
Dictionary data = new Dictionary
{
- {
- "width=300", new ResizeLayer(new Size(300, 0))
- },
- {
- "height=300", new ResizeLayer(new Size(0, 300))
- },
- {
- "height=300.6", new ResizeLayer(new Size(0, 301))
- },
- {
- "height=300&mode=crop", new ResizeLayer(new Size(0, 300), ResizeMode.Crop)
- },
- {
- "width=300&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop)
- },
- {
- "width=300.2&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop)
- },
- {
- "width=600&heightratio=0.416", new ResizeLayer(new Size(600, 250))
- },
- {
- "width=600&height=250&mode=max", new ResizeLayer(new Size(600, 250), ResizeMode.Max)
- }
+ { "width=300", new ResizeLayer(new Size(300, 0)) },
+ { "height=300", new ResizeLayer(new Size(0, 300)) },
+ { "height=300.6", new ResizeLayer(new Size(0, 301)) }, // Round size units
+ { "height=300&mode=crop", new ResizeLayer(new Size(0, 300), ResizeMode.Crop) },
+ { "width=300&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop) },
+ { "width=300.2&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop) }, // Round size units
+ { "width=600&heightratio=0.416", new ResizeLayer(new Size(600, 250)) },
+ { "width=600&height=250&mode=max", new ResizeLayer(new Size(600, 250), ResizeMode.Max) },
+ { "width=600&height=250¢er=1,0.5", new ResizeLayer(new Size(600, 250), centerCoordinates: new [] { 1f, 0.5f }) }, // Center coordinates (Y,X)
+ { "width=600&height=250¢er=0.5,0.25", new ResizeLayer(new Size(600, 250)) { Center = new PointF(0.25f, 0.5f) } }, // Center coordinates (Y,X) to PointF
+ { "width=600&height=250¢er=0.5", new ResizeLayer(new Size(600, 250)) }, // Invalid center coordinates should not result in 0,0
+ { "width=600&height=250¢er=y,x", new ResizeLayer(new Size(600, 250)) } // Invalid center coordinates should not result in 0,0
};
Processors.Resize resize = new Processors.Resize();