Browse Source

Update to c#6 syntax, make structs immutable

Former-commit-id: 422cca4d32fcde728b090058088408d56fd4cbb0
Former-commit-id: 8d29aadde9a6b84d9d873b14142907e8228da4cc
Former-commit-id: 79aba44ef77760b6d58bfa7cdaf59060c6041be5
af/merge-core
James South 11 years ago
parent
commit
6e0780bcc2
  1. 55
      src/ImageProcessor/Colors/Bgra.cs
  2. 48
      src/ImageProcessor/Colors/YCbCr.cs
  3. 10
      src/ImageProcessor/Common/Helpers/Guard.cs
  4. 8
      src/ImageProcessor/Formats/Bmp/BmpDecoder.cs
  5. 21
      src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs
  6. 5
      src/ImageProcessor/Formats/Bmp/BmpEncoder.cs
  7. 8
      src/ImageProcessor/Formats/Png/PngDecoder.cs
  8. 14
      src/ImageProcessor/Formats/Png/PngDecoderCore.cs
  9. 12
      src/ImageProcessor/Formats/Png/PngEncoder.cs
  10. 37
      src/ImageProcessor/Image.cs
  11. 61
      src/ImageProcessor/ImageBase.cs
  12. 34
      src/ImageProcessor/ImageProperty.cs
  13. 52
      src/ImageProcessor/Numerics/Point.cs
  14. 122
      src/ImageProcessor/Numerics/Rectangle.cs
  15. 51
      src/ImageProcessor/Numerics/Size.cs
  16. 1
      tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs

55
src/ImageProcessor/Colors/Bgra.cs

@ -44,31 +44,31 @@ namespace ImageProcessor
/// Holds the blue component of the color /// Holds the blue component of the color
/// </summary> /// </summary>
[FieldOffset(0)] [FieldOffset(0)]
public byte B; public readonly byte B;
/// <summary> /// <summary>
/// Holds the green component of the color /// Holds the green component of the color
/// </summary> /// </summary>
[FieldOffset(1)] [FieldOffset(1)]
public byte G; public readonly byte G;
/// <summary> /// <summary>
/// Holds the red component of the color /// Holds the red component of the color
/// </summary> /// </summary>
[FieldOffset(2)] [FieldOffset(2)]
public byte R; public readonly byte R;
/// <summary> /// <summary>
/// Holds the alpha component of the color /// Holds the alpha component of the color
/// </summary> /// </summary>
[FieldOffset(3)] [FieldOffset(3)]
public byte A; public readonly byte A;
/// <summary> /// <summary>
/// Permits the <see cref="Bgra"/> to be treated as a 32 bit integer. /// Permits the <see cref="Bgra"/> to be treated as a 32 bit integer.
/// </summary> /// </summary>
[FieldOffset(0)] [FieldOffset(0)]
public int BGRA; public readonly int BGRA;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Bgra"/> struct. /// Initializes a new instance of the <see cref="Bgra"/> struct.
@ -142,7 +142,7 @@ namespace ImageProcessor
if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3) if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3)
{ {
throw new ArgumentException("Hexadecimal string is not in the correct format.", "hex"); throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
} }
if (hex.Length == 8) if (hex.Length == 8)
@ -176,13 +176,7 @@ namespace ImageProcessor
/// Gets a value indicating whether this <see cref="Bgra"/> is empty. /// Gets a value indicating whether this <see cref="Bgra"/> is empty.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty public bool IsEmpty => this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0;
{
get
{
return this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="Bgra"/> objects. The result specifies whether the values /// Compares two <see cref="Bgra"/> objects. The result specifies whether the values
@ -249,7 +243,14 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
return this.GetHashCode(this); unchecked
{
int hashCode = this.B.GetHashCode();
hashCode = (hashCode * 397) ^ this.G.GetHashCode();
hashCode = (hashCode * 397) ^ this.R.GetHashCode();
hashCode = (hashCode * 397) ^ this.A.GetHashCode();
return hashCode;
}
} }
/// <summary> /// <summary>
@ -265,7 +266,7 @@ namespace ImageProcessor
return "Color [ Empty ]"; return "Color [ Empty ]";
} }
return string.Format("Color [ B={0}, G={1}, R={2}, A={3} ]", this.B, this.G, this.R, this.A); return $"Color [ B={this.B}, G={this.G}, R={this.R}, A={this.A} ]";
} }
/// <summary> /// <summary>
@ -277,29 +278,7 @@ namespace ImageProcessor
/// <param name="other">An object to compare with this object.</param> /// <param name="other">An object to compare with this object.</param>
public bool Equals(Bgra other) public bool Equals(Bgra other)
{ {
return this.B.Equals(other.B) && this.G.Equals(other.G) return this.BGRA == other.BGRA;
&& this.R.Equals(other.R) && this.A.Equals(other.A);
}
/// <summary>
/// Returns the hash code for the given instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Bgra"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(Bgra color)
{
unchecked
{
int hashCode = color.B.GetHashCode();
hashCode = (hashCode * 397) ^ color.G.GetHashCode();
hashCode = (hashCode * 397) ^ color.R.GetHashCode();
hashCode = (hashCode * 397) ^ color.A.GetHashCode();
return hashCode;
}
} }
} }
} }

48
src/ImageProcessor/Colors/YCbCr.cs

@ -31,19 +31,19 @@ namespace ImageProcessor
/// Holds the Y luminance component. /// Holds the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public float Y; public float Y { get; }
/// <summary> /// <summary>
/// Holds the Cb chroma component. /// Holds the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public float Cb; public float Cb { get; }
/// <summary> /// <summary>
/// Holds the Cr chroma component. /// Holds the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public float Cr; public float Cr { get; }
/// <summary> /// <summary>
/// The epsilon for comparing floating point numbers. /// The epsilon for comparing floating point numbers.
@ -67,15 +67,9 @@ namespace ImageProcessor
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty. /// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty public bool IsEmpty => Math.Abs(this.Y) < Epsilon
{ && Math.Abs(this.Cb) < Epsilon
get && Math.Abs(this.Cr) < Epsilon;
{
return Math.Abs(this.Y) < Epsilon
&& Math.Abs(this.Cb) < Epsilon
&& Math.Abs(this.Cr) < Epsilon;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="YCbCr"/> objects. The result specifies whether the values /// Compares two <see cref="YCbCr"/> objects. The result specifies whether the values
@ -190,7 +184,13 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
return this.GetHashCode(this); unchecked
{
int hashCode = this.Y.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cb.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cr.GetHashCode();
return hashCode;
}
} }
/// <summary> /// <summary>
@ -206,7 +206,7 @@ namespace ImageProcessor
return "YCbCrColor [ Empty ]"; return "YCbCrColor [ Empty ]";
} }
return string.Format("YCbCrColor [ Y={0:#0.##}, Cb={1:#0.##}, Cr={2:#0.##} ]", this.Y, this.Cb, this.Cr); return $"YCbCrColor [ Y={this.Y:#0.##}, Cb={this.Cb:#0.##}, Cr={this.Cr:#0.##} ]";
} }
/// <summary> /// <summary>
@ -222,25 +222,5 @@ namespace ImageProcessor
&& this.Cb.Equals(other.Cb) && this.Cb.Equals(other.Cb)
&& this.Cr.Equals(other.Cr); && this.Cr.Equals(other.Cr);
} }
/// <summary>
/// Returns the hash code for the given instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Bgra"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(YCbCr color)
{
unchecked
{
int hashCode = color.Y.GetHashCode();
hashCode = (hashCode * 397) ^ color.Cb.GetHashCode();
hashCode = (hashCode * 397) ^ color.Cr.GetHashCode();
return hashCode;
}
}
} }
} }

10
src/ImageProcessor/Common/Helpers/Guard.cs

@ -91,7 +91,7 @@ namespace ImageProcessor
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
string.Format(CultureInfo.CurrentCulture, "Value must be less than {0}.", max)); $"Value must be less than {max}.");
} }
} }
@ -112,7 +112,7 @@ namespace ImageProcessor
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
string.Format(CultureInfo.CurrentCulture, "Value must be less than or equal to {0}.", max)); $"Value must be less than or equal to {max}.");
} }
} }
@ -133,7 +133,7 @@ namespace ImageProcessor
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
string.Format(CultureInfo.CurrentCulture, "Value must be greater than {0}.", min)); $"Value must be greater than {min}.");
} }
} }
@ -154,7 +154,7 @@ namespace ImageProcessor
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
string.Format(CultureInfo.CurrentCulture, "Value must be greater than or equal to {0}.", min)); $"Value must be greater than or equal to {min}.");
} }
} }
@ -176,7 +176,7 @@ namespace ImageProcessor
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
parameterName, parameterName,
string.Format(CultureInfo.CurrentCulture, "Value must be greater than or equal to {0} and less than or equal to {1}.", min, max)); $"Value must be greater than or equal to {min} and less than or equal to {max}.");
} }
} }
} }

8
src/ImageProcessor/Formats/Bmp/BmpDecoder.cs

@ -34,13 +34,7 @@ namespace ImageProcessor.Formats
/// Gets the size of the header for this image type. /// Gets the size of the header for this image type.
/// </summary> /// </summary>
/// <value>The size of the header.</value> /// <value>The size of the header.</value>
public int HeaderSize public int HeaderSize => 2;
{
get
{
return 2;
}
}
/// <summary> /// <summary>
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified /// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified

21
src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs

@ -33,8 +33,6 @@ namespace ImageProcessor.Formats
/// </summary> /// </summary>
private const int Rgb16BMask = 0x0000001F; private const int Rgb16BMask = 0x0000001F;
#region Fields
/// <summary> /// <summary>
/// The stream to decode from. /// The stream to decode from.
/// </summary> /// </summary>
@ -51,10 +49,6 @@ namespace ImageProcessor.Formats
/// </summary> /// </summary>
private BmpInfoHeader infoHeader; private BmpInfoHeader infoHeader;
#endregion
#region IImageDecoder Members
/// <summary> /// <summary>
/// Decodes the image from the specified this._stream and sets /// Decodes the image from the specified this._stream and sets
/// the data to image. /// the data to image.
@ -99,8 +93,7 @@ namespace ImageProcessor.Formats
{ {
if (colorMapSize > 255 * 4) if (colorMapSize > 255 * 4)
{ {
throw new ImageFormatException( throw new ImageFormatException($"Invalid bmp colormap size '{colorMapSize}'");
string.Format("Invalid bmp colormap size '{0}'", colorMapSize));
} }
palette = new byte[colorMapSize]; palette = new byte[colorMapSize];
@ -111,12 +104,8 @@ namespace ImageProcessor.Formats
if (this.infoHeader.Width > ImageBase.MaxWidth || this.infoHeader.Height > ImageBase.MaxHeight) if (this.infoHeader.Width > ImageBase.MaxWidth || this.infoHeader.Height > ImageBase.MaxHeight)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
string.Format( $"The input bitmap '{this.infoHeader.Width}x{this.infoHeader.Height}' is "
"The input bitmap '{0}x{1}' is bigger then the max allowed size '{2}x{3}'", + $"bigger then the max allowed size '{ImageBase.MaxWidth}x{ImageBase.MaxHeight}'");
this.infoHeader.Width,
this.infoHeader.Height,
ImageBase.MaxWidth,
ImageBase.MaxHeight));
} }
byte[] imageData = new byte[this.infoHeader.Width * this.infoHeader.Height * 4]; byte[] imageData = new byte[this.infoHeader.Width * this.infoHeader.Height * 4];
@ -127,7 +116,7 @@ namespace ImageProcessor.Formats
if (this.infoHeader.HeaderSize != 40) if (this.infoHeader.HeaderSize != 40)
{ {
throw new ImageFormatException( throw new ImageFormatException(
string.Format("Header Size value '{0}' is not valid.", this.infoHeader.HeaderSize)); $"Header Size value '{this.infoHeader.HeaderSize}' is not valid.");
} }
if (this.infoHeader.BitsPerPixel == 32) if (this.infoHeader.BitsPerPixel == 32)
@ -416,7 +405,5 @@ namespace ImageProcessor.Formats
Offset = BitConverter.ToInt32(data, 10) Offset = BitConverter.ToInt32(data, 10)
}; };
} }
#endregion
} }
} }

5
src/ImageProcessor/Formats/Bmp/BmpEncoder.cs

@ -28,10 +28,7 @@ namespace ImageProcessor.Formats
/// <summary> /// <summary>
/// Gets the default file extension for this encoder. /// Gets the default file extension for this encoder.
/// </summary> /// </summary>
public string Extension public string Extension => "BMP";
{
get { return "BMP"; }
}
/// <summary> /// <summary>
/// Returns a value indicating whether the <see cref="IImageEncoder"/> supports the specified /// Returns a value indicating whether the <see cref="IImageEncoder"/> supports the specified

8
src/ImageProcessor/Formats/Png/PngDecoder.cs

@ -39,13 +39,7 @@ namespace ImageProcessor.Formats
/// Gets the size of the header for this image type. /// Gets the size of the header for this image type.
/// </summary> /// </summary>
/// <value>The size of the header.</value> /// <value>The size of the header.</value>
public int HeaderSize public int HeaderSize => 8;
{
get
{
return 8;
}
}
/// <summary> /// <summary>
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified /// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified

14
src/ImageProcessor/Formats/Png/PngDecoderCore.cs

@ -157,12 +157,8 @@ namespace ImageProcessor.Formats
if (this.header.Width > ImageBase.MaxWidth || this.header.Height > ImageBase.MaxHeight) if (this.header.Width > ImageBase.MaxWidth || this.header.Height > ImageBase.MaxHeight)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
string.Format( $"The input png '{this.header.Width}x{this.header.Height}' is bigger thean the "
"The input png '{0}x{1}' is bigger then the max allowed size '{2}x{3}'", + $"max allowed size '{ImageBase.MaxWidth}x{ImageBase.MaxHeight}'");
this.header.Width,
this.header.Height,
ImageBase.MaxWidth,
ImageBase.MaxHeight));
} }
byte[] pixels = new byte[this.header.Width * this.header.Height * 4]; byte[] pixels = new byte[this.header.Width * this.header.Height * 4];
@ -483,11 +479,7 @@ namespace ImageProcessor.Formats
{ {
if (chunk.Length > MaxChunkSize) if (chunk.Length > MaxChunkSize)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException($"Png chunk size '{chunk.Length}' exceeds the maximum '{MaxChunkSize}'");
string.Format(
"Png chunk size '{0}' exceeds the '{1}'",
chunk.Length,
MaxChunkSize));
} }
chunk.Data = new byte[chunk.Length]; chunk.Data = new byte[chunk.Length];

12
src/ImageProcessor/Formats/Png/PngEncoder.cs

@ -72,10 +72,7 @@ namespace ImageProcessor.Formats
/// Gets the default file extension for this encoder. /// Gets the default file extension for this encoder.
/// </summary> /// </summary>
/// <value>The default file extension for this encoder.</value> /// <value>The default file extension for this encoder.</value>
public string Extension public string Extension => "PNG";
{
get { return "PNG"; }
}
/// <summary> /// <summary>
/// Indicates if the image encoder supports the specified /// Indicates if the image encoder supports the specified
@ -389,10 +386,7 @@ namespace ImageProcessor.Formats
} }
finally finally
{ {
if (memoryStream != null) memoryStream?.Dispose();
{
memoryStream.Dispose();
}
} }
int numChunks = bufferLength / MaxBlockSize; int numChunks = bufferLength / MaxBlockSize;
@ -453,7 +447,7 @@ namespace ImageProcessor.Formats
/// <param name="data">The <see cref="T:byte[]"/> containing data.</param> /// <param name="data">The <see cref="T:byte[]"/> containing data.</param>
private void WriteChunk(Stream stream, string type, byte[] data) private void WriteChunk(Stream stream, string type, byte[] data)
{ {
this.WriteChunk(stream, type, data, 0, data != null ? data.Length : 0); this.WriteChunk(stream, type, data, 0, data?.Length ?? 0);
} }
/// <summary> /// <summary>

37
src/ImageProcessor/Image.cs

@ -18,7 +18,7 @@ namespace ImageProcessor
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ImageProcessor.Formats; using Formats;
/// <summary> /// <summary>
/// Image class which stores the pixels and provides common functionality /// Image class which stores the pixels and provides common functionality
@ -66,16 +66,6 @@ namespace ImageProcessor
new PngEncoder(), new PngEncoder(),
}); });
/// <summary>
/// The collection of image frames.
/// </summary>
private readonly IList<ImageFrame> frames = new List<ImageFrame>();
/// <summary>
/// The collection of image properties.
/// </summary>
private readonly IList<ImageProperty> properties = new List<ImageProperty>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Image"/> class. /// Initializes a new instance of the <see cref="Image"/> class.
/// </summary> /// </summary>
@ -152,18 +142,12 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Gets a list of default decoders. /// Gets a list of default decoders.
/// </summary> /// </summary>
public static IList<IImageDecoder> Decoders public static IList<IImageDecoder> Decoders => DefaultDecoders.Value;
{
get { return DefaultDecoders.Value; }
}
/// <summary> /// <summary>
/// Gets a list of default encoders. /// Gets a list of default encoders.
/// </summary> /// </summary>
public static IList<IImageEncoder> Encoders public static IList<IImageEncoder> Encoders => DefaultEncoders.Value;
{
get { return DefaultEncoders.Value; }
}
/// <summary> /// <summary>
/// Gets or sets the frame delay. /// Gets or sets the frame delay.
@ -236,28 +220,19 @@ namespace ImageProcessor
/// <value> /// <value>
/// <c>true</c> if this image is animated; otherwise, <c>false</c>. /// <c>true</c> if this image is animated; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsAnimated public bool IsAnimated => this.Frames.Count > 0;
{
get { return this.frames.Count > 0; }
}
/// <summary> /// <summary>
/// Gets the other frames for the animation. /// Gets the other frames for the animation.
/// </summary> /// </summary>
/// <value>The list of frame images.</value> /// <value>The list of frame images.</value>
public IList<ImageFrame> Frames public IList<ImageFrame> Frames { get; } = new List<ImageFrame>();
{
get { return this.frames; }
}
/// <summary> /// <summary>
/// Gets the list of properties for storing meta information about this image. /// Gets the list of properties for storing meta information about this image.
/// </summary> /// </summary>
/// <value>A list of image properties.</value> /// <value>A list of image properties.</value>
public IList<ImageProperty> Properties public IList<ImageProperty> Properties { get; } = new List<ImageProperty>();
{
get { return this.properties; }
}
/// <summary> /// <summary>
/// Loads the image from the given stream. /// Loads the image from the given stream.

61
src/ImageProcessor/ImageBase.cs

@ -19,16 +19,6 @@ namespace ImageProcessor
/// </summary> /// </summary>
public abstract class ImageBase public abstract class ImageBase
{ {
/// <summary>
/// The maximum allowable width in pixels.
/// </summary>
private static int maxWidth = int.MaxValue;
/// <summary>
/// The maximum allowable height in pixels.
/// </summary>
private static int maxHeight = int.MaxValue;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageBase"/> class. /// Initializes a new instance of the <see cref="ImageBase"/> class.
/// </summary> /// </summary>
@ -83,34 +73,12 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Gets or sets the maximum allowable width in pixels. /// Gets or sets the maximum allowable width in pixels.
/// </summary> /// </summary>
public static int MaxWidth public static int MaxWidth { get; set; } = int.MaxValue;
{
get
{
return maxWidth;
}
set
{
maxWidth = value;
}
}
/// <summary> /// <summary>
/// Gets or sets the maximum allowable height in pixels. /// Gets or sets the maximum allowable height in pixels.
/// </summary> /// </summary>
public static int MaxHeight public static int MaxHeight { get; set; } = int.MaxValue;
{
get
{
return maxHeight;
}
set
{
maxHeight = value;
}
}
/// <summary> /// <summary>
/// Gets the image pixels as byte array. /// Gets the image pixels as byte array.
@ -135,21 +103,12 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Gets the pixel ratio made up of the width and height. /// Gets the pixel ratio made up of the width and height.
/// </summary> /// </summary>
public double PixelRatio public double PixelRatio => (double)this.Width / this.Height;
{
get { return (double)this.Width / this.Height; }
}
/// <summary> /// <summary>
/// Gets the <see cref="Rectangle"/> representing the bounds of the image. /// Gets the <see cref="Rectangle"/> representing the bounds of the image.
/// </summary> /// </summary>
public Rectangle Bounds public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height);
{
get
{
return new Rectangle(0, 0, this.Width, this.Height);
}
}
/// <summary> /// <summary>
/// Gets or sets the color of a pixel at the specified position. /// Gets or sets the color of a pixel at the specified position.
@ -170,12 +129,12 @@ namespace ImageProcessor
#if DEBUG #if DEBUG
if ((x < 0) || (x >= this.Width)) if ((x < 0) || (x >= this.Width))
{ {
throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width."); throw new ArgumentOutOfRangeException(nameof(x), "Value cannot be less than zero or greater than the bitmap width.");
} }
if ((y < 0) || (y >= this.Width)) if ((y < 0) || (y >= this.Width))
{ {
throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height.");
} }
#endif #endif
@ -188,12 +147,12 @@ namespace ImageProcessor
#if DEBUG #if DEBUG
if ((x < 0) || (x >= this.Width)) if ((x < 0) || (x >= this.Width))
{ {
throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width."); throw new ArgumentOutOfRangeException(nameof(x), "Value cannot be less than zero or greater than the bitmap width.");
} }
if ((y < 0) || (y >= this.Width)) if ((y < 0) || (y >= this.Width))
{ {
throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height.");
} }
#endif #endif
@ -226,12 +185,12 @@ namespace ImageProcessor
{ {
if (width <= 0) if (width <= 0)
{ {
throw new ArgumentOutOfRangeException("width", "Width must be greater than or equals than zero."); throw new ArgumentOutOfRangeException(nameof(width), "Width must be greater than or equals than zero.");
} }
if (height <= 0) if (height <= 0)
{ {
throw new ArgumentOutOfRangeException("height", "Height must be greater than or equal than zero."); throw new ArgumentOutOfRangeException(nameof(height), "Height must be greater than or equal than zero.");
} }
if (pixels.Length != width * height * 4) if (pixels.Length != width * height * 4)

34
src/ImageProcessor/ImageProperty.cs

@ -22,19 +22,19 @@ namespace ImageProcessor
public struct ImageProperty : IEquatable<ImageProperty> public struct ImageProperty : IEquatable<ImageProperty>
{ {
/// <summary> /// <summary>
/// The name of this <see cref="ImageProperty"/> indicating which kind of /// Gets the name of this <see cref="ImageProperty"/> indicating which kind of
/// information this property stores. /// information this property stores.
/// </summary> /// </summary>
/// <example> /// <example>
/// Typical properties are the author, copyright /// Typical properties are the author, copyright
/// information or other meta information. /// information or other meta information.
/// </example> /// </example>
public string Name; public string Name { get; }
/// <summary> /// <summary>
/// The value of this <see cref="ImageProperty"/>. /// The value of this <see cref="ImageProperty"/>.
/// </summary> /// </summary>
public string Value; public string Value { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageProperty"/> struct. /// Initializes a new instance of the <see cref="ImageProperty"/> struct.
@ -119,7 +119,12 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
return this.GetHashCode(this); unchecked
{
int hashCode = this.Name.GetHashCode();
hashCode = (hashCode * 397) ^ this.Value.GetHashCode();
return hashCode;
}
} }
/// <summary> /// <summary>
@ -130,7 +135,7 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override string ToString() public override string ToString()
{ {
return "{Name=" + this.Name + ",Value=" + this.Value + "}"; return $"ImageProperty [ Name={this.Name}, Value={this.Value} ]";
} }
/// <summary> /// <summary>
@ -144,24 +149,5 @@ namespace ImageProcessor
{ {
return this.Name.Equals(other.Name) && this.Value.Equals(other.Value); return this.Name.Equals(other.Name) && this.Value.Equals(other.Value);
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="imageProperty">
/// The instance of <see cref="ImageProperty"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(ImageProperty imageProperty)
{
unchecked
{
int hashCode = imageProperty.Name.GetHashCode();
hashCode = (hashCode * 397) ^ imageProperty.Value.GetHashCode();
return hashCode;
}
}
} }
} }

52
src/ImageProcessor/Numerics/Point.cs

@ -17,10 +17,25 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Represents an ordered pair of integer x- and y-coordinates that defines a point in /// Represents an ordered pair of integer x- and y-coordinates that defines a point in
/// a two-dimensional plane. /// a two-dimensional plane.
/// </summary> /// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public struct Point : IEquatable<Point> public struct Point : IEquatable<Point>
{ {
/// <summary>
/// Initializes a new instance of the <see cref="Point"/> struct.
/// </summary>
/// <param name="x">The horizontal position of the point.</param>
/// <param name="y">The vertical position of the point.</param>
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
/// <summary> /// <summary>
/// Represents a <see cref="Point"/> that has X and Y values set to zero. /// Represents a <see cref="Point"/> that has X and Y values set to zero.
/// </summary> /// </summary>
@ -29,39 +44,18 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// The x-coordinate of this <see cref="Point"/>. /// The x-coordinate of this <see cref="Point"/>.
/// </summary> /// </summary>
public int X; public int X { get; set; }
/// <summary> /// <summary>
/// The y-coordinate of this <see cref="Point"/>. /// The y-coordinate of this <see cref="Point"/>.
/// </summary> /// </summary>
public int Y; public int Y { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Point"/> struct.
/// </summary>
/// <param name="x">
/// The horizontal position of the point.
/// </param>
/// <param name="y">
/// The vertical position of the point.
/// </param>
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
/// <summary> /// <summary>
/// Gets a value indicating whether this <see cref="Point"/> is empty. /// Gets a value indicating whether this <see cref="Point"/> is empty.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty public bool IsEmpty => this.X == 0 && this.Y == 0;
{
get
{
return this.X == 0 && this.Y == 0;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="Point"/> objects. The result specifies whether the values /// Compares two <see cref="Point"/> objects. The result specifies whether the values
@ -142,7 +136,13 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override string ToString() public override string ToString()
{ {
return "{X=" + this.X.ToString(CultureInfo.CurrentCulture) + ",Y=" + this.Y.ToString(CultureInfo.CurrentCulture) + "}"; if (this.IsEmpty)
{
return "Point [ Empty ]";
}
return
$"Point [ X={this.X.ToString(CultureInfo.CurrentCulture)}, Y={this.Y.ToString(CultureInfo.CurrentCulture)} ]";
} }
/// <summary> /// <summary>

122
src/ImageProcessor/Numerics/Rectangle.cs

@ -17,48 +17,19 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Stores a set of four integers that represent the location and size of a rectangle. /// Stores a set of four integers that represent the location and size of a rectangle.
/// </summary> /// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public struct Rectangle : IEquatable<Rectangle> public struct Rectangle : IEquatable<Rectangle>
{ {
/// <summary>
/// Represents a <see cref="Rectangle"/> that has X, Y, Width, and Height values set to zero.
/// </summary>
public static readonly Rectangle Empty = new Rectangle();
/// <summary>
/// The x-coordinate of this <see cref="Rectangle"/>.
/// </summary>
public int X;
/// <summary>
/// The y-coordinate of this <see cref="Rectangle"/>.
/// </summary>
public int Y;
/// <summary>
/// The width of this <see cref="Rectangle"/>.
/// </summary>
public int Width;
/// <summary>
/// The height of this <see cref="Rectangle"/>.
/// </summary>
public int Height;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rectangle"/> struct. /// Initializes a new instance of the <see cref="Rectangle"/> struct.
/// </summary> /// </summary>
/// <param name="x"> /// <param name="x">The horizontal position of the rectangle.</param>
/// The horizontal position of the rectangle. /// <param name="y">The vertical position of the rectangle.</param>
/// </param> /// <param name="width">The width of the rectangle.</param>
/// <param name="y"> /// <param name="height">The height of the rectangle.</param>
/// The vertical position of the rectangle.
/// </param>
/// <param name="width">
/// The width of the rectangle.
/// </param>
/// <param name="height">
/// The height of the rectangle.
/// </param>
public Rectangle(int x, int y, int width, int height) public Rectangle(int x, int y, int width, int height)
{ {
this.X = x; this.X = x;
@ -84,61 +55,56 @@ namespace ImageProcessor
this.Height = size.Height; this.Height = size.Height;
} }
/// <summary>
/// Represents a <see cref="Rectangle"/> that has X, Y, Width, and Height values set to zero.
/// </summary>
public static readonly Rectangle Empty = new Rectangle();
/// <summary>
/// The x-coordinate of this <see cref="Rectangle"/>.
/// </summary>
public int X { get; set; }
/// <summary>
/// The y-coordinate of this <see cref="Rectangle"/>.
/// </summary>
public int Y { get; set; }
/// <summary>
/// The width of this <see cref="Rectangle"/>.
/// </summary>
public int Width { get; set; }
/// <summary>
/// The height of this <see cref="Rectangle"/>.
/// </summary>
public int Height { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether this <see cref="Rectangle"/> is empty. /// Gets a value indicating whether this <see cref="Rectangle"/> is empty.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty public bool IsEmpty => this.X == 0 && this.Y == 0 && this.Width == 0 && this.Height == 0;
{
get
{
return this.X == 0 && this.Y == 0 && this.Width == 0 && this.Height == 0;
}
}
/// <summary> /// <summary>
/// Gets the y-coordinate of the top edge of this <see cref="Rectangle"/>. /// Gets the y-coordinate of the top edge of this <see cref="Rectangle"/>.
/// </summary> /// </summary>
public int Top public int Top => this.Y;
{
get
{
return this.Y;
}
}
/// <summary> /// <summary>
/// Gets the x-coordinate of the right edge of this <see cref="Rectangle"/>. /// Gets the x-coordinate of the right edge of this <see cref="Rectangle"/>.
/// </summary> /// </summary>
public int Right public int Right => this.X + this.Width;
{
get
{
return this.X + this.Width;
}
}
/// <summary> /// <summary>
/// Gets the y-coordinate of the bottom edge of this <see cref="Rectangle"/>. /// Gets the y-coordinate of the bottom edge of this <see cref="Rectangle"/>.
/// </summary> /// </summary>
public int Bottom public int Bottom => this.Y + this.Height;
{
get
{
return this.Y + this.Height;
}
}
/// <summary> /// <summary>
/// Gets the x-coordinate of the left edge of this <see cref="Rectangle"/>. /// Gets the x-coordinate of the left edge of this <see cref="Rectangle"/>.
/// </summary> /// </summary>
public int Left public int Left => this.X;
{
get
{
return this.X;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="Rectangle"/> objects. The result specifies whether the values /// Compares two <see cref="Rectangle"/> objects. The result specifies whether the values
@ -219,10 +185,14 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override string ToString() public override string ToString()
{ {
return "{X=" + this.X.ToString(CultureInfo.CurrentCulture) if (this.IsEmpty)
+ ",Y=" + this.Y.ToString(CultureInfo.CurrentCulture) {
+ ",Width=" + this.Width.ToString(CultureInfo.CurrentCulture) return "Rectangle [ Empty ]";
+ ",Height=" + this.Height.ToString(CultureInfo.CurrentCulture) + "}"; }
return
$"Rectangle [ X={this.X.ToString(CultureInfo.CurrentCulture)}, Y={this.Y.ToString(CultureInfo.CurrentCulture)}, "
+ $"Width={this.Width.ToString(CultureInfo.CurrentCulture)}, Height={this.Height.ToString(CultureInfo.CurrentCulture)}]";
} }
/// <summary> /// <summary>

51
src/ImageProcessor/Numerics/Size.cs

@ -17,23 +17,12 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Stores an ordered pair of integers, which specify a height and width. /// Stores an ordered pair of integers, which specify a height and width.
/// </summary> /// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public struct Size : IEquatable<Size> public struct Size : IEquatable<Size>
{ {
/// <summary>
/// Represents a <see cref="Size"/> that has Width and Height values set to zero.
/// </summary>
public static readonly Size Empty = new Size();
/// <summary>
/// The width of this <see cref="Size"/>.
/// </summary>
public int Width;
/// <summary>
/// The height of this <see cref="Size"/>.
/// </summary>
public int Height;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Size"/> struct. /// Initializes a new instance of the <see cref="Size"/> struct.
/// </summary> /// </summary>
@ -49,17 +38,26 @@ namespace ImageProcessor
this.Height = height; this.Height = height;
} }
/// <summary>
/// Represents a <see cref="Size"/> that has Width and Height values set to zero.
/// </summary>
public static readonly Size Empty = new Size();
/// <summary>
/// The width of this <see cref="Size"/>.
/// </summary>
public int Width { get; set; }
/// <summary>
/// The height of this <see cref="Size"/>.
/// </summary>
public int Height { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether this <see cref="Size"/> is empty. /// Gets a value indicating whether this <see cref="Size"/> is empty.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] [EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty public bool IsEmpty => this.Width == 0 && this.Height == 0;
{
get
{
return this.Width == 0 && this.Height == 0;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="Size"/> objects. The result specifies whether the values /// Compares two <see cref="Size"/> objects. The result specifies whether the values
@ -137,8 +135,13 @@ namespace ImageProcessor
/// </returns> /// </returns>
public override string ToString() public override string ToString()
{ {
return "{Width=" + this.Width.ToString(CultureInfo.CurrentCulture) if (this.IsEmpty)
+ ",Height=" + this.Height.ToString(CultureInfo.CurrentCulture) + "}"; {
return "Size [ Empty ]";
}
return
$"Size [ Width={this.Width.ToString(CultureInfo.CurrentCulture)}, Height={this.Height.ToString(CultureInfo.CurrentCulture)} ]";
} }
/// <summary> /// <summary>

1
tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs

@ -10,7 +10,6 @@
namespace ImageProcessor.Tests namespace ImageProcessor.Tests
{ {
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Xunit; using Xunit;

Loading…
Cancel
Save